Last active
May 13, 2024 06:16
-
-
Save broestls/f872872a00acee2fca02017160840624 to your computer and use it in GitHub Desktop.
Force removal of VMware Tools, Program Files, and Windows Services
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This script will manually rip out all VMware Tools registry entries and files for Windows 2008-2019 | |
# Tested for 2019, 2016, and probably works on 2012 R2 after the 2016 fixes. | |
# This function pulls out the common ID used for most of the VMware registry entries along with the ID | |
# associated with the MSI for VMware Tools. | |
function Get-VMwareToolsInstallerID { | |
foreach ($item in $(Get-ChildItem Registry::HKEY_CLASSES_ROOT\Installer\Products)) { | |
If ($item.GetValue('ProductName') -eq 'VMware Tools') { | |
return @{ | |
reg_id = $item.PSChildName; | |
msi_id = [Regex]::Match($item.GetValue('ProductIcon'), '(?<={)(.*?)(?=})') | Select-Object -ExpandProperty Value | |
} | |
} | |
} | |
} | |
$vmware_tools_ids = Get-VMwareToolsInstallerID | |
# Targets we can hit with the common registry ID from $vmware_tools_ids.reg_id | |
$reg_targets = @( | |
"Registry::HKEY_CLASSES_ROOT\Installer\Features\", | |
"Registry::HKEY_CLASSES_ROOT\Installer\Products\", | |
"HKLM:\SOFTWARE\Classes\Installer\Features\", | |
"HKLM:\SOFTWARE\Classes\Installer\Products\", | |
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\" | |
) | |
$VMware_Tools_Directory = "C:\Program Files\VMware" | |
$VMware_Common_Directory = "C:\Program Files\Common Files\VMware" | |
# Create an empty array to hold all the uninstallation targets and compose the entries into the target array | |
$targets = @() | |
If ($vmware_tools_ids) { | |
foreach ($item in $reg_targets) { | |
$targets += $item + $vmware_tools_ids.reg_id | |
} | |
# Add the MSI installer ID regkey | |
$targets += "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{$($vmware_tools_ids.msi_id)}" | |
} | |
# This is a bit of a shotgun approach, but if we are at a version less than 2016, add the Uninstaller entries we don't | |
# try to automatically determine. | |
If ([Environment]::OSVersion.Version.Major -lt 10) { | |
$targets += "HKCR:\CLSID\{D86ADE52-C4D9-4B98-AA0D-9B0C7F1EBBC8}" | |
$targets += "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{9709436B-5A41-4946-8BE7-2AA433CAF108}" | |
$targets += "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{FE2F6A2C-196E-4210-9C04-2B1BC21F07EF}" | |
} | |
# Add the VMware, Inc regkey | |
If (Test-Path "HKLM:\SOFTWARE\VMware, Inc.") { | |
$targets += "HKLM:\SOFTWARE\VMware, Inc." | |
} | |
# Add the VMware Tools directory | |
If(Test-Path $VMware_Tools_Directory) { | |
$targets += $VMware_Tools_Directory | |
} | |
# Thanks to @Gadgetgeek2000 for pointing out that the script leaves some 500mb of extra artifacts on disk. | |
# This blob removes those. | |
If(Test-Path $VMware_Common_Directory) { | |
$targets += $VMware_Common_Directory | |
} | |
# Create a list of services to stop and remove | |
$services = Get-Service -DisplayName "VMware*" | |
$services += Get-Service -DisplayName "GISvc" | |
# Warn the user about what is about to happen | |
# Takes only y for an answer, bails otherwise. | |
Write-Host "The following registry keys, filesystem folders, and services will be deleted:" | |
If (!$targets -and !$services ) { | |
Write-Host "Nothing to do!" | |
} | |
Else { | |
$targets | |
$services | |
$user_confirmed = Read-Host "Continue (y/n)" | |
If ($user_confirmed -eq "y") { | |
# Stop all running VMware Services | |
$services | Stop-Service -Confirm:$false | |
# Cover for Remove-Service not existing in PowerShell versions < 6.0 | |
If (Get-Command Remove-Service -errorAction SilentlyContinue) { | |
$services | Remove-Service -Confirm:$false | |
} | |
Else { | |
foreach ($s in $services) { | |
sc.exe DELETE $($s.Name) | |
} | |
} | |
# Remove all the files that are listed in $targets | |
foreach ($item in $targets) { | |
If(Test-Path $item) { | |
Remove-Item -Path $item -Recurse | |
} | |
} | |
Write-Host "Done. Reboot to complete removal." | |
} | |
Else { | |
Write-Host "Failed to get user confirmation" | |
} | |
} |
I'm sure someone can make this better, but my co-worker and I took this code and made a script to remove VMware tools from 300 domain servers remotely after migrating from on-prem to AWS. We also had issues deleting c:\Program Files\VMware\VMware Tools because eventlog and WMI services were running. We also removed the ask to continue prompts.
This script copies "removesvmware.ps1" and executes it on the target host.
# Step 1: Get a list of computers using get-ADcomputer
$computers = Get-ADComputer -Filter 'Name -like "*" -and Enabled -eq "True"' -Property * | Select-Object Name, OperatingSystem, OperatingSystemServicePack
# Step 2: Robocopy a ps1 file from the source machine to each computer in the list
foreach ($computer in $computers) {
robocopy "C:\temp" "\\$($computer.Name)\C$\temp" RemoveVMwareTools.ps1 /copy:dat /is /r:2 /w:2
}
# Step 3 & 4: Check if the ps1 file exists on the destination machine and execute it
foreach ($computer in $computers) {
$destinationPath = "\\$($computer.Name)\C$\Temp"
$ps1FilePath = "\\$($computer.Name)\C$\Temp\RemoveVMwareTools.ps1"
# Check if the ps1 file exists
if (Test-Path $ps1FilePath) {
# If the ps1 file exists, read its content
$scriptContent = Get-Content $ps1FilePath -Raw
# Execute the script content in a remote session
Invoke-Command -ComputerName $computer.Name -ScriptBlock {
param($scriptContent)
Invoke-Expression $using:scriptContent
} -ArgumentList $scriptContent
} else {
Write-Host "PS1 file not found on $($computer.Name)"
}
}
This is removevmware.ps1
# This script will manually rip out all VMware Tools registry entries and files for Windows 2008-2019
# Tested for 2019, 2016, and probably works on 2012 R2 after the 2016 fixes.
# This function pulls out the common ID used for most of the VMware registry entries along with the ID
# associated with the MSI for VMware Tools.
function Get-VMwareToolsInstallerID {
foreach ($item in $(Get-ChildItem Registry::HKEY_CLASSES_ROOT\Installer\Products)) {
If ($item.GetValue('ProductName') -eq 'VMware Tools') {
return @{
reg_id = $item.PSChildName;
msi_id = [Regex]::Match($item.GetValue('ProductIcon'), '(?<={)(.*?)(?=})') | Select-Object -ExpandProperty Value
}
}
}
}
$vmware_tools_ids = Get-VMwareToolsInstallerID
# Targets we can hit with the common registry ID from $vmware_tools_ids.reg_id
$reg_targets = @(
"Registry::HKEY_CLASSES_ROOT\Installer\Features\",
"Registry::HKEY_CLASSES_ROOT\Installer\Products\",
"HKLM:\SOFTWARE\Classes\Installer\Features\",
"HKLM:\SOFTWARE\Classes\Installer\Products\",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\"
)
$VMware_Tools_Directory = "C:\Program Files\VMware"
$VMware_Common_Directory = "C:\Program Files\Common Files\VMware"
# Create an empty array to hold all the uninstallation targets and compose the entries into the target array
$targets = @()
If ($vmware_tools_ids) {
foreach ($item in $reg_targets) {
$targets += $item + $vmware_tools_ids.reg_id
}
# Add the MSI installer ID regkey
$targets += "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{$($vmware_tools_ids.msi_id)}"
}
# This is a bit of a shotgun approach, but if we are at a version less than 2016, add the Uninstaller entries we don't
# try to automatically determine.
If ([Environment]::OSVersion.Version.Major -lt 10) {
$targets += "HKCR:\CLSID\{D86ADE52-C4D9-4B98-AA0D-9B0C7F1EBBC8}"
$targets += "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{9709436B-5A41-4946-8BE7-2AA433CAF108}"
$targets += "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{FE2F6A2C-196E-4210-9C04-2B1BC21F07EF}"
}
# Add the VMware, Inc regkey
If (Test-Path "HKLM:\SOFTWARE\VMware, Inc.") {
$targets += "HKLM:\SOFTWARE\VMware, Inc."
}
# Add the VMware Tools directory
If(Test-Path $VMware_Tools_Directory) {
$targets += $VMware_Tools_Directory
}
# Thanks to @Gadgetgeek2000 for pointing out that the script leaves some 500mb of extra artifacts on disk.
# This blob removes those.
If(Test-Path $VMware_Common_Directory) {
$targets += $VMware_Common_Directory
}
# Create a list of services to stop and remove
$services = Get-Service -DisplayName "VMware*"
$services += Get-Service -DisplayName "GISvc"
# Warn the user about what is about to happen
# Takes only y for an answer, bails otherwise.
#Write-Host "The following registry keys, filesystem folders, and services will be deleted:"
If (!$targets -and !$services ) {
#Write-Host "Nothing to do!"
}
Else {
$targets
$services
#$user_confirmed = Read-Host "Continue (y/n)"
If ($user_confirmed -eq "y") {
# Stop all running VMware Services
$services | Stop-Service -Confirm:$false
# Cover for Remove-Service not existing in PowerShell versions < 6.0
If (Get-Command Remove-Service -errorAction SilentlyContinue) {
$services | Remove-Service -Confirm:$false
}
Else {
foreach ($s in $services) {
sc.exe DELETE $($s.Name)
}
}
Get-Service -Name "EventLog" | Format-List -Property Name, DependentServices
Stop-Service -Name "EventLog" -Force
Stop-Service -Name "wmiApSvc" -Force
Start-Sleep -Seconds 5
# Remove all the files that are listed in $targets
foreach ($item in $targets) {
If(Test-Path $item) {
Remove-Item -Path $item -Recurse -Force
}
}
Start-Service -Name "EventLog"
Start-Service -Name "wmiApSvc"
Write-Host "Done. Reboot to complete removal."
}
Else {
Write-Host "Failed to get user confirmation"
}
}
Thanks, it was very useful in a migration from VMWare to Proxmox.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you very much!
Also I had to manually unregister the vmStatsProvider.dll:
REGSVR32 /U "c:\Program Files\VMware\VMware Tools\vmStatsProvider\win64\vmStatsProvider.dll"
Then I succeeded in removing the entire folder tree.