hsimah
hsimah

Reputation: 1303

Using PSCredentials in C# code

I am writing a binary cmdlet and I would like to accept a PSCredential parameter in order to use elevated credentials.

[Parameter]
public PSCredential Credential { get; set; }

There seems to be a distinct lack of documentation for this - all I can find is how to execute PowerShell cmdlets from C#, which is not what I wish to do.

I downloaded the SimpleImpersonation nuget package to avoid doing the Windows impersonation myself.

using (Impersonation.LogonUser("GLOBAL", "last.first", "mypassword", LogonType.Interactive))
{
    foreach (ServerInfo server in Targets)
        ProcessRecord();
}

When I check System.Security.Principal.WindowsIdentity.GetCurrent().Name the user is correct, but when I execute a command (eg ServerManager.OpenRemote(computerName)) I receive an UnauthorizedAccessException. If I run this code from a PowerShell instance running as the desired user the cmdlet executes flawlessly.

Does anyway have any clues as to how to utilise a PSCredential in a C# binary cmdlet?

Upvotes: 0

Views: 1909

Answers (1)

hsimah
hsimah

Reputation: 1303

I'm not sure why this has so little documentation online. As I suspected I needed to use impersonation to accomplish this. There seems to be a lot of plumbing involved with this, see here.

After some more investigation there's a nice nuget package called SimpleImpersonation.

Using:

[Parameter]
public PSCredential Credential { get; set; }

I can do this:

using (Impersonation.LogonUser("GLOBAL", Credential.UserName, Credential.Password, LogonType.Interactive))

This allows me to run commands as the impersonated user. LogonUser() takes the username and SecureString password.

This works fine for ServiceController calls, but ServerManager was still throwing COM unauthorised exceptions. I managed to find this post which said to not use OpenRemote() but to use a ctor overload. The following code works:

using (ServerManager serverManager = new ServerManager(@"\\server\c$\windows\system32\inetsrv\config\applicationHost.config"))
{
    ApplicationPoolCollection appPool = serverManager.ApplicationPools;
    Console.WriteLine(appPool.Count);
}

Upvotes: 2

Related Questions