Question:
I’m working on a C# web service that will be deployed on an Exchange 2013 server. This service will be responsible for running powershell commands to configure Exchange.
I connect via a runspace created like this
1 2 3 4 5 6 7 |
const string shellUri = "http://schemas.microsoft.com/powershell/microsoft.exchange"; var uri = new Uri(_exchangeConnectionUri); var credentials = (PSCredential)null; // Windows authentication var connectionInfo = new WSManConnectionInfo(uri, shellUri, credentials); connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos; var runspace = RunspaceFactory.CreateRunspace(connectionInfo); |
Using this runspace I am able to run basic powershell commands on the server.
1 2 |
get-mailbox -ResultSize unlimited |
But running more complicated commands gives me errors (this does work if run directly through powershell)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
get-mailbox -ResultSize unlimited | where {$_.emailaddresses -like "*test.com"} At line:1 char:43 + get-mailbox -ResultSize unlimited | where {$_.emailaddresses -like "*test.com ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Script block literals are not allowed in restricted language mode or a Data section. At line:1 char:44 + get-mailbox -ResultSize unlimited | where {$_.emailaddresses -like "*test.com ... + ~~~~~~~~~~~~~~~~~ Property references are not allowed in restricted language mode or a Data section. At line:1 char:44 + get-mailbox -ResultSize unlimited | where {$_.emailaddresses -like "*test.com ... + ~~ A variable that cannot be referenced in restricted language mode or a Data section is being referenced. Variables that can be referenced include the following: $PSCulture, $PSUICulture, $true, $false, and $null. |
After searching I found that I might have to register a new PSSessionConfiguration and make sure the scripts are running under PSLanguageMode = FullLanguage. See this post
I tried to do this, but as soon as I change the shellUri to http://schemas.microsoft.com/powershell/MyConfigName
I get the following error.
1 2 3 |
The WS-Management service cannot process the request. Cannot find the MyConfigName session configuration in the WSMan: drive on the ComputerName computer. |
Using the following shelllUri gave me the same error http://schemas.microsoft.com/powershell/Microsoft.Powershell
This led me to try the following directly through powershell on the exchange server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
> Get-PSSessionConfiguration | format-list -property name result: Name : MyConfigName Name : microsoft.powershell Name : microsoft.powershell.workflow Name : microsoft.powershell32 Name : microsoft.windows.servermanagerworkflows > $session = New-PSSession -ConfigurationName MyConfigName -ConnectionUri $uri -Authentication Kerberos result: error "Cannot find the MyConfigName session configuration in the WSMan: drive on the ComputerName computer." > $session = New-PSSession -ConfigurationName Microsoft.Powershell -ConnectionUri $uri -Authentication Kerberos result: error "Cannot find the Microsoft.Powershell session configuration in the WSMan: drive on the ComputerName." > $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $uri -Authentication Kerberos result: nothing, meaning $session variable set correctly |
Like from the C# code, I can only use the Microsoft.Exchange configuration, but this configuration doesn’t exist according to Get-PSSessionConfiguration
, and the configurations that do exist in that list won’t work.
I am now wondering how to add a configuration with FullLanguage that I can use when calling powershell from code.
I might also be completely wrong, and my issue is not related to PSSessionConfigurations at all, but then I still wonder why I can’t see the Microsoft.Exchange configuration anywhere.
Answer:
I ended up getting support from Microsoft and they provided the following solution which works. Instead of connection via a remote powershell session, it is possible to connect to the local powershell and then import the remote session. Doing this fixes the issue.
Error handling not included in example below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
var runspace = RunspaceFactory.CreateRunspace(); runspace.Open(); object psSessionConnection; // Create a powershell session for remote exchange server using (var powershell = PowerShell.Create()) { var command = new PSCommand(); command.AddCommand("New-PSSession"); command.AddParameter("ConfigurationName", "Microsoft.Exchange"); command.AddParameter("ConnectionUri", new Uri(_exchangeConnectionUri)); command.AddParameter("Authentication", "Kerberos"); powershell.Commands = command; powershell.Runspace = runspace; // TODO: Handle errors var result = powershell.Invoke(); psSessionConnection = result[0]; } // Set ExecutionPolicy on the process to unrestricted using (var powershell = PowerShell.Create()) { var command = new PSCommand(); command.AddCommand("Set-ExecutionPolicy"); command.AddParameter("Scope", "Process"); command.AddParameter("ExecutionPolicy", "Unrestricted"); powershell.Commands = command; powershell.Runspace = runspace; powershell.Invoke() } // Import remote exchange session into runspace using (var powershell = PowerShell.Create()) { var command = new PSCommand(); command.AddCommand("Import-PSSession"); command.AddParameter("Session", psSessionConnection); powershell.Commands = command; powershell.Runspace = runspace; powershell.Invoke(); } |