You can probably find several blog posts out there about remotely executing simple commands and scripts against Exchange servers, but trying to implement these examples on a “real” functional script, can introduce some annoying problems that nobody seems to mention. This was the case when I tried to develop a web page that was supposed to assist with managing a multi-tenant exchange 2010 SP2 environment. I got some startup scripts from Jacob Dixon’s blog and after some minor modifications I was able to execute them locally on the Exchange server without any problems, it was only when I tried to call these scripts from my web page that problems started:
Problem 1: Following a TechNet library post (http://technet.microsoft.com/en-us/library/dd335083), I tried, firstly, to open a remote PowerShell session from a C# application, to the Microsoft.Exchange configuration on a CAS server. I connected successfully but found that the execution context was very limited and restricted as it didn’t even allow assigning PowerShell variables, meaning you almost can’t do any scripting with it.
Problem 2: So I tried connecting to the default PowerShell WSMAN (http://{ServerName}:5985/wsman) and executing the script, only to find that although I have full permissions, when trying to execute an exchange’s command, it asked to provide the server context as it didn’t recognize it executing on an exchange server. I didn’t want to change my scripts, so I didn’t continue with this approach.
Problem 3: So I tried to open a local PowerShell session and from this session I used the Import-Session commandlet to connect to the remote Microsof.Exchange configuration. I connected successfully and had full permissions with the right execution context. However, while re-trying to execute the script I found that the commandlet New-Mailbox doesn’t exist. Quick solution: Executed the “Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010” command and magically the command is available.
Problem 4: Trying again to execute the script, I got a new error: “New-Mailbox : Load balancing failed to find a valid mailbox database.” Ok – so I tried to specify the database explicitly with the –Database argument and got this error: “New-Mailbox : Couldn’t find database “{DB Name}”. Make sure you have typed it correctly. ”. I googled it and found some forums that suggested to make sure the database exists and is mounted, of course my mailbox database did exist and was mounted as the script worked from the local exchange server. So I tried a different approach. I opened a remote PowerShell session to the default PowerShell WSMAN and from that remote session I imported a new session to the Microsoft.Exchange configuration. This approach eliminated the error message and the mailbox was successfully created.
Problem 5: The PS script also included some Active Directory commands for creating a new AD account with the mailbox. This required loading the active directory module. When I tried to import the module I got this warning: Error initializing default drive: ‘Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running.’ Not really a helpful message but googling it I understood that I got into a double hop problem as the AD is installed on a different machine. So I decided to open the first remote session with the CredSSP authentication method (which enables double hops). This wasn’t a trivial task but luckily, Drew has an excellent blog post about this topic (http://werepoint.blogspot.ca/2012/03/setting-up-ps-remoting-for-all-that.html) that helped me to enable it.
Problem 6: After successfully creating a remote PowerShell session with the CredSSP authentication, I tried again to import the active directory module and got “Out of Memory” Exception. To solve this one I executed this command on the remote server: winrm set winrm/config/winrs @{MaxMemoryPerShellMB=”1024″}
Problem 7: Now my script was executing successfully but with all the parameters still hardcoded on the script, when I tried to make it more generic and pass the remote script parameter values from the C# application, I found that I could not use the following code: powershell.Runspace.SessionStateProxy.SetVariable(“{Param name}”, “{Param value}”); As the SessionStateProxy object doesn’t initialize with a remote PowerShell sessions. To overcome this, I changed my code to iterate the parameters and for each, add a “Set-Variable” Command with the relevant values like
foreach (var parameter in parameters) { Command command = new Command("Set-Variable"); command.Parameters.Add("Name", parameter.Key); command.Parameters.Add("Value", parameter.Value); this.powerShell.Commands.AddCommand(command); } this.powerShell.Invoke();
So, after a challenging day I ended up with a basic but complete demo for remotely running a script on Exchange 2010 SP2 server that creates a new Tenant’s mailbox. Hopefully this post will save you some time implementing similar tasks.