Skip to content

Instantly share code, notes, and snippets.

@jborean93
Last active January 20, 2025 01:30
Show Gist options
  • Select an option

  • Save jborean93/3c148df03545023c671ddefb2d2b5ffc to your computer and use it in GitHub Desktop.

Select an option

Save jborean93/3c148df03545023c671ddefb2d2b5ffc to your computer and use it in GitHub Desktop.

Revisions

  1. jborean93 revised this gist Jun 6, 2024. 1 changed file with 9 additions and 2 deletions.
    11 changes: 9 additions & 2 deletions Invoke-WithImpersonation.ps1
    Original file line number Diff line number Diff line change
    @@ -65,6 +65,9 @@ Function Invoke-WithImpersonation {
    $LogonType = 'Interactive'
    )

    $LOGON32_PROVIDER_DEFAULT = 0
    $LOGON32_PROVIDER_WINNT50 = 3

    Add-Type -Namespace PInvoke -Name NativeMethods -MemberDefinition @'
    [DllImport("Advapi32.dll", EntryPoint = "ImpersonateLoggedOnUser", SetLastError = true)]
    private static extern bool NativeImpersonateLoggedOnUser(
    @@ -111,13 +114,17 @@ public static Microsoft.Win32.SafeHandles.SafeWaitHandle LogonUser(string userna
    public static extern bool RevertToSelf();
    '@

    $logonProvider = $LOGON32_PROVIDER_DEFAULT
    $logonTypeInt = switch($LogonType) {
    Interactive { 2 } # LOGON32_LOGON_INTERACTIVE
    Network { 3 } # LOGON32_LOGON_NETWORK
    Batch { 4 } # LOGON32_LOGON_BATCH
    Service { 5 } # LOGON32_LOGON_SERVICE
    NetworkCleartext { 8 } # LOGON32_LOGON_NETWORK_CLEARTEXT
    NewCredential { 9 } # LOGON32_LOGON_NEW_CREDENTIALS
    NewCredential {
    $logonProvider = $LOGON32_PROVIDER_WINNT50
    9 # LOGON32_LOGON_NEW_CREDENTIALS
    }
    }

    $user = $Credential.UserName
    @@ -132,7 +139,7 @@ public static extern bool RevertToSelf();
    $domain,
    $Credential.Password,
    $logonTypeInt,
    0 # LOGON32_PROVIDER_DEFAULT
    $logonProvider
    )
    [PInvoke.NativeMethods]::ImpersonateLoggedOnUser($token)

  2. jborean93 revised this gist Sep 28, 2022. 1 changed file with 47 additions and 39 deletions.
    86 changes: 47 additions & 39 deletions Invoke-WithImpersonation.ps1
    Original file line number Diff line number Diff line change
    @@ -66,22 +66,46 @@ Function Invoke-WithImpersonation {
    )

    Add-Type -Namespace PInvoke -Name NativeMethods -MemberDefinition @'
    [DllImport("Kernel32.dll")]
    public static extern bool CloseHandle(
    IntPtr hObject);
    [DllImport("Advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateLoggedOnUser(
    IntPtr hToken);
    [DllImport("Advapi32.dll", EntryPoint = "ImpersonateLoggedOnUser", SetLastError = true)]
    private static extern bool NativeImpersonateLoggedOnUser(
    SafeHandle hToken);
    public static void ImpersonateLoggedOnUser(SafeHandle token)
    {
    if (!NativeImpersonateLoggedOnUser(token))
    {
    throw new System.ComponentModel.Win32Exception();
    }
    }
    [DllImport("Advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool LogonUserW(
    private static extern bool LogonUserW(
    string lpszUsername,
    string lpszDomain,
    IntPtr lpszPassword,
    UInt32 dwLogonType,
    UInt32 dwLogonProvider,
    out IntPtr phToken);
    out Microsoft.Win32.SafeHandles.SafeWaitHandle phToken);
    public static Microsoft.Win32.SafeHandles.SafeWaitHandle LogonUser(string username, string domain,
    System.Security.SecureString password, uint logonType, uint logonProvider)
    {
    IntPtr passPtr = Marshal.SecureStringToGlobalAllocUnicode(password);
    try
    {
    Microsoft.Win32.SafeHandles.SafeWaitHandle token;
    if (!LogonUserW(username, domain, passPtr, logonType, logonProvider, out token))
    {
    throw new System.ComponentModel.Win32Exception();
    }
    return token;
    }
    finally
    {
    Marshal.ZeroFreeGlobalAllocUnicode(passPtr);
    }
    }
    [DllImport("Advapi32.dll")]
    public static extern bool RevertToSelf();
    @@ -102,43 +126,27 @@ public static extern bool RevertToSelf();
    $domain, $user = $user -split '\\', 2
    }

    $passPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($Credential.Password)
    try {
    $token = [IntPtr]::Zero
    $res = [PInvoke.NativeMethods]::LogonUserW(
    $token = [PInvoke.NativeMethods]::LogonUser(
    $user,
    $domain,
    $passPtr,
    $Credential.Password,
    $logonTypeInt,
    0, # LOGON32_PROVIDER_DEFAULT
    [ref]$token
    ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    } finally {
    [System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($passPtr)
    }

    if (-not $res) {
    $exp = [System.ComponentModel.Win32Exception]$err
    Write-Error -Message "Failed to log on user: $($exp.Exception.Message)" -Exception $exp
    return
    }

    try {
    $res = [PInvoke.NativeMethods]::ImpersonateLoggedOnUser(
    $token
    ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    if (-not $res) {
    $exp = [System.ComponentModel.Win32Exception]$err
    Write-Error -Message "Failed to impersonate user: $($exp.Exception.Message)" -Exception $exp
    return
    }

    0 # LOGON32_PROVIDER_DEFAULT
    )
    [PInvoke.NativeMethods]::ImpersonateLoggedOnUser($token)

    try {
    &$ScriptBlock
    } finally {
    }
    finally {
    $null = [PInvoke.NativeMethods]::RevertToSelf()
    }
    } finally {
    $null = [PInvoke.NativeMethods]::CloseHandle($token)
    }
    catch {
    $PSCmdlet.WriteError($_)
    }
    finally {
    if ($token) { $token.Dispose() }
    }
    }
  3. jborean93 revised this gist Oct 28, 2020. 1 changed file with 22 additions and 22 deletions.
    44 changes: 22 additions & 22 deletions Invoke-WithImpersonation.ps1
    Original file line number Diff line number Diff line change
    @@ -1,28 +1,6 @@
    # Copyright: (c) 2020, Jordan Borean (@jborean93) <jborean93@gmail.com>
    # MIT License (see LICENSE or https://opensource.org/licenses/MIT)

    Add-Type -Namespace PInvoke -Name NativeMethods -MemberDefinition @'
    [DllImport("Kernel32.dll")]
    public static extern bool CloseHandle(
    IntPtr hObject);
    [DllImport("Advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateLoggedOnUser(
    IntPtr hToken);
    [DllImport("Advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool LogonUserW(
    string lpszUsername,
    string lpszDomain,
    IntPtr lpszPassword,
    UInt32 dwLogonType,
    UInt32 dwLogonProvider,
    out IntPtr phToken);
    [DllImport("Advapi32.dll")]
    public static extern bool RevertToSelf();
    '@

    Function Invoke-WithImpersonation {
    <#
    .SYNOPSIS
    @@ -86,6 +64,28 @@ Function Invoke-WithImpersonation {
    [ValidateSet('Batch', 'Interactive', 'Network', 'NetworkCleartext', 'NewCredential', 'Service')]
    $LogonType = 'Interactive'
    )

    Add-Type -Namespace PInvoke -Name NativeMethods -MemberDefinition @'
    [DllImport("Kernel32.dll")]
    public static extern bool CloseHandle(
    IntPtr hObject);
    [DllImport("Advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateLoggedOnUser(
    IntPtr hToken);
    [DllImport("Advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool LogonUserW(
    string lpszUsername,
    string lpszDomain,
    IntPtr lpszPassword,
    UInt32 dwLogonType,
    UInt32 dwLogonProvider,
    out IntPtr phToken);
    [DllImport("Advapi32.dll")]
    public static extern bool RevertToSelf();
    '@

    $logonTypeInt = switch($LogonType) {
    Interactive { 2 } # LOGON32_LOGON_INTERACTIVE
  4. jborean93 revised this gist Jun 4, 2020. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions Invoke-WithImpersonation.ps1
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@
    # Copyright: (c) 2020, Jordan Borean (@jborean93) <jborean93@gmail.com>
    # MIT License (see LICENSE or https://opensource.org/licenses/MIT)

    Add-Type -Namespace PInvoke -Name NativeMethods -MemberDefinition @'
    [DllImport("Kernel32.dll")]
    public static extern bool CloseHandle(
  5. jborean93 revised this gist Jun 4, 2020. 1 changed file with 66 additions and 9 deletions.
    75 changes: 66 additions & 9 deletions Invoke-WithImpersonation.ps1
    Original file line number Diff line number Diff line change
    @@ -21,6 +21,54 @@ public static extern bool RevertToSelf();
    '@

    Function Invoke-WithImpersonation {
    <#
    .SYNOPSIS
    Invoke a scriptblock as another user.
    .DESCRIPTION
    Invoke a scriptblock and run it in the context of another user as supplied by -Credential.
    .PARAMETER ScriptBlock
    The PowerShell code to run. It is recommended to use '{}.GetNewClosure()' to ensure the scriptblock has access to
    the same values where it was defined. Anything output by this scriptblock will also be outputted by
    Invoke-WithImpersonation.
    .PARAMETER Credential
    The PSCredential that specifies the user to run the scriptblock as. This needs to be a valid local or domain user
    except when using '-LogonType NewCredential'. The user specified must have been granted the 'logon as ...' right
    for the -LogonType that was requested (except for -LogonType NewCredential).
    .PARAMETER LogonType
    The logon type to use for the impersonated token. By default it is set to 'Interactive' which is the logon type
    used when a user has logged on interactively. Each logon type has their own unique characteristics as specified.
    Batch: Replicates running as a scheduled task, will typically have the full rights of the user specified.
    Interactive: Replicates running as a normal logged on user, may have limited rights depending on whether UAC
    is enabled.
    Network: Replicates running from a network logon like WinRM, will not be able to delegate it's credential to
    further downstream servers.
    NetworkCleartext: Like Network but will have access to its credentials for delegation, similar to using
    CredSSP auth for WinRM.
    NewCredential: Can be used to specify any credentials and any network auth attempts will use those credentials.
    Any local actions are run as the existing users token.
    Service: Replicates running as a Windows service.
    .EXAMPLE Run as an interactive logon
    $cred = Get-Credential
    Invoke-WithImpersonation -Credential $cred -ScriptBlock {
    [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
    }.GetNewClosure()
    .EXAMPLE Access a network path with explicit credentials
    $cred = Get-Credential # Can be any username/password, does not have to be a valid local or domain account.
    $files = Invoke-WithImpersonation -Credential $cred -LogonType NewCredential -ScriptBlock {
    Get-ChildItem -Path \\192.168.1.1\share\folder
    }.GetNewClosure()
    .NOTES
    Starting a new process in the scriptblock will run as the original user and not the user supplied by -Credential.
    Use 'Start-Process' with -Credential to create a new process as another user.
    #>
    [CmdletBinding()]
    param (
    [Parameter(Mandatory=$true)]
    @@ -29,9 +77,22 @@ Function Invoke-WithImpersonation {

    [Parameter(Mandatory=$true)]
    [PSCredential]
    $Credential
    $Credential,

    [String]
    [ValidateSet('Batch', 'Interactive', 'Network', 'NetworkCleartext', 'NewCredential', 'Service')]
    $LogonType = 'Interactive'
    )

    $logonTypeInt = switch($LogonType) {
    Interactive { 2 } # LOGON32_LOGON_INTERACTIVE
    Network { 3 } # LOGON32_LOGON_NETWORK
    Batch { 4 } # LOGON32_LOGON_BATCH
    Service { 5 } # LOGON32_LOGON_SERVICE
    NetworkCleartext { 8 } # LOGON32_LOGON_NETWORK_CLEARTEXT
    NewCredential { 9 } # LOGON32_LOGON_NEW_CREDENTIALS
    }

    $user = $Credential.UserName
    $domain = $null
    if ($user.Contains('\')) {
    @@ -45,7 +106,7 @@ Function Invoke-WithImpersonation {
    $user,
    $domain,
    $passPtr,
    2, # LOGON32_LOGON_INTERACTIVE
    $logonTypeInt,
    0, # LOGON32_PROVIDER_DEFAULT
    [ref]$token
    ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    @@ -54,7 +115,7 @@ Function Invoke-WithImpersonation {
    }

    if (-not $res) {
    $exp = [System.ComponentModel.Win32Exception]$res
    $exp = [System.ComponentModel.Win32Exception]$err
    Write-Error -Message "Failed to log on user: $($exp.Exception.Message)" -Exception $exp
    return
    }
    @@ -64,7 +125,7 @@ Function Invoke-WithImpersonation {
    $token
    ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    if (-not $res) {
    $exp = [System.ComponentModel.Win32Exception]$res
    $exp = [System.ComponentModel.Win32Exception]$err
    Write-Error -Message "Failed to impersonate user: $($exp.Exception.Message)" -Exception $exp
    return
    }
    @@ -77,8 +138,4 @@ Function Invoke-WithImpersonation {
    } finally {
    $null = [PInvoke.NativeMethods]::CloseHandle($token)
    }
    }

    Invoke-WithImpersonation -Credential (Get-Credential) -ScriptBlock {
    [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
    }.GetNewClosure()
    }
  6. jborean93 created this gist Apr 23, 2020.
    84 changes: 84 additions & 0 deletions Invoke-WithImpersonation.ps1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    Add-Type -Namespace PInvoke -Name NativeMethods -MemberDefinition @'
    [DllImport("Kernel32.dll")]
    public static extern bool CloseHandle(
    IntPtr hObject);
    [DllImport("Advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateLoggedOnUser(
    IntPtr hToken);
    [DllImport("Advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool LogonUserW(
    string lpszUsername,
    string lpszDomain,
    IntPtr lpszPassword,
    UInt32 dwLogonType,
    UInt32 dwLogonProvider,
    out IntPtr phToken);
    [DllImport("Advapi32.dll")]
    public static extern bool RevertToSelf();
    '@

    Function Invoke-WithImpersonation {
    [CmdletBinding()]
    param (
    [Parameter(Mandatory=$true)]
    [ScriptBlock]
    $ScriptBlock,

    [Parameter(Mandatory=$true)]
    [PSCredential]
    $Credential
    )

    $user = $Credential.UserName
    $domain = $null
    if ($user.Contains('\')) {
    $domain, $user = $user -split '\\', 2
    }

    $passPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($Credential.Password)
    try {
    $token = [IntPtr]::Zero
    $res = [PInvoke.NativeMethods]::LogonUserW(
    $user,
    $domain,
    $passPtr,
    2, # LOGON32_LOGON_INTERACTIVE
    0, # LOGON32_PROVIDER_DEFAULT
    [ref]$token
    ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    } finally {
    [System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($passPtr)
    }

    if (-not $res) {
    $exp = [System.ComponentModel.Win32Exception]$res
    Write-Error -Message "Failed to log on user: $($exp.Exception.Message)" -Exception $exp
    return
    }

    try {
    $res = [PInvoke.NativeMethods]::ImpersonateLoggedOnUser(
    $token
    ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    if (-not $res) {
    $exp = [System.ComponentModel.Win32Exception]$res
    Write-Error -Message "Failed to impersonate user: $($exp.Exception.Message)" -Exception $exp
    return
    }

    try {
    &$ScriptBlock
    } finally {
    $null = [PInvoke.NativeMethods]::RevertToSelf()
    }
    } finally {
    $null = [PInvoke.NativeMethods]::CloseHandle($token)
    }
    }

    Invoke-WithImpersonation -Credential (Get-Credential) -ScriptBlock {
    [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
    }.GetNewClosure()