我在我的脚本中使用下面的函数来确保用户没有使用本地帐户的特定密码列表。当针对密码错误的用户名进行测试时,该函数工作正常,并以正确的用户名和密码返回“True”,并以正确的错误“用户名或密码不正确”返回“False”。问题是当我使用带有 SYSTEM 帐户的任务计划程序运行我的脚本时,它仍然返回正确的验证,但是用户名密码错误的错误代码是“0”:操作成功完成。有谁知道为什么 GetLastWin32Error() 在使用任务计划程序时返回代码 0 而不是 0x0000052E?
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
}