Condividi tramite


Aggiungere il supporto delle credenziali alle funzioni di PowerShell

Annotazioni

La versione originale di questo articolo è apparsa sul blog scritto da @joshduffney. Questo articolo è stato modificato per l'inclusione in questo sito. Il team di PowerShell ringrazia Josh per condividere questo contenuto con noi. Per favore, consulta il suo blog all'indirizzo duffney.io.

Questo articolo illustra come aggiungere parametri delle credenziali alle funzioni di PowerShell e perché si vuole. Un parametro delle credenziali consente di eseguire la funzione o il cmdlet come utente diverso. L'uso più comune consiste nell'eseguire la funzione o il cmdlet come account utente con privilegi elevati.

Ad esempio, il cmdlet New-ADUser ha un parametro Credential , che è possibile fornire credenziali di amministratore di dominio per creare un account in un dominio. Supponendo che l'account normale che esegue la sessione di PowerShell non abbia già tale accesso.

Creazione di un oggetto credenziale

L'oggetto PSCredential rappresenta un set di credenziali di sicurezza, ad esempio un nome utente e una password. L'oggetto può essere passato come parametro a una funzione eseguita come account utente in tale oggetto credenziale. Esistono alcuni modi per creare un oggetto credenziale. Il primo modo per creare un oggetto credenziale consiste nell'usare il cmdlet Get-Credentialdi PowerShell . Quando si esegue senza parametri, viene richiesto un nome utente e una password. In alternativa, è possibile chiamare il cmdlet con alcuni parametri facoltativi.

Per specificare il nome di dominio e il nome utente in anticipo, è possibile usare i parametri Credential o UserName . Quando si usa il parametro UserName , è necessario specificare anche un valore Message . Il codice seguente illustra l'uso del cmdlet . È anche possibile archiviare l'oggetto credenziale in una variabile in modo che sia possibile usare le credenziali più volte. Nell'esempio seguente l'oggetto credenziale viene archiviato nella variabile $Cred.

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

In alcuni casi, non è possibile usare il metodo interattivo per la creazione di oggetti credenziali illustrati nell'esempio precedente. La maggior parte degli strumenti di automazione richiede un metodo non interattivo. Per creare credenziali senza interazione dell'utente, creare una stringa sicura contenente la password. Passare quindi la stringa sicura e il nome utente al System.Management.Automation.PSCredential() metodo .

Usare il comando seguente per creare una stringa sicura contenente la password:

ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force

Sono necessari entrambi i parametri AsPlainText e Force . Senza questi parametri, viene visualizzato un messaggio di avviso che indica che non è consigliabile passare testo normale in una stringa sicura. PowerShell restituisce questo avviso perché la password di testo normale viene registrata in vari log. Dopo aver creato una stringa sicura, è necessario passarla al PSCredential() metodo per creare l'oggetto credenziale. Nell'esempio seguente la variabile $password contiene la stringa $Cred protetta contenente l'oggetto credenziale.

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

Ora che si è appreso come creare oggetti credenziali, è possibile aggiungere parametri delle credenziali alle funzioni di PowerShell.

Aggiungere un parametro delle credenziali

Proprio come qualsiasi altro parametro, si inizia aggiungendolo nel param blocco della funzione. È consigliabile assegnare al parametro $Credential il nome utilizzato dai cmdlet di PowerShell esistenti. Il tipo del parametro deve essere [System.Management.Automation.PSCredential].

Nell'esempio seguente viene illustrato il blocco di parametri per una funzione denominata Get-Something. Ha due parametri: $Name e $Credential.

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

Il codice in questo esempio è sufficiente per avere un parametro di credenziale funzionante, ma esistono alcuni elementi che è possibile aggiungere per renderlo più affidabile.

  • Aggiungere l'attributo [ValidateNotNull()] di convalida per verificare che il valore passato a Credential. Se il valore del parametro è Null, questo attributo impedisce l'esecuzione della funzione con credenziali non valide.

  • Aggiungere [System.Management.Automation.Credential()]. In questo modo è possibile passare un nome utente come stringa e richiedere la password in modo interattivo.

  • Impostare un valore predefinito per il $Credential parametro su [System.Management.Automation.PSCredential]::Empty. È possibile che la funzione passi questo $Credential oggetto ai cmdlet di PowerShell esistenti. Se si specifica un valore Null al cmdlet chiamato all'interno della funzione, viene generato un errore. Se si specifica un oggetto credenziale vuoto, si evita questo errore.

Suggerimento

Alcuni cmdlet che accettano un parametro delle credenziali non supportano [System.Management.Automation.PSCredential]::Empty come dovrebbero. Per una soluzione alternativa, vedere la sezione Gestione dei cmdlet legacy .

Uso dei parametri delle credenziali

Nell'esempio seguente viene illustrato come usare i parametri delle credenziali. In questo esempio viene illustrata una funzione denominata Set-RemoteRegistryValue, che è fuori da The Pester Book. Questa funzione definisce il parametro delle credenziali usando le tecniche descritte nella sezione precedente. La funzione chiama Invoke-Command usando la $Credential variabile creata dalla funzione . In questo modo è possibile modificare l'utente che esegue Invoke-Command. Poiché il valore predefinito di $Credential è una credenziale vuota, la funzione può essere eseguita senza fornire credenziali.

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
}

Le sezioni seguenti illustrano diversi metodi per fornire le credenziali a Set-RemoteRegistryValue.

Richiesta di credenziali

Se si usano Get-Credential tra parentesi () in fase di esecuzione, l'oggetto Get-Credential viene eseguito per primo. Viene richiesto un nome utente e una password. È possibile usare i parametri Credential o UserName di Get-Credential per precompilare il nome utente e il dominio. Nell'esempio seguente viene utilizzata una tecnica chiamata splatting per passare i parametri alla funzione Set-RemoteRegistryValue. Per ulteriori informazioni sulla splatting, consulta l'articolo about_Splatting.

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

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

Ottenere credenziali in fase di esecuzione

L'uso (Get-Credential) sembra complesso. In genere, quando si usa il parametro Credential con solo un nome utente, il cmdlet richiede automaticamente la password. L'attributo [System.Management.Automation.Credential()] abilita questo comportamento.

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

Set-RemoteRegistryValue @remoteKeyParams -Credential duffney

Richiedi credenziali

Annotazioni

Per impostare il valore del Registro di sistema visualizzato, questi esempi presuppongono che siano installate le funzionalità server Web di Windows. Eseguire Install-WindowsFeature Web-Server e Install-WindowsFeature web-mgmt-tools se necessario.

Specificare le credenziali in una variabile

È anche possibile popolare una variabile delle credenziali in anticipo e passarla al parametro Credential della Set-RemoteRegistryValue funzione. Usare questo metodo con strumenti di integrazione continua/distribuzione continua (CI/CD), ad esempio Jenkins, TeamCity e Octopus Deploy. Per un esempio relativo all'uso di Jenkins, vedere il post di blog di Hodge Automating with Jenkins and PowerShell on Windows - Part 2 (Automazione con Jenkins e PowerShell in Windows - Parte 2).

In questo esempio viene usato il metodo .NET per creare l'oggetto credenziali e una stringa sicura come input per la password.

$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

Per questo esempio, la stringa protetta viene creata usando una password di testo non crittografato. Tutti i CI/CD indicati in precedenza hanno un metodo sicuro per fornire tale password in fase di esecuzione. Quando si usano questi strumenti, sostituire la password di testo normale con la variabile definita nello strumento CI/CD usato.

Esegui senza credenziali

Poiché $Credential l'impostazione predefinita è un oggetto credenziali vuoto, è possibile eseguire il comando senza credenziali, come illustrato in questo esempio:

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

Set-RemoteRegistryValue @remoteKeyParams

Gestione dei cmdlet legacy

Non tutti i cmdlet supportano oggetti credenziali o consentono credenziali vuote. Il cmdlet desidera invece parametri nome utente e password come stringhe. Esistono alcuni modi per aggirare questa limitazione.

Uso di if-else per gestire credenziali vuote

In questo scenario, il cmdlet da eseguire non accetta un oggetto credenziale vuoto. In questo esempio, il parametro Credential viene aggiunto a Invoke-Command solo se non è vuoto. In caso contrario, esegue Invoke-Command senza il parametro Credential .

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

Uso dello splatting per gestire le credenziali vuote

In questo esempio viene usato lo splatting dei parametri per chiamare il cmdlet legacy. L'oggetto $Credential viene aggiunto alla tabella hash in modo condizionale per lo splatting, evitando la necessità di ripetere il blocco di script Invoke-Command. Per ulteriori informazioni sullo splatting all'interno delle funzioni, vedere il post di blog Splatting Parameters Inside Advanced Functions (Parametri di splatting all'interno di funzioni avanzate).

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
}

Uso delle password delle stringhe

Il Invoke-Sqlcmd cmdlet è un esempio di cmdlet che accetta una stringa come password. Invoke-Sqlcmd consente di eseguire semplici istruzioni di inserimento, aggiornamento ed eliminazione di SQL. Invoke-Sqlcmd richiede un nome utente e una password non crittografati anziché un oggetto credenziali più sicuro. Questo esempio illustra come estrarre il nome utente e la password da un oggetto credenziale.

La Get-AllSQLDatabases funzione in questo esempio chiama il Invoke-Sqlcmd cmdlet per eseguire query su un server SQL per tutti i relativi database. La funzione definisce un parametro Credential con lo stesso attributo usato negli esempi precedenti. Poiché il nome utente e la password esistono all'interno della $Credential variabile, è possibile estrarre tali valori da usare con Invoke-Sqlcmd.

Il nome utente è disponibile dalla proprietà UserName della $Credential variabile. Per ottenere la password, è necessario usare il GetNetworkCredential() metodo dell'oggetto $Credential . I valori vengono estratti in variabili aggiunte a una tabella hash usata per il "splatting" dei parametri in 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

Gestione continua delle credenziali di apprendimento

La creazione e l'archiviazione di oggetti credenziali in modo sicuro possono risultare difficili. Le risorse seguenti consentono di gestire le credenziali di PowerShell.