Я запускаю следующий код:
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", который помог не получить предыдущее исключение. Но когда в Invoke я получаю следующее исключение: InvalidRunspaceStateException "Невозможно вызвать конвейер, потому что его состояние выполнения не открыто, его текущее состояние -" Открытие ". (Также переведен с французского)
Я не знаю...
Любая помощь приветствуется!!! Спасибо!!!
С 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()
С 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, и я прошел мимо ошибки Open но теперь у меня есть следующее в Invoke. Я изменил свою команду на:
Enable-Mailbox -Identity "Aagtest Abe" -Alias Aagtest.Abe -PrimarySmtpAddress [email protected] -DisplayName "Aagtest Abe" -Database "myDb" -DomainController adc.domain.int
Команда отлично работает от powershell. Я получаю следующее исключение CmdletInvocationException: "Une exception a été levée par l'initialiseur de type pour '<Module> '." Не знаю, как это сделать...
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()
Итак, окончательный ответ на эту проблему заключается в том, что вы не можете выполнять удаленные команды командной строки Exchange, если вы выдаете себя за использование advapi32 LogonUser.
Wether, команды выполняются в потоке или вообще не имеют значения, насколько я проверял.
Кажется, что правильный путь - и тот, который работает для меня, - это аутентификация сразу после подключения к 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();
}
Спасибо, Рональд. Даже если ваш ответ не помог OP, это помогло мне.
У меня возникла проблема, просто пытающаяся запустить что-то в 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;
}
Мне, вероятно, не нужно ставить старого принципала назад, а также, возможно, решить эту проблему, изменив текущий принцип перед созданием потока, о котором идет речь, но спасибо, Рональд: это работает как топ!
Что не так, когда вы вызываете Runspace.Open
из другого потока, является симптомом той же проблемы, описанной здесь. У меня была такая же проблема в веб-проекте, где я начал новый поток из потока, который обслуживал запрос. Новый поток в конечном итоге называется командлетом Enable-Mailbox
.
В моем случае проблема заключалась в том, что сам веб-запрос давно закончился до того, как произошел вызов Runspace.Open
. Веб-запрос связан с WindowsIdentity
, который хранится в потоке. Идентификатор передается потоку, который вызывает Runspace.Open
. Тем не менее, поскольку поток, который обрабатывает веб-запрос, заканчивается перед этим вызовом, идентификатор удаляется до открытия рабочей области. Где-то во время вызова Runspace.Open
предпринимается попытка получить токен безопасности для теперь удаленного идентификатора (см. Первую строку в вашем стеке: Microsoft.Win32.Win32Native.GetTokenInformation
). Это не работает с ObjectDisposedException
.
Есть два способа исправить это:
Runspace.Open
из другого потока. По крайней мере, не тогда, когда вызывающий поток заканчивается до Runspace.Open
.Перед тем, как позвонить Runspace.Open
, убедитесь, что в потоке есть другая личность. Например, вы можете сделать следующее:
Thread.CurrentPrincipal =
new GenericPrincipal(new GenericIdentity("PSTest"), null)
То, что вы заполните для имени GenericIdentity
, действительно не имеет значения.
Вы пробовали это?
//set the default runspace for this thread
System.Management.Automation.Runspaces.Runspace.DefaultRunspace = runspace;