Categories: PowerShell

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

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

$PlainPassword |
ConvertTo-SecureString -AsPlainText -Force |
ConvertFrom-SecureString

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

С ростом числа скриптов и автоматизируемых процессов встал вопрос, как хранить пароли, чтобы это было безопасно, удобно и бесплатно. Мой коллега нашел менеджер паролей, который называется KeePass и позволяет удобно работать с паролями как вручную, так и из PowerShell. Он удовлетворяет всем требованиям, которые мы предъявляем к менеджеру паролей.

Ну и самое главное. Как же посредством PowerShell получить доступ к паролям? Чтобы открыть базу KeePass я также использую пароль, поэтому надо сохранить этот пароль в кусте реестра HKCU моей учетной записи (зашифрованный таким образом пароль сможет расшифровать только моя учетная запись):

Function Set-PasswordEncrypted() {
 <# .SYNOPSIS Эта функция шифрует пароль и сохраняет в реестр для последующего получения функцией Get-PasswordFromKeePass. .DESCRIPTION Эта функция сохранит пароль, зашифрованный таким образом, что пароль сможет расшифровать только текущая учетная запись, в кусте реестра HKCU текущей учетной записи. Пароль в последующем может быть использован функцией Get-PasswordFromKeePass. .PARAMETER Name Имя пароля, необходимо для последующего извлечения этого пароля из реестра. .PARAMETER PlainPassword Пароль в виде нешифрованного текста. .EXAMPLE Set-PasswordEncrypted -Name 'saqwel' -PlainPassword 'P@ssw0rd' #>

 param(
  [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()]
  [string]$Name,
  [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()]
  [string]$PlainPassword
 )

 $SecurePassword = $PlainPassword | 
  ConvertTo-SecureString -AsPlainText -Force | 
  ConvertFrom-SecureString
 $RegPath = "HKCU:\Software\Passwords"
 if(!(Test-Path -Path $RegPath)) {
  New-Item -Path $RegPath -Confirm:$false -Force -ErrorAction Stop | Out-Null
 }
 New-ItemProperty -Path $RegPath -Name $Name -Value $SecurePassword -Force -ErrorAction Stop | Out-Null
}

Ниже функция, которая возвращает логин и соответствующий ему пароль из KeePass. Подроности его работы в комментариях к коду.

Function Get-PasswordFromKeePass() {
 <# .SYNOPSIS Эта функция возвращает логин и пароль запрашиваемой записи из базы данных KeePass. .DESCRIPTION Эта функция помогает получить любой пароль из базы данных KeePass, зная имя записи и родительской группы, в которой хранятся логин и пароль. Пояснение. В KeePass можно создавать группы (или папки), которые и надо наполнять данными. Эти группы называются ParentGroup. Для получения пароля надо знать не только имя записи, в которой хранится требуемый пароль, но и имя родительской группы, где хранится запись. Мы разбили все пароли по принадлежности к операционке. Для использования этой функции необходимо зашифровать пароль и поместить в реестр командлетом Set-PasswordEncrypted. .PARAMETER UserName Имя записи, в которой хранится логин и пароль. Имя записи может совпадать или не совпадать с логином. .PARAMETER ParentGroupName Группа в базе данных KeePass, в которой находится запись, хранящая пароль. .EXAMPLE Get-PasswordFromKeePass -UserName 'MegaAdmin' -ParentGroupName 'Windows' .EXAMPLE Get-PasswordFromKeePass -UserName 'MegaRoot' -ParentGroupName 'Linux' #>

 param(
  [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()]
  [string]$UserName,
  [Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()]
  [string]$ParentGroupName
 )

 # Пароль от KeePass хранится в кусте реестра
 $RegPath = "HKCU:\Software\KeePass"
 # Параметр, который хранит зашифрованный пароль - KeePassPassword
 $Encrypted = (Get-ItemProperty -Path $RegPath).KeePassPassword
 # Перед расшифровшкой пароля надо его конвертировать
 $SecureString  = $Encrypted | ConvertTo-SecureString
 # Получить пароль готовый для открытия базы паролей KeePass
 $KeePass = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString))

 # Загрузить класс из KeePass.exe:
 [Reflection.Assembly]::LoadFile('C:\Keepass\KeePass.exe') | Out-Null
 # Получить параметры, необходимые для подключения к базе KeePass
 $KcpUserAccount = New-Object -TypeName KeePassLib.Keys.KcpUserAccount
 $KcpPassword    = New-Object -TypeName KeePassLib.Keys.KcpPassword($KeePass)
 $CompositeKey   = New-Object -TypeName KeePassLib.Keys.CompositeKey 
 $CompositeKey.AddUserKey( $KcpPassword )

 # Требуется файл .KDBX для открытия базы данных KeePass
 $IOConnectionInfo = New-Object KeePassLib.Serialization.IOConnectionInfo
 $IOConnectionInfo.Path = 'C:\Keepass\gpikkit.kdbx'

 # Открыть базу данных, наконец-то
 $PwDatabase = New-Object -TypeName KeePassLib.PwDatabase
 $PwDatabase.Open($IOConnectionInfo, $CompositeKey, $Null)

 # Получить требуемый пароль
 $PwCollection = $PwDatabase.RootGroup.GetEntries($True) | 
  Where{ $_.ParentGroup.Name -eq $ParentGroupName -and $_.Strings.ReadSafe("Title") -eq $UserName }
 $PwDatabase.Close()

 # Вернуть только один пароль и логин пользователя
 If($PwCollection.Uuid.Count -eq 1) {
  $Object = @{
   Password = $PwCollection.Strings.ReadSafe("Password")
   UserName = $PwCollection.Strings.ReadSafe("UserName")
  }
 } else {
  $Object = $False
 }

 return $Object
}
Saqwel

Share
Published by
Saqwel

Recent Posts

Azure App Configuration and access to Key Vault references

We decided to use an Azure App Configuration to store configs of backend. App Configuration…

2023-08-24

Azure cli az acr login hangs

I have encountered an issue with az acr login --name <acr_name> command. It hanged and…

2023-08-23

Error: Unable to read Docker image into resource: unable to find or pull image nginx:latest

I have tried to learn terraform from scratch and found pretty simple tutorial for beginners.…

2022-09-09

Скрыть поле модели от Swagger (Hide field of model from Swagger)

При внедрении Swagger в проекте .Net Core Web API потребовалось скрыть одно поле из примера,…

2020-04-24

Прогноз цен на акции

Около года назад я решил попробовать заработать на фондовой бирже, покупая и продавая акции. Изучая…

2019-07-20

Installation failed with error code: (0x00000490), “Element not found. “

Во время установки .NET Framework столкнулся с ошибкой Installation failed with error code: (0x00000490), "Element…

2018-12-20