Skip to content

Instantly share code, notes, and snippets.

@jasonrush
Created January 24, 2020 20:28
Show Gist options
  • Save jasonrush/5ab7f9b6a743ef95431bd1edcb6d0dc5 to your computer and use it in GitHub Desktop.
Save jasonrush/5ab7f9b6a743ef95431bd1edcb6d0dc5 to your computer and use it in GitHub Desktop.
Test credentials for local computer (update arg 2 on line 40 from $null to domain name for domain auth). Slightly modified from Ansible.
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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment