Adicionar suporte de Credenciais a funções do PowerShell

Nota

A versão original deste artigo apareceu no blog escrito por @joshduffney. Este artigo foi editado para inclusão neste site. A equipe do PowerShell agradece a Josh por compartilhar esse conteúdo conosco. Por favor, confira seu blog em duffney.io.

Este artigo mostra como adicionar parâmetros de credenciais às funções do PowerShell e por que você deseja. Um parâmetro de credencial é permitir que você execute a função ou cmdlet como um usuário diferente. O uso mais comum é executar a função ou cmdlet como uma conta de usuário elevada.

Por exemplo, o cmdlet New-ADUser tem um parâmetro Credential , que você pode fornecer credenciais de administrador de domínio para criar uma conta em um domínio. Supondo que sua conta normal executando a sessão do PowerShell ainda não tenha esse acesso.

Criando objeto de credencial

O objeto PSCredential representa um conjunto de credenciais de segurança, como um nome de usuário e senha. O objeto pode ser passado como um parâmetro para uma função que é executada como a conta de usuário nesse objeto de credencial. Há algumas maneiras de criar um objeto de credencial. A primeira maneira de criar um objeto de credencial é usar o cmdlet Get-Credentialdo PowerShell. Quando você executa sem parâmetros, ele solicita um nome de usuário e senha. Ou você pode chamar o cmdlet com alguns parâmetros opcionais.

Para especificar o nome de domínio e o nome de usuário com antecedência, você pode usar os parâmetros Credential ou UserName . Quando você usa o parâmetro UserName , também é necessário fornecer um valor Message . O código abaixo demonstra o uso do cmdlet. Você também pode armazenar o objeto de credencial em uma variável para que possa usá-la várias vezes. No exemplo abaixo, o objeto de credencial é armazenado na variável $Cred.

$Cred = Get-Credential
$Cred = Get-Credential -Credential domain\user
$Cred = Get-Credential -UserName domain\user -Message 'Enter Password'

Às vezes, você não pode usar o método interativo de criação de objetos de credencial mostrado no exemplo anterior. A maioria das ferramentas de automação requer um método não interativo. Para criar uma credencial sem interação do usuário, crie uma cadeia de caracteres segura contendo a senha. Em seguida, passe a cadeia de caracteres segura e o nome de usuário para o System.Management.Automation.PSCredential() método.

Use o seguinte comando para criar uma cadeia de caracteres segura contendo a senha:

ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force

Os parâmetros AsPlainText e Force são necessários. Sem esses parâmetros, você recebe uma mensagem avisando que não deve passar texto sem formatação para uma cadeia de caracteres segura. O PowerShell retorna esse aviso porque a senha de texto sem formatação é registrada em vários logs. Depois de criar uma cadeia de caracteres segura, você precisa passá-la para o PSCredential() método para criar o objeto de credencial. No exemplo a seguir, a variável $password contém a cadeia de caracteres $Cred segura que contém o objeto credential.

$password = ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ("username", $password)

Agora que você sabe como criar objetos de credencial, pode adicionar parâmetros de credenciais às suas funções do PowerShell.

Adicionando um parâmetro de credencial

Assim como qualquer outro parâmetro, você começa adicionando-o no param bloco da sua função. É recomendável nomear o parâmetro $Credential porque é isso que os cmdlets existentes do PowerShell usam. O tipo do parâmetro deve ser [System.Management.Automation.PSCredential].

O exemplo a seguir mostra o bloco de parâmetros para uma função chamada Get-Something. Tem dois parâmetros: $Name e $Credential.

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

O código neste exemplo é suficiente para ter um parâmetro de credencial de trabalho, no entanto, há algumas coisas que você pode adicionar para torná-lo mais robusto.

  • Adicione o [ValidateNotNull()] atributo de validação para verificar se o valor que está sendo passado para Credential. Se o valor do parâmetro for null, esse atributo impedirá que a função seja executada com credenciais inválidas.

  • Adicionar [System.Management.Automation.Credential()]. Isso permite que você passe um nome de usuário como uma cadeia de caracteres e tenha um prompt interativo para a senha.

  • Defina um valor padrão para o $Credential parâmetro como [System.Management.Automation.PSCredential]::Empty. Sua função você pode estar passando esse $Credential objeto para cmdlets existentes do PowerShell. Fornecer um valor nulo para o cmdlet chamado dentro de sua função causa um erro. Fornecer um objeto de credencial vazio evita esse erro.

Gorjeta

Alguns cmdlets que aceitam um parâmetro de credencial não oferecem suporte [System.Management.Automation.PSCredential]::Empty como deveriam. Consulte a seção Lidando com cmdlets herdados para obter uma solução alternativa.

Usando parâmetros de credencial

O exemplo a seguir demonstra como usar parâmetros de credencial. Este exemplo mostra uma função chamada Set-RemoteRegistryValue, que está fora do The Pester Book. Esta função define o parâmetro de credencial usando as técnicas descritas na seção anterior. A função chama Invoke-Command usando a $Credential variável criada pela função. Isso permite que você altere o usuário que está executando Invoke-Commando . Como o valor padrão de é uma credencial vazia, a função pode ser executada $Credential sem fornecer credenciais.

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
}

As seções a seguir mostram diferentes métodos de fornecimento de credenciais para Set-RemoteRegistryValueo .

Solicitando credenciais

Usar Get-Credential entre parênteses () em tempo de execução faz com que o Get-credential seja executado primeiro. Ser-lhe-á pedido um nome de utilizador e uma palavra-passe. Você pode usar os parâmetros Credential ou UserName do para preencher previamente o nome de Get-credential usuário e o domínio. O exemplo a seguir usa uma técnica chamada splatting para passar parâmetros para a Set-RemoteRegistryValue função. Para obter mais informações sobre splatting, confira o artigo about_Splatting.

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

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

Obter uma credencial em tempo de execução

Usar (Get-Credential) parece complicado. Normalmente, quando você usa o parâmetro Credential com apenas um nome de usuário, o cmdlet solicita automaticamente a senha. O [System.Management.Automation.Credential()] atributo habilita esse comportamento.

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

Set-RemoteRegistryValue @remoteKeyParams -Credential duffney

Solicitar credenciais

Nota

Para definir o valor do Registro mostrado, esses exemplos pressupõem que você tenha os recursos do Servidor Web do Windows instalados. Execute Install-WindowsFeature Web-Server e Install-WindowsFeature web-mgmt-tools se necessário.

Fornecer credenciais em uma variável

Você também pode preencher uma variável de credencial com antecedência e passá-la para o parâmetro Credential da Set-RemoteRegistryValue função. Use esse método com ferramentas de Integração Contínua / Implantação Contínua (CI/CD), como Jenkins, TeamCity e Octopus Deploy. Para obter um exemplo usando Jenkins, confira a postagem do blog de Hodge Automatizando com Jenkins e PowerShell no Windows - Parte 2.

Este exemplo usa o método .NET para criar o objeto de credencial e uma cadeia de caracteres segura para passar a senha.

$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

Neste exemplo, a cadeia de caracteres segura é criada usando uma senha de texto não criptografado. Todos os CI/CD mencionados anteriormente têm um método seguro de fornecer essa senha em tempo de execução. Ao usar essas ferramentas, substitua a senha de texto sem formatação pela variável definida na ferramenta CI/CD que você usa.

Executar sem credenciais

Como $Credential o padrão é um objeto de credencial vazio, você pode executar o comando sem credenciais, conforme mostrado neste exemplo:

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

Set-RemoteRegistryValue @remoteKeyParams

Lidando com cmdlets herdados

Nem todos os cmdlets oferecem suporte a objetos de credenciais ou permitem credenciais vazias. Em vez disso, o cmdlet deseja parâmetros de nome de usuário e senha como cadeias de caracteres. Existem algumas maneiras de contornar essa limitação.

Usando if-else para lidar com credenciais vazias

Nesse cenário, o cmdlet que você deseja executar não aceita um objeto de credencial vazio. Este exemplo adiciona o parâmetro Credential somente Invoke-Command se ele não estiver vazio. Caso contrário, ele executa o Invoke-Command sem o parâmetro 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
        }
    }
}

Usando splatting para lidar com credenciais vazias

Este exemplo usa o splatting de parâmetros para chamar o cmdlet herdado. O $Credential objeto é adicionado condicionalmente à tabela de hash para splatting e evita a necessidade de repetir o Invoke-Command bloco de script. Para saber mais sobre o splatting dentro de funções, consulte a postagem do blog Splatting Parameters Inside Advanced Functions .

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
}

Trabalhando com senhas de cadeia de caracteres

O Invoke-Sqlcmd cmdlet é um exemplo de um cmdlet que aceita uma cadeia de caracteres como senha. Invoke-Sqlcmd permite que você execute instruções simples de inserção, atualização e exclusão de SQL. Invoke-Sqlcmd requer um nome de usuário e senha de texto não criptografado em vez de um objeto de credencial mais seguro. Este exemplo mostra como extrair o nome de usuário e a senha de um objeto de credencial.

A Get-AllSQLDatabases função neste exemplo chama o Invoke-Sqlcmd cmdlet para consultar um servidor SQL para todos os seus bancos de dados. A função define um parâmetro Credential com o mesmo atributo usado nos exemplos anteriores. Como o nome de usuário e a senha existem dentro da variável, você pode extrair esses valores para uso com Invoke-Sqlcmdo $Credential .

O nome de usuário está disponível na propriedade UserName da $Credential variável. Para obter a senha, você tem que usar o GetNetworkCredential() método do $Credential objeto. Os valores são extraídos em variáveis que são adicionadas a uma tabela de hash usada para splatting parâmetros para 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

Gestão de credenciais de aprendizagem contínua

Criar e armazenar objetos de credenciais com segurança pode ser difícil. Os recursos a seguir podem ajudá-lo a manter as credenciais do PowerShell.