Share via


Impersonation and PSRemoting

Question

Tuesday, March 6, 2012 7:54 AM

Hello,

If I use impersonation in PowerShell, remoting seems to fail. Not just fail, it actually crashes. The following script is an illustration of the problem.

It contains of 3 blocks:

  1. Try to do remoting => works
  2. Try to do remoting while being impersonated => fails
  3. Try to do remoting while being back under the original identity => works.

The error I am getting is inside PowerShell. I managed to trace it back to some unmanaged API calls, but now I'm stuck. Any ideas?

Or am I doing the impersonation incorrect?

$cred = Get-Credential 'DOM1\USER1'$cn = 'S000010'$port = 80# Without impersonation# =====================try{  $result = Invoke-Command -ComputerName $cn -Port $port -Credential $cred { 1 }    if ($result -ne 1)  {    Write-Host 'Remoting seems to work, but the result is unexpected.'  }  else  {    Write-Host 'Remoting works as expected.'  }}catch{  Write-Error 'FAILURE'  Write-Error $_}# With impersonation# ==================$ImpersonationLib = Add-Type -Namespace 'Lib.Impersonation' -Name ImpersonationLib -MemberDefinition @"    [DllImport("advapi32.dll", SetLastError = true)]    public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);    [DllImport("advapi32.dll", SetLastError = true)]    public static extern bool DuplicateToken(IntPtr token, int impersonationLevel, ref IntPtr duplication);       [DllImport("kernel32.dll")]    public static extern Boolean CloseHandle(IntPtr hObject);"@ -PassThru[System.IntPtr]$userToken = [System.IntPtr]::Zero$success = $ImpersonationLib::LogonUser('USER1',      # UserName                                        'DOM1',       # Domain                                        'SECRETPASS', #Password                                        2, # LOGON32_LOGON_INTERACTIVE                                        0, # LOGON32_PROVIDER_DEFAULT                                        [ref]$userToken)                                           if ($success -eq $false){  Write-Host 'Failure to execute logon user.'  Exit}# Create an identity.$Identity = New-Object Security.Principal.WindowsIdentity $userToken# Close open handles.if ($userToken -ne [System.IntPtr]::Zero){  $null = $ImpersonationLib::CloseHandle($userToken)  $userToken = [System.IntPtr]::Zero}# Current user.Write-Host "Before impersonation: UserName: $([Security.Principal.WindowsIdentity]::GetCurrent().Name)"# Do the impersonation.$context = $Identity.Impersonate()# New user.Write-Host "After impersonation: UserName: $([Security.Principal.WindowsIdentity]::GetCurrent().Name)"try{  $result = Invoke-Command -ComputerName $cn -Port $port -Credential $cred { 1 }    if ($result -ne 1)  {    Write-Host 'Remoting seems to work, but the result is unexpected.'  }  else  {    Write-Host 'Remoting works as expected.'  }}catch{  Write-Error 'FAILURE'  Write-Error $_}# Return to original user.$context.Undo()$context.Dispose()# Old user.Write-Host "After undoing impersonation: UserName: $([Security.Principal.WindowsIdentity]::GetCurrent().Name)"# Once more without impersonation# ===============================try{  $result = Invoke-Command -ComputerName $cn -Port $port -Credential $cred { 1 }    if ($result -ne 1)  {    Write-Host 'Remoting seems to work, but the result is unexpected.'  }  else  {    Write-Host 'Remoting works as expected.'  }}catch{  Write-Error 'FAILURE'  Write-Error $_}

The actual error I'm getting when the code fails is:

C:\WINDOWS\TEMP\70bacc02-7fab-4130-a240-a4047460467c.ps1 : System.Management.Automation.PSInvalidOperationException   at System.Management.Automation.Remoting.Client.WSManClientSessionTransportManager.Initialize(Uri connectionUri, WSManConnectionInfo connectionInfo)   at System.Management.Automation.Remoting.Client.WSManClientSessionTransportManager..ctor(Guid runspacePoolInstanceId, WSManConnectionInfo connectionInfo, PSRemotingCryptoHelper cryptoHelper)   at System.Management.Automation.Remoting.ClientRemoteSessionDSHandlerImpl..ctor(ClientRemoteSession session, PSRemotingCryptoHelper cryptoHelper, RunspaceConnectionInfo connectionInfo, URIDirectionReported uriRedirectionHandler)   at System.Management.Automation.Remoting.ClientRemoteSessionImpl..ctor(RemoteRunspacePoolInternal rsPool, URIDirectionReported uriRedirectionHandler)   at System.Management.Automation.Internal.ClientRunspacePoolDataStructureHandler.CreateClientRemoteSession(RemoteRunspacePoolInternal rsPoolInternal)   at System.Management.Automation.Internal.ClientRunspacePoolDataStructureHandler..ctor(RemoteRunspacePoolInternal clientRunspacePool, TypeTable typeTable)   at System.Management.Automation.Runspaces.Internal.RemoteRunspacePoolInternal..ctor(Int32 minRunspaces, Int32 maxRunspaces, TypeTable typeTable, PSHost host, PSPrimitiveDictionary applicationArguments, RunspaceConnectionInfo connectionInfo)   at System.Management.Automation.Runspaces.RunspacePool..ctor(Int32 minRunspaces, Int32 maxRunspaces, TypeTable typeTable, PSHost host, PSPrimitiveDictionary applicationArguments, RunspaceConnectionInfo connectionInfo)   at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspacePool(Int32 minRunspaces, Int32 maxRunspaces, RunspaceConnectionInfo connectionInfo, PSHost host, TypeTable typeTable, PSPrimitiveDictionary applicationArguments)   at System.Management.Automation.RemoteRunspace..ctor(TypeTable typeTable, RunspaceConnectionInfo connectionInfo, PSHost host, PSPrimitiveDictionary applicationArguments)   at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(RunspaceConnectionInfo connectionInfo, PSHost host, TypeTable typeTable, PSPrimitiveDictionary applicationArguments)   at Microsoft.PowerShell.Commands.PSExecutionCmdlet.CreateHelpersForSpecifiedComputerNames()   at Microsoft.PowerShell.Commands.PSExecutionCmdlet.BeginProcessing()   at Microsoft.PowerShell.Commands.InvokeCommandCommand.BeginProcessing()   at System.Management.Automation.Cmdlet.DoBeginProcessing()   at System.Management.Automation.CommandProcessorBase.DoBegin()At line:1 char:2+ . <<<< 'C:\WINDOWS\TEMP\70bacc02-7fab-4130-a240-a4047460467c.ps1'    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorExcep   tion    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorExceptio   n,70bacc02-7fab-4130-a240-a4047460467c.ps1

All replies (2)

Wednesday, March 7, 2012 7:38 AM

Hi,

I have searched the internet and the below links should be helpful:

http://poshcode.org/1867

http://poshcode.org/1856

Best Regards,

Yan Li

Yan Li

TechNet Community Support


Wednesday, March 7, 2012 8:42 AM

The difference between that code and mine is that LogonUser is called with

  LOGON32_LOGON_NEW_CREDENTIALS  (9)

instead of

  LOGON32_LOGON_INTERACTIVE (2)

I actually expect that once I do an impersonate as the new user, I could call invoke-command without having to provide the credentials parameter.

So I expect this to work:

$context = $Identity.Impersonate()$result = Invoke-Command -ComputerName $cn -Port $port { 1 }

This won't work if you specify LOGON32_LOGON_NEW_CREDENTIALS (9) in the call to LogonUser as it will just clone your current token and the invoke-command will connect you as the user which originally started the PowerShell session (the current one), and not the impersonated user. Although one would expect that it is an outbound connection and the specified credentials of the LogonUser would be used.