views:

1205

answers:

6

Hello !

I'm running the following code :

RunspaceConfiguration config = RunspaceConfiguration.Create();
PSSnapInException warning;
config.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out warning);
if (warning != null) throw warning;            

Runspace thisRunspace = RunspaceFactory.CreateRunspace(config);
thisRunspace.Open();

string alias = usr.AD.CN.Replace(' ', '.');
string letter = usr.AD.CN.Substring(0, 1);
string email = alias + "@" + (!usr.Mdph ? Constantes.AD_DOMAIN : Constantes.MDPH_DOMAIN) + "." + Constantes.AD_LANG;
string db = "CN=IS-" + letter + ",CN=SG-" + letter + ",CN=InformationStore,CN=" + ((char)letter.ToCharArray()[0] < 'K' ? Constantes.EXC_SRVC : Constantes.EXC_SRVD) + Constantes.EXC_DBMEL;
string cmd = "Enable-Mailbox -Identity \"" + usr.AD.CN + "\" -Alias " + alias + " -PrimarySmtpAddress " + email + " -DisplayName \"" + usr.AD.CN + "\" -Database \"" + db + "\"";
Pipeline thisPipeline = thisRunspace.CreatePipeline(cmd);
thisPipeline.Invoke();

The code is running in a thread created that way :

        t.WorkThread = new Thread(cu.CreerUser);
        t.WorkThread.Start();

If I run the code directly (not through a thread), it's working.

When in a thread it throws the following exception : ObjectDisposedException "The safe handle has been closed." (Translated from french)

I then replaced "Open" wirh "OpenAsync" which helped not getting the previous exception. But when on Invoke I get the following exception : InvalidRunspaceStateException "Unable to call the pipeline because its state of execution is not Opened. Its current state is Opening." (Also translated from french)

I'm clueless...

Any help welcome !!! Thanks !!!

A: 

Can you give us the full stacktrace for the ObjectDisposedException?

x0n
Had to post a full answer since it cas too huge to fit in a comment box... Sorry
Vincent
A: 

With Open:

   à Microsoft.Win32.Win32Native.GetTokenInformation(SafeTokenHandle TokenHandle, UInt32 TokenInformationClass, SafeLocalAllocHandle TokenInformation, UInt32 TokenInformationLength, UInt32& ReturnLength)
   à System.Security.Principal.WindowsIdentity.GetTokenInformation(SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass, UInt32& dwLength)
   à System.Security.Principal.WindowsIdentity.get_User()
   à System.Security.Principal.WindowsIdentity.GetName()
   à System.Security.Principal.WindowsIdentity.get_Name()
   à System.Management.Automation.MshLog.GetLogContext(ExecutionContext executionContext, InvocationInfo invocationInfo, Severity severity)
   à System.Management.Automation.MshLog.GetLogContext(ExecutionContext executionContext, InvocationInfo invocationInfo)
   à System.Management.Automation.MshLog.LogEngineLifecycleEvent(ExecutionContext executionContext, EngineState engineState, InvocationInfo invocationInfo)
   à System.Management.Automation.MshLog.LogEngineLifecycleEvent(ExecutionContext executionContext, EngineState engineState)
   à System.Management.Automation.Runspaces.LocalRunspace.OpenHelper()
   à System.Management.Automation.Runspaces.RunspaceBase.CoreOpen(Boolean syncCall)
   à System.Management.Automation.Runspaces.RunspaceBase.Open()
   à Cg62.ComposantsCommuns.ActiveDirectory.Exchange.BoitesAuxLettres.CreationBAL(User usr, IList`1 log) dans D:\Applications\Commun\Sources  .Net\COMIAD\COMIAD\Exchange.cs:ligne 141
   à Cg62.ComposantsCommuns.ActiveDirectory.ComptesUtilisateurs.CreationUser.CreerUser() dans D:\Applications\Commun\Sources  .Net\COMIAD\COMIAD\ComptesUtilisateurs.cs:ligne 199
   à System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   à System.Threading.ExecutionContext.runTryCode(Object userData)
   à System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   à System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   à System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   à System.Threading.ThreadHelper.ThreadStart()

With OpenAsync:

   à System.Management.Automation.Runspaces.RunspaceBase.AddToRunningPipelineList(PipelineBase pipeline)
   à System.Management.Automation.Runspaces.RunspaceBase.DoConcurrentCheckAndAddToRunningPipelines(PipelineBase pipeline, Boolean syncCall)
   à System.Management.Automation.Runspaces.PipelineBase.CoreInvoke(IEnumerable input, Boolean syncCall)
   à System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input)
   à System.Management.Automation.Runspaces.Pipeline.Invoke()
   à Cg62.ComposantsCommuns.ActiveDirectory.Exchange.BoitesAuxLettres.CreationBAL(User usr, IList`1 log) dans D:\Applications\Commun\Sources  .Net\COMIAD\COMIAD\Exchange.cs:ligne 149
   à Cg62.ComposantsCommuns.ActiveDirectory.ComptesUtilisateurs.CreationUser.CreerUser() dans D:\Applications\Commun\Sources  .Net\COMIAD\COMIAD\ComptesUtilisateurs.cs:ligne 199
   à System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   à System.Threading.ExecutionContext.runTryCode(Object userData)
   à System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   à System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   à System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   à System.Threading.ThreadHelper.ThreadStart()

Sorry for the late reply... I had a lot going on

Vincent
A: 

Upgraded to Powershell 2.0 and I got past the Open error but now I have the following on the Invoke. I changed my command to :

Enable-Mailbox -Identity "Aagtest Abe" -Alias Aagtest.Abe -PrimarySmtpAddress [email protected] -DisplayName "Aagtest Abe" -Database "myDb" -DomainController adc.domain.int

The command works fine from powershell. I get the following exception CmdletInvocationException : "Une exception a été levée par l'initialiseur de type pour '<Module>'." No idea on how to translate that...

StackTrace :

   à Microsoft.Exchange.Data.Directory.DSAccessTopologyProvider..ctor(String machineName)
   à Microsoft.Exchange.Data.Directory.DSAccessTopologyProvider..ctor()
   à Microsoft.Exchange.Data.Directory.DirectoryServicesTopologyProvider.DiscoverConfigDC()
   à Microsoft.Exchange.Data.Directory.DirectoryServicesTopologyProvider..ctor()
   à Microsoft.Exchange.Data.Directory.TopologyProvider.InitializeInstance()
   à Microsoft.Exchange.Data.Directory.TopologyProvider.GetInstance()
   à Microsoft.Exchange.Data.Directory.ADSession.GetConnection(String preferredServer, Boolean isWriteOperation, Boolean isNotifyOperation, ADObjectId& rootId)
   à Microsoft.Exchange.Data.Directory.ADSession.GetReadConnection(String preferredServer, ADObjectId& rootId)
   à Microsoft.Exchange.Data.Directory.ADSession.IsReadConnectionAvailable()
   à Microsoft.Exchange.Configuration.Tasks.RecipientObjectActionTask`2.InternalBeginProcessing()
   à Microsoft.Exchange.Management.RecipientTasks.EnableMailbox.InternalBeginProcessing()
   à Microsoft.Exchange.Configuration.Tasks.Task.BeginProcessing()
   à System.Management.Automation.Cmdlet.DoBeginProcessing()
   à System.Management.Automation.CommandProcessorBase.DoBegin()
Vincent
Vincent did you ever get a answer for this.
scope_creep
Sadly no...I reverted to non-threaded solution...
Vincent
This is probably caused by a custom identity you put on the thread. The Enable-Mailbox cmdlet is executed in another app domain (don't know why). In this case the thread context is serialized to the other app domain and then deserialized. Inside the other app domain your custom identity is unknown so you get this deserialization error: The type initializer for Module threw an exception.
Ronald Wildenberg
A: 

Did you try this?

//set the default runspace for this thread
System.Management.Automation.Runspaces.Runspace.DefaultRunspace = runspace;
A: 

What goes wrong when you call Runspace.Open from another thread is a symptom of the same problem described here. I had the exact same problem in a web project where I started a new thread from the thread that served the request. The new thread eventually called the Enable-Mailbox cmdlet.

The problem in my case was that the web request itself had long finished before the call to Runspace.Open occurred. The web request is associated with a WindowsIdentity that is stored on the thread. The identity is passed to the thread that calls Runspace.Open. However, since the thread that handles the web request finishes before this call, the identity is disposed before the runspace is opened. Somewhere during the Runspace.Open call, an attempt is made to get the security token of the now disposed identity (see the first line in your stacktrace: Microsoft.Win32.Win32Native.GetTokenInformation). This fails with an ObjectDisposedException.

There are two ways to fix this:

  1. Do not call Runspace.Open from another thread. At least not when the calling thread finishes before Runspace.Open is called.
  2. Make sure there is another identity on the thread before you call Runspace.Open. For example, you can do the following:

    Thread.CurrentPrincipal =
        new GenericPrincipal(new GenericIdentity("PSTest"), null)
    

    What you fill in for the name of the GenericIdentity doesn't really matter.

Ronald Wildenberg
A: 

So after well deserved holidays, I'm back on my project. As I tested out other things in it, I had the strangest luck... my code worked ?!

The code uses a singleton to create the powershell object since it's pretty "slow" to initialize and well it's prettier that way anyway.

So when I first call the powershell class from static (I mean not in a thread), it initializes ok and the command works. Then if I stop my project, switch to thread code, it works !!! The singleton still lives and the call from the thread doesn't fail.

I then made a init function I call prior to create my thread and everything works the way it should.

The class I use is the one from from here : http://knicksmith.blogspot.com/2007/03/managing-exchange-2007-recipients-with.html

Vincent
I forgot to tell I had to execute an exchange command in my initialisation otherwise I still would get the error.
Vincent