I'm using function below in my script to ensure that user are not using specific list of passwords for local account. The function works fine and return "True" with correct username and password and return "False" with correct Error "The user name or password is incorrect" when tested against a username with wrong password. The issue is when I run my script using Task Scheduler with SYSTEM account, it still return correct validation, but the Error code for username with wrong password is "0" : The operation completed successfully. Does anyone knows why the GetLastWin32Error() return code 0 instead of 0x0000052E when using Task Scheduler?
Function Test-LocalCredential{
<#
Test credential/password for local account.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][String]$UserName,
[Parameter(Mandatory=$True)][String]$Password
)
IF (!($UserName) -or !($Password)) {
Write-Warning 'Username and password not provided'
Return
}
[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("System.Runtime.InteropServices") | Out-Null
$logonUserSignature =
@'
[DllImport( "advapi32.dll", SetLastError = true )]
public static extern bool LogonUser( String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken );
'@
$closeHandleSignature =
@'
[DllImport( "kernel32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern bool CloseHandle( IntPtr handle );
'@
$AdvApi32 = Add-Type -MemberDefinition $logonUserSignature -Name "AdvApi32" -Namespace "PsInvoke.NativeMethods" -PassThru
$Kernel32 = Add-Type -MemberDefinition $closeHandleSignature -Name "Kernel32" -Namespace "PsInvoke.NativeMethods" -PassThru
<#
LOGON32_PROVIDER_DEFAULT = 0
LOGON32_PROVIDER_WINNT35 = 1
LOGON32_PROVIDER_WINNT40 = 2
LOGON32_PROVIDER_WINNT50 = 3
#>
$Logon32Provider = 0
<#
LOGON32_LOGON_INTERACTIVE = 2
LOGON32_LOGON_NETWORK = 3
LOGON32_LOGON_BATCH = 4
LOGON32_LOGON_SERVICE = 5
LOGON32_LOGON_UNLOCK = 7
LOGON32_LOGON_NETWORK_CLEARTEXT = 8
LOGON32_LOGON_NEW_CREDENTIALS = 9
#>
$Logon32Type = 3
$tokenHandle = [IntPtr]::Zero
$TestLogon = $False
<#
Unless $userName is supplied using UPN format (e.g administrator@servername or administrator@domain) domain name should not be of null value as it would
default the logon provider authentication to NTLM
#>
$DomainName = $env:COMPUTERNAME
$TestLogon = $AdvApi32::LogonUser($UserName, $DomainName, $Password, $Logon32Type, $Logon32Provider, [Ref]$tokenHandle)
$success_codes = @(
0x0000052F, # ERROR_ACCOUNT_RESTRICTION
0x00000530, # ERROR_INVALID_LOGON_HOURS
0x00000531, # ERROR_INVALID_WORKSTATION
0x00000569 # ERROR_LOGON_TYPE_GRANTED
)
if (!$TestLogon){
$err_code = $Null
$err_code = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
$Msg = $(([ComponentModel.Win32Exception] $err_code).Message)
Write-Verbose $Msg
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 = "LogonUser failed: $($win32_exp.Message) (Win32ErrorCode: $err_code) ($Password)"
Write-Verbose $err_msg
throw New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList $err_code, $err_msg
$valid_credentials = $false
}
} else {
$Kernel32::CloseHandle($tokenHandle) | Out-Null
$valid_credentials = $True
}
Return $valid_credentials
}
User contributions licensed under CC BY-SA 3.0