C# PowerShell с RunspacePool - Как импортировать командлеты Exchange, такие как Get-Mailbox?
В настоящее время я создаю Windows-сервис, который будет выполнять команды PowerShell при поступлении некоторых запросов. Будет много запросов, поэтому я принял код из: Использование многопоточного Powershell RunspacePool на удаленный сервер из C#
Я не использую WSManConnectionInfo, но просто делаю New-PSSession. Смотрите мой код в конце этого вопроса.
Похоже, это прекрасно работает для всех обычных команд, кроме той, которая использует командлеты Exhange и ранее выполняла Import-PSSession. Я не хочу импортировать командлеты каждый раз, когда запускается скрипт, но я не получаю правильный импорт из C#. После вызова PowerShell ErrorStream также отмечает, что термин "Get-Mailbox" неизвестен. Я не понимаю, почему импорт не работает и что мне нужно для этого сделать.
Я работал на этот раз, но только с одним пространством. После перехода на RunspacePool я не смог заставить его работать снова.
Любая помощь будет высоко оценен.
КОД:
static void Main(string[] args)
{
string connectionUri = "https://.../Powershell";
string userName = @"...\...";
string password = "...";
System.Uri uri = new Uri(connectionUri);
System.Security.SecureString securePassword = String2SecureString(password);
System.Management.Automation.PSCredential creds = new System.Management.Automation.PSCredential(userName, securePassword);
//InitialSessionState iss = InitialSessionState.CreateDefault();
//iss.ImportPSModule(new[] { "Get-Mailbox", "Get-MailboxStatistics" });
RunspacePool runspacePool = RunspaceFactory.CreateRunspacePool();
runspacePool.ThreadOptions = PSThreadOptions.UseNewThread;
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand(string.Format("New-PSSession"));
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("ConnectionUri", uri);
command.AddParameter("Credential", creds);
command.AddParameter("Authentication", "Basic");
command.AddParameter("AllowRedirection");
// IS THIS NEEDED?
PSSessionOption sessionOption = new PSSessionOption();
sessionOption.SkipCACheck = true;
sessionOption.SkipCNCheck = true;
sessionOption.SkipRevocationCheck = true;
command.AddParameter("SessionOption", sessionOption);
powershell.Commands = command;
runspacePool.Open();
powershell.RunspacePool = runspacePool;
Collection<PSSession> result = powershell.Invoke<PSSession>();
foreach (ErrorRecord current in powershell.Streams.Error)
{
Console.WriteLine("Exception: " + current.Exception.ToString());
Console.WriteLine("Inner Exception: " + current.Exception.InnerException);
}
// Returns the session
if (result.Count != 1)
throw new Exception("Unexpected number of Remote Runspace connections returned.");
// THATS THE PART NOT WORKING
// First import the cmdlets in the current runspace (using Import-PSSession)
powershell = PowerShell.Create();
command = new PSCommand();
command.AddScript("Import-PSSession $Session -CommandName Get-Mailbox, Get-MailboxStatistics -AllowClobber -WarningAction SilentlyContinue -ErrorAction Stop -DisableNameChecking | Out-Null");
command.AddParameter("Session", result[0]);
// This is also strange... without the RunspaceInvoke I always get a SecurityException...
RunspaceInvoke scriptInvoker = new RunspaceInvoke();
scriptInvoker.Invoke("Set-ExecutionPolicy -Scope Process Unrestricted");
var tasks = new List<Task>();
for (var i = 0; i < 3; i++)
{
var taskID = i;
var ps = PowerShell.Create();
ps.RunspacePool = runspacePool;
PSCommand cmd = new PSCommand();
cmd.AddCommand(@".\PSScript1.ps1");
//cmd.AddScript("Get-Mailbox -ResultSize 5");
cmd.AddParameter("Session", result[0]);
ps.Commands = cmd;
var task = Task<PSDataCollection<PSObject>>.Factory.FromAsync(
ps.BeginInvoke(), r => ps.EndInvoke(r));
System.Diagnostics.Debug.WriteLine(
string.Format("Task {0} created", task.Id));
task.ContinueWith(t => System.Diagnostics.Debug.WriteLine(
string.Format("Task {0} completed", t.Id)),
TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(t => System.Diagnostics.Debug.WriteLine(
string.Format("Task {0} faulted ({1} {2})", t.Id,
t.Exception.InnerExceptions.Count,
t.Exception.InnerException.Message)),
TaskContinuationOptions.OnlyOnFaulted);
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}
private static SecureString String2SecureString(string password)
{
SecureString remotePassword = new SecureString();
for (int i = 0; i < password.Length; i++)
remotePassword.AppendChar(password[i]);
return remotePassword;
}
Сценарий в краткой форме:
Param($Session)
Import-PSSession $Session -CommandName Get-Mailbox, Get-MailboxStatistics -ErrorAction SilentlyContinue | Out-Null
Get-Mailbox -ResultSize 5 | SElectObject Name, Alias, ...
Скрипт работает так, но когда я пытаюсь закомментировать часть Import-PSSession, я получаю неизвестный термин Get-Mailbox error.
Спасибо заранее и наилучшими пожеланиями Gope
2 ответа
Я нашел способ заставить это работать, это кажется. Я изменил AddScript на AddCommand и использовал AddParameter.
// First import the cmdlets in the current runspace (using Import-PSSession)
powershell = PowerShell.Create();
powerShell.RunspacePool = runspacePool;
command = new PSCommand();
command.AddScript("Import-PSSession");
command.AddParameter("Session", result[0]);
command.AddParameter("CommandName", new[]{"Get-Mailbox", "Get-MailboxStatistics"});
command.AddParameter("ErrorAction ", "SilentlyContinue ");
powerShell.Invoke();
Это сделало трюк...
Вам нужно раскомментировать материал с МКС. Сделайте что-то вроде этого:
$iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$iss.ImportPSModule($module)
Замените $module именем модуля Exchange или просто заполните переменную именем модуля.
Затем при создании RunspacePool сделайте что-то вроде этого:
$runspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool($minRunspaces, $maxRunspaces, $iss, $Host)
Это должно сделать модуль доступным для всех пространств выполнения, созданных из пула пространств выполнения.