Hinzufügen von Unterstützung für Anmeldeinformationen zu PowerShell-Funktionen

Hinweis

Die Originalversion dieses Artikels erschien ursprünglich im Blog von @joshduffney. Dieser Artikel wurde für die Einbindung in diese Website bearbeitet. Das PowerShell-Team dankt Josh Duffney, dass er uns diesen Inhalt zur Verfügung stellt. Weitere Informationen finden Sie in seinem Blog unter duffney.io.

In diesem Artikel erfahren Sie, wie Sie PowerShell-Funktionen Parameter mit Anmeldeinformationen hinzufügen und warum dies gewünscht ist. Mit einem Parameter mit Anmeldeinformationen können Sie die Funktion oder das Cmdlet als ein anderer Benutzer ausführen. Der häufigste Zweck ist das Ausführen der Funktion oder des Cmdlets mit einem Benutzerkonto mit erhöhten Rechten.

Beispielsweise verfügt das Cmdlet New-ADUser über den Parameter Credential, mit dem Sie Anmeldeinformationen eines Domänenadministrators bereitstellen können, um in einer Domäne ein Konto zu erstellen. Es wird angenommen, dass Ihr normales Konto, mit dem die PowerShell-Sitzung ausgeführt wird, nicht bereits über diesen Zugriff verfügt.

Erstellen des Objekts mit Anmeldeinformationen

Das Objekt PSCredential stellt sicherheitsrelevante Anmeldeinformationen wie einen Benutzernamen und ein Kennwort dar. Das Objekt kann als Parameter an eine Funktion übergeben werden, die in diesem Objekt mit Anmeldeinformationen mit dem entsprechenden Benutzerkonto ausgeführt wird. Es gibt mehrere Möglichkeiten, ein Objekt mit Anmeldeinformationen zu erstellen. Die erste ist das PowerShell-Cmdlet Get-Credential. Wenn Sie es ohne Parameter ausführen, werden Sie aufgefordert, einen Benutzernamen und ein Kennwort einzugeben. Oder Sie können das Cmdlet mit optionalen Parametern aufrufen.

Um den Domänennamen und den Benutzernamen im Voraus anzugeben, können Sie entweder den Parameter Credential oder den Parameter UserName verwenden. Beim Parameter UserName müssen Sie auch einen Wert für Message angeben. Der folgende Code veranschaulicht die Verwendung des Cmdlets. Sie können das Objekt mit Anmeldeinformationen auch in einer Variablen speichern, damit Sie diese mehrmals verwenden können. Im folgenden Beispiel wird das Objekt mit Anmeldeinformationen in der Variablen $Credgespeichert.

$Cred = Get-Credential
$Cred = Get-Credential -Credential domain\user
$Cred = Get-Credential -UserName domain\user -Message 'Enter Password'

Mitunter ist es nicht möglich, die im vorherigen Beispiel gezeigte interaktive Methode zum Erstellen von Objekten mit Anmeldeinformationen einzusetzen. Die meisten Automatisierungstools erfordern eine nicht interaktive Methode. Erstellen Sie eine sichere Zeichenfolge mit dem Kennwort, um Anmeldeinformationen ohne Interaktion mit dem Benutzer zu erstellen. Übergeben Sie dann die sichere Zeichenfolge und den Benutzernamen an die System.Management.Automation.PSCredential()-Methode.

Erstellen Sie mit dem folgenden Befehl eine sichere Zeichenfolge mit dem Kennwort:

ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force

AsPlainText und Force sind Pflichtparameter. Ohne diese Parameter erhalten Sie eine Warnmeldung, dass Sie keinen Klartext in eine sichere Zeichenfolge eingeben dürfen. PowerShell gibt diese Warnung zurück, da das Kennwort im Klartext in verschiedenen Protokollen aufgezeichnet wird. Nachdem Sie eine sichere Zeichenfolge erstellt haben, müssen Sie sie an die PSCredential()-Methode übergeben, um das Objekt für Anmeldeinformationen zu erstellen. Im folgenden Beispiel enthält die Variable $password die sichere Zeichenfolge $Cred mit dem Objekt mit Anmeldeinformationen.

$password = ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ("username", $password)

Nachdem Sie nun wissen, wie Objekte mit Anmeldeinformationen erstellt werden, können Sie Ihren PowerShell-Funktionen Parameter mit Anmeldeinformationen hinzufügen.

Hinzufügen eines Parameters mit Anmeldeinformationen

Wie bei jedem anderen Parameter beginnen Sie, indem Sie ihn dem Block param Ihrer Funktion hinzufügen. Es wird empfohlen, den Parameter $Credential zu nennen, weil dieser von vorhandenen PowerShell-Cmdlets verwendet wird. Der Typ des Parameters muss [System.Management.Automation.PSCredential] sein.

Das folgende Beispiel zeigt den Parameterblock für eine Funktion mit dem Namen Get-Something. Sie hat zwei Parameter: $Name und $Credential.

function Get-Something {
    param(
        $Name,
        [System.Management.Automation.PSCredential]$Credential
    )

Der Code in diesem Beispiel reicht für einen funktionierenden Parameter mit Anmeldeinformationen aus. Es gibt jedoch ein paar Dinge, die Sie hinzufügen können, um ihn stabiler zu machen.

  • Fügen Sie das Überprüfungsattribut [ValidateNotNull()] hinzu, um zu prüfen, ob der Wert an Credential übergeben wird. Wenn der Parameterwert NULL ist, verhindert dieses Attribut die Ausführung der Funktion mit ungültigen Anmeldeinformationen.

  • Fügen Sie [System.Management.Automation.Credential()] hinzu. Dies ermöglicht Ihnen die Eingabe eines Benutzernamens als Zeichenfolge und eine interaktive Abfrage des Kennworts.

  • Legen Sie den Standardwert des Parameters $Credential auf [System.Management.Automation.PSCredential]::Empty fest. Ihre Funktion übergibt dieses $Credential-Objekt möglicherweise an vorhandene PowerShell-Cmdlets. Das Angeben eines NULL-Werts für das Cmdlet, das in Ihrer Funktion aufgerufen wird, verursacht einen Fehler. Durch Angeben eines leeren Objekts mit Anmeldeinformationen wird dieser Fehler vermieden.

Tipp

Einige Cmdlets, die einen Parameter mit Anmeldeinformationen akzeptieren, unterstützen [System.Management.Automation.PSCredential]::Empty nicht. Eine Problemumgehung finden Sie im Abschnitt Umgang mit Legacy-Cmdlets.

Verwenden von Parametern mit Anmeldeinformationen

Im folgenden Beispiel wird die Verwendung von Parametern mit Anmeldeinformationen veranschaulicht. Dieses Beispiel zeigt eine Funktion mit dem Namen Set-RemoteRegistryValue, die aus The Pester Book stammt. Diese Funktion definiert den Parameter mit Anmeldeinformationen mithilfe der im vorherigen Abschnitt beschriebenen Techniken. Die Funktion ruft Invoke-Command mithilfe der Variablen $Credential auf, die von der Funktion erstellt wurde. Dies ermöglicht Ihnen das Ändern des Benutzers, der Invoke-Command ausführt. Da der Standardwert von $Credential leere Anmeldeinformationen sind, kann die Funktion ohne Angabe von Anmeldeinformationen ausgeführt werden.

function Set-RemoteRegistryValue {
    param(
        $ComputerName,
        $Path,
        $Name,
        $Value,
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )
        $null = Invoke-Command -ComputerName $ComputerName -ScriptBlock {
            Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
        } -Credential $Credential
}

In den folgenden Abschnitten werden verschiedene Methoden zum Bereitstellen von Anmeldeinformationen für Set-RemoteRegistryValue erläutert.

Anfordern von Anmeldeinformationen

Die Verwendung von Get-Credential in Klammern () zur Laufzeit bewirkt, dass Get-credential zuerst ausgeführt wird. Sie werden aufgefordert, einen Benutzernamen und ein Kennwort einzugeben. Sie könnten die Parameter Credential oder UserName von Get-credential verwenden, um den Benutzernamen und die Domäne vorab auszufüllen. Im folgenden Beispiel wird eine Technik namens „Splatting“ verwendet, um Parameter an die Set-RemoteRegistryValue-Funktion zu übergeben. Weitere Informationen zu Splatting finden Sie im Artikel about_Splatting.

$remoteKeyParams = @{
    ComputerName = $env:COMPUTERNAME
    Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
    Name = 'EnableRemoteManagement'
    Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams -Credential (Get-Credential)

Abrufen von Anmeldeinformationen zur Laufzeit

Die Verwendung von (Get-Credential) scheint umständlich. Wenn Sie den Parameter Credential nur mit einem Benutzernamen verwenden, fordert das Cmdlet normalerweise automatisch zur Eingabe des Kennworts auf. Das Attribut [System.Management.Automation.Credential()] ermöglicht dieses Verhalten.

$remoteKeyParams = @{
    ComputerName = $env:COMPUTERNAME
    Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
    Name = 'EnableRemoteManagement'
    Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams -Credential duffney

Aufforderung zur Eingabe von Anmeldeinformationen

Hinweis

Um den angezeigten Registrierungswert festzulegen, wird in diesen Beispielen davon ausgegangen, dass die Webserver-Features von Windows installiert sind. Führen Sie bei Bedarf Install-WindowsFeature Web-Server und Install-WindowsFeature web-mgmt-tools aus.

Angeben von Anmeldeinformationen in einer Variablen

Sie können eine Variable für Anmeldeinformationen auch vorab auffüllen und an den Credential-Parameter der Set-RemoteRegistryValue-Funktion übergeben. Verwenden Sie diese Methode mit Continuous Integration-/Continuous Deployment-Tools (CI/CD) wie Jenkins, TeamCity und Octopus Deploy. Ein Beispiel für Jenkins finden Sie im Blogbeitrag von Matthew Hodgkins Automating with Jenkins and PowerShell on Windows - Part 2.

In diesem Beispiel wird die .NET-Methode verwendet, um das Objekt für Anmeldeinformationen und eine sichere Zeichenfolge für die Übergabe des Kennworts zu erstellen.

$password = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ("duffney", $password)

$remoteKeyParams = @{
    ComputerName = $env:COMPUTERNAME
    Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
    Name = 'EnableRemoteManagement'
    Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams -Credential $Cred

In diesem Beispiel wird die sichere Zeichenfolge mit einem Kennwort in Klartext erstellt. Alle zuvor erwähnten CI/CD-Tools verfügen über eine sichere Methode zur Bereitstellung dieses Kennworts zur Laufzeit. Ersetzen Sie bei Nutzung dieser Tools das Kennwort im Klartext durch die Variable, die in dem von Ihnen verwendeten CI/CD-Tool definiert ist.

Ausführung ohne Anmeldeinformationen

Da $Credential standardmäßig ein leeres Anmeldeinformationsobjekt ist, können Sie den Befehl, wie in diesem Beispiel gezeigt, ohne Anmeldeinformationen ausführen:

$remoteKeyParams = @{
    ComputerName = $env:COMPUTERNAME
    Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
    Name = 'EnableRemoteManagement'
    Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams

Umgang mit Legacy-Cmdlets

Nicht alle Cmdlets unterstützen Objekte mit Anmeldeinformationen oder lassen leere Anmeldeinformationen zu. Stattdessen fordert das Cmdlet Parameter für Benutzername und Kennwort als Zeichenfolgen an. Es gibt mehrere Möglichkeiten, diese Einschränkung zu umgehen.

Verwenden von IF-ELSE bei leeren Anmeldeinformationen

In diesem Szenario akzeptiert das Cmdlet, das Sie ausführen möchten, kein leeres Objekt für Anmeldeinformationen. Bei diesem Beispiel wird der Parameter Credential nur dann Invoke-Command hinzugefügt, wenn er nicht leer ist. Andernfalls wird Invoke-Command ohne den Parameter Credential ausgeführt.

function Set-RemoteRegistryValue {
    param(
        $ComputerName,
        $Path,
        $Name,
        $Value,
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    if($Credential -ne [System.Management.Automation.PSCredential]::Empty) {
        Invoke-Command -ComputerName:$ComputerName -Credential:$Credential  {
            Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
        }
    } else {
        Invoke-Command -ComputerName:$ComputerName {
            Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
        }
    }
}

Verwenden von Splatting bei leeren Anmeldeinformationen

Bei diesem Beispiel wird der Parameter „Splatting“ verwendet, um das Legacy-Cmdlet aufzurufen. Das Objekt $Credential wird der Hashtabelle für Splatting bedingt hinzugefügt und vermeidet, dass der Skriptblock Invoke-Command wiederholt werden muss. Weitere Informationen zu Splatting innerhalb von Funktionen finden Sie im Blogbeitrag Splatting Parameters Inside Advanced Functions.

function Set-RemoteRegistryValue {
    param(
        $ComputerName,
        $Path,
        $Name,
        $Value,
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

        $Splat = @{
            ComputerName = $ComputerName
        }

        if ($Credential -ne [System.Management.Automation.PSCredential]::Empty) {
            $Splat['Credential'] = $Credential
        }

        $null = Invoke-Command -ScriptBlock {
            Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
        } @splat
}

Arbeiten mit Zeichenfolgen als Kennwörtern

Das Cmdlet Invoke-Sqlcmd ist ein Beispiel eines Cmdlets, das eine Zeichenfolge als Kennwort akzeptiert. Invoke-Sqlcmd ermöglicht das Ausführen der einfachen SQL-Anweisungen INSERT, UPDATE und DELETE. Invoke-Sqlcmd erfordert einen Benutzernamen in Klartext und ein Kennwort anstelle eines sichereren Objekts mit Anmeldeinformationen. Dieses Beispiel zeigt, wie Benutzername und Kennwort aus einem Objekt mit Anmeldeinformationen extrahiert werden.

Die Get-AllSQLDatabases-Funktion in diesem Beispiel ruft das Cmdlet Invoke-Sqlcmd auf, um alle in einer SQL Server-Instanz enthaltenen Datenbanken abzufragen. Die Funktion definiert den Parameter Credential mit dem gleichen Attribut, das in den vorherigen Beispielen verwendet wurde. Da Benutzername und Kennwort innerhalb der Variablen $Credential vorhanden sind, können Sie diese Werte für die Verwendung mit Invoke-Sqlcmd extrahieren.

Der Benutzername ist über die Eigenschaft UserName der Variablen $Credential verfügbar. Zum Abrufen des Kennworts müssen Sie die GetNetworkCredential()-Methode des $Credential-Objekts verwenden. Die Werte werden in Variablen extrahiert, die einer Hashtabelle hinzugefügt werden, die zum Splatting von Parametern in Invoke-Sqlcmd dient.

function Get-AllSQLDatabases {
    param(
        $SQLServer,
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

        $UserName = $Credential.UserName
        $Password = $Credential.GetNetworkCredential().Password

        $splat = @{
            UserName = $UserName
            Password = $Password
            ServerInstance = 'SQLServer'
            Query = "Select * from Sys.Databases"
        }

        Invoke-Sqlcmd @splat
}

$credSplat = @{
    TypeName = 'System.Management.Automation.PSCredential'
    ArgumentList = 'duffney',('P@ssw0rd' | ConvertTo-SecureString -AsPlainText -Force)
}
$Credential = New-Object @credSplat

Get-AllSQLDatabases -SQLServer SQL01 -Credential $Credential

Weitere Informationen zur Verwaltung von Anmeldeinformationen

Die sichere Erstellung und Speicherung von Objekten mit Anmeldeinformationen kann schwierig sein. Die folgenden Ressourcen können Ihnen bei der Verwaltung von PowerShell-Anmeldeinformationen helfen.