Skip to content

Instantly share code, notes, and snippets.

@andshrew
Last active May 17, 2025 02:46
Show Gist options
  • Save andshrew/bf6e5e8fa09b957caffc09c6dee58472 to your computer and use it in GitHub Desktop.
Save andshrew/bf6e5e8fa09b957caffc09c6dee58472 to your computer and use it in GitHub Desktop.
VMware Workstation VM encryption passwords saved in the the Windows Credential Manager

Retrieving VMware Workstation VM encryption passwords saved in the the Windows Credential Manager

When creating an encrypted VM, VMware Workstation gives you the option to remember the password. It does this by storing the password in the Windows Credential Manager.

VMware does not provide a way to retrieve this stored password, but it can be accessed via the Win32 CredReadW API function.

There are a number of PowerShell projects including PowerShell Credential Manager which provide access to this API, but in testing I found they were unable to correctly display the VMware password.

This PowerShell example has been tested using Windows PowerShell (v5.1) and PowerShell (v7) using VMware Workstation 17.5 on Windows 11 23H2. Windows Terminal is used as the host for command line apps. It has been written with the assistance of ChatGPT.

1. Locate Encrypted VMs GUID

Open the .vmx file for your VM and look for encryptedVM.guid. This is the name of the credential within Windows Credential Manager. For example:

encryptedVM.guid = "{833AB4F5-587E-4B11-9260-4DB13742FA7F}"

2. Retrieve the password via PowerShell

Open PowerShell or Windows PowerShell, copy and paste the below code. This provides an interface to the Win32 API via C#.

Add-Type @"
using System;
using System.Runtime.InteropServices;

public class Win32Cred
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct CREDENTIAL
    {
        public int Flags;
        public int Type;
        public IntPtr TargetName;
        public IntPtr Comment;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
        public int CredentialBlobSize;
        public IntPtr CredentialBlob;
        public int Persist;
        public int AttributeCount;
        public IntPtr Attributes;
        public IntPtr TargetAlias;
        public IntPtr UserName;
    }

    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool CredReadW(string target, int type, int reservedFlag, out IntPtr credentialPtr);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern void CredFree(IntPtr buffer);

    public static string CredRead(string targetName, int type = 1)
    {
        IntPtr credPtr;
        if (CredReadW(targetName, type, 0, out credPtr))
        {
            CREDENTIAL cred = (CREDENTIAL)Marshal.PtrToStructure(credPtr, typeof(CREDENTIAL));
            string pass = Marshal.PtrToStringAnsi(cred.CredentialBlob, cred.CredentialBlobSize);
            CredFree(credPtr);
            return pass;
        }
        throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
    }
}
"@

Run the following command replacing {encryptedVM.guid} with the GUID identified in step 1:

[Win32Cred]::CredRead("{encryptedVM.guid}")

For example:

[Win32Cred]::CredRead("{833AB4F5-587E-4B11-9260-4DB13742FA7F}")

3. End of Procedure

The password should be output to the screen:

PS C:\Users\Andrew [Win32Cred]::CredRead("{833AB4F5-587E-4B11-9260-4DB13742FA7F}")
MySecretPassword

A note on Marshal.PtrToString

In this example I use Marshal.PtrToStringAnsi to convert the pointer to the password into a string.

This works in both Windows PowerShell and PowerShell, as it is a C# method available in both .NET Framework and modern .NET (Core).

Marshal.PtrToStringUni does not seem to work, but Marshal.PtrToStringUTF8 does and may be more flexible. This would require the use of PowerShell as this method is only implemented in modern .NET.

It may be preferable to use this, as not all characters will display using ANSI. For example, say your password was made up of emoji characters. Using the above example with Marshal.PtrToStringAnsi the password is going to be output as incorrect characters:

Marshal.PtrToStringAnsi Emoji Example

But using Marshal.PtrToStringUTF8 the password will be correctly displayed, and can be copied/pasted as required:

Marshal.PtrToStringUTF8 Emoji Example

So if this doesn't work for you, you may want to try swapping these functions in the above code, from:

string pass = Marshal.PtrToStringAnsi(cred.CredentialBlob, cred.CredentialBlobSize);

To:

string pass = Marshal.PtrToStringUTF8(cred.CredentialBlob, cred.CredentialBlobSize);

Remember, you must use PowerShell and not Windows PowerShell when using this method.

Here is the full code example using Marshal.PtrToStringUTF8:

Add-Type @"
using System;
using System.Runtime.InteropServices;

public class Win32Cred
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct CREDENTIAL
    {
        public int Flags;
        public int Type;
        public IntPtr TargetName;
        public IntPtr Comment;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
        public int CredentialBlobSize;
        public IntPtr CredentialBlob;
        public int Persist;
        public int AttributeCount;
        public IntPtr Attributes;
        public IntPtr TargetAlias;
        public IntPtr UserName;
    }

    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool CredReadW(string target, int type, int reservedFlag, out IntPtr credentialPtr);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern void CredFree(IntPtr buffer);

    public static string CredRead(string targetName, int type = 1)
    {
        IntPtr credPtr;
        if (CredReadW(targetName, type, 0, out credPtr))
        {
            CREDENTIAL cred = (CREDENTIAL)Marshal.PtrToStructure(credPtr, typeof(CREDENTIAL));
            string pass = Marshal.PtrToStringUTF8(cred.CredentialBlob, cred.CredentialBlobSize);
            CredFree(credPtr);
            return pass;
        }
        throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
    }
}
"@

You then invoke it in the same was as in step 2.

@mupsza
Copy link

mupsza commented Jan 10, 2025

Hi,
just tried your work with power shell 7 and the Marshal.PtrToStringUTF8 way on a Win11 system.
code works, but the encryptedVM.guid can not be found.
I am sure I took the right one from the vmx file.
Currently .. no idea where I could go wrong / why it does not work on my environment

-> PS C:\Windows\System32> [Win32Cred]::CredRead("{0115B4E7-8751-48B4-****-A5214749917D}")
-> MethodInvocationException: Exception calling "CredRead" with "1" argument(s): "Element not found."

@andshrew
Copy link
Author

andshrew commented Jan 10, 2025

Hi @mupsza

That error means that the GUID you're searching for doesn't exist in the Windows Credential Manager; so either you're looking up the wrong GUID, or it is the correct GUID but the password isn't actually saved.

If you look directly in Credential Manger, click Windows Credentials and then look under Generic Credentials then you should see everything that you have saved. This is how the example I used appears in Credential Manager for me:

image

@catester
Copy link

catester commented Jan 29, 2025

Thank god, great method, I moved a win11 VM to a new PC and was puzzled by VMWare asking for encryption password because I didn't set anything like that.
It turned out VMWare used the same password as windows VM's Administrator account, for the encryption password. With this method I saw the same password and said doh. So first try your VM admin pass and save the hassle.

@labthe3rd
Copy link

Thank you! It worked!

@silverlox
Copy link

Hello Andrew
Thanks for the procedure you have here, it worked for me.

I had purchased and used without success, Easeus Key Finder.
Contacting the support guys, they admitted that their program could not help me and immediately refunded me the purchasse price.
They are interested in your procedure here and wanted me to send them a link to it so they can find out how it worked and incorporate it into the Key Finder program
Is it OK if I do this or would you like to contact them direct and maybe get paid for your work?

Mike

@andshrew
Copy link
Author

Hi @silverlox

Glad this helped you out, feel free to share it on if you like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment