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

Примечание.

Исходная версия этой статьи появилась в блоге, написанном @joshduffney. Эта статья была изменена для включения на этом сайте. Команда PowerShell благодарит Джоша за то, что он поделился с нами этим содержанием. Пожалуйста, ознакомьтесь с его блогом на duffney.io.

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

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

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

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

Чтобы указать доменное имя и имя пользователя заранее, можно использовать параметры Credential или UserName . При использовании параметра UserName необходимо также указать значение сообщения . Ниже показан код, демонстрирующий использование командлета. Вы также можете хранить объект учетных данных в переменной, чтобы использовать учетные данные несколько раз. В приведенном ниже примере объект учетных данных хранится в переменной $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()]. Это позволяет передавать имя пользователя в виде строки и иметь интерактивный запрос пароля.

  • Задайте для параметра [System.Management.Automation.PSCredential]::Emptyзначение $Credential по умолчанию. Возможно, ваша функция передаёт этот объект в существующие командлеты PowerShell $Credential. При передаче значения null командлету, вызываемому внутри вашей функции, возникает ошибка. Предоставление пустого объекта учетных данных позволяет избежать этой ошибки.

Подсказка

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

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

В следующем примере показано, как использовать параметры учетных данных. В этом примере показана функция Set-RemoteRegistryValue, которая взята из Книги Пестера. Эта функция определяет параметр учетных данных с помощью методов, описанных в предыдущем разделе. Функция вызывает 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 или UserNameGet-Credential можно использовать для предварительного заполнения имени пользователя и домена. В следующем примере используется метод с именем splatting для передачи параметров функции 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 только с именем пользователя, командлет автоматически потребует пароль. Атрибут [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 при необходимости.

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

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

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

Этот пример демонстрирует использование объединения параметров для вызова устаревшего командлета. Объект $Credential условно добавляется в хэш-таблицу для сплаттинга, что позволяет избежать необходимости повторять блок скрипта Invoke-Command. Чтобы узнать больше о разложении параметров в функциях, ознакомьтесь с записью в блоге "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
}

Работа с строковыми паролями

Командлет Invoke-Sqlcmd является примером командлета, который принимает строку в качестве пароля. Invoke-Sqlcmd позволяет выполнять простые инструкции SQL insert, update и delete. Invoke-Sqlcmd требуется явное имя пользователя и пароль, а не более безопасный объект учетных данных. В этом примере показано, как извлечь имя пользователя и пароль из объекта учетных данных.

Функция Get-AllSQLDatabases в этом примере вызывает командлет Invoke-Sqlcmd для запроса всех баз данных на SQL Server. Функция определяет параметр 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.