PowerShell SecureString: Store Passwords Safely in Scripts

A hard-coded password in a PowerShell script is a security audit failure waiting to happen — and when that script ends up in source control, a shared folder, or a log file, the damage is done. Using PowerShell SecureString password patterns eliminates plain-text credentials from your scripts entirely. This post covers every pattern from interactive prompts to encrypted files to the Windows Credential Manager, so you can choose the right level of security for each automation scenario.
Read-Host -AsSecureString
For interactive scripts, Read-Host -AsSecureString prompts the user and stores the typed characters in a SecureString without ever materializing as plain text in memory:
$securePassword = Read-Host -Prompt "Enter password" -AsSecureString
# The variable holds a SecureString — not readable as plain text
Write-Host "Type: $($securePassword.GetType().Name)" # SecureString
# Use directly with AD cmdlets
Set-ADAccountPassword -Identity "jsmith" -NewPassword $securePassword -Reset
# Pass to a PSCredential
$cred = New-Object System.Management.Automation.PSCredential("CORP\jsmith", $securePassword)
Type: SecureString
Convert Plain Text to SecureString
Sometimes you receive a password from an API response or config file as plain text. Convert it immediately to SecureString and discard the plain-text variable:
$plainText = "MyP@ssw0rd123" # received from config file
$secureString = ConvertTo-SecureString $plainText -AsPlainText -Force
# Clear the plain-text variable immediately
Clear-Variable plainText
# Note: -AsPlainText requires -Force — this is intentional friction to discourage misuse
-Force is required as a deliberate design choice — using a plain-text string as input to ConvertTo-SecureString is considered insecure, and PowerShell warns you through this mandatory flag.
Create a PSCredential Object
PSCredential bundles a username and a SecureString password into a single object accepted by most PowerShell cmdlets that support -Credential:
# Prompt interactively — opens a dialog or console prompt
$cred = Get-Credential -Message "Enter credentials for CORP domain" -UserName "CORP\admin"
# Build programmatically from stored secure string
$username = "CORP\svc-backup"
$password = Get-Content "C:\Scripts\cred.txt" | ConvertTo-SecureString
$cred = New-Object System.Management.Automation.PSCredential($username, $password)
# Use with remoting, AD, web requests, etc.
Invoke-Command -ComputerName "Server01" -Credential $cred -ScriptBlock { hostname }
Save Encrypted Password to File
ConvertFrom-SecureString exports the SecureString as an encrypted string using the Windows Data Protection API (DPAPI). The key is tied to the current user account on the current machine:
$securePassword = Read-Host "Enter password to store" -AsSecureString
# Encrypt and save — only this user on this machine can decrypt it
$securePassword | ConvertFrom-SecureString | Set-Content "C:\Scripts\cred.txt"
Write-Host "Password saved to C:\Scripts\cred.txt (DPAPI encrypted)"
Load Encrypted Password in Script
In the automation script (running as the same user account on the same machine), load and decrypt the stored password:
$credFile = "C:\Scripts\cred.txt"
if (-not (Test-Path $credFile)) {
throw "Credential file not found: $credFile"
}
$password = Get-Content $credFile | ConvertTo-SecureString
$cred = New-Object System.Management.Automation.PSCredential("CORP\svc-backup", $password)
# Now use $cred in your operations
Connect-ExchangeOnline -Credential $cred
# No plain text anywhere — password remains encrypted in memory
Windows Credential Manager Alternative
The Windows Credential Manager stores credentials in the user’s profile and is accessible from PowerShell via the CredentialManager module or direct API calls. This is more portable than encrypted files for scripts that need to run as a service account:
# Install the module (optional but convenient)
Install-Module CredentialManager -Scope CurrentUser -Force
# Store a credential
New-StoredCredential -Target "BackupServiceAccount" `
-UserName "CORP\svc-backup" -Password "MyP@ssw0rd" -Type Generic -Persist LocalMachine
# Retrieve in script
$cred = Get-StoredCredential -Target "BackupServiceAccount"
Write-Host "Retrieved credential for: $($cred.UserName)"
Common Errors and Fixes
-
Encrypted password file only decryptable by same user on same machine. DPAPI encryption is scoped to the current user account on the current machine. If you create the credential file while logged in as
admin, the service account that runs your scheduled task cannot decrypt it. Create the file while running as the service account:Start-Process pwsh -Credential $serviceCred -ArgumentList "-File C:\Scripts\Save-Cred.ps1". -
ConvertTo-SecureString with -AsPlainText requires -Force flag. Omitting
-Forcewhen using-AsPlainTextthrows a terminating error. This is intentional — PowerShell requires explicit acknowledgment that you know you are converting a plain-text string, which is inherently less secure than the DPAPI-based approach.
Related Cmdlets / See Also
Wrapping Up
Never store passwords as plain text in scripts. Use Read-Host -AsSecureString for interactive prompts, DPAPI-encrypted files for scheduled service accounts (running as the correct identity), PSCredential objects for all cmdlets that accept -Credential, and the Windows Credential Manager for more portable storage. Eliminate the last plain-text password from your scripts and your next security audit becomes much less stressful.


