Programmatic Access via Remote PowerShell in Exchange Server 2010
Published Nov 02 2009 07:24 PM 22.3K Views

The management experience given by Exchange 2010 through PowerShell has been moved all the way from Local to Remote. This will mean that enterprise Admins will have to adjust their regular scripts to connect to Remote PowerShell instead of creating a local session.

Here are some examples on how can this be achieved and the differences that may have to be done in order to create the connection and run the cmdlets.

Using programmatic API

The programmatic API is the simplest method that will allow you to make a remote connection requiring only the Uri for the connection and a set of suitable credentials that need to be provided through a method.

SCredential credential = new PSCredential(username, password);

Note: The password here must be of type SecureString.

After you just need to create the connection Information that will allow the creation of the runspace.

// Set the connection Info
    WSManConnectionInfo connectionInfo = new WSManConnectionInfo(
      new Uri(liveIdconnectionUri),
      http://schemas.microsoft.com/powershell/Microsoft.Exchange,
      credential);

    connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;

// create a runspace on a remote path
// the returned instance must be of type RemoteRunspace

Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(connectionInfo);

From here it is just you only need to create a PowerShell instance and fill it with your cmdlets and then invoke it through the run space we've just created. Here is a simple example with get-mailbox.

PowerShell powershell = PowerShell.Create();
      PSCommand command = new PSCommand();
      command.AddCommand("Get-Mailbox");
      command.AddParameter("Identity", mailboxName);
      powershell.Commands = command;
      try
      {
          // open the remote runspace
          runspace.Open();
          // associate the runspace with powershell
          powershell.Runspace = runspace;
          // invoke the powershell to obtain the results
          return powershell.Invoke();
      }
      finally
      {
          // dispose the runspace and enable garbage collection
          runspace.Dispose();
          runspace = null;
          // Finally dispose the powershell and set all variables to null to free
          // up any resources.
          powershell.Dispose();
          powershell = null;
      }

Using Programmatic API and Certificate Thumbprint

This uses the exact same syntax than the Programmatic API except that we would need to connect to a Uri that is has a Certificate Thumbprint enabled when we create the WSMAN connection in this syntax.

WSManConnectionInfo connectionInfo = new WSManConnectionInfo(
              "E75C847ADF7B355DAAC2C6D1A4EDD8284A0C0FDC",
              new Uri(certconnectionUri),
              "http://schemas.microsoft.com/powershell/Microsoft.Exchange");

Remote Request using a local run space (Scripting the remote class)

This is the best to create scripts and run your cmdlets using remote PowerShell. For this case, we have to script in the code a call to create a New-PSSession using our credential, the connection Uri and method of authentication. This is basically using the cmdlet:

New-PSSession -ConnectionUri Microsoft.Exchange -ConnectionUri $Uri -Credential $LiveCred -Authentication Basic

To do this, we have to create the Run space in which we will run the cmdlet and then create a PowerShell instance to add the cmdlet.

Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();
        PowerShell powershell = PowerShell.Create();
        PSCommand command = new PSCommand();
        command.AddCommand("New-PSSession");
        command.AddParameter("ConfigurationName", "Microsoft.Exchange");
        command.AddParameter("ConnectionUri", new Uri(liveIdconnectionUri));
        command.AddParameter("Credential", cred);
        command.AddParameter("Authentication", "Basic");
        powershell.Commands = command;

Now invoke this cmdlet and set it as a variable on the local Run Space that will be used to do the remote calls.

try
     {
         // open the remote runspace
         runspace.Open();
         // associate the runspace with powershell
          powershell.Runspace = runspace;
         // invoke the powershell to obtain the results
         Collection<RemoteRunspaceInfo> result = powershell.Invoke<RemoteRunspaceInfo>();
         foreach (ErrorRecord current in powershell.Streams.Error)
         Console.WriteLine("The following Error happen when opening the remote Runspace: " + current.Exception.ToString() + " | InnerException: " + current.Exception.InnerException);
         if (result.Count != 1)
             throw new Exception("Unexpected number of Remote Runspace connections returned.");
         // Set the runspace as a local variable on the runspace
     powershell = PowerShell.Create();
     command = new PSCommand();
     command.AddCommand("Set-Variable");
     command.AddParameter("Name", "ra");
     command.AddParameter("Value", result[0]);
     powershell.Commands = command;
         powershell.Runspace = runspace;
         powershell.Invoke();

After we have done this, we can now do the remote calls that will be executed on the server side as script blocks.

         powershell = PowerShell.Create();
     command = new PSCommand();
     command.AddScript("Invoke-Command -ScriptBlock { Get-Mailbox -Identity:" + mailboxName + " } -     Session $ra");
     powershell.Commands = command;
     powershell.Runspace = runspace;
         return powershell.Invoke();
     }
     finally
     {
         // dispose the runspace and enable garbage collection
         runspace.Dispose();
         runspace = null;
         // Finally dispose the powershell and set all variables to null to free
         // up any resources.
         powershell.Dispose();
         powershell = null;
     }

- Mario Trigueros Solorio

7 Comments
Version history
Last update:
‎Jul 01 2019 03:47 PM
Updated by: