Добавление поддержки учетных данных в функции PowerShell

Примечание.

Оригинал этой статьи впервые был опубликован в блоге автора @joshduffney. Эта статья была изменена для публикации на этом сайте. Группа разработчиков PowerShell благодарит Джоша (Josh) за то, что он поделился с нами этим содержимым. Посетите его блог duffney.io.

В этой статье показано, как и зачем добавлять параметры учетных данных в функции PowerShell. Параметр учетных данных позволяет выполнять функцию или командлет от лица другого пользователя. Чаще всего такая возможность используется для выполнения функции или командлета от лица пользователя с повышенными привилегиями.

Например, командлет New-ADUser имеет параметр учетных данных Credential, в котором вы можете указать учетные данные администратора домена при создании учетной записи в домене, если ваша обычная учетная запись с запущенным сеансом PowerShell не имеет таких прав.

Создание объекта учетных данных

Объект PSCredential представляет набор учетных данных для безопасности, таких как имя пользователя и пароль. Объект можно передать в качестве параметра функции, которая выполняется от имени учетной записи пользователя в таком объекте учетных данных. Существует несколько способов создания объекта учетных данных. Первый способ заключается в использовании командлета PowerShell Get-Credential. Если запустить его без параметров, отобразится запрос на ввод имени пользователя и пароля. Или же вы можете вызвать командлет с необязательными параметрами.

Чтобы предварительно указать имя домена и имя пользователя, вы можете использовать параметр Credential или UserName. Если используется параметр UserName, вам также необходимо указать значение Message. В блоке кода ниже демонстрируется использование этого командлета. Вы также можете сохранить объект учетных данных в переменной для многократного использования учетных данных. В примере ниже объект учетных данных сохраняется в переменной $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. Параметр должен иметь тип [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. Указание значения NULL для командлета, вызываемого в вашей функции, приведет к ошибке. Указание пустого объекта учетных данных позволяет избежать этой ошибки.

Совет

Некоторые командлеты, которые принимают параметр учетных данных, не поддерживают [System.Management.Automation.PSCredential]::Empty. Временное решение см. в разделе Работа с устаревшими командлетами.

Использование параметров учетных данных

В следующем примере кода показано, как использовать параметры учетных данных. В этом примере демонстрируется функция с именем Set-RemoteRegistryValue, которая приведена в книге The Pester Book. Эта функция определяет параметр учетных данных с помощью техник, описанных в предыдущем разделе. Функция вызывает Invoke-Command с помощью переменной $Credential, создаваемой функцией. Это позволяет вам изменить пользователя, выполняющего 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 выполняется первым. Появится запрос на ввод имени пользователя и пароль. Вы можете использовать параметр Credential или UserName командлета Get-credential, чтобы указать имя пользователя и домен. В следующем примере используется техника, называемая сплаттинг, для передачи параметров функции Set-RemoteRegistryValue. Дополнительные сведения о сплаттинге см. в этой статье.

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

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

Получение учетных данных во время выполнения

Использование (Get-Credential) может сделать код громоздким. Обычно при использовании параметра Credential только с именем пользователя командлет автоматически запрашивает пароль. Такое поведение обеспечивается атрибутом [System.Management.Automation.Credential()].

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

Set-RemoteRegistryValue @remoteKeyParams -Credential duffney

Запрос учетных данных

Примечание.

При задании показанного значения реестра в этих примерах предполагается, что у вас установлены функции веб-сервера Windows. Выполните Install-WindowsFeature Web-Server и Install-WindowsFeature web-mgmt-tools при необходимости.

Указание учетных данных в переменной

Вы также можете предварительно указать переменную учетных данных и передать ее параметру Credential функции Set-RemoteRegistryValue. Используйте этот метод с инструментами непрерывной интеграции и непрерывного развертывания (CI/CD), такими как Jenkins, TeamCity и Octopus Deploy. Пример использования Jenkins можно найти в записи блога Hodge Автоматизация с помощью Jenkins и PowerShell в Windows — часть 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

Работа с устаревшими командлетами

Не все командлеты поддерживают объекты учетных данных или позволяют использовать пустые учетные данные. Для них требуется указать имя пользователя и пароль в формате строк. Существует несколько способов обойти такое ограничение.

Использование оператора if-else для обработки пустых учетных данных

В этом сценарии командлет, который вы хотите выполнить, не принимает пустой объект учетных данных. В этом примере параметр 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
        }
    }
}

Использование сплаттинга для обработки пустых учетных данных

В этом примере используется сплаттинг параметра для вызова устаревшего командлета. Объект $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 является примером командлета, который принимает пароль в формате строки. Командлет Invoke-Sqlcmd позволяет вам выполнять простые инструкции SQL для вставки, обновления и удаления. Командлет Invoke-Sqlcmd требует указания имени пользователя и пароля в формате открытого текста, а не более защищенного объекта учетных данных. В этом примере показано, как извлечь имя пользователя и пароль из объекта учетных данных.

Функция Get-AllSQLDatabases в этом примере вызывает командлет Invoke-Sqlcmd для отправки серверу SQL запроса по всем его базам данных. Функция определяет параметр Credential с теми же атрибутами, которые были использованы в предыдущих примерах. Так как имя пользователя и пароль существуют в переменной $Credential, вы можете извлечь эти значения для использования с командлетом Invoke-Sqlcmd.

Имя пользователя доступно из свойства UserName переменной $Credential. Чтобы получить пароль, используйте метод 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.