Aggiungere il supporto delle credenziali alle funzioni di PowerShellAdd Credential support to PowerShell functions

Nota

La versione originale di questo articolo è apparsa nel blog a cura di @joshduffney.The original version of this article appeared on the blog written by @joshduffney. Questo articolo è stato modificato per essere incluso in questo sito.This article has been edited for inclusion on this site. Il team di PowerShell ringrazia Josh per averne condiviso il contenuto.The PowerShell team thanks Josh for sharing this content with us. Visitare il suo blog all'indirizzo duffney.io.Please check out his blog at duffney.io.

Questo articolo illustra come aggiungere i parametri delle credenziali alle funzioni di PowerShell e i motivi per cui eseguire questa operazione.This article shows you how to add credential parameters to PowerShell functions and why you'd want to. I parametri delle credenziali consentono di eseguire la funzione o il cmdlet come altro utente.A credential parameter is to allow you to run the function or cmdlet as a different user. L'uso più comune consiste nell'eseguire la funzione o il cmdlet come un account utente con privilegi elevati.The most common use is to run the function or cmdlet as an elevated user account.

Ad esempio, il cmdlet New-ADUser ha un parametro Credential che consente di specificare le credenziali di amministratore di dominio per creare un account in un dominio,For example, the cmdlet New-ADUser has a Credential parameter, which you could provide domain admin credentials to create an account in a domain. supponendo che il normale account che esegue la sessione di PowerShell non abbia già tale accesso.Assuming your normal account running the PowerShell session doesn't have that access already.

Creazione di un oggetto credenzialiCreating credential object

L'oggetto PSCredential rappresenta un set di credenziali di sicurezza, come ad esempio un nome utente e una password.The PSCredential object represents a set of security credentials such as a user name and password. L'oggetto può essere passato come parametro a una funzione che viene eseguita con l'account utente in tale oggetto credenziali.The object can be passed as a parameter to a function that runs as the user account in that credential object. È possibile creare un oggetto credenziali in diversi modi.There are a few ways that you can create a credential object. Il primo modo per creare un oggetto credenziali consiste nell'usare il cmdlet di PowerShell Get-Credential.The first way to create a credential object is to use the PowerShell cmdlet Get-Credential. Quando l'esecuzione avviene senza parametri, viene richiesto un nome utente e una password.When you run without parameters, it prompts you for a username and password. In alternativa, è possibile chiamare il cmdlet con alcuni parametri facoltativi.Or you can call the cmdlet with some optional parameters.

Per specificare il nome di dominio e il nome utente in anticipo, è possibile usare i parametri Credential o UserName.To specify the domain name and username ahead of time you can use either the Credential or UserName parameters. Quando si usa il parametro UserName , è necessario specificare anche un valore Message.When you use the UserName parameter, you're also required to provide a Message value. Il codice seguente illustra l'uso del cmdlet.The code below demonstrates using the cmdlet. È anche possibile archiviare l'oggetto credenziali in una variabile in modo da poter usare più volte le credenziali.You can also store the credential object in a variable so that you can use the credential multiple times. Nell'esempio seguente l'oggetto credenziali viene archiviato nella variabile $Cred.In the example below, the credential object is stored in the variable $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 descritto nell'esempio precedente.Sometimes, you can't use the interactive method of creating credential objects shown in the previous example. La maggior parte degli strumenti di automazione richiede un metodo non interattivo.Most automation tools require a non-interactive method. Per creare credenziali senza interazione dell'utente, creare una stringa sicura contenente la password.To create a credential without user interaction, create a secure string containing the password. Passare quindi la stringa sicura e il nome utente al metodo System.Management.Automation.PSCredential().Then pass the secure string and user name to the System.Management.Automation.PSCredential() method.

Usare il comando seguente per creare una stringa sicura che contiene la password:Use the following command to create a secure string containing the password:

ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force

Sono necessari entrambi i parametri AsPlainText e Force.Both the AsPlainText and Force parameters are required. Senza questi parametri, viene visualizzato un messaggio di avviso che indica di non passare testo normale in una stringa sicura.Without those parameters, you receive a message warning that you shouldn't pass plain text into a secure string. PowerShell restituisce questo avviso perché la password in testo normale viene registrata in diversi log.PowerShell returns this warning because the plain text password gets recorded in various logs. Una volta creata una stringa sicura, è necessario passarla al metodo PSCredential() per creare l'oggetto credenziali.Once you have a secure string created, you need to pass it to the PSCredential() method to create the credential object. Nell'esempio seguente la variabile $password contiene la stringa sicura $Cred contenente l'oggetto credenziali.In the following example, the variable $password contains the secure string $Cred contains the credential object.

$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 i parametri delle credenziali alle funzioni di PowerShell.Now that you know how to create credential objects, you can add credential parameters to your PowerShell functions.

Aggiunta di un parametro CredentialAdding a Credential Parameter

Come per qualsiasi altro parametro, iniziare aggiungendolo al blocco param della funzione.Just like any other parameter, you start off by adding it in the param block of your function. È consigliabile denominare il parametro $Credential perché è il nome che viene usato dai cmdlet di PowerShell esistenti.It's recommended that you name the parameter $Credential because that's what existing PowerShell cmdlets use. Il tipo del parametro deve essere [System.Management.Automation.PSCredential].The type of the parameter should be [System.Management.Automation.PSCredential].

Nell'esempio seguente viene illustrato il blocco di parametri per una funzione denominata Get-Something cheThe following example shows the parameter block for a function called Get-Something. contiene due parametri: $Name e $Credential.It has two parameters: $Name and $Credential.

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

Il codice in questo esempio è sufficiente per avere un parametro di credenziali funzionante, tuttavia esistono alcuni elementi che è possibile aggiungere per renderlo più affidabile.The code in this example is enough to have a working credential parameter, however there are a few things you can add to make it more robust.

  • Aggiungere l'attributo di convalida [ValidateNotNull()] per verificare che il valore venga passato a Credential.Add the [ValidateNotNull()] validation attribute to check that the value being passed to Credential. Se il valore del parametro è Null, questo attributo impedisce l'esecuzione della funzione con credenziali non valide.If the parameter value is null, this attribute prevents the function from executing with invalid credentials.

  • Aggiungere [System.Management.Automation.Credential()].Add [System.Management.Automation.Credential()]. In questo modo è possibile passare un nome utente come stringa e avere un prompt interattivo per la password.This allows you to pass in a username as a string and have an interactive prompt for the password.

  • Impostare un valore predefinito per il parametro $Credential su [System.Management.Automation.PSCredential]::Empty.Set a default value for the $Credential parameter to [System.Management.Automation.PSCredential]::Empty. La funzione potrebbe passare questo oggetto $Credential ai cmdlet di PowerShell esistenti.Your function you might be passing this $Credential object to existing PowerShell cmdlets. Se si specifica un valore Null per il cmdlet chiamato all'interno della funzione, viene generato un errore.Providing a null value to the cmdlet called inside your function causes an error. Per evitare questo errore, specificare un oggetto credenziali vuoto.Providing an empty credential object avoids this error.

Suggerimento

Alcuni cmdlet che accettano un parametro delle credenziali non supportano [System.Management.Automation.PSCredential]::Empty come dovrebbero.Some cmdlets that accept a credential parameter do not support [System.Management.Automation.PSCredential]::Empty as they should. Per una soluzione alternativa, vedere la sezione Gestione dei cmdlet legacy.See the Dealing with Legacy Cmdlets section for a workaround.

Uso dei parametri delle credenzialiUsing credential parameters

L'esempio seguente illustra come usare i parametri delle credenziali.The following example demonstrates how to use credential parameters. In questo esempio viene illustrata una funzione denominata Set-RemoteRegistryValue, presa dal The Pester Book.This example shows a function called Set-RemoteRegistryValue, which is out of The Pester Book. Questa funzione definisce il parametro delle credenziali usando le tecniche descritte nella sezione precedente.This function defines the credential parameter using the techniques describe in the previous section. La funzione chiama Invoke-Command usando la variabile $Credential creata dalla funzione.The function calls Invoke-Command using the $Credential variable created by the function. In questo modo è possibile modificare l'utente che esegue Invoke-Command.This allows you to change the user who's running Invoke-Command. Poiché il valore predefinito di $Credential è una credenziale vuota, la funzione può essere eseguita senza specificare le credenziali.Because the default value of $Credential is an empty credential, the function can run without providing credentials.

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 metodi diversi per specificare le credenziali per Set-RemoteRegistryValue.The following sections show different methods of providing credentials to Set-RemoteRegistryValue.

Richiesta di credenzialiPrompting for credentials

Se si usa Get-Credential tra parentesi () in fase di esecuzione, Get-credential viene eseguito per primo.Using Get-Credential in parentheses () at run time causes the Get-credential to run first. Vengono richiesti un nome utente e una password.You are prompted for a username and password. Per prepopolare il nome utente e il dominio, è possibile usare i parametri Credential o UserName di Get-credential.You could use the Credential or UserName parameters of Get-credential to pre-populate the username and domain. Nell'esempio seguente viene usata una tecnica denominata splatting per passare i parametri alla funzione Set-RemoteRegistryValue.The following example uses a technique called splatting to pass parameters to the Set-RemoteRegistryValue function. Per altre informazioni sullo splatting, vedere l'articolo [Informazioni sullo splatting][].For more information about splatting, check out the about_Splatting article.

$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 di (Get-Credential) sembra complesso.Using (Get-Credential) seems cumbersome. In genere, quando si usa il parametro Credential con solo un nome utente, il cmdlet richiede automaticamente la password.Normally, when you use the Credential parameter with only a username, the cmdlet automatically prompts for the password. L'attributo [System.Management.Automation.Credential()] abilita questo comportamento.The [System.Management.Automation.Credential()] attribute enables this behavior.

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

Set-RemoteRegistryValue @remoteKeyParams -Credential duffney

Richiesta di credenziali

Nota

Per impostare il valore del Registro di sistema visualizzato, in questi esempi si presuppone che le funzionalità Server Web di Windows siano installate.To set the registry value shown, these examples assume you have the Web Server features of Windows installed. Eseguire Install-WindowsFeature Web-Server e Install-WindowsFeature web-mgmt-tools se necessario.Run Install-WindowsFeature Web-Server and Install-WindowsFeature web-mgmt-tools if required.

Specificare le credenziali in una variabileProvide credentials in a variable

È anche possibile popolare anticipatamente una variabile credenziali e passarla al parametro Credential della funzione Set-RemoteRegistryValue.You can also populate a credential variable ahead of time and pass it to the Credential parameter of Set-RemoteRegistryValue function. Usare questo metodo con strumenti di integrazione continua/distribuzione continua (CI/CD), come ad esempio Jenkins, TeamCity e Octopus Deploy.Use this method with Continuous Integration / Continuous Deployment (CI/CD) tools such as Jenkins, TeamCity, and Octopus Deploy. Per un esempio di uso di Jenkins, vedere il post di blog di Hodge Automating with Jenkins and PowerShell on Windows - Part 2.For an example using Jenkins, check out Hodge's blog post Automating with Jenkins and PowerShell on Windows - Part 2.

In questo esempio viene usato il metodo .NET per creare l'oggetto credenziali e una stringa sicura da passare alla password.This example uses the .NET method to create the credential object and a secure string to pass in the 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 sicura viene creata usando una password non crittografata.For this example, the secure string is created using a clear text password. Tutti gli strumenti CI/CD indicati in precedenza hanno un metodo sicuro per specificare la password in fase di esecuzione.All of the previously mentioned CI/CD have a secure method of providing that password at run time. Quando si usano questi strumenti, sostituire la password in testo normale con la variabile definita nello strumento CI/CD usato.When using those tools, replace the plain text password with the variable defined within the CI/CD tool you use.

Esecuzione senza credenzialiRun without credentials

Poiché $Credential ha come impostazione predefinita un oggetto credenziali vuoto, è possibile eseguire il comando senza credenziali, come illustrato nell'esempio seguente:Since $Credential defaults to an empty credential object, you can run the command without credentials, as shown in this example:

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

Set-RemoteRegistryValue @remoteKeyParams

Gestione dei cmdlet legacyDealing with legacy cmdlets

Non tutti i cmdlet supportano gli oggetti credenziali o consentono credenziali vuote.Not all cmdlets support credential objects or allow empty credentials. Al contrario, richiedono i parametri nome utente e password come stringhe.Instead, the cmdlet wants username and password parameters as strings. Esistono diversi modi per aggirare questa limitazione.There are a few ways to work around this limitation.

Uso di if-else per gestire le credenziali vuoteUsing if-else to handle empty credentials

In questo scenario il cmdlet che si vuole eseguire non accetta un oggetto credenziali vuoto.In this scenario, the cmdlet you want to run doesn't accept an empty credential object. In questo esempio viene aggiunto il parametro Credential per Invoke-Command solo se non è vuoto.This example adds the Credential parameter to Invoke-Command only if it's not empty. In caso contrario, viene eseguito Invoke-Command senza il parametro Credential.Otherwise, it runs the Invoke-Command without the Credential parameter.

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 vuoteUsing splatting to handle empty credentials

Questo esempio usa lo splatting del parametro per chiamare il cmdlet legacy.This example uses parameter splatting to call the legacy cmdlet. L'oggetto $Credential viene aggiunto in modo condizionale alla tabella hash per lo splatting ed evita la necessità di ripetere il blocco di script Invoke-Command.The $Credential object is conditionally added to the hash table for splatting and avoids the need to repeat the Invoke-Command script block. Per altre informazioni sulle funzioni di splatting, vedere il post di blog Splatting di parametri all'interno di funzioni avanzate.To learn more about splatting inside functions, see the Splatting Parameters Inside Advanced Functions blog post.

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 in stringheWorking with string passwords

Il cmdlet Invoke-Sqlcmd è un esempio di cmdlet che accetta una stringa come password.The Invoke-Sqlcmd cmdlet is an example of a cmdlet that accepts a string as a password. Invoke-Sqlcmd consente di eseguire semplici istruzioni SQL di inserimento, aggiornamento ed eliminazione.Invoke-Sqlcmd allows you to run simple SQL insert, update, and delete statements. Invoke-Sqlcmd richiede un nome utente e una password non crittografati anziché un oggetto credenziali più sicuro.Invoke-Sqlcmd requires a clear-text username and password rather than a more secure credential object. Questo esempio illustra come estrarre il nome utente e la password da un oggetto credenziali.This example shows how to extract the username and password from a credential object.

La funzione Get-AllSQLDatabases in questo esempio chiama il cmdlet Invoke-Sqlcmd per eseguire una query su SQL Server per tutti i relativi database.The Get-AllSQLDatabases function in this example calls the Invoke-Sqlcmd cmdlet to query a SQL server for all its databases. La funzione definisce un parametro Credential con lo stesso attributo usato negli esempi precedenti.The function defines a Credential parameter with the same attribute used in the previous examples. Poiché il nome utente e la password sono presenti all'interno della variabile $Credential, è possibile estrarli per l'uso con Invoke-Sqlcmd.Since the username and password exist within the $Credential variable, you can extract those values for use with Invoke-Sqlcmd.

Il nome utente è disponibile dalla proprietà UserName della variabile $Credential.The user name is available from the UserName property of the $Credential variable. Per ottenere la password, è necessario usare il metodo GetNetworkCredential() dell'oggetto $Credential.To obtain the password, you have to use the GetNetworkCredential() method of the $Credential object. I valori vengono estratti in variabili aggiunte a una tabella hash usata per lo splatting dei parametri in Invoke-Sqlcmd.The values are extracted into variables that are added to a hash table used for splatting parameters to 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
ConvertTo-SecureString -AsPlainText -Force)

Get-AllSQLDatabases -SQLServer SQL01 -Credential $Credential

Gestione delle credenziali - formazione continuaContinued learning credential management

La creazione e l'archiviazione di oggetti credenziali in modo sicuro possono risultare difficili.Creating and storing credential objects securely can be difficult. Le risorse seguenti consentono di gestire le credenziali di PowerShell.The following resources can help you maintain PowerShell credentials.