Lägg till support för autentiseringsuppgifter in PowerShell-funktioner

Anteckning

Den ursprungliga versionen av den här artikeln dök upp på bloggen skriven av @joshduffney. Den här artikeln har redigerats för inkludering på den här webbplatsen. PowerShell-teamet tackar Josh för att ha delat det här innehållet med oss. Kolla in hans blogg på duffney.io.

Den här artikeln visar hur du lägger till parametrar för autentiseringsuppgifter i PowerShell-funktioner och varför du vill. En parameter för autentiseringsuppgifter är att du kan köra funktionen eller cmdleten som en annan användare. Den vanligaste användningen är att köra funktionen eller cmdleten som ett förhöjt användarkonto.

Cmdleten New-ADUser har till exempel en parameter för autentiseringsuppgifter , som du kan ange domänadministratörsautentiseringsuppgifter för att skapa ett konto i en domän. Förutsatt att ditt vanliga konto som kör PowerShell-sessionen inte redan har den åtkomsten.

Skapa autentiseringsobjekt

PSCredential-objektet representerar en uppsättning säkerhetsautentiseringsuppgifter, till exempel användarnamn och lösenord. Objektet kan skickas som en parameter till en funktion som körs som användarkonto i det autentiseringsobjektet. Det finns några sätt att skapa ett autentiseringsobjekt. Det första sättet att skapa ett autentiseringsobjekt är att använda PowerShell-cmdleten Get-Credential. När du kör utan parametrar uppmanas du att ange ett användarnamn och lösenord. Eller så kan du anropa cmdleten med några valfria parametrar.

Om du vill ange domännamn och användarnamn i förväg kan du använda parametrarna Credential eller UserName . När du använder parametern UserName måste du också ange ett meddelandevärde . Koden nedan visar hur du använder cmdleten. Du kan också lagra objektet för autentiseringsuppgifter i en variabel så att du kan använda autentiseringsuppgifterna flera gånger. I exemplet nedan lagras autentiseringsobjektet i variabeln $Cred.

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

Ibland kan du inte använda den interaktiva metoden för att skapa autentiseringsobjekt som visas i föregående exempel. De flesta automatiseringsverktyg kräver en icke-interaktiv metod. Om du vill skapa en autentiseringsuppgift utan användarinteraktion skapar du en säker sträng som innehåller lösenordet. Skicka sedan den säkra strängen och användarnamnet System.Management.Automation.PSCredential() till metoden.

Använd följande kommando för att skapa en säker sträng som innehåller lösenordet:

ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force

Både Parametrarna AsPlainText och Force krävs. Utan dessa parametrar får du en meddelandevarning om att du inte ska skicka oformaterad text till en säker sträng. PowerShell returnerar den här varningen eftersom lösenordet för oformaterad text registreras i olika loggar. När du har skapat en säker sträng måste du skicka den PSCredential() till metoden för att skapa objektet för autentiseringsuppgifter. I följande exempel innehåller variabeln $password den säkra strängen $Cred som innehåller objektet för autentiseringsuppgifter.

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

Nu när du vet hur du skapar autentiseringsobjekt kan du lägga till parametrar för autentiseringsuppgifter i powershell-funktionerna.

Lägga till en parameter för autentiseringsuppgifter

Precis som med andra parametrar börjar du med att lägga till den i funktionsblocket param . Vi rekommenderar att du namnger parametern $Credential eftersom det är vad befintliga PowerShell-cmdletar använder. Parametertypen ska vara [System.Management.Automation.PSCredential].

I följande exempel visas parameterblocket för en funktion som heter Get-Something. Den har två parametrar: $Name och $Credential.

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

Koden i det här exemplet räcker för att ha en fungerande parameter för autentiseringsuppgifter, men det finns några saker du kan lägga till för att göra den mer robust.

  • Lägg till verifieringsattributet [ValidateNotNull()] för att kontrollera att värdet skickas till Autentiseringsuppgifter. Om parametervärdet är null förhindrar det här attributet att funktionen körs med ogiltiga autentiseringsuppgifter.

  • Lägg till [System.Management.Automation.Credential()]. På så sätt kan du skicka in ett användarnamn som en sträng och ha en interaktiv fråga efter lösenordet.

  • Ange ett standardvärde för parametern $Credential till [System.Management.Automation.PSCredential]::Empty. Funktionen som du kanske skickar det här $Credential objektet till befintliga PowerShell-cmdletar. Om du anger ett null-värde för cmdleten som anropas i funktionen uppstår ett fel. Om du anger ett tomt autentiseringsobjekt undviker du det här felet.

Tips

Vissa cmdletar som accepterar en parameter för autentiseringsuppgifter stöder [System.Management.Automation.PSCredential]::Empty inte som de ska. En lösning finns i avsnittet Hantera äldre cmdletar .

Använda parametrar för autentiseringsuppgifter

I följande exempel visas hur du använder parametrar för autentiseringsuppgifter. Det här exemplet visar en funktion som heter Set-RemoteRegistryValue, som inte finns i Pester-boken. Den här funktionen definierar parametern för autentiseringsuppgifter med hjälp av de tekniker som beskrivs i föregående avsnitt. Funktionen anropar Invoke-Command med hjälp av variabeln $Credential som skapats av funktionen. På så sätt kan du ändra den användare som kör Invoke-Command. Eftersom standardvärdet $Credential för är en tom autentiseringsuppgift kan funktionen köras utan att ange autentiseringsuppgifter.

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
}

I följande avsnitt visas olika metoder för att ange autentiseringsuppgifter till Set-RemoteRegistryValue.

Fråga efter autentiseringsuppgifter

Om du använder Get-Credential parenteser () vid körningen körs Get-credential körs först. Du uppmanas att ange ett användarnamn och lösenord. Du kan använda parametrarna Get-credentialCredential eller UserName för för att fylla i användarnamnet och domänen i förväg. I följande exempel används en teknik som kallas splatting för att skicka parametrar till Set-RemoteRegistryValue funktionen. Mer information om splatting finns i artikeln about_Splatting .

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

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

Hämta en autentiseringsuppgift vid körning

Att använda (Get-Credential) verkar besvärligt. När du använder parametern Credential med endast ett användarnamn uppmanar cmdleten normalt lösenordet. Attributet [System.Management.Automation.Credential()] aktiverar det här beteendet.

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

Set-RemoteRegistryValue @remoteKeyParams -Credential duffney

Fråga efter autentiseringsuppgifter

Anteckning

Om du vill ange registervärdet som visas förutsätter de här exemplen att du har webbserverfunktionerna i Windows installerade. Kör Install-WindowsFeature Web-Server och Install-WindowsFeature web-mgmt-tools om det behövs.

Ange autentiseringsuppgifter i en variabel

Du kan också fylla i en variabel för autentiseringsuppgifter i förväg och skicka den till parametern Credential för Set-RemoteRegistryValue funktionen. Använd den här metoden med CI/CD-verktyg (Continuous Integration/Continuous Deployment), till exempel Jenkins, TeamCity och Octopus Deploy. Ett exempel på hur du använder Jenkins finns i Hodges blogginlägg Automatisera med Jenkins och PowerShell i Windows – del 2.

I det här exemplet används .NET-metoden för att skapa objektet för autentiseringsuppgifter och en säker sträng för att skicka lösenordet.

$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

I det här exemplet skapas den säkra strängen med ett lösenord för klartext. Alla tidigare nämnda CI/CD har en säker metod för att ange lösenordet vid körning. När du använder dessa verktyg ersätter du lösenordet för oformaterad text med variabeln som definierats i ci/CD-verktyget som du använder.

Kör utan autentiseringsuppgifter

Eftersom $Credential standardvärdet är ett tomt autentiseringsobjekt kan du köra kommandot utan autentiseringsuppgifter, som du ser i det här exemplet:

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

Set-RemoteRegistryValue @remoteKeyParams

Hantera äldre cmdletar

Alla cmdletar stöder inte autentiseringsuppgifter eller tillåter tomma autentiseringsuppgifter. I stället vill cmdleten ha parametrar för användarnamn och lösenord som strängar. Det finns några sätt att kringgå den här begränsningen.

Använda if-else för att hantera tomma autentiseringsuppgifter

I det här scenariot accepterar cmdleten som du vill köra inte ett tomt autentiseringsobjekt. I det här exemplet läggs parametern Credential till Invoke-Command endast om den inte är tom. Annars körs Invoke-Command parametern utan autentiseringsuppgifter .

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
        }
    }
}

Använda splatting för att hantera tomma autentiseringsuppgifter

I det här exemplet används parametersplatting för att anropa den äldre cmdleten. Objektet $Credential läggs villkorligt till i hash-tabellen för splatting och undviker behovet av att upprepa skriptblocket Invoke-Command . Mer information om att splatta inuti funktioner finns i blogginlägget Splatting Parameters Inside Advanced Functions (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
}

Arbeta med stränglösenord

Cmdleten Invoke-Sqlcmd är ett exempel på en cmdlet som accepterar en sträng som ett lösenord. Invoke-Sqlcmd gör att du kan köra enkla SQL-infognings-, uppdaterings- och borttagningsinstruktioner. Invoke-Sqlcmd kräver ett användarnamn och lösenord i klartext i stället för ett säkrare autentiseringsobjekt. Det här exemplet visar hur du extraherar användarnamnet och lösenordet från ett autentiseringsobjekt.

Funktionen Get-AllSQLDatabases i det här exemplet anropar cmdleten Invoke-Sqlcmd för att fråga en SQL-server om alla dess databaser. Funktionen definierar en parameter för autentiseringsuppgifter med samma attribut som användes i föregående exempel. Eftersom användarnamnet och lösenordet finns i variabeln $Credential kan du extrahera dessa värden för användning med Invoke-Sqlcmd.

Användarnamnet är tillgängligt från egenskapen UserName för variabeln $Credential . För att hämta lösenordet måste du använda GetNetworkCredential() -metoden för $Credential objektet. Värdena extraheras till variabler som läggs till i en hash-tabell som används för att splatta parametrar till Invoke-Sqlcmd.

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

Fortsatt hantering av autentiseringsuppgifter för inlärning

Det kan vara svårt att skapa och lagra autentiseringsobjekt på ett säkert sätt. Följande resurser kan hjälpa dig att underhålla PowerShell-autentiseringsuppgifter.