I have this function which create a distribution exchange group (this function works well) :
private void createDistributionGroup()
{
System.Security.SecureString pass = new System.Security.SecureString();
foreach (char c in password)
pass.AppendChar(c);
PSCredential cred = new PSCredential(username, pass);
WSManConnectionInfo connection = new WSManConnectionInfo(new Uri("http://[my_exchange].[my_domain].com/PowerShell/"), "Microsoft.Exchange", cred);
connection.AuthenticationMechanism = AuthenticationMechanism.Default;
Runspace runspace = RunspaceFactory.CreateRunspace(connection);
PowerShell ps = PowerShell.Create();
try
{
runspace.Open();
ps.Runspace = runspace;
ps.AddCommand("New-DistributionGroup").AddParameter("Name", "GRP_DIF_" + textBox1.Text));
ps.Invoke();
}
finally
{
runspace.Dispose();
runspace = null;
ps.Dispose();
ps = null;
}
}
I have to execute my app using impersonation, using the msdn example I impersonate to a service account (the MSDN example works well and impersonates with success).
Before implementing impersonation the connection works, since I do impersonation when I try to execute the createDistributionGroup()
function I get an error:
Access Denied : About remote troubleshooting
I have immediately tested to open remote PowerShell session in a local PowerShell using
$credential = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://[my_exchange].[my_domain].com/PowerShell/ -Authentication Default -Credential $credential
Import-PSSession $Session
And the session was opened successfully...
Why when I impersonate the account is denied and how to grant access ?
Impersonation isn't going to work for remote authentication. At that point the local process can't prove to the remote process that it is indeed the original client (which is good, because it isn't).
When you connect with the credentials supplied in Get-Credential
, the actual password is there and available, so authentication works.
So, this is in essence a kerberos double-hop issue, just not the one that people usually run into.
If you must use impersonation, then you will need some way to re-authenticate on the remote machine.
One possible way, which isn't necessarily a good idea, is to store the credentials in an encrypted file, which must be accessed by the account you're impersonating. I'm actually not 100% sure this will work with impersonation, but it might be worth a try:
First, store your encrypted credential (run this as the user being impersonated):
$cred = Get-Credential
$cred | Export-Clixml -Path "C:\Creds\appcred_${env:USERNAME}_${env:COMPUTERNAME}.xml"
In your application code, after impersonation:
$cred = Import-Clixml -Path "C:\Creds\appcred_${env:USERNAME}_${env:COMPUTERNAME}.xml"
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://[my_exchange].[my_domain].com/PowerShell/ -Authentication Default -Credential $cred
This sequence works generally. The credetial's password in the XML is encrypted using the Windows Data Protection API (DPAPI) with a key related to the user and computer, so it can only be decrypted by the same user, on the same computer.
As I said I don't know if this would work with impersonation or not.
This also means that the file needs to be updated manually if you change the account's password in AD.