共用方式為


將認證支援新增至 PowerShell 函式

注意

本文的原始版本出現在@joshduffney撰寫的部落格上。 本文已編輯為包含此網站。 PowerShell 小組感謝 Josh 與我們共用此內容。 請在 duffney.io 查看他的部落格

本文說明如何將認證參數新增至 PowerShell 函式,以及您想要的原因。 認證參數是可讓您以不同的使用者身分執行函式或 Cmdlet。 最常見的用法是將函式或 Cmdlet 以提升許可權的用戶帳戶執行。

例如,Cmdlet New-ADUser 具有 Credential 參數,您可以提供網域管理員認證,以在網域中建立帳戶。 假設執行 PowerShell 會話的一般帳戶還沒有該存取權。

建立認證物件

PSCredential 物件代表一組安全性認證,例如使用者名稱和密碼。 物件可以當做參數傳遞至做為該認證對象中用戶帳戶執行的函式。 有幾種方式可以建立認證物件。 建立認證物件的第一種方式是使用 PowerShell Cmdlet Get-Credential。 當您在沒有參數的情況下執行時,它會提示您輸入使用者名稱和密碼。 或者,您可以使用一些選擇性參數來呼叫 Cmdlet。

若要事先指定功能變數名稱和用戶名稱,您可以使用 CredentialUserName 參數。 當您使用 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

需要 AsPlainTextForce 參數。 如果沒有這些參數,您會收到訊息警告,指出您不應該將純文本傳遞至安全字串。 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 CredentialUserName 參數預先填入使用者名稱和網域。 下列範例使用稱為「展開」的技術,將參數傳遞至函 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-ServerInstall-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認證。