При работе в Powershell вы часто используете другие учетные данные. Один из способов ввести учетные данные - это использовать команду Get-Credential, которая показывает диалоговое окно:
Далее мы можем использовать эту переменную $cred в командах, как на примере ниже. Команда будет запущена от имени пользователя, который был указан в диалоговом окне выше:
Invoke-Command -ComputerName "localhost" `
-ScriptBlock {Get-ComputerInfo} `
-Credential $cred
Альтернативный способ использования - это совместить два действия описанные выше в одно:
Invoke-Command -ComputerName "localhost" `
-ScriptBlock {Get-ComputerInfo} `
-Credential $(Get-Credential)
Минусы описанных вариантов в том, что нам требуется вводить нужный логин и пароль каждый раз, когда мы запускаем Powershell (открываем/закрываем сессию). В этой статье будут рассмотрены несколько вариантов хранения учетных данных и их загрузка.
В чем особенность хранения учетных данных в Powershell?
Powershell не совсем очевидно хранит и обрабатывает введенный логин и пароль. После ввода логина и пароля создается объект PSCredential, в котором хранится логин (в обычном виде) и пароль в защищенном виде(называется SecureString). Этот объект хранится в оперативной памяти компьютера и что бы PSCredential (а точнее SecureString) мог быть выгружен - он должен быть зашифрован. Такое шифрование, в основном выполняется автоматически командами конвертации и экспорта. Например мы сможем выгрузить данные c Export-CliXML сразу, а с Export-CSV этого не получится.
Кроме этого, процесс создания SecureString и последующее шифрование уникальны для каждого компьютера и пользователя. Поэтому мы не сможем просто перенести этот файл на другой компьютер и использовать. Такой процесс работы с данными называется Windows Data Protection API.
В статье будут рассмотрены большинство способов работы и переноса учетных данных.
Импорт и экспорт в XML
После ввода учетных данных мы получаем обычный объект, который будет выглядеть так:
Экспорт в XML мы можем выполнить с помощью следующей команды, которая выполнит шифрование пароля и сохранит данные в корне диска 'C':
$cred = Get-Credential
$cred | Export-CliXML -Path 'C:\mycredentials.xml'
На примере ниже можно увидеть, что логин пользователя не зашифрован, в отличие от пароля:
Теперь мы можем загружать этот файл и использовать другие учетные данные без повторного ввода:
$cred = Import-CliXML -Path 'C:\mycredentials.xml'
Мы можем конвертировать пароль из SecureString обратно в строку:
$cred = Import-CliXML -Path 'C:\mycredentials.xml'
$cred.GetNetworkCredential().Password
Минусы этого способа будут в том, вы должны будете генерировать такой файл для каждого компьютера и пользователя отдельно.
Импорт и экспорт пароля из обычного файла
В Powershell есть команда ConvertTo-SecureString, которая может преобразовывать обычные строки в объект SecureString. Результатом команды будет такой же объект, который был у команды Get-Credential , свойства 'Password':
'somepassword' | ConvertTo-SecureString -AsPlainText -Force
Для того что бы безопасно сохранять эти данные в файл мы можем зашифровать их с помощью команды ConvertFrom-SecureString:
$sec_string = 'somepassword' | ConvertTo-SecureString -AsPlainText -Force
$sec_string | ConvertFrom-SecureString | Set-Content -Path 'C:\secure.txt'
Результат команды выше будет та же строка, что была у пароля при выполнении команды Export-CliXML:
Мы можем открыть этот, и преобразовать зашифрованный пароль в объект SecureString:
$sec_string = Get-Content -Path 'C:\secure.txt' | ConvertTo-SecureString
# Получаем чистый пароль
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((($sec_string))))
Создание объекта PSCredential
Любой ключ -Credential в командах ожидает получить объект PSCredential, а не просто пароль. Мы можем создать такой объект следующим способом:
# Логин
$login = 'admin@domain.local'
# Объявления пароля с последующем конвертированием в защищенную строку
$password = 'password123' | ConvertTo-SecureString -AsPlainText -Force
# Преобразование логина и пароля в специальный объект
$cred = New-Object system.Management.Automation.PSCredential($login,$password)
Т.е. с этим способом мы можем создать учетные данные в нужном формате, но для этого мы должны будем хранить файл с паролем в чистом виде.
Шифрование пароля используя симметричный ключ
Мы можем шифровать файл с паролем используя симметричное шифрование (AES). После шифрования вы сможете опубликовать пароль в открытой папке и выдавать права или предоставлять сам ключ шифрования.
С помощью следующей команды мы создадим симметричный ключ для последующего шифрования пароля:
$key = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($key)
$key | Out-File C:\powershell.key
Далее я создам SecureString (объект в оперативной памяти) что бы потом его зашифровать ключом созданным выше:
# Преобразуем пароль в Secure.String
$password = "Somepassword123!" | ConvertTo-SecureString -AsPlainText -Force
# Открываем файл с ключом AES
$key = Get-Content -Path "C:\powershell.key"
# Шифруем пароль
$secure_password = ConvertFrom-SecureString -Key $key -SecureString $password
# Сохраняем пароль в файл
Set-Content -Path 'C:\password.txt' -Value $secure_password
Теперь у нас есть 2 файла, с помощью которого мы можем организовывать доступ к паролю. Это файл:
- powershell.key - ключ AES с помощью которого можно зашифровать файл и расшифровать;
- password.txt - зашифрованная строка типа SecureString (пароль), который может быть расшифрован ключом выше.
Вы сможете перенести эти файлы на другой компьютер и выполнить следующую операцию для расшифровки:
# Открываем файл с зашифрованным паролем
$secure_password = Get-Content -Path "C:\password.txt"
# Расшифровываем объект в SecureString
$password = ConvertTo-SecureString -Key C:\Passwords\aes.key -String $secure_password
# Создаем объект PSCredential
$credential = New-Object System.Management.Automation.PsCredential("administrator@domain.local",$password)
# Можем убедиться, что пароль был расшифрован корректно
$credential.GetNetworkCredential().Password
Использование Credential Manager (Диспетчер учетных данных)
Многие знают, что пароли от сетевых дисков (и многие другие) хранятся в специальном месте под названием Credential Manager. В панели управления он выглядит так:
Мы можем получить доступ к этим объектам использовав модуль CredentialManager. Этот модуль не относится к стандартным и устанавливается отдельно:
Install-Module CredentialManager
У вас могут появится два уведомления говорящие об установке репозитория NuGet и о том, что он является не доверенным.
У нас станут доступны 4 команды:
- Get-StoredCredential - получает учетные данные из хранилища;
- Get-StrongPassword - генерирует случайный пароль;
- New-StoredCredential - создает учетные данные;
- Remove-StoredCredential - удаляет учетные данные.
Далее мы сможем получить все учетные данные указав нужный тип в атрибуте Type или Target (источник) которому эти данные принадлежат:
Get-StoredCredential -Target 'localhost'
Мы получаем объект типа PSCredential, который мы можем использовать в командах. Создавать новые учетные данные и добавлять их в хранилище CredentialManager мы тоже можем:
New-StoredCredential -Target 'localhost' -Type Generic -UserName 'admin@domain.local' -Password '123' -Persist 'LocalMachine'
Кроме логина и пароля мы указываем:
- Target - кому принадлежит учетная запись. Проще говоря имя компьютера;
- Type - тип учетной записи;
- Persist - тип хранения. Может быть session (временной), localmachine (сохраненной) и enterprise(как я понимаю это тип перемещаемый, например с MS Passport).
Первые два пункта особого значения не имеют. Они предназначены для программ, которые получают пароли по определенным идентификаторам. В ваших скриптах вы выбираете идентификаторы для себя.
Так же у меня была ошибка 'New-StoredCredential : CredWrite failed with the error code 1312'. Эта ошибка проявляет себя только в удаленных сессиях PSSession. Если вы работаете локально - то она не проявляется. Причина ошибки и ее решение - пока не ясно (нет ответа на github).
Как загружать переменную с учетными данными при открытии Powershell
В Powershell есть возможность загружать переменные (и другие данные) при открытии самой консоли. Например мы сможем единожды объявить переменные '$credential_local', '$credential_domain', '$credential_forest' и каждый раз открывать консоль Powershell они сами будут импортироваться.
Первое что нужно сделать - проверить существования файла 'Microsoft.PowerShell_profile.ps1', который является профилем Powershell. Путь до этого файла лежит следующей переменной (если работаете в сессии PSsession - ничего не вернется):
$profile
Если этого файла нет - его нужно создать (c PS 6+ он должен создаваться автоматически):
New-item –type file –force $profile
В этот файл мы помещаем один из скриптов написанных выше:
# Логин
$login = 'admin@domain.local'
# Объявления пароля с последующем конвертированием в защищенную строку
$password = 'password123' | ConvertTo-SecureString -AsPlainText -Force
# Преобразование логина и пароля в специальный объект
$credential_domain = New-Object system.Management.Automation.PSCredential($login,$password)
Теперь, открывая консоль, вы всегда сможете вызвать эту переменную:
...
Подписывайтесь на наш Telegram канал
Теги: #powershell