C # PowerShell with RunspacePool - How to import Exchange cmdlets like Get-Mailbox?

I am currently creating a Windows service that will execute wenn PowerShell commands that are requested. Lots of requests will be made, so I took the code from: Using Powershell RunspacePool multithreading to remote server from C #

I am not using WSManConnectionInfo, but just doing New-PSSession. See my code at the end of this question.

It looks like it works great for all normal commands, but the one that uses the Exhange cmdlets and imported the PSSession previously. I don't want to import cmdlets every time I run the script, but I don't get the import directly from C #. After calling PowerShell, ErrorStream also notes that the term "Get-Mailbox" is unknown. I don't understand why the import is not working and what I need to do for it.

I worked once, but with only one space. After going to RunspacePool, I was unable to get it to work again.

Any help would be much appreciated.

CODE:

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;
}

      

script in short form:

Param($Session)

Import-PSSession $Session -CommandName Get-Mailbox, Get-MailboxStatistics -ErrorAction SilentlyContinue | Out-Null

Get-Mailbox -ResultSize 5 | SElectObject Name, Alias, ...

      

The script works like this, but when I try to comment out the Import-PSSession part, I get the unknown Get-Mailbox term.

Thanks in advance and best regards Gope

+3


source to share


2 answers


I found a way to make it work. I changed AddScript to AddCommand and used 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();

      



It did the trick ...

0


source


You need to uncomment the ISS stuff. Do something like this:

$iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$iss.ImportPSModule($module)

      

Replace $ module with the name of your Exchange module, or simply fill in this variable with the name of the module.



Then, when you create the RunspacePool, do something like this:

$runspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool($minRunspaces, $maxRunspaces, $iss, $Host)

      

This should make the module available to all spaces created in the space pool.

+2


source







All Articles