Saturday, November 01, 2014

PowerShell + Azure + Exchange - Connect Remotely

My recent dive into the Mobile Device & Email Management space has presented me with an opportunity to learn Exchange & Office 365.

I have built up an Azure VM running Server 2008 R2 with Exchange 2010 Server on it. It didn't made a whole lot of sense to connect to the machine using RDP and then running cmdlets on Exchange Management Shell.

Well I must admit that I tried opening a normal PSSession and importing the Exchange cmdlets in there but that didn't work as the Microsoft.Exchange endpoint configuration is hosted on IIS.

So here are the steps I followed to get the Exchange cmldets via Implicit Remoting, this is very similar to what we do with Office 365. This is a beginner post as am still wrapping my head around Exchange ;)

Open the endpoint on the cloud service to allow the HTTPS traffic to your Exchange Server. Here is how the endpoints appear for my Exchange box.

Note that the Public and Private port are both 443 which means when I try reach my cloud service on port 443 it will essentially redirect the request to my Exchange Box.

If you don't have that endpoint open then you need to use the cmdlet Add-AzureEndpoint to do that.

Another thing we need to do is allow Basic authentication for the \PowerShell virtual directory on the Exchange Server. This is straight forward, open the IIS Manager and click on the Authentication for the Virtual Directory :

Now Right click on the Basic Authentication and "Enable" it.

We can even do this using PowerShell for IIS :)

We are using basic authentication because my machine from which I will try to use Remote PowerShell to connect to my Exchange Server is not part of the domain.

All done, now time to try opening a PSSession to the Exchange Server.

let's store the Credentials in a variable first:

$creds = Get-Credential -Message 'Enter the Exchange Admin Credentials'

Now let's use the New-PSSession cmdlet to connect to the PowerShell endpoint using the connection URI for the cloud service and the Configuration name to which we connect is Microsoft.Exchange.

Note : As already pointed out, we will be using the basic authentication. 

PS>New-PSSession -ConnectionUri '' -ConfigurationName 'Microsoft.Exchange' -Authentication Basic -Credential $creds
New-PSSession : [] Connecting to remote server failed with the
following error message : The server certificate on the destination computer ( has the
following errors:
The SSL certificate is signed by an unknown certificate authority.
The SSL certificate contains a common name (CN) that does not match the hostname. For more information, see the
about_Remote_Troubleshooting Help topic.

Take a look at the Error thrown it clearly tells that the Certificate which is used to connect over SSL (we are using https in the connection uri ) is signed by an unknown CA -- this is evident from the fact that on the Exchange Server the binding for the default site uses the Certificate issued by Exchange Server.

Below is the binding for port 443 on my Exchange Server (on IIS).

Look at the second error telling that the Common Name does not match the hostname of the cloud service used to connect to, makes sense as we are not using the certificate issued to our Cloud Service here but the cert issued by Exchange Server.

So let's use New-PSSessionOption cmdlet to skip the CA & CN check
PS>$PSSessionOption = New-PSSessionOption -SkipCNCheck -SkipCACheck 
PS>New-PSSession -ConnectionUri '' -ConfigurationName 'Microsoft.Exchange' -Credential $creds -SessionOption $PSSessionOption -Authentication Basic

 Id Name            ComputerName    State         ConfigurationName     Availability
 -- ----            ------------    -----         -----------------     ------------
 10 Session10       dexterposhcl... Opened        Microsoft.Exchange       Available

Voila ! I have the Remote PowerShell session established to Exchange. Now time to load the Exchange Module using the Implicit Remoting.

PS>Import-PSSession -Session (Get-PSSession)
WARNING: The names of some imported commands from the module 'tmp_h5mgeuko.1ux' include unapproved verbs that might make
them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with the Verbose
parameter. For a list of approved verbs, type Get-Verb.

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.0        tmp_h5mgeuko.1ux                    {Add-ADPermission, Add-AvailabilityAddressSpace, Add-Content...

It will take some time and once done you will get all the Exchange cmdlets available to you based on your Role.

One more thing if you don't wanna do all the above steps again and again then you can use Export-PSSession to dump the module locally and just import it next time.

Here is how you do it :

PS>Export-PSSession -Session (Get-PSSession) -OutputModule AzureExchange

    Directory: C:\Users\DDhami\Documents\WindowsPowerShell\Modules\AzureExchange

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         11/1/2014   5:04 PM     252399 AzureExchange.format.ps1xml
-a---         11/1/2014   5:04 PM        592 AzureExchange.psd1
-a---         11/1/2014   5:04 PM    1534799 AzureExchange.psm1

This will put a Module name AzureExchange in your Modules directory and next time you Import the module it will prompt you for credentials to enter and then use those to open a PSSession

Thanks for reading fellas. If you have an Exchange Lab up on Azure then do use this tip :)

Now the gotcha with using Implicit Remoting is that I get de-serialized objects back. I remember this from one of the session on Exchange by Sahal Omar for PSBUG.

So on my local machine the below is seen:

While on the Exchange Management Shell , I see this :

I must say that after having worked to automate bits of ConfigMgr with PowerShell, working with Exchange is really Cool. The integration is superb !