Skip to content

Instantly share code, notes, and snippets.

@KGHague
Last active March 18, 2025 15:16
Show Gist options
  • Save KGHague/2c562ee88492c1c0c0eac1b3ae0fecd8 to your computer and use it in GitHub Desktop.
Save KGHague/2c562ee88492c1c0c0eac1b3ae0fecd8 to your computer and use it in GitHub Desktop.
function ConvertTo-PackedGuid {
<#
.SYNOPSIS
https://gist.github.com/MyITGuy/d3e039c5ec7865edefc157fcd625a20a
Converts a GUID string into a packed globally unique identifier (GUID) string.
.DESCRIPTION
Takes a GUID string and breaks it into 6 parts. It then loops through the first five parts and reversing the order. It loops through the sixth part and reversing the order of every 2 characters. It then joins the parts back together and returns a packed GUID string.
.EXAMPLE
ConvertTo-PackedGuid -Guid '{7C6F0282-3DCD-4A80-95AC-BB298E821C44}'
The output of this example would be: 2820F6C7DCD308A459CABB92E828C144
.PARAMETER Guid
A globally unique identifier (GUID).
#>
[CmdletBinding()]
[OutputType([System.String])]
param (
[Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)]
[ValidateScript( { [System.Guid]::Parse($_) -is [System.Guid] })]
[System.Guid]$Guid
)
process {
Write-Verbose "Guid: $($Guid)"
$GuidString = $Guid.ToString('N')
Write-Verbose "GuidString: $($GuidString)"
$Indexes = [ordered]@{
0 = 8
8 = 4
12 = 4
16 = 2
18 = 2
20 = 12
}
$PackedGuid = ''
foreach ($index in $Indexes.GetEnumerator()) {
$Substring = $GuidString.Substring($index.Key, $index.Value)
Write-Verbose "Substring: $($Substring)"
switch ($index.Key) {
20 {
$parts = $Substring -split '(.{2})' | Where-Object { $_ }
foreach ($part In $parts) {
$part = $part -split '(.{1})'
Write-Verbose "Part: $($part)"
[System.Array]::Reverse($part)
Write-Verbose "Reversed: $($part)"
$PackedGuid += $part -join ''
}
}
default {
$part = $Substring.ToCharArray()
Write-Verbose "Part: $($part)"
[System.Array]::Reverse($part)
Write-Verbose "Reversed: $($part)"
$PackedGuid += $part -join ''
}
}
}
[System.Guid]::Parse($PackedGuid).ToString('N').ToUpper()
}
}
# Create an instance of the WindowsInstaller.Installer object
$installer = New-Object -ComObject WindowsInstaller.Installer
# Get the list of installed programs and find the VMware Tools entry
$vmwareTools = Get-WmiObject -Query "SELECT * FROM Win32_Product WHERE Name = 'VMware Tools'"
if ($vmwareTools) {
# Extract the identifying number (GUID)
[guid]$guid = $vmwareTools.IdentifyingNumber
# Convert the guid to a packed guid
[string]$packedguid = ConvertTo-PackedGuid $guid
# Get the LocalPackage path from the registry
$localPackage = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\$packedguid\InstallProperties" | Select-Object -ExpandProperty LocalPackage
if ($localPackage) {
Write-Output "VMware Tools MSI path: $localPackage"
# Open the MSI database in read-write mode
$database = $installer.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $null, $installer, @("$localPackage", 2))
# Remove the VM_LogStart row in the CustomAction table
$query = "DELETE FROM CustomAction WHERE Action='VM_LogStart'"
$view = $database.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $database, @($query))
$view.GetType().InvokeMember("Execute", "InvokeMethod", $null, $view, $null)
$view.GetType().InvokeMember("Close", "InvokeMethod", $null, $view, $null)
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($view)
# Commit the changes and close the database
$database.GetType().InvokeMember("Commit", "InvokeMethod", $null, $database, $null)
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($database)
# Uninstall VMware Tools
Start-Process msiexec.exe -ArgumentList "/x `"$localPackage`" /qn" -Wait
} else {
Write-Output "LocalPackage path not found in the registry."
}
} else {
Write-Output "VMware Tools is not installed."
}
@KGHague
Copy link
Author

KGHague commented Mar 8, 2025

Fixed type mismatch error in OpenDatabase method by putting quotes around "$localPackage"

@whit3hawk
Copy link

does this script remove the monitor driver and vmxnet3?

@aadnehovda
Copy link

Thanks for this! Much cleaner uninstall than the brute-force cleanup method.

@KGHague
Copy link
Author

KGHague commented Mar 12, 2025

does this script remove the monitor driver and vmxnet3?

It does not. It only does as much as what VMware's own uninstall does, which is a bit less than desired. This script could probably be combined with some of the brute-force methods to clean up some of the various drivers and non-present devices left behind.

@KGHague
Copy link
Author

KGHague commented Mar 13, 2025

does this script remove the monitor driver and vmxnet3?

@aadnehovda I threw this into my own clean-up script I'm using:

Get-PnpDevice -Status "UNKNOWN" -Class "Processor" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" -Class "System" | ForEach-Object {pnputil /remove-device $_.InstanceId
Get-PnpDevice -Status "UNKNOWN" -Class "USB" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" -Class "Volume" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" -Class "SCSIAdapter" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" -Class "Ports" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" -Class "HDC" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" -Class "FloppyDisk" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" -Class "FDC" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" -Class "HIDClass" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" -Class "Battery" | ForEach-Object {pnputil /remove-device $_.InstanceId}
Get-PnpDevice -Status "UNKNOWN" | Where-Object {$_.FriendlyName -like "VMware*"} | ForEach-Object {pnputil /remove-device $_.InstanceId}

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