Überprüfen Sie, ob die Benutzerkennworteingabe im Powershell-Skript gültig ist

30

Ich arbeite mit einem Powershell-Skript, das geplante Aufgaben zu Systemen in unserer Domäne hinzufügt. Wenn ich dieses Skript ausführe, werde ich zur Eingabe meines Passworts aufgefordert. Ich habe manchmal fette Finger das Passwort und der Prozess beginnt, der mein Konto sperrt. Gibt es eine Möglichkeit, meine Anmeldeinformationen zu überprüfen, um sicherzustellen, dass meine Eingaben für die Domain gültig sind?

Ich möchte eine Möglichkeit finden, den Domänencontroller abzufragen. Ich habe einige Google-Suchen durchgeführt und sollte in der Lage sein, eine WMI-Abfrage durchzuführen und nach einem Fehler zu suchen. Ich möchte diesen Validierungsstil nach Möglichkeit vermeiden.

Irgendwelche Ideen? Danke im Voraus.

Doltknuckle
quelle

Antworten:

26

Ich habe das in meiner Bibliothek:

$cred = Get-Credential #Read credentials
 $username = $cred.username
 $password = $cred.GetNetworkCredential().password

 # Get current domain using logged-on user's credentials
 $CurrentDomain = "LDAP://" + ([ADSI]"").distinguishedName
 $domain = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain,$UserName,$Password)

if ($domain.name -eq $null)
{
 write-host "Authentication failed - please verify your username and password."
 exit #terminate the script.
}
else
{
 write-host "Successfully authenticated with domain $domain.name"
}
Jim B
quelle
1
Wenn ich mich nicht irre, würde dies dazu führen, dass das Passwort im Klartext über das Netzwerk gesendet wird, oder? Wenn AccountManagement.PrincipalContext.ValidateCredentials()ja , habe ich dann Recht, wenn ich davon ausgehe , dass dies nicht der Fall ist (wenn Sie eine Sicherheitsabfrage für das Kennwort angeben)?
Code Jockey
Warum verwenden Sie das ActiveDirectoryModul nicht für Ihre LDAP-Abfrage?
Kolob Canyon
Vor 6 Jahren gab es kein Active Directory-Modul
Jim B
Dieses Skript hilft auch in Situationen, in denen Sie die AD PowerShell-Module aus dem einen oder anderen Grund nicht installieren können.
Dodzi Dzakuma
16

Dies ist, was ich in der Vergangenheit verwendet habe; Es soll für lokale Computerkonten und "Anwendungsverzeichnis" funktionieren, aber bisher habe ich es nur mit AD-Anmeldeinformationen erfolgreich verwendet:

    function Test-Credential {
    <#
    .SYNOPSIS
        Takes a PSCredential object and validates it against the domain (or local machine, or ADAM instance).

    .PARAMETER cred
        A PScredential object with the username/password you wish to test. Typically this is generated using the Get-Credential cmdlet. Accepts pipeline input.

    .PARAMETER context
        An optional parameter specifying what type of credential this is. Possible values are 'Domain','Machine',and 'ApplicationDirectory.' The default is 'Domain.'

    .OUTPUTS
        A boolean, indicating whether the credentials were successfully validated.

    #>
    param(
        [parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Management.Automation.PSCredential]$credential,
        [parameter()][validateset('Domain','Machine','ApplicationDirectory')]
        [string]$context = 'Domain'
    )
    begin {
        Add-Type -assemblyname system.DirectoryServices.accountmanagement
        $DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::$context) 
    }
    process {
        $DS.ValidateCredentials($credential.UserName, $credential.GetNetworkCredential().password)
    }
}
Schmied
quelle
Ich würde gerne hören, wenn jemand dies bemerkt. Ich glaube, wenn ich ValidateCredentials () auf diese Weise mit einem falschen Kennwort verwende, scheint dies zwei (2) falsche Kennwortversuche auszulösen. Ich kann den Schwellenwert für die Anzahl der Versuche nicht steuern auf unserer Domain, und es ist niedrig, so würde ich es vorziehen, nicht zwei schlechte Versuche zu haben, wenn ich einen einzelnen Anruf tätige ... kann jemand dies auch sehen?
Code Jockey
Verwenden Sie das Format Domäne \ Benutzer oder UPN (Benutzer @ Domäne)? Ich bin nicht in der Lage, dies zu replizieren, aber die folgende URL beschreibt ein ähnliches Problem: social.msdn.microsoft.com/Forums/vstudio/en-US/…
jbsmith
Sie sollten nur in der Lage sein $context, dem Konstruktor das Argument zu übergeben. PowerShell konvertiert Zeichenfolgen automatisch in eine Aufzählung. Besser noch, machen Sie einfach [System.DirectoryServices.AccountManagement.ContextType]die Art von $context. Auch warum benutzt du beginund processhier? Die Pipeline scheint eine seltsame Art zu sein, diese Funktion zu verwenden.
jpmc26
@ jpmc26: die Eingabe - $contextParameter ist [System.DirectoryServices.AccountManagement.ContextType]keine Option, da die Anordnung , die nicht bis die Funktion geladen wird Körper ausgeführt wird; Die Verwendung der Pipeline ist hilfreich, wenn Sie mehrere Anmeldeinformationen überprüfen möchten.
Mklement
@mklement Es gibt keinen Grund, warum der Add-TypeAufruf nicht außerhalb der Funktion verschoben werden kann, bevor seine Definition ausgeführt wird. Ich zögere, einen Add-TypeAnruf innerhalb der Funktion unbedingt wiederholt ausführen zu lassen, auch wenn sie ohnehin schon geladen ist. Das gleichzeitige Überprüfen mehrerer Anmeldeinformationen erscheint zunächst als eine merkwürdige Situation. In dem seltenen Fall, dass Sie dies wünschen, können Sie den Anruf einfach einwickeln ForEach-Object, sodass ich keinen Grund sehe, die Funktion damit zu komplizieren.
jpmc26
1

Ich fand diesen Beitrag nützlich, konnte mein Problem jedoch nicht lösen, da ich versuchte, ihn über ein Skript auszuführen, bei dem das lokale Administratorkonto angemeldet war. Es scheint nicht als lokaler Administrator zu funktionieren (nur wenn Sie als Domänenbenutzer angemeldet sind).

Aber ich habe es endlich geschafft, eine funktionierende Lösung zu finden und da es so viel Mühe gab, dachte ich, ich würde es hier teilen, damit jeder andere mit diesem Problem die Antwort hier haben kann. Beide Antworten auf einer Seite je nach Bedarf.

Beachten Sie, dass oben im Skript (hier nicht enthalten, da dies nur der Abschnitt zum Abrufen von Anmeldeinformationen ist) powergui installiert ist und für diesen Code (sowie für die Zeile "Add-PSSnapin Quest.ActiveRoles.ADManagement") erforderlich ist. Ich bin nicht sicher, was Powergui anders macht, aber niemand sonst kann es mir sagen und es funktioniert.

Ersetzen Sie Ihren eigenen Domainnamen in den Abschnitten "domain_name".

#Get credentials
$credential_ok = 0
while ($credential_ok -ne 1)
{
    $credential = get-credential
    $result = connect-qadservice -service *domain_name* -credential $credential
    [string]$result_string = $result.domain
    if ($result_string -eq "*domain_name*")
    {
        $credential_ok = 1
        #authenticated
    }
    else
    {
        #failed
    }     
}
$username = $credential.username 
$password = $credential.GetNetworkCredential().password 

$date = get-date
Add-Content "c:\lbin\Install_log.txt" "Successfully authenticated XP script as $username $date"
Michael
quelle
1

(noch) eine andere Version:

param([string]$preloadServiceAccountUserName = "")

function HarvestCredentials()
{

        [System.Management.Automation.PSCredential]$credentialsOfCurrentUser = Get-Credential -Message "Please enter your username & password" -UserName $preloadServiceAccountUserName

        if ( $credentialsOfCurrentUser )
        {
            $credentialsOfCurrentUser = $credentialsOfCurrentUser
        }
        else
        {
            throw [System.ArgumentOutOfRangeException] "Gui credentials not entered correctly"          
        }

    Try
    {


        # see https://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.path(v=vs.110).aspx
        # validate the credentials are legitimate
        $validateCredentialsTest = (new-object System.DirectoryServices.DirectoryEntry ("WinNT://"+$credentialsOfCurrentUser.GetNetworkCredential().Domain), $credentialsOfCurrentUser.GetNetworkCredential().UserName, $credentialsOfCurrentUser.GetNetworkCredential().Password).psbase.name
        if ( $null -eq  $validateCredentialsTest)
        {
            throw [System.ArgumentOutOfRangeException] "Credentials are not valid.  ('" + $credentialsOfCurrentUser.GetNetworkCredential().Domain + '\' + $credentialsOfCurrentUser.GetNetworkCredential().UserName + "')"
        }
        else
        {
            $t = $host.ui.RawUI.ForegroundColor
            $host.ui.RawUI.ForegroundColor = "Magenta"
            Write-Output "GOOD CREDENTIALS"
            $host.ui.RawUI.ForegroundColor = $t
        }
    }
    Catch
    {

        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
        $StackTrace = $_.Exception.StackTrace

        $t = $host.ui.RawUI.ForegroundColor
        $host.ui.RawUI.ForegroundColor = "Red"

        Write-Output "Exception - $ErrorMessage"
        Write-Output "Exception - $FailedItem"
        Write-Output "Exception - $StackTrace"

        $host.ui.RawUI.ForegroundColor = $t

        throw [System.ArgumentOutOfRangeException] "Attempt to create System.DirectoryServices.DirectoryEntry failed.  Most likely reason is that credentials are not valid."
    }

}


Try
{

    HarvestCredentials

}
Catch
{
    $ErrorMessage = $_.Exception.Message
    $FailedItem = $_.Exception.ItemName
    $StackTrace = $_.Exception.StackTrace

    $t = $host.ui.RawUI.ForegroundColor
    $host.ui.RawUI.ForegroundColor = "Red"

    Write-Output "Exception - " + $ErrorMessage
    Write-Output "Exception - " + $FailedItem
    Write-Output "Exception - " + $StackTrace

    $host.ui.RawUI.ForegroundColor = $t

    Break
}
Finally
{
    $Time=Get-Date
    Write-Output "Done - " + $Time
}

und

.\TestCredentials.ps1 -preloadServiceAccountUserName "mydomain\myusername"
granadaCoder
quelle