Secure Passwords With PowerShell Module
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.