⚠️ Important Ethical Note ⚠️
This script should only be used in environments you own—like a home lab—where you are explicitly authorized to access these credentials.
Never use this in production, and never use it to access passwords you’re not supposed to know.
Automation is a tool; use it responsibly. Don’t be the reason someone disables API access for everyone.
Problem
Unlike Aria Lifecycle Manager, VCF Fleet Manager gives you no bulk export, no CLI command, and no straightforward API to fetch plain-text passwords. Everything is locked behind a multi-step process designed for security—which is great in production, but frustrating during lab operations.
Every time I redeployed VCF Automation or debugged a failed workflow, I had to:
- Open the browser
- Navigate to Locker
- Click through each credential
- Re-enter the root password (yes, every time)
After the fifth time in one afternoon, I knew: this has to be scriptable.
Troubleshooting the API
My first attempt was straightforward:
- Authenticate with Basic Auth
- GET
/lcm/locker/api/passwords→ get list of password IDs - POST to
/lcm/locker/api/v2/passwords/{id}/decryptedwith the root password
But I kept getting HTTP 500 Internal Server Errors on decryption—even though the same request worked in Postman.
After digging through logs and comparing raw requests, I discovered two key quirks:
🔸 Quirk #1: The JSON body must be exactly formatted
VCF’s decryption endpoint is picky. Using PowerShell’s
ConvertTo-Json added subtle formatting that the Java backend rejected. The only format that worked reliably was:{"rootPassword": "VMware123!"}
…as a literal string, no extra spaces, no PowerShell object conversion.
🔸 Quirk #2: Not all passwords are decryptable
Only system-generated passwords (like
lcm_root_user) can be decrypted using the global root password. Manually added credentials? They require their own passphrase—and won’t work with this method. That’s why you might see 9 entries but only decrypt 2–3.Also, yes—VCF’s login API returns
"Login succeessfully" (with three e’s). I’m not kidding. You have to match that typo in your success check.The Solution: A Reusable PowerShell Script
After ironing out the issues, I built a clean, parameterized PowerShell script that:
- Accepts VCF FQDN, username, auth password, and root password as inputs
- Bypasses SSL validation (safe in a home lab)
- Retrieves all password metadata
- Attempts to decrypt each one using the exact JSON format VCF expects
- Outputs a clear table of results
Here’s the core logic:
# Decrypt using literal JSON string (critical!)
$body = "{`"rootPassword`": `"$RootPassword`"}"
$response = Invoke-RestMethod -Method POST -Uri $url -Headers $headers -Body $body
You run it like this:
.\Get-VcfPasswords.ps1 ` -VcfFqdn "vcffleet.home.lab" ` -Username "admin@local" ` -Password "VMware123!" ` -RootPassword "VMware123!"
Sample output:
============================================================ DECRYPTED PASSWORDS REPORT ============================================================ Name Id Tenant Password ---- -- ------ -------- lcm_root_user 2b3dfa03-... default VMware123! VCF Automation - Root 8e6d2556-... default VMware123!
Why This Matters for Home Lab Operators
In a lab, speed and repeatability win. Being able to:
- Rebuild an environment from scratch
- Validate credential consistency
- Debug failed deployments by checking actual passwords
…saves hours over manual clicking. Plus, this script integrates nicely into larger automation workflows (like my VCF policy creator).
It’s not fancy—but it solves a real pain point I faced weekly.
Final Thoughts
This script isn’t just about passwords—it’s about taking control of your lab’s operational data instead of being blocked by UI limitations.
If you’re running a VCF home lab, give it a try. And if you improve it (maybe add CSV export or credential vault support), I’d love to hear about it!
Script
Get-VcfPasswords.ps1
#requires -Version 5.1
<#
.SYNOPSIS
Retrieves and decrypts stored passwords from VMware Cloud Foundation (VCF) Fleet Manager.
.DESCRIPTION
This script authenticates to a VCF Fleet Manager instance, retrieves password metadata,
and decrypts each password using the provided root password. Designed for home lab use.
.NOTES
Author: Kabir Ali - info@whatkabirwrites.nl
Date: February 2026
Environment: Trusted home lab – SSL validation bypassed.
#>
#region Parameters
Param (
[Parameter(Mandatory = $true)][string]$VcfFqdn,
[Parameter(Mandatory = $true)][string]$Username,
[Parameter(Mandatory = $true)][string]$Password,
[Parameter(Mandatory = $true)][string]$RootPassword
)
#endregion
#region SSL Bypass (Home Lab Only!)
Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
#endregion
#region Configuration
$Config = @{
VcfFqdn = $VcfFqdn
Username = $Username
Password = $Password
RootPassword = $RootPassword
}
#endregion
#region Helper Functions
function Write-Log {
param(
[Parameter(Mandatory)]
[string]$Message,
[ValidateSet('Info', 'Success', 'Warning', 'Error')]
[string]$Level = 'Info'
)
$ColorMap = @{ Info = 'White'; Success = 'Green'; Warning = 'Yellow'; Error = 'Red' }
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Host "[$Timestamp] [$Level] $Message" -ForegroundColor $ColorMap[$Level]
}
function Get-VcfAuthToken {
param(
[string]$VcfFqdn,
[string]$Username,
[string]$Password
)
try {
$pair = "$($Username):$($Password)"
$encoded = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($pair))
$headers = @{
"Accept" = "application/json"
"Authorization" = "Basic $encoded"
"Content-Type" = "application/json"
}
$authUrl = "https://$VcfFqdn/lcm/authzn/api/login"
$response = Invoke-RestMethod -Method POST -Uri $authUrl -Headers $headers -Body "" -ErrorAction Stop
if ($response -eq "Login succeessfully") { # Note: VCF has typo
Write-Log "Authentication successful." -Level Success
return $headers
} else {
throw "Unexpected authentication response: $response"
}
} catch {
Write-Log "Authentication failed: $($_.Exception.Message)" -Level Error
throw
}
}
function Get-VcfPasswordMetadata {
param(
[string]$VcfFqdn,
[hashtable]$AuthHeaders
)
try {
$url = "https://$VcfFqdn/lcm/locker/api/passwords"
$response = Invoke-RestMethod -Method GET -Uri $url -Headers $AuthHeaders -ErrorAction Stop
Write-Log "Retrieved $($response.Count) password entries." -Level Info
return $response
} catch {
Write-Log "Failed to retrieve password metadata: $($_.Exception.Message)" -Level Error
throw
}
}
function Decrypt-VcfPassword {
param(
[string]$VcfFqdn,
[hashtable]$AuthHeaders,
[string]$PasswordId,
[string]$RootPassword
)
try {
$url = "https://$VcfFqdn/lcm/locker/api/v2/passwords/$PasswordId/decrypted"
# Use exact string format as in original working script
$body = ' { "rootPassword": "VMware123!VMware123!" } '
$response = Invoke-RestMethod -Method POST -Uri $url -Headers $AuthHeaders -Body $body -ErrorAction Stop
return $response
} catch {
Write-Log "Failed to decrypt password ID '$PasswordId': $($_.Exception.Message)" -Level Warning
return $null
}
}
#endregion
#region Main Execution
try {
Write-Log "Starting VCF Fleet Manager password extraction..." -Level Info
# Authenticate
$authHeaders = Get-VcfAuthToken -VcfFqdn $Config.VcfFqdn -Username $Config.Username -Password $Config.Password
# Fetch password metadata
$passwordMetadata = Get-VcfPasswordMetadata -VcfFqdn $Config.VcfFqdn -AuthHeaders $authHeaders
if (-not $passwordMetadata -or $passwordMetadata.Count -eq 0) {
Write-Log "No passwords found in locker." -Level Warning
exit
}
# Decrypt each password
$decryptedPasswords = @()
foreach ($entry in $passwordMetadata) {
Write-Log "Decrypting password: $($entry.Alias) (ID: $($entry.vmid))" -Level Info
$plainText = Decrypt-VcfPassword -VcfFqdn $Config.VcfFqdn -AuthHeaders $authHeaders `
-PasswordId $entry.vmid -RootPassword $Config.RootPassword
if ($plainText) {
$decryptedPasswords += [PSCustomObject]@{
Name = $entry.Alias
Tenant = $entry.tenant
Password = $plainText.password
Id = $entry.vmid
}
}
}
# Final Reporting
Write-Log "Extraction complete. Found $($decryptedPasswords.Count) decrypted passwords." -Level Success
if ($decryptedPasswords.Count -gt 0) {
Write-Host "`n" + ("=" * 60) -ForegroundColor Cyan
Write-Host "DECRYPTED PASSWORDS REPORT" -ForegroundColor Cyan
Write-Host ("=" * 60) -ForegroundColor Cyan
$decryptedPasswords | Format-Table -Property Name, Id, Tenant, Password -AutoSize
} else {
Write-Log "No passwords were successfully decrypted." -Level Warning
}
} catch {
Write-Log "Script terminated due to error: $($_.Exception.Message)" -Level Error
exit 1
}