Using PasswordVault with PowerShell

A handy way to securely store credentials for use by a PowerShell script (particularly one running from within a Scheduled Task) is to use the Windows PasswordVault class.  Please note that this should not be confused with the Credential Manager module.

Credentials are store and incrypted in the PasswordVault on a per-user basis.  If credentials are being stored for use by a Scheduled Task, be sure to login to the system and stash the credentials using the account that the Task will be running under.

Initializing the PasswordVault Object

The first step is to load the Credentials and PasswordVault assemblies:

[Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]

Once this is done, you can instantiate an object of the PasswordVault class to work with:

$vault = New-Object Windows.Security.Credentials.PasswordVault

Initially, your vault object should probably be empy (assuming that you have not run any scripts or applications which have populated items into it.  You can verify this by reading the contents of the vault to see if anything is returned:

$vault.RetrieveAll()

Adding A Credential

To populate the vault with a credential, we’ll first create a credential object, then set its Resource, UserName, and Password attributes. The Resource attribute can be a friendly descriptive name, or some other identifier such as a URL. The Resource attribute (sometimes in conjunction with the UserName attribute, as we’ll see below) are used to identify which credential in the PasswordVault that we are working with.

Once these attributes are populated, we can invoke the vault object’s “Add()” method to store the credentials into the vault.

$cred = New-Object windows.Security.Credentials.PasswordCredential
$cred.Resource = 'My Credentials'
$cred.UserName = 'MyDomain\MyUserName'
$cred.Password = 'MyPassword'
$vault.Add($cred)
Remove-Variable cred # So that we don't have the password lingering in memory!

We can verify that the credential was successfully stored by re-running the “RetrieveAll()” method.

PS C:\> $vault.RetrieveAll()

UserName            Resource       Password Properties
--------            --------       -------- ----------
MyDomain\MyUserName My Credentials          {[hidden, False], [applicationid, 00000000-0000-0000-0000-000000000000],...

If we want to avoid having the password entered in clear text (as above), we can use the Get-Credential command to have Windows prompt us for credentials.  The UserName and Password attributes will get populated (with the password never appearing in clear text, getting directly stored as a secure string). However, the resulting credential object is of a different type, so we’ll have to perform a conversion to the appropriate object type (specifying the Resource attribute as we go). Then we can add the credential to the vault.

$cred2 = Get-Credential
$Resource = 'My Other Credentials'
$CredObject = New-Object Windows.Security.Credentials.PasswordCredential -ArgumentList ($Resource, $Cred2.UserName,$Cred2.GetNetworkCredential().Password)
$vault.Add($CredObject)
Remove-Variable cred2
Remove-Variable CredObject

We should now have two sets of credentials in our vault:

PS C:\> $vault.RetrieveAll()

UserName                 Resource             Password Properties
--------                 --------             -------- ----------
MyDomain\MyOtherUserName My Other Credentials          {[hidden, False], [applicationid, 00000000-0000-0000-0000-000...
MyDomain\MyUserName      My Credentials                {[hidden, False], [applicationid, 00000000-0000-0000-0000-000...

Bravo! Now let’s see about actually retrieving them from the vault so that we can use them.

Retrieving A Credential

First, let’s stuff everything in our vault into a variable.  (This is overkill, though, as we will see shortly.)

$creds = $vault.RetrieveAll()

Now let’s pluck out the specific credential we want.

$StoredCredential = $creds.where({$_.Resource -eq "My Other Credentials"})

The username, “MyDomain\MyOtherUserName” is in the UserName attribute of this object, but we need to pull the password in a form that we can use.

$StoredCredential.RetrievePassword()

Sure enough, there it is:

PS C:\> $StoredCredential.Password
MySecurePassword

Now we have the username password, ready and waiting for whatever use our script has for it.

A slightly different syntax for doing the above can be seen here.  Note that the “Select-Object” cmdlets are included to address the off chance of multiple matches for a particular Resource.

[string]$userName = ($vault.RetrieveAll() | Where-Object {$_.Resource -eq "My Other Credentials"} | Select-Object -First 1).UserName
[string]$userPass = ($vault.Retrieve("My Other Credentials",$userName) | Select-Object -First 1).Password

In either case, the end result is a password that is in cleartext.  To convert it to a more PowerShell-friendly SecureString object, use the following:

[SecureString]$securePass = ConvertTo-SecureString -String $userPass -AsPlainText -Force

Removing A Credential

Everyone knows that you should change passwords periodically.  The easiest way to update a password in the vault is to simply delete the old object and add a new one.  Deletion is rather simple, but note that specifying the credential to delete keys upon both the Resource attribute and UserName attribute.

$cred = New-Object Windows.Security.Credentials.PasswordCredential
$cred.Resource = "My Credentials"
$cred.UserName = "MyDomain\MyUserName"
$vault.Remove($cred)

Leave a Reply