2009-06-18 18 views
2

:コードがスレッドで実行されているのPowerShell /実行空間私は、次のコードを実行している

がそのように作成した

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(); 

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

私は、コードを直接実行する場合(いませんスレッドを介して)、それは働いている。

スレッドでは、次の例外がスローされます。ObjectDisposedException "安全ハンドルが閉じられました。"

私は、以前の例外を得られなかった "Open" wirh "OpenAsync"を置き換えました。 しかし、呼び出し時に次の例外が発生します:InvalidRunspaceStateException "実行状態が開かれていないためパイプラインを呼び出すことができません。現在の状態はオープニングです。" (また、フランス語から翻訳)

私は無知だ...

任意のヘルプを歓迎! ありがとうございます!

開く

à 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() 

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() 

返事が遅れて申し訳ありません...私はにアップグレード


に行くたくさんありましたPowershell 2.0と私はオープンエラーを通過しましたしかし、今私はInvoke上で次のようにしています。 私はに私のコマンドを変更:

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

コマンドは、PowerShellのから正常に動作します。 次の例外が発生しました。CmdletInvocationException: "初期例外の型が初期値の型になりました。<モジュール> ' それを翻訳する方法については考え...

の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() 
+1

私は同じ問題を抱えています。あなたは答えを受け取ったことがありますか?この問題は、2年間にわたって正常に動作していたコード(Windows Vista、Windows 7およびWindows Server 2003でテスト済み)に現れます。しかし、Windows Server 2008に導入して以来、このエラーが発生しています。 –

答えて

2

したがって、advapi32 LogonUserで偽装した場合、リモートExchange powershellコマンドを実行できないという問題があります。

命令はスレッドで実行されるかどうかは、テストした限りでは全く問題にはなりません。

正しい方法であるように思えます - 私にとってはうまくいく方法 - は、Runspaceに接続した直後に認証することです。

なぜこのようなことが起こったかについては、教えてください。

このコードは、偽装中にを実行してはいけません。

 IContexteRemotePowerShell crp: 
     crp.ConfigurationName = "Microsoft.Exchange"; 
     crp.RemoteUri = "http://exhangeserver/powershell"; 
     crp.User = "account who has rights to do stuff on the exchange server"; 
     crp.Password = "its password"; 
     crp.Domaine = "Domain"; 


private static void Connect(IContexteRemotePowerShell contexte) 
    { 
     try 
     { 
      Espace = RunspaceFactory.CreateRunspace(); 
      Espace.Open(); 
     } 
     catch (InvalidRunspaceStateException ex) 
     { 
      throw new TechniqueException(MethodBase.GetCurrentMethod(), "Error while creating runspace.", ex); 
     } 

     // Create secure password 
     SecureString password = new SecureString(); 
     foreach (char c in contexte.Password) 
     { 
      password.AppendChar(c); 
     } 

     // Create credential 
     PSCredential psc = new PSCredential(contexte.User, password); 

     PSCommand command = new PSCommand(); 
     command.AddCommand("New-PSSession"); 
     command.AddParameter("Credential", psc); 

     if (!String.IsNullOrEmpty(contexte.Serveur)) 
      command.AddParameter("computername", contexte.Serveur); 
     if (!String.IsNullOrEmpty(contexte.RemoteUri)) 
      command.AddParameter("ConnectionUri", new Uri(contexte.RemoteUri)); 
     if (!string.IsNullOrEmpty(contexte.ConfigurationName)) 
      command.AddParameter("ConfigurationName", contexte.ConfigurationName); 

     //// Create the session 
     PowerShell powershell = PowerShell.Create(); 
     powershell.Commands = command; 
     powershell.Runspace = Espace; 
     Collection<PSObject> result = ExecuterCommande(command); 

     if (result.Count != 1) 
      throw new TechniqueException(MethodBase.GetCurrentMethod(), 
              "Error while connecting."); 

     // Create session variable 
     command = new PSCommand(); 
     command.AddCommand("Set-Variable"); 
     command.AddParameter("Name", "ra"); 
     command.AddParameter("Value", result[0]); 
     ExecuterCommande(command); 
    } 

private const string InvokeCommand = "Invoke-Command -ScriptBlock {{ {0} }} -Session $ra"; 

    private static string ExecuteRemoteScript(string cmd) 
    { 
     PSCommand command = new PSCommand(); 
     command.AddScript(string.Format(InvokeCommand, cmd)); 
     Collection<PSObject> result = ExecuterCommande(command); 

     StringBuilder sb = new StringBuilder(); 
     foreach (PSObject obj in result) 
     { 
      sb.AppendLine(obj.ToString()); 
     } 
     return sb.ToString().Trim(); 
    } 
1

あなたはこれを試してみましたか?

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

あなたは別のスレッドからRunspace.Openを呼び出したときにうまくいかないことは同じ問題hereを説明する症状です。私は、Webプロジェクトで全く同じ問題を抱えていました。ここで、リクエストに対応したスレッドから新しいスレッドを開始しました。新しいスレッドは最終的にEnable-Mailboxコマンドレットと呼ばれました。

私の場合の問題は、Runspace.Openへの呼び出しが発生する前に、Web要求自体が長く完了していたことでした。ウェブリクエストは、スレッドに格納されているWindowsIdentityに関連付けられています。 IDはRunspace.Openを呼び出すスレッドに渡されます。ただし、この呼び出しの前にWeb要求を処理するスレッドが終了するため、アイデンティティは実行領域が開かれる前に破棄されます。Runspace.Openの呼び出し中に、現在廃棄されているIDのセキュリティトークンを取得しようとします(スタックトレースの最初の行:Microsoft.Win32.Win32Native.GetTokenInformationを参照)。これは、ObjectDisposedExceptionで失敗します。

これを修正するには、2つの方法があります。

  1. は別のスレッドからRunspace.Openを呼び出さないでください。少なくとも、呼び出しスレッドが終了してからRunspace.Openが呼び出されるまでは、
  2. Runspace.Openを呼び出す前にスレッドに別のIDがあることを確認してください。たとえば、次の操作を行うことができますあなたは本当に重要ではありませんGenericIdentityの名前を記入何

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

1

ありがとう、ロナルド。あなたの答えがOPを助けなかったとしても、それは私を助けました。

Webサーバー上のAppDomainで何かを起動しようとすると問題が発生しました。右の行に:

ObjectHandle handle = domain.CreateInstance(_assemblyName, _className); 

...それは説明ObjectDisposedExceptionで爆発しました。私は私の人生のためにそれを理解することができませんでした - AppDomainの何も処分されていなかった、これは他のサーバーで動作しているようでした。

私は逆アセンブリを踏み出し、スレッド実行コンテキスト、それに含まれる論理呼び出しコンテキスト、およびそれに含まれるプリンシパルをシリアル化しようとしていました。プリンシパルはそれが展開したものです。

ユーザーがログオンしたときにこのスレッドが実行され、IISが「偽装」モードであったため、スレッドの現在のプリンシパルが元のユーザーの期限切れプリンシパルになっていたことが判明しました。

私は、コードの周りにこれを置く:

IPrincipal oldPrincipal = Thread.CurrentPrincipal; 
try 
{ 
    Thread.CurrentPrincipal = new GenericPrincipal(
     new GenericIdentity("NetPlugins"), null); 
    ObjectHandle handle = domain.CreateInstance(_assemblyName, _className); 
    // unwrapping and calling code omitted 
} 
finally 
{ 
    Thread.CurrentPrincipal = oldPrincipal; 
} 

は、私はおそらく戻って古い校長を置く必要はなく、また、おそらく問題のスレッドを作成する前に、現在のプリンシパルを変更することでこの問題を解決できますが、あなたに感謝し、 Ronald:これはトップのように機能します!