Creating an Exchange 2010 Mailbox from a remote C# program
On this post, I’ll show you how to create an Exchange Mailbox from a C# program that is not running on the Exchange Server (a client program). What C# is really doing is remotely executing Exchange PowerShell cmdlets.
If this is the first time you’re attempting to run Exchange cmdlets from C#, you probably want to follow this blog post to make sure things are set up properly on the server and that C# can run Exchange cmdlets when running from the server.
This is the client’s code. But it doesn’t “just work”, you need to complete the setup instructions on this post.
using System;
using System.Security;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
namespace PowerShellTest
{
class Program
{
static void Main(string[] args)
{
// Prepare the credentials that will be used when connecting
// to the server. More info on the user to use on the notes
// below this code snippet.
string runasUsername = @"username";
string runasPassword = "password";
SecureString ssRunasPassword = new SecureString();
foreach (char x in runasPassword)
ssRunasPassword.AppendChar(x);
PSCredential credentials =
new PSCredential(runasUsername, ssRunasPassword);
// Prepare the connection
var connInfo = new WSManConnectionInfo(
new Uri("http://ServersIpAddress/PowerShell"),
"http://schemas.microsoft.com/powershell/Microsoft.Exchange",
credentials);
connInfo.AuthenticationMechanism =
AuthenticationMechanism.Basic;
// Create the runspace where the command will be executed
var runspace = RunspaceFactory.CreateRunspace(connInfo);
// generate the command parameters
var testNumber = 18;
var firstName = "Test";
var lastName = "User" + testNumber;
var username = "tuser" + testNumber;
var domainName = "pedro.test.local";
var password = "ActiveDirectoryPassword1234";
var ssPassword = new SecureString();
foreach (char c in password)
ssPassword.AppendChar(c);
// create the PowerShell command
var command = new Command("New-Mailbox");
command.Parameters.Add("Name", firstName + " " + lastName);
command.Parameters.Add("Alias", username);
command.Parameters.Add(
"UserPrincipalName", username + "@" + domainName);
command.Parameters.Add("SamAccountName", username);
command.Parameters.Add("FirstName", firstName);
command.Parameters.Add("LastName", lastName);
command.Parameters.Add("Password", ssPassword);
command.Parameters.Add("ResetPasswordOnNextLogon", false);
command.Parameters.Add(
"OrganizationalUnit", "NeumontStudents");
// Add the command to the runspace's pipeline
runspace.Open();
var pipeline = runspace.CreatePipeline();
pipeline.Commands.Add(command);
// Execute the command
var results = pipeline.Invoke();
runspace.Dispose();
if (results.Count > 0)
Console.WriteLine("SUCCESS");
else
Console.WriteLine("FAIL");
}
}
}
Some important things to notice on the code:
- The “runas” user must:
- Belong to a Role Group that has Mail Recipient Creation rights. To do this, make the runas user belong to the “Recipient Management” Role Goup by going to “Exchange Management Console > Microsoft Exchange > Microsoft Exchange On-Premises > Toolbox > Role Based Access Control (RBAC) User Editor”.
- Must have Remote PowerShell rights. Do this by going to the Exchange Management Shell and running the following cmdlet: Set-User UserNameHere -RemotePowerShellEnabled:$true
- It works using Basic authentication, which means that the “runas” credentials are being sent in clear text over the network. This is ok if you trust the network (which is my case because it never leaves the server room) or if you set up SSL.
- Because of the parameters sent to the New-Mailbox cmdlet, besides creating an Exchange mailbox, I’m also creating an Active Directory user.
You need to configure WinRM on the client to:
- Allow unencrypted traffic
- Trust the remote machine
The easiest way to to this is via the Local Group Policy user interface. To access it, hit the windows start button, type run, run the “run” program, this opens the famous “run” window (which is wired to the Windows Key + R shortcut), on the run window enter gpedit.msc . You’re now looking at the Local Group Policy user interface. In the tree view go to “Local Computer Policy > Computer Configuration > Administrative Templates > Windows Components > Windows Remote Management (WinRM) > WinRM Client” and configure the previously listed items.
If you don’t configure the WinRM client, you’ll get these exceptions:
System.Management.Automation.Remoting.PSRemotingTransportException was unhandled Message=Connecting to remote server failed with the following error message : The WinRM client cannot process the request. Unencrypted traffic is currently disabled in the client configuration. Change the client configuration and try the request again. For more information, see the about_Remote_Troubleshooting Help topic. Source=System.Management.Automation WasThrownFromThrowStatement=false ErrorCode=-2144108322 TransportMessage=The WinRM client cannot process the request. Unencrypted traffic is currently disabled in the client configuration. Change the client configuration and try the request again.
System.Management.Automation.Remoting.PSRemotingTransportException was unhandled Message=Connecting to remote server failed with the following error message : The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. You can get more information about that by running the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic. Source=System.Management.Automation WasThrownFromThrowStatement=false ErrorCode=-2144108316 TransportMessage=The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. You can get more information about that by running the following command: winrm help config.
On the server, you must configure the PowerShell IIS virtual directory to:
- Not Require SSL
- Allow Basic Authentication
To not require SSL, you simply go to “IIS Manager > Sites > Default Website > Powershell”, then select the “SSL Settings” feature and make sure “Require SSL” is not checked.
To allow Basic Authentication you go again to “IIS Manager > Sites > Default Website > Powershell”, this time select the “Authentication” feature and enable “Basic Authentication”.
If Basic Authentication is not an option on the Authentication feature page, you need to install it by going to the Server Manager, select the Web Server role, say “Add Role Services”, under the Security node in the treeview, select Basic Authentication.
You’re all set! Running the C# code on a remote machine should work.



Running Exchange 2010 Management Shell Commands (PowerShell) with C# « Pedro Liska's Blog said,
July 28, 2011 at 10:39 am
[...] If what you want to do is execute the C# code on a client machine that executes cmdlets on the Exchange server, check out this post. [...]
Nicolas said,
November 21, 2011 at 1:00 pm
Hi there,
very useful post you wrote here. Got one question:
Can you, and if yes how, create a mailbox on Exchange using an existing Active Directory user?
Thanks
Pedro Liska said,
November 21, 2011 at 1:07 pm
I never tested that but I’m sure there is a way. If the New-Mailbox cmdlet does not do it, try Enable-Mailbox .
Nicolas said,
December 15, 2011 at 1:46 pm
Im testing this now, so fare the Enable-Mailbox fails. Will keep trying and post back.
Btw, I have to add new permissions to the user:
New-ManagementRoleAssignment -Role “Mail Recipients” -User username
Nicolas said,
December 15, 2011 at 1:54 pm
It worked! I guess I had permission issues before, but I was able to use Enable-Mailbox for an existent AD user.
zura said,
November 29, 2011 at 6:01 am
i have this error
” Connecting to remote server failed with the following error message : The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. You can get more information about that by running the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic. “
Pedro Liska said,
November 30, 2011 at 9:13 am
please read the “If you don’t configure the WinRM client, you’ll get these exceptions” section of my blog post.
zura said,
December 2, 2011 at 5:04 am
Is written correctly?
var connInfo = new WSManConnectionInfo(new Uri(“http://server ip address/’C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe’”),
“http://schemas.microsoft.com/powershell/Microsoft.Exchange”, credentials);
WinRM client I did same as you had in your blog post
Pedro Liska said,
December 2, 2011 at 7:51 am
Well, the first parameter when you create the connection does not look right: “http://server ip address/’C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe”. It should be “http://ServersIpAddress/PowerShell” where the ServersIpAddress is the IP address you added to the TrustedHosts .
The error is clear that this is a problem on the client side so don’t bother tweaking anything on the server until you make this go away.
I had to play for hours with my client and server configuration to get things working on my environment. Good luck!
Nicolas said,
December 14, 2011 at 7:13 pm
Hi Pedro, Ive tried to run the program but im getting this error:
“”"
Unhandled Exception: System.Management.Automation.RemoteException: The term ‘New-Mailbox’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
at System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke(IEnumerable input, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke(IEnumerable input)
at System.Management.Automation.RemotePipeline.Invoke(IEnumerable input)
at System.Management.Automation.Runspaces.Pipeline.Invoke()
at PowerShell.Program.Main(String[] args) in Program.cs:line 66
“”"
What can be the problem?
Thanks
Nicolas said,
December 14, 2011 at 7:45 pm
got it working, was a permission issue
solved with:
New-ManagementRoleAssignment –Role “Mail Recipient Creation” –User domain\user
Pedro Liska said,
December 14, 2011 at 7:51 pm
Great! And thanks for posting the solution!
sathis said,
January 26, 2012 at 10:02 am
Hi Pedro,
Great blog awesome. !
Do you have any sample code to remote c# program exchange 2007 ?.
Pedro Liska said,
January 26, 2012 at 10:22 am
I don’t =(. And I think exchange 2007 does not have enough PowerShell support to do things like described on this post.
Chandra said,
May 24, 2012 at 2:20 pm
Awesome. Great. Just what I was looking for. I had the code ready but was getting frustrated with the errors. Thanks to your blog, I can sleep well tonight.
Sheila Wu said,
July 11, 2012 at 2:49 pm
I have done every steps in your post but I still no luck to make it work. It still complains “Connecting to remote server failed with the following error message : The WinRM client cannot process the request. Unencrypted traffic is currently disabled in the client configuration. Change the client configuration and try the request again. For more information, see the about_Remote_Troubleshooting Help topic.”
Thanks,
Pedro Liska said,
July 11, 2012 at 3:50 pm
If you have Allow unencrypted traffic and added the remote machine to the trusted hosts, it should work. Are you sure you set up the trusted hosts properly? I know it works if you put the server’s ip address in there.
One more thing you can do is verify that there are no firewalls blocking the communication. To do this I like to telnet the server from the client on the desired port. I can’t remember which port is used by all of this though. Was it just over port 80?
Sheila Wu said,
July 12, 2012 at 8:24 am
I tried to use winrm id -r:”My exchange server ip address”, I got this error:
WSManFault
Message = The WinRM client cannot process the request. Default authentication may be used with an IP address under t
he following conditions: the transport is HTTPS or the destination is in the TrustedHosts list, and explicit credentials
are provided. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authen
ticated. For more information on how to set TrustedHosts run the following command: winrm help config.
Error number: -2144108101 0x803381BB
The WinRM client cannot process the request. Default authentication may be used with an IP address under the following c
onditions: the transport is HTTPS or the destination is in the TrustedHosts list, and explicit credentials are provided.
Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. For m
ore information on how to set TrustedHosts run the following command: winrm help config.
Should I do something on the remote server?
Thanks,
Pedro Liska said,
July 12, 2012 at 9:39 am
It sounds like the client is not even sending out the request to the server. I think the problem is on the client side right now. Did you add the server’s IP address to the trusted hosts list? This list is on the client machine.
Sheila Wu said,
July 11, 2012 at 2:57 pm
Sorry. I got the error like this:Connecting to remote server failed with the following error message : The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. You can get more information about that by running the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic.
Thanks,
Pedro Liska said,
July 11, 2012 at 3:51 pm
Well, try to follow the directions specified in the error. That will probably fix it.
Chandra said,
July 12, 2012 at 9:47 am
Well…I had a similar problem. I later found out that I was not using the correct IP address. Please double check.
Sheila Wu said,
July 12, 2012 at 9:56 am
Well. I did check and add the correct server’s ip address. I checked the winrm config and the address looks like:
5985
5986
1.2.3.5
Any possible those ports have been blocked by firewall in the server?
Thanks,
Pedro Liska said,
July 12, 2012 at 10:52 am
To debug firewall issues I use telnet. I know this is not the purpose of the telnet client but with telnet you receive different responses if ANYTHING is listening on the specified server’s port or if it is blocked by a firewall.
You usually get a “connection error” if it is blocked by a firewall. And you get a prompt if the connection is successful.
I would try going to the command prompt on the client and typing “telnet 1.2.3.5 5985″. Also experiment with telnet to see how it behaves with other sites. Enter stuff like “telnet google.com 80″ , on this you get a prompt right away. If you enter “telnet google.com 80888″ it hangs, this means nothing is listening on 80888 or a firewall is blocking you.
Sheila Wu said,
July 12, 2012 at 12:20 pm
Yes. this port has been blocked by firewall. I will test it again once this port has been opened.
Thanks,
Sheila Wu said,
August 23, 2012 at 8:42 am
I think the port is opend. Now I get an error like “Connecting to remote server failed with the following error message : Access is denied. For more information, see the about_Remote_Troubleshooting Help topic.”
It looks like I don’t have right to access the remote server. I checked the user right and it is a domain administrator and I can this account to login the remote exchange server and no problem at all.
I checked this account rights: It has Organization management, Recipient management and server management.
It is working if I use enter-pssession remote server.
I am not what else I need to do to solve this problem.
Any help will be appreciated,
Thanks,
Sheila Wu said,
September 7, 2012 at 7:05 am
I finally got everything working. It was a permission problem.
I used the user name “xxxx” instead of “domain\xxxx”. That’s the problem was.
Thanks!
Pedro Liska said,
September 7, 2012 at 8:24 am
I’m glad it works Sheila!
Ray said,
August 29, 2012 at 10:16 am
Hi, I have used your directions and am executing the code on the exchange server (local) with admin permissions, but I still recieve an error like “serversettings cannot be null”. Any cluse as to what I’m missing?. The only line that I have added apart from your script is command.Parameters.Add( “database”,”ABC-xyz”).
This DB does exist and is being used.
fredflint said,
October 19, 2012 at 3:01 pm
Thank you for putting this code up. I’ve worked through the configuration of the ports, WinRM etc for other tasks so this suited me just fine.
Cory said,
February 28, 2013 at 2:18 pm
So when run this way, I’m unable to pipeline exchange 2010 commands into standard powershell commands.
In other words, “Get-Mailbox foo” works. But I can’t pipeline it into standard powershell cmdlets like “Format-List”:
The term ‘format-list’ is not recognized as the name of a cmdlet, function, script file, or operable program.
I could understand if I were just using the standard powershell shell URI and I couldn’t use Exchange cmdlets, but the reverse seems ridiculous.
Karel said,
April 24, 2013 at 12:54 am
Hi, I have checked everything in your post, but when I’m executing the code, I always get the error:
“Connecting to remote server failed with the following error message : Access is denied. For more information, see the about_Remote_Troubleshooting Help topic.” My runas user is a domain administrator, and i’m using “domain\xxxx” to connect. What is going wrong here?