Aggiungere il supporto delle credenziali alle funzioni di PowerShell
Nota
La versione originale di questo articolo è apparsa nel blog scritto da @joshduffney. Questo articolo è stato modificato per essere incluso in questo sito. Il team di PowerShell ringrazia Josh per averne condiviso il contenuto. Visitare il suo blog all'indirizzo duffney.io.
Questo articolo illustra come aggiungere i parametri delle credenziali alle funzioni di PowerShell e i motivi per cui eseguire questa operazione. I parametri delle credenziali consentono di eseguire la funzione o il cmdlet come altro utente. L'uso più comune consiste nell'eseguire la funzione o il cmdlet come un account utente con privilegi elevati.
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, supponendo che il normale account che esegue la sessione di PowerShell non abbia già tale accesso.
Creazione di un oggetto credenziali
L'oggetto PSCredential rappresenta un set di credenziali di sicurezza, come ad esempio un nome utente e una password. L'oggetto può essere passato come parametro a una funzione che viene eseguita con l'account utente in tale oggetto credenziali. È possibile creare un oggetto credenziali in diversi modi. Il primo modo per creare un oggetto credenziali consiste nell'usare il cmdlet di PowerShell Get-Credential
. Quando l'esecuzione avviene 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 credenziali in una variabile in modo da poter usare più volte le credenziali. Nell'esempio seguente l'oggetto credenziali 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 descritto 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 metodo System.Management.Automation.PSCredential()
.
Usare il comando seguente per creare una stringa sicura che contiene 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 di non passare testo normale in una stringa sicura. PowerShell restituisce questo avviso perché la password in testo normale viene registrata in diversi log. Una volta creata una stringa sicura, è necessario passarla al metodo PSCredential()
per creare l'oggetto credenziali. Nell'esempio seguente la variabile $password
contiene la stringa sicura $Cred
contenente l'oggetto credenziali.
$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.
Aggiunta di un parametro Credential
Come per qualsiasi altro parametro, iniziare aggiungendolo al blocco param
della funzione.
È consigliabile denominare il parametro $Credential
perché è il nome che viene usato 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
che contiene 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 credenziali funzionante, tuttavia esistono alcuni elementi che è possibile aggiungere per renderlo più affidabile.
Aggiungere l'attributo di convalida
[ValidateNotNull()]
per verificare che il valore venga 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 avere un prompt interattivo per la password.Impostare un valore predefinito per il parametro
$Credential
su[System.Management.Automation.PSCredential]::Empty
. La funzione potrebbe passare questo oggetto$Credential
ai cmdlet di PowerShell esistenti. Se si specifica un valore Null per il cmdlet chiamato all'interno della funzione, viene generato un errore. Per evitare questo errore, specificare un oggetto credenziali vuoto.
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
L'esempio seguente illustra come usare i parametri delle credenziali. In questo esempio viene illustrata una funzione denominata Set-RemoteRegistryValue
, presa dal The Pester Book. Questa funzione definisce il parametro delle credenziali usando le tecniche descritte nella sezione precedente. La funzione chiama Invoke-Command
usando la variabile $Credential
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 specificare le 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 metodi diversi per specificare le credenziali per Set-RemoteRegistryValue
.
Richiesta di credenziali
Se si usa Get-Credential
tra parentesi ()
in fase di esecuzione, Get-credential
viene eseguito per primo. Vengono richiesti un nome utente e una password. Per prepopolare il nome utente e il dominio, è possibile usare i parametri Credential o UserName di Get-credential
. Nell'esempio seguente viene usata una tecnica denominata splatting per passare i parametri alla funzione Set-RemoteRegistryValue
. Per altre informazioni sullo splatting, vedere l'articolo Informazioni sullo splatting.
$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
}
Set-RemoteRegistryValue @remoteKeyParams -Credential (Get-Credential)
L'uso di (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
Nota
Per impostare il valore del Registro di sistema visualizzato, in questi esempi si presuppone che le funzionalità Server Web di Windows siano installate. Eseguire Install-WindowsFeature Web-Server
e Install-WindowsFeature web-mgmt-tools
se necessario.
Specificare le credenziali in una variabile
È anche possibile popolare anticipatamente una variabile credenziali e passarla al parametro Credential della funzione Set-RemoteRegistryValue
. Usare questo metodo con strumenti di integrazione continua/distribuzione continua (CI/CD), come ad esempio Jenkins, TeamCity e 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.
In questo esempio viene usato il metodo .NET per creare l'oggetto credenziali e una stringa sicura da passare alla 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. Tutti gli strumenti CI/CD indicati in precedenza hanno un metodo sicuro per specificare la password in fase di esecuzione. Quando si usano questi strumenti, sostituire la password in testo normale con la variabile definita nello strumento CI/CD usato.
Esecuzione senza credenziali
Poiché $Credential
ha come impostazione predefinita un oggetto credenziali vuoto, è possibile eseguire il comando senza credenziali, come illustrato nell'esempio seguente:
$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 gli oggetti credenziali o consentono credenziali vuote. Al contrario, richiedono i parametri nome utente e password come stringhe. Esistono diversi modi per aggirare questa limitazione.
Uso di if-else per gestire le credenziali vuote
In questo scenario il cmdlet che si vuole eseguire non accetta un oggetto credenziali vuoto. In questo esempio viene aggiunto il parametro Credential per Invoke-Command
solo se non è vuoto. In caso contrario, viene eseguito 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
Questo esempio usa lo splatting del parametro per chiamare il cmdlet legacy. 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
. Per altre informazioni sulle funzioni di splatting, vedere il post di blog Splatting di parametri 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 in stringhe
Il cmdlet Invoke-Sqlcmd
è un esempio di cmdlet che accetta una stringa come password.
Invoke-Sqlcmd
consente di eseguire semplici istruzioni SQL di inserimento, aggiornamento ed eliminazione. 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 credenziali.
La funzione Get-AllSQLDatabases
in questo esempio chiama il cmdlet Invoke-Sqlcmd
per eseguire una query su SQL Server 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 sono presenti all'interno della variabile $Credential
, è possibile estrarli per l'uso con Invoke-Sqlcmd
.
Il nome utente è disponibile dalla proprietà UserName della variabile $Credential
. Per ottenere la password, è necessario usare il metodo GetNetworkCredential()
dell'oggetto $Credential
. I valori vengono estratti in variabili aggiunte a una tabella hash usata per lo 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 delle credenziali - formazione continua
La creazione e l'archiviazione di oggetti credenziali in modo sicuro possono risultare difficili. Le risorse seguenti consentono di gestire le credenziali di PowerShell.