-
-
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." | |
} |
does this script remove the monitor driver and vmxnet3?
Thanks for this! Much cleaner uninstall than the brute-force cleanup method.
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.
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}
Fixed type mismatch error in OpenDatabase method by putting quotes around "$localPackage"