DeployVault is a security-focused local credential vault engine written in PowerShell. It is designed to replace plaintext credentials in answer files (Unattend.xml, .ini, .txt, .json) and scripts used by automated deployment environments such as MDT, SCCM/MECM, task sequences, and WinPE.
DeployVault provides authenticated encryption, crash-resilient writes, NTFS ACL integration, and credential lifecycle management. It has not undergone an independent security audit and should be deployed as one control within a secured deployment environment.
DeployVault is intended for a controlled deployment share where authorized WinPE clients and deployment operators can read both the encrypted vault and its companion seed file. Access to the deployment share is the primary authorization boundary.
The following limitations are intentional and must be understood before deployment:
- A credential ID is a lookup selector, not a per-credential authorization boundary.
- Any identity or device that can read both
localvault.binandlocalseed.bincan copy the pair and decrypt every enabled credential offline. - DeployVault does not protect credentials from a compromised or malicious authorized WinPE client.
- Encryption protects against plaintext exposure, accidental inspection, and undetected vault modification. It does not replace SMB permissions, NTFS ACLs, network isolation, or deployment-account governance.
- Passwords are not intentionally written to plaintext files. During a credential operation, plaintext temporarily exists in process memory as managed PowerShell/.NET objects and may be exposed by process dumps, a compromised host, or unsafe diagnostic tooling.
Use DeployVault only when every principal granted access to both files is trusted to retrieve all credentials stored in that vault. Use separate vault-and-seed pairs when different deployment groups require different credential access.
DeployVault is designed to work with WinPECT as part of an end-to-end deployment credential flow:
Deployment-share server Windows PE Installed Windows
----------------------- ---------- -----------------
Administrators manage vault Read credential by ID Verify transfer
and seed material into process memory Import as DPAPI-protected
| PSCredential CLIXML
v files
WinPECT creates an reboot
authenticated encrypted ------>
transfer package and
separate bootstrap data
- Credential add, update, removal, seed rotation, backup, and restore operations are administrative tasks performed on the server hosting the deployment share.
- Authorized WinPE deployment identities receive read-only access, and the deployment workflow requests the credential IDs it requires. This is workflow selection, not technical enforcement against other IDs in the same vault.
- The retrieved
PSCredentialis passed to WinPECT in memory. DeployVault and WinPECT do not intentionally write the plaintext username/password pair to an unattended file, script, command line, registry value, or transfer package. - WinPECT stores an authenticated encrypted package on the target volume and separate protected bootstrap data in the offline Windows
SOFTWAREregistry hive. - After Windows starts, WinPECT verifies and decrypts the transfer and exports DPAPI-protected
PSCredentialCLIXML for the importing Windows identity. Successful import removes the temporary package and bootstrap registry data.
This workflow prevents intentional plaintext persistence during transfer. It does not protect credentials from a compromised WinPE environment, a compromised importing process, memory inspection, or a principal that can copy both the DeployVault vault and seed files.
DeployVault uses standard cryptographic primitives with operational safeguards appropriate to its documented trust boundary:
- Encryption Algorithm: AES-256-CBC with a cryptographically secure 16-byte initialization vector (IV) generated per write.
- Message Authentication Tag: HMAC-SHA256 computed over the binary header (which contains the IV) and ciphertext (
Encrypt-then-MAC). - Protection Scope: Detects payload tampering and prevents unauthenticated ciphertext modification. Confidentiality depends on keeping the vault-and-seed pair inside the trusted deployment boundary.
- Key Derivation Function: PBKDF2 (
Rfc2898DeriveBytes) utilizing 100,000 iterations over a 32-byte cryptographically random salt. - Key Separation: Generates 64 derived bytes total: 32 bytes for the AES-256 encryption key and 32 bytes for the HMAC-SHA256 authentication tag.
- Memory Hygiene: Sensitive byte arrays are explicitly cleared when practical via
[Array]::Clear(). Managed strings and PowerShell objects cannot be reliably zeroed and may remain in process memory until reclaimed by .NET.
- Fixed-Work Comparison:
Test-VaultFixedTimeEqualcompares every byte when the tag lengths match, avoiding an early exit based on the first differing byte. The implementation has not undergone dedicated side-channel analysis.
- Pre-Commit Verification: All write operations build and encrypt a candidate payload into a temporary file (
.tmp), re-read, and decrypt the temporary file in memory before touching the live vault. - Single-File Replacement: Normal vault-content updates use
[System.IO.File]::Replaceto replace the live vault file and retain a backup. Seed rotation and restore update a vault-and-seed pair sequentially and must be treated as maintenance operations with recovery artifacts.
- Exclusive Mutation Lock: Credential mutations and lifecycle operations acquire an exclusive filesystem lock (
localvault.bin.lock) with timeout retry behavior. Credential reads are lock-free; prevent WinPE reads during seed rotation or restore.
- Policy Check:
Assert-VaultSafeLoggingblocks secret operations when Windows PowerShell transcription is enabled through the checkedHKLMorHKCUpolicy locations. - Operator Requirement: An interactively started transcript is not reliably detectable through supported Windows PowerShell 5.1 APIs. Stop all transcripts and disable diagnostic command/output capture before retrieving or updating credentials.
| File | Description |
|---|---|
| DeployVault.ps1 | Core credential engine containing cryptographic functions, CRUD commands, and lifecycle routines. |
| Init.ps1 | Interactive deployment helper to initialize new vault/seed pairs and prompt for initial credentials. |
| SetDeployVaultACL.ps1 | Elevated administrative script to break permission inheritance and enforce strict NTFS ACLs for Active Directory deployment groups. |
| TestDeployVault.ps1 | Automated 8-stage verification test suite covering initialization, encryption, backups, restores, rotation, tamper detection, and concurrency. |
| README.md | Official documentation and reference guide. |
| SECURITY.md | Security boundary, deployment requirements, limitations, and vulnerability-reporting policy. |
| LICENSE | MIT license governing use and distribution. |
- Windows PowerShell 5.1
- Windows or Windows PE with the PowerShell, .NET, scripting, and WMI optional components required by the surrounding deployment workflow
- NTFS storage for live vault, seed, backup, and recovery files
- A controlled SMB deployment share when the vault is accessed remotely
PowerShell 7 may work for some operations but is not the primary compatibility target. Validate the complete DeployVault and WinPECT workflow on every supported Windows PE image and Windows build before production rollout.
Dot-source the engine script inside your task sequence or deployment script:
. .\DeployVault.ps1Initialize a new master seed (localseed.bin) and vault binary (localvault.bin). The seed file is automatically assigned Hidden and System filesystem attributes:
Initialize-Vault `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.binRun SetDeployVaultACL.ps1 from an elevated Administrator PowerShell session to grant Read access only to specified Active Directory deployment accounts while giving Full Control to Administrators and SYSTEM:
.\SetDeployVaultACL.ps1 `
-VaultDirectory .\Vault `
-ReadIdentities "CONTOSO\DeploymentReaders", "CONTOSO\Domain Admins"Trust warning: Every identity in
ReadIdentitiescan read both the seed and vault and must therefore be trusted to decrypt every credential in that vault. Do not use this list as a per-credential access-control mechanism.
Add or update a credential in the vault using a SecureString password input:
$secPassword = Read-Host "Enter Password" -AsSecureString
Set-VaultCredential `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin `
-CredentialId "DomainJoin" `
-Username "CONTOSO\svc-domainjoin" `
-Password $secPassword `
-Description "MDT Automated Domain Join Account"Retrieve credentials directly as a standard PSCredential object for use with standard cmdlets (New-PSDrive, Invoke-Command, Join-Domain):
$cred = Get-VaultCredential `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin `
-CredentialId "DomainJoin"
Write-Host "Loaded credential for identity: $($cred.UserName)"
# Memory cleanup: Clear variable after execution
$cred = $nullView non-secret metadata (passwords are strictly excluded from summary output):
Get-VaultSummary `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin | Format-Table -AutoSizeDelete an entry from the vault by its ID:
Remove-VaultCredential `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin `
-CredentialId "DomainJoin"DeployVault stores credentials as a username plus a protected password/secret value. It does not currently expose a separate arbitrary-secret object type.
Use a deployment-specific local Administrator credential only when the deployment workflow requires one. Prefer a unique password per device and use Windows LAPS to manage the account after the installed operating system is enrolled.
$localAdminPassword = Read-Host "Enter the temporary local Administrator password" -AsSecureString
try {
Set-VaultCredential `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin `
-CredentialId "LocalAdministrator" `
-Username ".\Administrator" `
-Password $localAdminPassword `
-Description "Temporary deployment-time local Administrator"
}
finally {
$localAdminPassword.Dispose()
}Retrieve it in WinPE as a PSCredential for the deployment step or WinPECT handoff:
$localAdminCredential = Get-VaultCredential `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin `
-CredentialId "LocalAdministrator"
# Pass $localAdminCredential directly to the deployment operation or WinPECT.
# Do not print or serialize the credential.For an API client credential, store the client ID or service identity in Username and the client secret or API key in Password:
$apiSecret = Read-Host "Enter the deployment API secret" -AsSecureString
try {
Set-VaultCredential `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin `
-CredentialId "DeploymentApi" `
-Username "deployment-client" `
-Password $apiSecret `
-Description "Deployment service API credential"
}
finally {
$apiSecret.Dispose()
}Retrieve the pair as a PSCredential and pass it directly to an SDK or helper that accepts PSCredential or SecureString:
$apiCredential = Get-VaultCredential `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin `
-CredentialId "DeploymentApi"
$clientId = $apiCredential.UserName
$secret = $apiCredential.Password
# Prefer an API client that accepts SecureString or PSCredential directly.
# Converting $secret to a normal string creates managed plaintext in memory.For a key with no natural username, use a non-secret descriptor such as api-key in Username. Never place an API key in CredentialId, Username, Description, a command line, or diagnostic output.
Re-key the vault with a new master seed while retaining saved credentials. Rotation executes under an exclusive mutation lock and creates recovery files:
Invoke-VaultSeedRotation `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.binSchedule rotation during a maintenance window with no active WinPE readers. The seed and vault files are replaced sequentially, so an unlocked reader could otherwise observe a mismatched pair. Protect and remove recovery files according to your recovery and retention policy after validating the rotated vault.
Create timestamped, ACL-protected backup pairs (vault-YYYYMMDDTHHMMSSfffZ.bin and seed-YYYYMMDDTHHMMSSfffZ.bin) with configurable retention purging:
Backup-Vault `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin `
-BackupDirectory .\Vault\Backups `
-RetentionCount 10After backup creation, verify the effective NTFS ACLs and confirm that only the intended administrative identities can read the backup directory. Treat any ACL error as a failed backup-security operation.
Restore a decryptable backup pair after validating its envelope schema. Restore-Vault verifies the installed result against the selected candidate pair, but it does not require the candidate VaultId to match the current live vault. Administrators must select and verify the intended backup pair before approving restoration:
Restore-Vault `
-VaultPath .\Vault\localvault.bin `
-SeedPath .\Vault\localseed.bin `
-VaultBackup .\Vault\Backups\vault-20260802T100000000Z.bin `
-SeedBackup .\Vault\Backups\seed-20260802T100000000Z.binPerform restores during a maintenance window with no active WinPE readers. Keep the generated pre-restore recovery files until the restored vault has been validated, then protect or remove them according to policy.
- Any reader that can copy both the vault and seed can decrypt the complete vault offline.
- Interactive
Start-Transcriptsessions are not reliably detected; operators must stop them before secret operations. - Normal vault-file writes use atomic replacement, but seed rotation and restore cannot atomically replace both files as one filesystem transaction.
- Reads do not acquire the mutation lock. Block deployment access during seed rotation and restore.
- ACL application must be independently verified. A successful file copy alone does not prove the destination permissions are correct.
- DeployVault has not undergone an independent cryptographic or security audit.
Run the built-in 8-stage automated test suite before deploying new vault configurations to production environments:
powershell.exe -ExecutionPolicy Bypass -File .\TestDeployVault.ps1The test suite validates:
- Vault initialization & hidden file attributes
- Credential round-trip operations & schema metadata envelope tracking
- Timestamped backup creation
- Authentication-tag tamper rejection
- Backup restoration capabilities
- Seed rotation, recovery-file creation, and credential continuity
- Concurrency lock contention
- Credential deletion cleanups
The suite does not currently prove effective ACL configuration, resistance to memory inspection, transcript detection, two-file crash atomicity, or cryptographic side-channel properties. Validate those controls operationally in the target deployment environment.
- Secure the Share First: Require SMB 3 encryption where supported, disable guest access, restrict share permissions, and limit the deployment network to approved clients.
- NTFS ACL Lockdown: Enforce strict ACLs using
SetDeployVaultACL.ps1. Never grant Write or Full Control access to standard users or automated reader accounts. - Treat Readers as Vault Administrators: A reader of both files can decrypt the entire vault. Create separate vaults for groups that must not share credential access.
- Use Least-Privilege Credentials: Store deployment-specific accounts with the minimum required permissions. Avoid domain-administrator and other broadly privileged credentials.
- Prevent Log Serialization: Do not log
$cred, call$cred.GetNetworkCredential().Passwordin diagnostic output, or echo plaintext secrets to console, transcript, or task-sequence logs. - Harden WinPE: Treat boot images, prestart commands, task-sequence variables, and command shells as part of the trusted boundary. Remove debugging tools and interactive access where operationally possible.
- Rotate After Exposure: Rotate the stored credential and the vault seed if an authorized client, deployment account, seed, vault, or backup pair may have been copied or compromised.
- Protect Backups as Live Secrets: Store vault and seed backups together only in access-controlled locations protected to the same standard as the live deployment share.
- Avoid Persistent Copies: Do not copy the seed, vault, recovery files, or decrypted credentials to local disks, logs, package caches, or general-purpose file shares.
- Clear References After Use: Dispose
SecureStringobjects where possible and clear credential variables promptly. Garbage collection is not a guarantee that managed plaintext has been physically erased. - Use WinPECT for OS Handoff: Transfer selected credentials into the installed operating system through WinPECT's authenticated package and protected bootstrap workflow. Do not substitute plaintext task-sequence variables, unattended-file values, or command-line arguments.
- Use Maintenance Windows: Prevent WinPE vault access while rotating the seed or restoring a backup, then validate the live pair before resuming deployments.
For vulnerability reporting and the supported security scope, see SECURITY.md.
DeployVault is available under the MIT License.
The software is provided as is, without warranty of any kind. Its security controls reduce risk but cannot guarantee that credentials will never be exposed. Validate DeployVault and its surrounding deployment workflow against your own Windows PE images, Windows versions, infrastructure, and threat model before production use.