This module will securely store passwords in PowerShell with ease. I wrote this back in 2019 while working on replacing some Python code with PowerShell. Recently I needed to use this on another sever and found that it throws a key error.
Import-cliXml: Key not valid for use in specified state.
It makes sense but was something that I hadn’t thought about when initially writing the module.
To get past that issue I added two new methods. It’s a simple export to CSV on the original server and import of the CSV on the other server(s) to create the XML.
The base use of this module allows you store credentials, fetch, and delete and will keep passwords out of your scripts. You can find usage examples in the script itself and you can store passwords for databases, sftp, or Windows accounts.
Using This Module
Simply copy the code, save as PSVault.psm1 and place it where you store your modules or add it to the default PowerShell modules location. Then you should be able to import and use like any other module.
Secure Passwords PowerShell Module Code
<#
.Synopsis
PS-Vault.psm1: Simple password vault for PowerShell scripts.
Author: Charles Nichols
Updated: Sept. 2022 > Added ability to export and import to other servers.
.Description
Get, Set, and Delete passwords securely within PowerShell.
Export-ExternalCredsFrom-CSV and Import-ExternalCredsFrom-CSV are work arounds
where password files cannot be used on other machines or accounts where created
on another machine. You can export from the source machine then import on
new machine to move passwords.
.Parameter Account
The account associated with the password; also used to load the correct password.
.Parameter Password
The password.
.Example
# Add a PSCredential Object.
Import-Module "E:\MyScripts\PS-Vault.psm1"
$auth = Set-Creds -Account "MyAccount" -Password "MyPassword"
.Example
# Delete a PSCredential Object.
Import-Module "E:\MyScripts\PS-Vault.psm1"
Remove-Creds -Account "MyAccount"
# Retrieve a PSCredential Object.
Import-Module "E:\MyScripts\PS-Vault.psm1"
$auth = Get-Creds -Account "MyAccount"
# Get the password in plain text.
Get-Password -SecurePassword $auth.Password
.Author
C. Nichols, 2019
#>
# Set path to your secure storage location.
$SafeStore = "E:\PSScripts\SecStore"
<#
.Synopsis
Fetch a creditial by account name.
.Description
Get account auth data for use in scripts.
.Parameter Account
The account or ID used to extract an encrypted password.
.Returns
System.Management.Automation.PSCredential
#>
Function Get-Creds {
Param(
[parameter(Mandatory=$true)]
[String]$Account
)
$Creds = $null
$Store = "$SafeStore\$($Account).xml"
if (Test-Path -Path $Store) {
$Creds = Import-CliXml -Path $Store
} else {
Write-Host "File not found."
}
return $Creds
}
<#
.Synopsis
Store a creditial by account name.
.Description
Set account auth data for use in scripts.
.Parameter Account
The account name or ID.
.Parameter $Password
Password to be encrypted.
.Output
CliXml file.
#>
Function Set-Creds {
Param(
[parameter(Mandatory=$true)]
[String]$Account,
[parameter(Mandatory=$true)]
[String]$Password
)
$Exists = Test-Path $SafeStore
If (-not $Exists) {
New-Item -ItemType directory -Path $SafeStore
}
$secPass = ConvertTo-SecureString $Password -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ($Account, $secPass)
$Store = "$SafeStore\$($Account).xml"
$Cred | Export-CliXml -Path $Store
}
<#
.Synopsis
Store a creditial for any account.
.Description
Will display a user logon dialog and set the account auth data for use in scripts.
Beneficial if you need to store a password for use in tasks or with an account you
are not currently logged on with.
.Output
CliXml file.
#>
Function Set-CredsForSpecificAccount {
Get-Credential | Export-CliXml -Path $SafeStore
}
<#
.Synopsis
Remove a creditial by account name.
.Description
This will remove the physical XML file from the server.
.Parameter Account
The account name or ID.
.Output
CliXml file.
#>
Function Remove-Creds {
Param(
[parameter(Mandatory=$true)]
[String]$Account
)
$Store = "$SafeStore\$($Account).xml"
Remove-Item -Path $Store
}
<#
.Synopsis
Converts an encrypted SecureString to plain text.
.Description
Use if you need to verify or view a password stored
as a SecureString.
.Parameter SecurePassword
Password as SecureString.
.Output
string
#>
Function Get-Password {
Param(
[parameter(Mandatory=$true)]
[SecureString]$SecurePassword
)
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
}
<#
.Synopsis
Creates a list of creds from another server.
.Description
Use if you need to grab all the passwords from one server to
another. Passwords are encrypted to server as well as user account.
This will remove the CSV file upon completion.
.Parameter CSVPath
Path to CSV.
.Output
CliXml (multiple)
#>
Function Import-ExternalCredsFromCSV {
Param(
[parameter(Mandatory=$true)]
[String]$CSVPath
)
$StoreExists = Test-Path $SafeStore
If (-not($StoreExists)) {
New-Item -Path $BasePath -ItemType Directory
}
$BaseFile = "Plain_Text_Password_List_Export.csv"
if ($CSVPath.ToLower().Contains(".csv")) {
$BasePath = Split-Path $CSVPath -Parent
$CSVPath = "{0}\{1}" -f $BasePath, $BaseFile
} else {
$CSVPath = "{0}\{1}" -f $CSVPath, $BaseFile
}
$RecCount = 0
$FileCount = 0
$CSVExists = Test-Path $CSVPath
if ($CSVExists) {
Get-Content -Path $CSVPath | ForEach-Object {
$RecCount += 1
$Parts = $_.Split(',')
$Account = $Parts[0].Trim()
$PAssword = $Parts[1].Trim()
$secPass = ConvertTo-SecureString $Password -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ($Account, $secPass)
$Store = "$SafeStore\$($Account).xml"
$Cred | Export-CliXml -Path $Store
if (Test-Path -Path $Store) {
$FileCount += 1
}
}
} else {
Write-Host "File not found: Invalid path."
}
if ($RecCount -eq $FileCount) {
Remove-Item -Path $CSVPath
} else {
Write-Host "Record mismatch: Verify all accounts saved. Not removing export CSV. Please remove manually once corrected."
}
}
<#
.Synopsis
Export a list of creds from current server.
.Description
Use if you need to grab all the passwords from one server to
another. Passwords are encrypted to server as well as user account.
This will create a list of unencrypted passwords for use with
Import-ExternalCredsFromCSV.
.Parameter CSVPath
Path to CSV.
.Output
CSV
#>
Function Export-ExternalCredsToCSV {
Param(
[parameter(Mandatory=$true)]
[String]$CSVPath
)
$ExportList = @()
$Exists = Test-Path $SafeStore
If ($Exists) {
$FPath = "{0}\*" -f $SafeStore
Get-ChildItem -Path $FPath -Include "*.xml" | ForEach-Object {
$Creds = Import-CliXml -Path $_.FullName
$Account = $Creds.UserName
$Password = Get-Password -SecurePassword $Creds.Password
$StrLine = "{0},{1}" -f $Account, $Password
$ExportList += $StrLine
}
}
$BaseFile = "Plain_Text_Password_List_Export.csv"
if ($SafeStore.ToLower().Contains(".csv")) {
$BasePath = Split-Path $SafeStore -Parent
if (-not(Test-Path -Path $BasePath)) {
New-Item -Path $BasePath -ItemType Directory
}
$CSVPath = "{0}\{1}" -f $BasePath, $BaseFile
} else {
$CSVPath = "{0}\{1}" -f $CSVPath, $BaseFile
}
$ExportList | Set-Content -Path $CSVPath
}
Export-ModuleMember -Function Get-Creds
Export-ModuleMember -Function Set-Creds
Export-ModuleMember -Function Set-CredsForSpecificAccount
Export-ModuleMember -Function Remove-Creds
Export-ModuleMember -Function Get-Password
Export-ModuleMember -Function Import-ExternalCredsFromCSV
Export-ModuleMember -Function Export-ExternalCredsToCSV
<# Testing ...
PS C:\Users\NICHOLSCD_x> using module "E:\PSScripts\PSModules\PS-Vault.psm1"
PS C:\Users\NICHOLSCD_x> Set-Creds -Account "mohawke" -Password "P@ssw0rd"
PS C:\Users\NICHOLSCD_x> $Auth = Get-Creds -Account "mohawke"
PS C:\Users\NICHOLSCD_x> $Auth.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True PSCredential System.Object
PS C:\Users\NICHOLSCD_x> $Auth.UserName
mohawke
PS C:\Users\NICHOLSCD_x> Get-Password -SecurePassword $Auth.Password
P@ssw0rd
PS C:\Users\NICHOLSCD_x> Remove-Creds -Account "mohawke"
# Export from one server then import to another. This should create a key on the new server.
# ** You may need to run as the account that will be using the creds.
PS C:\Users\NICHOLSCD_x> Export-ExternalCredsTo-CSV -CSVPath "E:\PSScripts\SecStore"
PS C:\Users\NICHOLSCD_x> Import-ExternalCredsFrom-CSV -CSVPath "E:\PSScripts\SecStore"
#>
Hope this is useful to someone.