Skip to content

PowerShell Secret and Credential Management

How PowerShell uses SecureString, Get-Credential, and SecretManagement to securely store and retrieve API keys, passwords, and credentials without hardcoding sensitive data.

Secure credential management ensures that sensitive secrets (such as administrative passwords, API keys, and connection strings) are never stored in plaintext within scripts or version control repositories. PowerShell protects sensitive data using System.Security.SecureString memory-encrypted objects, credential objects via Get-Credential, and modern vault orchestration using the Microsoft.PowerShell.SecretManagement module.

Interactive Authentication with Get-Credential

The Get-Credential cmdlet prompts an interactive user for a username and password, returning a System.Management.Automation.PSCredential object. In a PSCredential object, the username is accessible as plain text (.UserName), but the password is encrypted and stored in memory as a SecureString (.Password).

get-credential-demo.ps1powershell
$cred = Get-Credential -UserName "CORP\admin_svc" -Message "Enter administrative credentials"

[PSCustomObject]@{
    UserName     = $cred.UserName
    PasswordType = $cred.Password.GetType().Name
    IsEncrypted  = ($cred.Password -is [System.Security.SecureString])
}

where:

  • Get-Credential launches an authentication dialog or terminal prompt to collect login details.
  • -UserName pre-populates the username field, requiring the user to supply only the password.
  • -Message sets the administrative banner or prompt text.
  • $cred.Password returns the password encapsulated inside a SecureString object, preventing plaintext memory exposure.
Consolepowershell
./get-credential-demo.ps1
Outputplaintext
UserName       PasswordType IsEncrypted
--------       ------------ -----------
CORP\admin_svc SecureString        True

Pre-populating the Username

Consolepowershell
$cred = Get-Credential -UserName "admin" -Message "Enter password for deployment account"

Using a Credential Object

Consolepowershell
Invoke-Command -ComputerName "SRV01" -Credential $cred -ScriptBlock { Get-Service }

where -Credential accepts the PSCredential object for authenticating the remote connection.

Working with SecureString

A SecureString encrypts string data in memory, reducing the risk of the value being exposed accidentally (e.g., in a process dump or console log).

Converting Plain Text to SecureString

Consolepowershell
$securePassword = ConvertTo-SecureString -String "P@ssw0rd123!" -AsPlainText -Force

where:

  • -String is the plain text value to convert.
  • -AsPlainText is required to explicitly acknowledge you're converting from plain text.
  • -Force confirms the (inherently risky) conversion without an additional prompt.

Converting SecureString Back to Plain Text

Consolepowershell
$plainText = [System.Net.NetworkCredential]::new("", $securePassword).Password

Encrypting Data: ConvertTo-SecureString and ConvertFrom-SecureString

The ConvertTo-SecureString and ConvertFrom-SecureString cmdlets convert sensitive strings into encrypted data structures and back. By default, Windows encrypts these strings using the Windows Data Protection API (DPAPI), binding the ciphertext to the current Windows user profile on the local computer.

dpapi-encryption.ps1powershell
$securePass = ConvertTo-SecureString "ConfidentialToken2026!" -AsPlainText -Force

$encryptedCipher = ConvertFrom-SecureString -SecureString $securePass

$encryptedCipher.Substring(0, 48) + "..."

$decryptedPass = ConvertTo-SecureString $encryptedCipher

where:

  • ConvertTo-SecureString converts plaintext into an encrypted in-memory SecureString object.
  • -AsPlainText instructs the cmdlet to accept a standard string input.
  • -Force is required safety override acknowledging the risk of passing plaintext into memory.
  • ConvertFrom-SecureString serializes the SecureString into an encrypted hexadecimal ciphertext string using DPAPI.
Consolepowershell
./dpapi-encryption.ps1
Outputplaintext
01000000d08c9ddf0115d1118c7a00c04fc297eb01000000...

Saving a SecureString to Disk

Consolepowershell
$securePassword | ConvertFrom-SecureString | Out-File -FilePath "C:\Secrets\password.txt"

where ConvertFrom-SecureString encrypts the SecureString into a text representation, tied to the current user and machine.

Consolepowershell
$loadedSecure = Get-Content -Path "C:\Secrets\password.txt" | ConvertTo-SecureString

Persistent Secret Storage with SecretManagement

For scripts that need to securely store and retrieve secrets across sessions (without the machine/user limitations of DPAPI), the Microsoft.PowerShell.SecretManagement module provides a standardized interface backed by pluggable vaults.

To standardize secret retrieval across cloud platforms, local servers, and development machines, Microsoft provides two complementary modules:

  • Microsoft.PowerShell.SecretManagement: an abstraction layer providing unified cmdlets (Get-Secret, Set-Secret) that connect to any configured vault backend.
  • Microsoft.PowerShell.SecretStore: a cross-platform, local, file-based vault extension that encrypts secrets using .NET cryptographic libraries.
Consolepowershell
Install-Module -Name Microsoft.PowerShell.SecretManagement -Scope CurrentUser
Install-Module -Name Microsoft.PowerShell.SecretStore -Scope CurrentUser

Registering a Vault

Consolepowershell
Register-SecretVault -Name "LocalVault" -ModuleName Microsoft.PowerShell.SecretStore -Default

where:

  • -Name is a friendly name for this vault.
  • -Default marks this vault as the default target for secret operations.

Storing a Secret with Set-Secret

Consolepowershell
Set-Secret -Name "DeployApiKey" -Secret "sk_live_abc123XYZ"

where:

  • -Name is the identifier used to retrieve the secret later.
  • -Secret is the sensitive value to store (accepts strings, SecureString, or PSCredential).

Retrieving a Secret with Get-Secret

Consolepowershell
$apiKey = Get-Secret -Name "DeployApiKey" -AsPlainText

where -AsPlainText returns the secret as a plain string rather than a SecureString object.

Listing Stored Secrets

Consolepowershell
Get-SecretInfo
Outputplaintext
Name         Type   VaultName
----         ----   ---------
DeployApiKey String LocalVault

Removing a Secret

Consolepowershell
Remove-Secret -Name "DeployApiKey"

Complete Secret Store Example

secret-store-demo.ps1powershell
Register-SecretVault -Name "LocalVault" -ModuleName "Microsoft.PowerShell.SecretStore" -DefaultVault

$apiToken = "sk_live_9847120938401923"
Set-Secret -Name "ProductionApiKey" -Secret $apiToken -Vault "LocalVault"

Get-SecretInfo -Vault "LocalVault" | Select-Object -Property Name, Type, VaultName

$retrievedToken = Get-Secret -Name "ProductionApiKey" -AsPlainText
Write-Output "Retrieved secret length: $($retrievedToken.Length)"

where:

  • Register-SecretVault connects a vault implementation module to the SecretManagement framework.
  • Set-Secret securely stores a string, SecureString, PSCredential, or hashtable into the specified vault.
  • Get-SecretInfo discovers stored secret names and metadata without exposing the underlying secret payloads.
  • Get-Secret fetches the decrypted secret payload from the vault backend.
  • -AsPlainText decrypts the secret directly to a standard string for REST endpoints or binaries.
Consolepowershell
./secret-store-demo.ps1
Outputplaintext
Name             Type   VaultName
----             ----   ---------
ProductionApiKey String LocalVault
Retrieved secret length: 24

Practical Usage

Secure Script Authentication Without Hardcoded Credentials

A common pattern uses SecretManagement to retrieve credentials at runtime, keeping automation scripts free of hardcoded secrets entirely.

deploy-with-secret.ps1powershell
$apiKey = Get-Secret -Name "DeployApiKey" -AsPlainText

$headers = @{
    Authorization = "Bearer $apiKey"
}

Invoke-RestMethod -Uri "https://api.example.com/deploy" -Method Post -Headers $headers

where:

  • Get-Secret retrieves the API key at runtime from the encrypted local vault.
  • $headers builds an authorization header using the retrieved secret, never written to disk in plain text.
Consolepowershell
./deploy-with-secret.ps1
Outputplaintext
Deployment triggered successfully.

Non-Interactive Script Authentication Using Exported DPAPI Credentials

Scheduled tasks and continuous automation scripts frequently need to run without human intervention while avoiding hardcoded credentials in the script body.

setup-headless-credential.ps1powershell
$credPath = "C:\SecureConfig\svc_backup.cred"

$credential = Get-Credential -UserName "CORP\svc_backup" -Message "Set Service Account Password"
$credential.Password | ConvertFrom-SecureString | Set-Content -Path $credPath

Write-Output "Encrypted credential file generated at $credPath"
Consolepowershell
./setup-headless-credential.ps1
Outputplaintext
Encrypted credential file generated at C:\SecureConfig\svc_backup.cred
unattended-script.ps1powershell
$credPath = "C:\SecureConfig\svc_backup.cred"
$serviceUser = "CORP\svc_backup"

if (-not (Test-Path -Path $credPath)) {
    throw "Credential file missing at $credPath!"
}

$encryptedData = Get-Content -Path $credPath

$securePassword = ConvertTo-SecureString $encryptedData

$runtimeCred = [System.Management.Automation.PSCredential]::new($serviceUser, $securePassword)

$session = New-PSSession -ComputerName "Server01" -Credential $runtimeCred

[PSCustomObject]@{
    TargetServer = $session.ComputerName
    SessionState = $session.State
    ConnectedAs  = $runtimeCred.UserName
}

Remove-PSSession -Session $session

where:

  • [System.Management.Automation.PSCredential]::new() is the strongly-typed constructor creating a PSCredential object from a username and SecureString.
  • Test-Path validates that the credential file is accessible before initiating the connection.
  • New-PSSession consumes the rehydrated PSCredential to establish an authenticated remote session without displaying the password.
Consolepowershell
./unattended-script.ps1
Outputplaintext
TargetServer SessionState ConnectedAs
------------ ------------ -----------
Server01           Opened CORP\svc_backup
Navigation