Automating VMware Tools Upgrades with PowerShell and N-Central
As a systems engineer supporting a wide range of clients with all kinds of VMware environments—from vSphere to standalone ESXi hosts—I kept running into the same challenge: VMware Tools versions were often out of date. Manual upgrades were inconsistent, time-consuming, and prone to being forgotten. We already had a well-established patch management process using N-Central RMM, and I figured: Why not piggyback off the same maintenance window to upgrade VMware Tools, too? That would eliminate the manual effort and ensure every machine stayed updated and supported, automatically. This blog is a story of how a simple PowerShell script helped streamline this process—and how you can use it too. The Problem VMware Tools is essential for good VM performance, better guest OS integration, and clean VM shutdowns. But in environments with dozens or hundreds of virtual machines, keeping it updated across different versions of ESXi is messy. N-Central, our Remote Monitoring and Management (RMM) tool, allowed us to schedule tasks during patching windows. So I decided to build a PowerShell script that: Checks the latest VMware Tools version online Compares it with the version installed locally Downloads and silently installs the update—only if needed Logs everything along the way The PowerShell Script Here’s the full script. I’ll explain it part by part in a moment. You can download it from my GitHub here $URL = "https://packages.vmware.com/tools/esx/latest/windows/x64/" $LogFilePath = "C:\temp\VMwareToolsUpdateScript.log" (Get-Date).ToString() + " : Script Initiated" >> $logfilepath $PSversion = Get-Host | Select-Object Version (Get-Date).ToString() + " : PowerShell version = " + $PSversion >> $logfilepath $QueryVMWareToolsVersion = Invoke-WebRequest $URL -UseBasicParsing $VMWareToolsSetupName = $QueryVMWareToolsVersion.Links.HREF | Select -Skip 1 [string]$VMWareToolsNewestVersion = $VMWareToolsSetupName -replace ".*VMware-tools-" -replace "-.*" $VMWareToolsInstalledVersion = Get-WmiObject Win32_Product -Filter "Name like 'VMware Tools'" | Select-Object -ExpandProperty Version [string]$VMWareToolsInstalledVersion = $VMWareToolsInstalledVersion.Substring(0,$VMWareToolsInstalledVersion.LastIndexOf('.')) If ([version]$VMWareToolsInstalledVersion -lt [version]$VMWareToolsNewestVersion) { $DownloadURL = $URL + $VMWareToolsSetupName try { Invoke-WebRequest -Uri $DownloadURL -OutFile "C:\temp\$VMWareToolsSetupName" (Get-Date).ToString() + " : Download Finished!" >> $logfilepath } catch { (Get-Date).ToString() + " : Download Failed" >> $logfilepath } $ArgumentList = "/S /v " + '"/qn REBOOT=R ADDLOCAL=ALL"' + " /l C:\temp\VMwareToolsSetup.log" $FilePath = "C:\temp\" + $VMWareToolsSetupName try { Start-Process -FilePath $FilePath -ArgumentList $ArgumentList (Get-Date).ToString() + " : Installation Finished!" >> $logfilepath } catch { (Get-Date).ToString() + " : Installation Failed" >> $logfilepath } } else { (Get-Date).ToString() + " : VMware latest version is already installed!" >> $logfilepath } (Get-Date).ToString() + " : Script executed successfully" >> $logfilepath How It Works Let’s break this down step by step: 1. Logging and PowerShell Version Detection (Get-Date).ToString() + " : Script Initiated" >> $logfilepath $PSversion = Get-Host | Select-Object Version We start with timestamped logging and note which PowerShell version is running. This helps in troubleshooting if the script fails due to version incompatibility (some older versions have quirks with Invoke-WebRequest). 2. Check for the Latest VMware Tools Version $QueryVMWareToolsVersion = Invoke-WebRequest $URL -UseBasicParsing $VMWareToolsSetupName = $QueryVMWareToolsVersion.Links.HREF | Select -Skip 1 We hit VMware’s official tools repository and look at the second link on the page (the first is usually ../). This should be the .exe file for the latest version. [string]$VMWareToolsNewestVersion = $VMWareToolsSetupName -replace ".*VMware-tools-" -replace "-.*" Using a little regex magic, we extract the version string from the filename. 3. Detect the Currently Installed Version $VMWareToolsInstalledVersion = Get-WmiObject Win32_Product -Filter "Name like 'VMware Tools'" We use WMI to get the currently installed version of VMware Tools. Since VMware’s versioning can include build numbers (e.g. 12.2.5.45654), we trim that last segment for a cleaner version comparison. 4. Version Comparison and Conditional Upgrade If ([version]$VMWareToolsInstalledVersion -lt [version]$VMWareToolsNewestVersion) If the installed version is older, we build the download URL and pull the installer. 5. Silent Install and Logging $ArgumentList = "/S /v " + '"/qn REBOOT=R ADDLOCAL=ALL"' + " /l C:\temp\VMwareToolsSetup.log" Start-Process -FilePath $FilePath -ArgumentList $ArgumentList The in

As a systems engineer supporting a wide range of clients with all kinds of VMware environments—from vSphere to standalone ESXi hosts—I kept running into the same challenge: VMware Tools versions were often out of date. Manual upgrades were inconsistent, time-consuming, and prone to being forgotten.
We already had a well-established patch management process using N-Central RMM, and I figured: Why not piggyback off the same maintenance window to upgrade VMware Tools, too? That would eliminate the manual effort and ensure every machine stayed updated and supported, automatically.
This blog is a story of how a simple PowerShell script helped streamline this process—and how you can use it too.
The Problem
VMware Tools is essential for good VM performance, better guest OS integration, and clean VM shutdowns. But in environments with dozens or hundreds of virtual machines, keeping it updated across different versions of ESXi is messy.
N-Central, our Remote Monitoring and Management (RMM) tool, allowed us to schedule tasks during patching windows. So I decided to build a PowerShell script that:
- Checks the latest VMware Tools version online
- Compares it with the version installed locally
- Downloads and silently installs the update—only if needed
- Logs everything along the way
The PowerShell Script
Here’s the full script. I’ll explain it part by part in a moment. You can download it from my GitHub here
$URL = "https://packages.vmware.com/tools/esx/latest/windows/x64/"
$LogFilePath = "C:\temp\VMwareToolsUpdateScript.log"
(Get-Date).ToString() + " : Script Initiated" >> $logfilepath
$PSversion = Get-Host | Select-Object Version
(Get-Date).ToString() + " : PowerShell version = " + $PSversion >> $logfilepath
$QueryVMWareToolsVersion = Invoke-WebRequest $URL -UseBasicParsing
$VMWareToolsSetupName = $QueryVMWareToolsVersion.Links.HREF | Select -Skip 1
[string]$VMWareToolsNewestVersion = $VMWareToolsSetupName -replace ".*VMware-tools-" -replace "-.*"
$VMWareToolsInstalledVersion = Get-WmiObject Win32_Product -Filter "Name like 'VMware Tools'" | Select-Object -ExpandProperty Version
[string]$VMWareToolsInstalledVersion = $VMWareToolsInstalledVersion.Substring(0,$VMWareToolsInstalledVersion.LastIndexOf('.'))
If ([version]$VMWareToolsInstalledVersion -lt [version]$VMWareToolsNewestVersion) {
$DownloadURL = $URL + $VMWareToolsSetupName
try {
Invoke-WebRequest -Uri $DownloadURL -OutFile "C:\temp\$VMWareToolsSetupName"
(Get-Date).ToString() + " : Download Finished!" >> $logfilepath
} catch {
(Get-Date).ToString() + " : Download Failed" >> $logfilepath
}
$ArgumentList = "/S /v " + '"/qn REBOOT=R ADDLOCAL=ALL"' + " /l C:\temp\VMwareToolsSetup.log"
$FilePath = "C:\temp\" + $VMWareToolsSetupName
try {
Start-Process -FilePath $FilePath -ArgumentList $ArgumentList
(Get-Date).ToString() + " : Installation Finished!" >> $logfilepath
} catch {
(Get-Date).ToString() + " : Installation Failed" >> $logfilepath
}
} else {
(Get-Date).ToString() + " : VMware latest version is already installed!" >> $logfilepath
}
(Get-Date).ToString() + " : Script executed successfully" >> $logfilepath
How It Works
Let’s break this down step by step:
1. Logging and PowerShell Version Detection
(Get-Date).ToString() + " : Script Initiated" >> $logfilepath
$PSversion = Get-Host | Select-Object Version
We start with timestamped logging and note which PowerShell version is running. This helps in troubleshooting if the script fails due to version incompatibility (some older versions have quirks with Invoke-WebRequest
).
2. Check for the Latest VMware Tools Version
$QueryVMWareToolsVersion = Invoke-WebRequest $URL -UseBasicParsing
$VMWareToolsSetupName = $QueryVMWareToolsVersion.Links.HREF | Select -Skip 1
We hit VMware’s official tools repository and look at the second link on the page (the first is usually ../
). This should be the .exe
file for the latest version.
[string]$VMWareToolsNewestVersion = $VMWareToolsSetupName -replace ".*VMware-tools-" -replace "-.*"
Using a little regex magic, we extract the version string from the filename.
3. Detect the Currently Installed Version
$VMWareToolsInstalledVersion = Get-WmiObject Win32_Product -Filter "Name like 'VMware Tools'"
We use WMI to get the currently installed version of VMware Tools. Since VMware’s versioning can include build numbers (e.g. 12.2.5.45654
), we trim that last segment for a cleaner version comparison.
4. Version Comparison and Conditional Upgrade
If ([version]$VMWareToolsInstalledVersion -lt [version]$VMWareToolsNewestVersion)
If the installed version is older, we build the download URL and pull the installer.
5. Silent Install and Logging
$ArgumentList = "/S /v " + '"/qn REBOOT=R ADDLOCAL=ALL"' + " /l C:\temp\VMwareToolsSetup.log"
Start-Process -FilePath $FilePath -ArgumentList $ArgumentList
The installer is launched silently (/qn
) with reboot handling (REBOOT=R
) and full feature installation (ADDLOCAL=ALL
). The log file helps diagnose any install issues.
Why This Approach Worked
- No reliance on vCenter or ESXi APIs — just plain HTTP and PowerShell
- Compatible with any guest OS that supports VMware Tools on Windows
- No unnecessary upgrades — it installs only when there’s a newer version
- Built-in logging makes it easy to audit and troubleshoot
We scheduled the script to run during our regular patch maintenance window, so every machine was updated without manual intervention. It’s a small thing, but it shaved hours off our monthly maintenance efforts and ensured better consistency across customer environments.
Download the Script