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

Kommentar

Den ursprungliga versionen av den här artikeln visades 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 autentiseringsparametrar i PowerShell-funktioner och varför du vill det. 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 autentiseringsuppgifter för domänadministratör för att skapa ett konto i en domän. Förutsatt att ditt normala 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ännamnet och användarnamnet i förväg kan du använda parametrarna Autentiseringsuppgifter eller Användarnamn . 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 objektet för autentiseringsuppgifter 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 ett meddelande 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 till PSCredential() 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 autentiseringsobjektet.

$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 dina PowerShell-funktioner.

Lägga till en parameter för autentiseringsuppgifter

Precis som 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 med namnet 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. Din funktion 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.

Dricks

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

Använda parametrar för autentiseringsuppgifter

I följande exempel visas hur du använder parametrar för autentiseringsuppgifter. I det här exemplet visas en funktion med namnet 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 användaren 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

Att använda Get-Credential inom parenteser () vid körning gör att körningen Get-credential först. Du uppmanas att ange ett användarnamn och lösenord. Du kan använda parametrarna Get-credential Credential 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 uppmanas cmdleten automatiskt att ange 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

Kommentar

För att ange registervärdet som visas förutsätter dessa exempel 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 Set-RemoteRegistryValue Credential för funktionen. Använd den här metoden med CI/CD-verktyg (Continuous Integration/Continuous Deployment), till exempel Jenkins, TeamCity och Octopus Deploy. Ett exempel med 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 autentiseringsobjektet och en säker sträng för att skicka in 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 autentiseringsobjekt 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 inte den cmdlet som du vill köra ett tomt autentiseringsobjekt. Det här exemplet lägger bara till parametern Credential om Invoke-Command den inte är tom. Annars körs parametern Invoke-Commandutan 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änds 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 få 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

Hantering av kontinuerlig inlärning av autentiseringsuppgifter

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.