How to manage PowerShell secrets with the SecretsManagement module

Andrew Pla
Andrew Pla|April 7, 2022
Powershell Secret Management Image
Powershell Secret Management Image

Secrets are anything that is privileged and worth keeping, you guessed it, secret. That could be anything from passwords, API keys, webhook URLs, or even that time in third grade when a kid ran up on the playground and told you who they had a crush on and made you promise to keep it a secret. You could put that in there also. By the end of this, you can securely store and access secrets.

SecretManagement basics

SecretManagement is an open source PowerShell module owned by Microsoft that provides a solution for managing secrets with a variety of different vaults. This module interacts with extension vaults, which are PowerShell modules that connect the SecretManagement module with the vault containing the secrets.

SecretManagement is a module abstraction layer that enables you to use one set of commands for any secret extension vault. This enables you to share a script with others without having to make assumptions about their environment or what vault they use. The Get-Secret command is the same, regardless of the secret vault that the consumer of the script has in their environment.

The SecretManagement module commands can be logically separated into two different groups: Secret commands and SecretVault commands.

The secret commands are responsible for interacting with secrets and the secret info (metadata). These commands become useful once a secret vault is configured (more on that later).

Command Screenshot-1

The other type of commands are SecretVault commands, which help you to configure the secret extension vaults. 

Commands Screenshot 2

Before moving on, it’s important to cover what secret extension vaults are and how they play into SecretManagement.

Extension Vaults

Extension vaults are PowerShell modules that connect the SecretManagement module with a vault. At the time of this writing, there are over 15 different secret extension vaults available. Microsoft is responsible for the Az.KeyVault and the Microsoft.PowerShell.SecretStore. There are also several other extension vaults for Chromium, KeePass, HashiCorp, and more. 

When paired with the SecretManagement module, this approach allows you to write scripts that work in a variety of environments, whether you are using Azure KeyVault, KeePass, Chromium, or any of the other extension vault providers. In this blog, we are going to set up the Microsoft.PowerShell.SecretStore extension vault.

You can find the full list of the extension vault modules visiting https://aka.ms/SecretManagementVaults or by running:

find-module -Tag SecretManagement

In order to begin fully using the SecretManagement module, we need to configure a vault extension. The SecretStore module is a great starting point, as it stores secrets locally on file. This module relies on the .NET crypto APIs for encryption and can be used on Windows, Linux, and macOS.

Install the modules

To install the modules:

Install-Module Microsoft.PowerShell.SecretManagement -Repository PSGallery Install-Module Microsoft.PowerShell.SecretStore -Repository PSGallery

SecretStore configuration

For starters, run Get-SecretStoreConfiguration to take a look at how the secret store is configured by default. If this is your first time running this command, it will prompt you to enter a password. This is the password that will be used to unlock the vault.

Unlock Vault Command Screenshot

By default, this module is configured for best security and for interactive use. Notice how the Interaction type is set to “Prompt.” While that is great for security, keep in mind that this will not work silently, though I really appreciate a “secure by default” approach.

Before we can add our first secret, we need to register the SecretStore module as a SecretVault.

Register-SecretVault-Name MyFirstSecretStore -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault

Adding and retrieving secrets

Next, use Set-Secret to add our first secret. 

Set-Secret-Name BestKeptSecret -Secret “Pineapple on pizza is great!”

Note: Earlier when you ran Get-SecretStoreConfiguration, it should’ve prompted you for a password. If that initial setup didn’t take place earlier, this command will ask you to set a password for the vault.

You can return the secret by running Get-Secret -Name BestKeptSecret. This command will return a System.Security.SecureString. If you want to return the secret in plaintext, you will need to add the -AsPlainText parameter.

Get-Secret -Name BestKeptSecret -AsPlainText

Use metadata

While that is a silly example, a more practical secret would be storing a webhook URL. A webhook URL contains a secret in the URL and should be treated the same as a password. One common use of webhooks is to send messages into a chat channel from PowerShell.

Set-Secret-Name DiscordWebhook -Secret 'https://discord.com/api/webhooks/123456789/xxxxxxxx' -Metadata @{Description ='This is a webhook that posts to the #general channel in my discord server.'}

This command also contains some metadata. The metadata parameter is expecting a hash table, which has been provided with a description property. Adding context to your secrets can help you easily identify what your secret was designed to do. Take the extra moment to make things easier on yourself in the future. Trust me, your future self will be thankful. 

At the time of this writing, you can store secret values of the following types:

  • byte[]

  • String

  • SecureString

  • PSCredential

  • Hashtable

To query your secrets, use the Get-SecretInfo command. The metadata property isn’t displayed by default, so you can use Select-Object to ensure that the metadata property is added.

Metadata Property Screenshot

Configure SecretStore for use in automation

Now you should have a vault configured for interactive use. To get the most value out of your scripts, you need to configure your automation to run non-interactively. Let’s see how we would configure the SecretStore in such a way that would allow us to have our scripts silently access our information. These secrets are encrypted per-user, so ensure that you are logged in with the appropriate user.

We are still going to use a password on the vault, but we want to avoid typing that into plaintext. For this example, we will use Export and Import-CliXml to store and retrieve the vault password. The -CliXml commands make use of the Data Protection API and only work on Windows. If you wanted to run this in another automation context, like a CI/CD pipeline, you could make use of something like secure variables to provide the password. This eliminates the risk of exposing plaintext passwords in your scripts. Alternatively, PDQ has a two-part blog series that covers encrypting credentials and passwords with PowerShell that you could also look into as it provides some alternatives to Export-CliXml that may be useful for you. 

$pass = Read-Host -AsSecureString -Prompt 'Enter the extension vault password' $passwordPath = Join-Path (Split-Path $profile) SecretStore.vault.credential # Uses the DPAPI to encrypt the password $pass | Export-CliXml $passwordPath Install-Module -Name Microsoft.PowerShell.SecretStore, Microsoft.PowerShell.SecretManagement -Repository PSGallery -Force $pass = Import-CliXml $passwordPath Set-SecretStoreConfiguration -Scope CurrentUser -Authentication Password -PasswordTimeout (60*60) -Interaction None -Password $pass -Confirm:$false Register-SecretVault -Name SecretStore -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault Unlock-SecretStore -Password $pass

Once this is configured, you only need to use the following snippet of code in your scripts to unlock the secret store using the encrypted password.

$pass = Import-CliXml 'C:\Users\username\Documents\PowerShell\SecretStore.vault.credential' Unlock-SecretStore -Password $pass

If you find yourself having issues with your secret store configuration and want to start fresh, use the Reset-SecretStore command instead of the Set-SecretStoreConfiguration. They share many of the same parameters.

Use with PDQ Deploy

If you want to use scripts that retrieve secrets from a secret store in PDQ Deploy, you only need to run a PowerShell step that targets a computer that has the secret vault configured on it. As previously mentioned, make sure that you run the configuration commands on the target computer as the user that you are using for deployment when running the configuration script. This is usually the Deploy User.

Deploy User Configuration Screenshot

The above example is simple, but this allows you to access any number of secrets from your scripts. Remember: don’t save passwords in your scripts! Protect yourself with SecretManagement.

If you’ve followed along this whole time, you now have the required exposure to begin using the SecretManagement module to keep your secrets secure. If the SecretStore vault isn’t the extension vault that you want to use, make sure to check out the other available secret vaults: https://aka.ms/SecretManagementVaults 

Interested in more PowerShell goodness? We have you covered. We talk about secret management on The PowerShell Podcast and have great articles that go into further detail on using Foreach in PowerShell and provide tricks to power up PowerShell scanners with Git you should check out.

If you have any PowerShell-related feedback to share, email us at powershell@pdq.com.


Andrew Pla
Andrew Pla

Andrew loves automation, PowerShell, and building tools that last. He has spent nearly a decade in IT with a focus on automation, infrastructure, and toolmaking. He has a passion for sharing knowledge and prefers humans to computers, and is a host of the PowerShell Podcast.

Related Articles