当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 向 PowerShell 函数添加凭据支持

作者:精品下载站 日期:2024-12-14 03:03:47 浏览:11 分类:玩电脑

向 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。向函数内调用的 cmdlet 提供 null 值会导致错误。提供空凭证对象可以避免此错误。

有用的提示

某些接受凭据参数的 cmdlet 不支持 [System.Management.Automation.PSCredential]::Empty,因为它们应该支持。请参阅处理旧版 Cmdlet 部分以获取解决方法。

使用凭证参数

以下示例演示了如何使用凭据参数。此示例显示了一个名为 Set-RemoteRegistryValue 的函数,该函数来自 The 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-credentialCredentialUserName 参数来预填充用户名和域。以下示例使用称为 splatting 的技术将参数传递给 Set-RemoteRegistryValue 函数。有关 splatting 的更多信息,请查看 about_Splatting 文章。

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

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

[玩转系统] 向 PowerShell 函数添加凭据支持

使用 (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

[玩转系统] 向 PowerShell 函数添加凭据支持

笔记

要设置显示的注册表值,这些示例假设您安装了 Windows 的Web 服务器功能。如果需要,运行 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 中。否则,它将运行不带 Credential 参数的 Invoke-Command

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 脚本块。要了解有关函数内部展开的更多信息,请参阅高级函数内部展开参数博客文章。

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
}

使用字符串密码

Invoke-Sqlcmd cmdlet 是接受字符串作为密码的 cmdlet 示例。 Invoke-Sqlcmd 允许您运行简单的 SQL 插入、更新和删除语句。 Invoke-Sqlcmd 需要明文用户名和密码,而不是更安全的凭据对象。此示例演示如何从凭证对象中提取用户名和密码。

本示例中的 Get-AllSQLDatabases 函数调用 Invoke-Sqlcmd cmdlet 来查询 SQL Server 的所有数据库。该函数定义了一个 Credential 参数,其属性与前面示例中使用的属性相同。由于用户名和密码存在于 $Credential 变量中,因此您可以提取这些值以与 Invoke-Sqlcmd 一起使用。

用户名可从 $Credential 变量的 UserName 属性获取。要获取密码,您必须使用 $Credential 对象的 GetNetworkCredential() 方法。这些值被提取到变量中,这些变量被添加到哈希表中,用于将参数分配给 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 凭据。

  • BetterCredentials
  • Azure 密钥保管库
  • 避难所项目
  • 秘密管理模块

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯