bin/Public/Get-sqmADAccountStatus.ps1
|
function Get-sqmADAccountStatus { <# .SYNOPSIS Prueft den Status eines Active Directory Benutzerkontos. .DESCRIPTION Ermittelt den Kontostatus ueber das ActiveDirectory-Modul (RSAT) mit automatischem Fallback auf ADSI, falls RSAT nicht verfuegbar ist. Gibt ein detailliertes PSObject mit Enabled, LockedOut, PasswordExpired und AccountExpired zurueck. .PARAMETER SamAccountName Der SamAccountName des zu pruefenden AD-Kontos. .PARAMETER DomainController Optionaler Ziel-DC. Wird nur beim RSAT-Pfad verwendet. .OUTPUTS PSCustomObject mit folgenden Eigenschaften: SamAccountName [string] Enabled [bool] LockedOut [bool] PasswordExpired [bool] AccountExpired [bool] Source [string] 'RSAT' oder 'ADSI' QueryTime [datetime] ErrorMessage [string] leer wenn erfolgreich .EXAMPLE Get-sqmADAccountStatus -SamAccountName 'jdoe' .EXAMPLE 'jdoe','jsmith' | Get-sqmADAccountStatus .EXAMPLE Get-sqmADAccountStatus -SamAccountName 'jdoe' -DomainController 'DC01' #> [CmdletBinding()] [OutputType([PSCustomObject])] param ( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [string[]] $SamAccountName, [Parameter()] [string] $DomainController ) begin { #region --- Modul-Verfuegbarkeit einmalig pruefen --- $useRSAT = $false if (Get-Module -Name ActiveDirectory -ListAvailable) { try { Import-Module ActiveDirectory -ErrorAction Stop $useRSAT = $true Write-Verbose 'ActiveDirectory-Modul geladen (RSAT-Pfad aktiv).' } catch { Write-Verbose "ActiveDirectory-Modul nicht ladbar: $_ - Fallback auf ADSI." } } else { Write-Verbose 'ActiveDirectory-Modul nicht installiert - Fallback auf ADSI.' } # Hilfsfunktion: Ergebnis-Objekt erzeugen function New-ResultObject { param ( [string] $Sam, [bool] $Enabled = $false, [bool] $LockedOut = $false, [bool] $PwdExpired = $false, [bool] $AcctExpired = $false, [string] $Source = '', [string] $ErrorMessage = '' ) [PSCustomObject]@{ SamAccountName = $Sam Enabled = $Enabled LockedOut = $LockedOut PasswordExpired = $PwdExpired AccountExpired = $AcctExpired Source = $Source QueryTime = (Get-Date) ErrorMessage = $ErrorMessage } } #region --- ADSI-Hilfsfunktion --- function Get-ADAccountStatusViaADSI { param ([string] $Sam) # Searcher aufbauen $searcher = [adsisearcher]"(sAMAccountName=$Sam)" $searcher.PropertiesToLoad.AddRange(@( 'sAMAccountName', 'userAccountControl', 'lockoutTime', 'pwdLastSet', 'accountExpires', 'msDS-UserPasswordExpiryTimeComputed' )) | Out-Null $searcher.SizeLimit = 1 $entry = $searcher.FindOne() if (-not $entry) { throw "Konto '$Sam' wurde im Verzeichnis nicht gefunden." } $uac = [int]$entry.Properties['useraccountcontrol'][0] # Enabled: Bit 2 (0x0002) = disabled $enabled = -not [bool]($uac -band 0x0002) # LockedOut: Bit 16 (0x0010) oder lockoutTime > 0 $lockedBit = [bool]($uac -band 0x0010) $lockoutTimeRaw = $entry.Properties['lockouttime'] $lockedTime = $false if ($lockoutTimeRaw.Count -gt 0) { $lt = [long]$lockoutTimeRaw[0] $lockedTime = ($lt -gt 0) } $lockedOut = $lockedBit -or $lockedTime # PasswordExpired: Bit 8388608 (0x800000) oder msDS-Attribut $pwdExpiredBit = [bool]($uac -band 0x800000) $pwdExpired = $pwdExpiredBit if (-not $pwdExpired) { $expiryRaw = $entry.Properties['msds-userpasswordexpirytimecomputed'] if ($expiryRaw.Count -gt 0) { $expiryFt = [long]$expiryRaw[0] # 0 = laeuft nie ab, 9223372036854775807 = nie if ($expiryFt -gt 0 -and $expiryFt -ne [long]::MaxValue) { $expiryDate = [datetime]::FromFileTime($expiryFt) $pwdExpired = ($expiryDate -lt (Get-Date)) } } } # AccountExpired $acctExpired = $false $acctExpiresRaw = $entry.Properties['accountexpires'] if ($acctExpiresRaw.Count -gt 0) { $ae = [long]$acctExpiresRaw[0] # 0 und Int64.MaxValue bedeuten "laeuft nie ab" if ($ae -gt 0 -and $ae -ne [long]::MaxValue) { $expDate = [datetime]::FromFileTime($ae) $acctExpired = ($expDate -lt (Get-Date)) } } return [PSCustomObject]@{ Enabled = $enabled LockedOut = $lockedOut PasswordExpired = $pwdExpired AccountExpired = $acctExpired } } #endregion } process { foreach ($sam in $SamAccountName) { Write-Verbose "Verarbeite Konto: $sam" #region --- RSAT-Pfad --- if ($useRSAT) { try { $params = @{ Identity = $sam Properties = @( 'Enabled', 'LockedOut', 'PasswordExpired', 'AccountExpirationDate' # 'AccountExpired' ist keine abrufbare Property ) ErrorAction = 'Stop' } if ($DomainController) { $params['Server'] = $DomainController } $adUser = Get-ADUser @params # AccountExpired: ExpirationDate vorhanden und in der Vergangenheit? $acctExpired = ($null -ne $adUser.AccountExpirationDate) -and ($adUser.AccountExpirationDate -lt (Get-Date)) New-ResultObject ` -Sam $sam ` -Enabled ([bool]$adUser.Enabled) ` -LockedOut ([bool]$adUser.LockedOut) ` -PwdExpired ([bool]$adUser.PasswordExpired) ` -AcctExpired $acctExpired ` -Source 'RSAT' continue } catch { # Konto nicht gefunden ? direkt Fehlerobjekt, kein ADSI-Fallback if ($_.Exception.GetType().Name -eq 'ADIdentityNotFoundException') { New-ResultObject -Sam $sam -ErrorMessage "Konto nicht gefunden: $_" -Source 'RSAT' continue } Write-Verbose "RSAT-Fehler fuer '$sam': $_ - Fallback auf ADSI." } } #endregion #region --- ADSI-Fallback --- try { $adsi = Get-ADAccountStatusViaADSI -Sam $sam New-ResultObject ` -Sam $sam ` -Enabled $adsi.Enabled ` -LockedOut $adsi.LockedOut ` -PwdExpired $adsi.PasswordExpired ` -AcctExpired $adsi.AccountExpired ` -Source 'ADSI' } catch { New-ResultObject -Sam $sam -ErrorMessage $_.ToString() -Source 'ADSI' } #endregion } } } |