Skip to content

Instantly share code, notes, and snippets.

@jasonrush
Created January 24, 2020 20:28
Show Gist options
  • Select an option

  • Save jasonrush/5ab7f9b6a743ef95431bd1edcb6d0dc5 to your computer and use it in GitHub Desktop.

Select an option

Save jasonrush/5ab7f9b6a743ef95431bd1edcb6d0dc5 to your computer and use it in GitHub Desktop.

Revisions

  1. jasonrush created this gist Jan 24, 2020.
    71 changes: 71 additions & 0 deletions TestLocalCredential.ps1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    Function Test-Credential {
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "", Justification="We need to use the plaintext pass in the Win32 call, also the source isn't a secure string to using that is just a waste of time/code")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "", Justification="See above")]
    param([String]$Username, [String]$Password)

    $platform_util = @'
    using System;
    using System.Runtime.InteropServices;
    namespace TempNamespace
    {
    public class WinUserPInvoke
    {
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(
    string lpszUsername,
    string lpszDomain,
    string lpszPassword,
    UInt32 dwLogonType,
    UInt32 dwLogonProvider,
    out IntPtr phToken);
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool CloseHandle(
    IntPtr hObject);
    }
    }
    '@

    $original_tmp = $env:TMP
    $original_temp = $env:TEMP
    $env:TMP = $_remote_tmp
    $env:TEMP = $_remote_tmp
    Add-Type -TypeDefinition $platform_util
    $env:TMP = $original_tmp
    $env:TEMP = $original_temp

    $Logon32LogonInteractive = 2
    $LOGON32_PROVIDER_DEFAULT = 0

    $handle = [IntPtr]::Zero
    $logon_res = [TempNamespace.WinUserPInvoke]::LogonUser($Username, $null, $Password,
    $Logon32LogonInteractive, $LOGON32_PROVIDER_DEFAULT, [Ref]$handle)

    if ($logon_res) {
    $valid_credentials = $true
    [TempNamespace.WinUserPInvoke]::CloseHandle($handle) > $null
    } else {
    $err_code = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    # following errors indicate the creds are correct but the user was
    # unable to log on for other reasons, which we don't care about
    $success_codes = @(
    0x0000052F, # ERROR_ACCOUNT_RESTRICTION
    0x00000530, # ERROR_INVALID_LOGON_HOURS
    0x00000531, # ERROR_INVALID_WORKSTATION
    0x00000569 # ERROR_LOGON_TYPE_GRANTED
    )

    if ($err_code -eq 0x0000052E) {
    # ERROR_LOGON_FAILURE - the user or pass was incorrect
    $valid_credentials = $false
    } elseif ($err_code -in $success_codes) {
    $valid_credentials = $true
    } else {
    # an unknown failure, raise an Exception for this
    $win32_exp = New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList $err_code
    $err_msg = "LogonUserW failed: $($win32_exp.Message) (Win32ErrorCode: $err_code)"
    throw New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList $err_code, $err_msg
    }
    }

    return $valid_credentials
    }