將認證支援新增至 PowerShell 函式
注意
本文的原始版本出現在@joshduffney撰寫的部落格上。 本文已編輯為包含此網站。 PowerShell 小組感謝 Josh 與我們共用此內容。 請在 duffney.io 查看他的部落格。
本文說明如何將認證參數新增至 PowerShell 函式,以及您想要的原因。 認證參數是可讓您以不同的使用者身分執行函式或 Cmdlet。 最常見的用法是將函式或 Cmdlet 以提升許可權的用戶帳戶執行。
例如,Cmdlet New-ADUser
具有 Credential 參數,您可以提供網域管理員認證,以在網域中建立帳戶。 假設執行 PowerShell 會話的一般帳戶還沒有該存取權。
建立認證物件
PSCredential 物件代表一組安全性認證,例如使用者名稱和密碼。 物件可以當做參數傳遞至做為該認證對象中用戶帳戶執行的函式。 有幾種方式可以建立認證物件。 建立認證物件的第一種方式是使用 PowerShell Cmdlet Get-Credential
。 當您在沒有參數的情況下執行時,它會提示您輸入使用者名稱和密碼。 或者,您可以使用一些選擇性參數來呼叫 Cmdlet。
若要事先指定功能變數名稱和用戶名稱,您可以使用 Credential 或 UserName 參數。 當您使用 UserName 參數時,也需要提供 Message 值。 下列程式代碼示範如何使用 Cmdlet。 您也可以將認證物件儲存在變數中,以便多次使用認證。 在下列範例中,認證物件會儲存在 變數 $Cred
中。
$Cred = Get-Credential
$Cred = Get-Credential -Credential domain\user
$Cred = Get-Credential -UserName domain\user -Message 'Enter Password'
有時候,您無法使用互動式方法來建立上一個範例所示的認證物件。 大部分的自動化工具都需要非互動式方法。 若要在沒有使用者互動的情況下建立認證,請建立包含密碼的安全字串。 然後將安全字串和使用者名稱傳遞至 System.Management.Automation.PSCredential()
方法。
使用下列命令來建立包含密碼的安全字串:
ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force
需要 AsPlainText 和 Force 參數。 如果沒有這些參數,您會收到訊息警告,指出您不應該將純文本傳遞至安全字串。 PowerShell 會傳回此警告,因為純文本密碼會記錄在各種記錄中。 建立安全字串之後,您必須將它傳遞至 PSCredential()
方法來建立認證物件。 在下列範例中,變數 $password
包含安全字串 $Cred
包含認證物件。
$password = ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ("username", $password)
既然您已瞭解如何建立認證物件,您可以將認證參數新增至 PowerShell 函式。
新增認證參數
就像任何其他參數一樣,您一開始是在函式的 區塊中 param
新增它。
建議您命名 參數 $Credential
,因為這是現有PowerShell Cmdlet所使用的名稱。 參數的類型應該是 [System.Management.Automation.PSCredential]
。
下列範例顯示名為 Get-Something
之函式的參數區塊。 它有兩個參數: $Name
和 $Credential
。
function Get-Something {
param(
$Name,
[System.Management.Automation.PSCredential]$Credential
)
此範例中的程式代碼足以擁有運作中的認證參數,不過您可以新增一些專案,使其更健全。
[ValidateNotNull()]
新增驗證屬性,以檢查傳遞至 Credential 的值。 如果參數值為 null,這個屬性會防止函式以無效的認證執行。加入
[System.Management.Automation.Credential()]
。 這可讓您以字串的形式傳入用戶名稱,並具有密碼的互動式提示。將參數預設
$Credential
值設定為[System.Management.Automation.PSCredential]::Empty
。 您的函式可能會將此$Credential
對象傳遞至現有的PowerShell Cmdlet。 將 Null 值提供給函式內呼叫的 Cmdlet 會導致錯誤。 提供空的認證物件可避免此錯誤。
提示
某些接受認證參數的 Cmdlet 不支援,因為它們應該支援 [System.Management.Automation.PSCredential]::Empty
。 如需因應措施,請參閱處理舊版 Cmdlet 一節。
使用認證參數
下列範例示範如何使用認證參數。 此範例顯示名為 Set-RemoteRegistryValue
的函式,其出 自 Pester Book。 此函式會使用上一節所述的技術來定義認證參數。 函式會使用 $Credential
函式所建立的變數來呼叫 Invoke-Command
。 這可讓您變更執行 Invoke-Command
的使用者。 因為的預設值 $Credential
是空的認證,因此函式可以在不提供認證的情況下執行。
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
}
下列各節顯示將認證提供給 Set-RemoteRegistryValue
的不同方法。
提示輸入認證
在Get-Credential
執行時間Get-credential
使用 括號()
會導致 先執行 。 系統會提示您輸入使用者名稱和密碼。 您可以使用 的 Get-credential
Credential 或 UserName 參數預先填入使用者名稱和網域。 下列範例使用稱為「展開」的技術,將參數傳遞至函 Set-RemoteRegistryValue
式。 如需有關展開的詳細資訊,請參閱 about_Splatting 文章。
$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
}
Set-RemoteRegistryValue @remoteKeyParams -Credential (Get-Credential)
使用 (Get-Credential)
似乎很麻煩。 一般而言,當您只搭配用戶名稱使用 Credential 參數時,Cmdlet 會自動提示輸入密碼。 屬性 [System.Management.Automation.Credential()]
會啟用此行為。
$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
}
Set-RemoteRegistryValue @remoteKeyParams -Credential duffney
注意
若要設定顯示的登錄值,這些範例假設您已安裝 Windows 的 Web Server 功能。 視需要執行 Install-WindowsFeature Web-Server
和 Install-WindowsFeature web-mgmt-tools
。
在變數中提供認證
您也可以事先填入認證變數,並將它傳遞給函式的 Set-RemoteRegistryValue
Credential 參數。 使用此方法搭配持續整合/持續部署 (CI/CD) 工具,例如 Jenkins、TeamCity 和 Octopus Deploy。 如需使用 Jenkins 的範例,請參閱 Hodge 的部落格文章 :在 Windows 上使用 Jenkins 和 PowerShell 進行自動化 - 第 2 部分。
這個範例會使用 .NET 方法來建立認證物件和安全字串,以傳入密碼。
$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
在此範例中,會使用純文本密碼建立安全字串。 所有先前提及的 CI/CD 都有一個安全的方法,在運行時間提供該密碼。 使用這些工具時,請將純文本密碼取代為您所使用的 CI/CD 工具內定義的變數。
不使用認證執行
由於 $Credential
預設為空的認證物件,因此您可以執行不含認證的命令,如下列範例所示:
$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
}
Set-RemoteRegistryValue @remoteKeyParams
處理舊版 Cmdlet
並非所有 Cmdlet 都支援認證物件,或允許空的認證。 相反地,Cmdlet 想要將使用者名稱和密碼參數當做字串。 有幾種方法可以解決這項限制。
使用 if-else 來處理空的認證
在此案例中,您想要執行的 Cmdlet 不接受空的認證物件。 本範例只會在認證參數不是空白時,才將 Credential 參數新增至 Invoke-Command
。 否則,它會執行 Invoke-Command
不含 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
}
}
}
使用 Splatting 來處理空的認證
此範例會使用參數展開來呼叫舊版 Cmdlet。 物件 $Credential
會有條件地新增至哈希表以進行展開,並避免需要重複 Invoke-Command
腳本區塊。 若要深入瞭解在函式內展開,請參閱 進階函 式內部的Splatting參數部落格文章。
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
}
使用字串密碼
Cmdlet Invoke-Sqlcmd
是接受字串做為密碼的 Cmdlet 範例。
Invoke-Sqlcmd
可讓您執行簡單的 SQL 插入、更新和刪除語句。 Invoke-Sqlcmd
需要純文字用戶名稱和密碼,而不是更安全的認證物件。 此範例示範如何從認證物件擷取使用者名稱和密碼。
此範例中的函 Get-AllSQLDatabases
式會呼叫 Invoke-Sqlcmd
Cmdlet 來查詢其所有資料庫的 SQL Server。 函式會 使用先前範例中使用的相同屬性來定義 Credential 參數。 由於使用者名稱和密碼存在於變數內 $Credential
,因此您可以擷取這些值以搭配 Invoke-Sqlcmd
使用。
用戶名稱可從變數的 $Credential
UserName屬性取得。 若要取得密碼,您必須使用 GetNetworkCredential()
物件的 方法 $Credential
。 這些值會擷取至變數,這些變數會新增至哈希表,以便將參數展開至 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
持續學習認證管理
建立和儲存認證物件可能會很困難。 下列資源可協助您維護PowerShell認證。