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
Not applicable
Hi, I am in the process of creating a project around remoting via Powershell from 2008 C#/VB using powershell 2.0 & WinRM 2.0 from a Windows Server 2008 SP2 machine. I have added the system.management.automation reference, but I am unable expose the RemoteRunspaceInfo class and my code therefore fails.  I cannot seem to expose in the fashion listed in the example above. Can you provide more information around which this class.
Not applicable
The sticking point for me seems to be the liveIdConnectionUri... what should be there? I'm using an Exchange 2010 installation that is not federated... should I point to

https://login.live.com?


Not applicable
when executed a powershell 2.0 command using vb.net to add mailbox to MS Exchange 2010 having WinRM client and server machines as same machine, i encountered the following error.



"The WinRM client cannot process the request. The authentication mechanism requested by the client is not supported by the server or unencrypted traffic is disabled in the service configuration. Verify the unencrypted traffic setting in the service configuration or specify one of the authentication mechanisms supported by the server. To use Kerberos, specify the computer name as the remote destination. Also verify that the client computer and the destination computer are joined to a domain. To use Basic, specify the computer name as the remote destination, specify Basic authentication and provide user name and password. Possible authentication mechanisms reported by server: For more information, see the about_Remote_Troubleshooting Help topic."



Environment i am using is

Windows Server 2008 R2 64-bit

MS Exchange 2010

PowerShell V2.0
Not applicable
Hi ,

i executed following code to get MailBoxDatabase  

Dim Pass As New System.Security.SecureString
       Dim MyPassword As String = Password
       For Each c As Char In MyPassword
           Pass.AppendChar(c)
       Next

       Dim credential As PSCredential = New PSCredential(UserName, Pass)


       Dim connectionInfo As New WSManConnectionInfo(New Uri("http://" & FQDN & "/powershell?serializationLevel=Full"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credential)

       connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos

       Dim RSpace As Runspace
       Try
           RSpace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(connectionInfo)
           
       Catch ex As Exception
           Throw New Exception("RSPACE: " & ex.Message)
       End Try
 

 Dim Shell As PowerShell = PowerShell.Create()
       Dim PCommand As New PSCommand


       Try
           PCommand.AddCommand("Get-MailboxDatabase")
           PCommand.AddParameter("Server", New Microsoft.Exchange.Configuration.Tasks.ServerIdParameter(New Microsoft.Exchange.Data.Fqdn(ServerName)))

           ' PCommand.AddParameter("DomainController", PreferredDC)

           Shell.Commands = PCommand
       Catch ex As Exception
           Throw New Exception("Build command: " & ex.Message)
       End Try
       
       Dim results As Collection(Of PSObject)
       Dim Msg As String
       Dim Databases As String
       Try
           RSpace.Open()
           Shell.Runspace = RSpace
           results = Shell.Invoke()

           Dim Enm As System.Collections.Generic.IEnumerator(Of System.Management.Automation.PSObject) = results.GetEnumerator
           Dim index As Integer = 0
           Do While Enm.MoveNext()


               Databases = Enm.Current.Members("Identity").Value.ToString '& "" & Enm.Current.Members("AdminDisplayName").Value.ToString
           
           Loop

           RSpace.Close()



       Catch err As Exception
           Throw New Exception("Run command: " & err.Message)
       Finally
           RSpace.Dispose()
           RSpace = Nothing
           Shell.Dispose()
           Shell = Nothing
       End Try

and encountered the following error.
Cannot process argument transformation on parameter 'Server'. Cannot convert the "Clients.exmtemp.com" value of type "Deserialized.Microsoft.Exchange.Configuration.Tasks.ServerIdParameter" to type "Microsoft.Exchange.Configuration.Tasks.ServerIdParameter".

any help regarding above issue will be appreciated.
Thanks in Advance.

Best Regards,

cute devil
Not applicable
How can I write a code that recognize the exchange powershell and the basic powershell?

I mean:
get-mailbox | Format-list

Format-list is not recognized as a powershell command, when I use the constructor with the credential!!
Not applicable
What should the liveIdconnectionUri be in
   WSManConnectionInfo connectionInfo = new WSManConnectionInfo(
     new Uri(liveIdconnectionUri),
     "http://schemas.microsoft.com/powershell/Microsoft.Exchange",
     credential);
Not applicable
looks like liveIdConnectionUri should be

https://ps.outlook.com/powershell/



found it here:

http://help.outlook.com/en-us/140/cc713521.aspx#ScriptOptions

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