Skip to content

convert/convert_windows.ml: Attempt to remove VMware drivers#144

Open
rwmjones wants to merge 2 commits into
libguestfs:masterfrom
rwmjones:2026-remove-vmware-drivers
Open

convert/convert_windows.ml: Attempt to remove VMware drivers#144
rwmjones wants to merge 2 commits into
libguestfs:masterfrom
rwmjones:2026-remove-vmware-drivers

Conversation

@rwmjones

@rwmjones rwmjones commented Mar 3, 2026

Copy link
Copy Markdown
Member

We essentially expect that uninstalling VMware drivers will fail (because the VMware uninstaller is broken). Therefore add a firstboot script which does the next best thing, removing VMware drivers by hand.

This requires Microsoft pnputil which is present in Windows >= Vista.

Most of the hard work was done by and all of the batch file was written by Vadim Rozenfeld.

Thanks: Vadim Rozenfeld
Fixes: https://issues.redhat.com/browse/RHEL-112249
Related: https://github.com/virtio-win/vmwremover/blob/main/drivers/remove_vmware_driver_packages.bat

@rwmjones

rwmjones commented Mar 3, 2026

Copy link
Copy Markdown
Member Author

Draft because this doesn't work for me. There are two main problems:

  • [Fixed in upcoming commit] Pnputil fails to run with the error: 'pnputil' is not recognized as an internal or external command, operable program or batch file.. Yet I am able to run pnputil from cmd.exe just fine. @vrozenfe do you know why the script cannot find pnputil, but yet the command seems to be present?
  • (Relatively minor) There is a second log written to C:\Program Files\Guestfs\Firstboot\scripts\5000-0005-uninstall-VMware-Tools.log. (edit: actually this log file is from the previous step, however the next bit is true) We should probably delete all that code, all logs should be written to stdout so they end up in the normal log.

@rwmjones rwmjones force-pushed the 2026-remove-vmware-drivers branch from 0389f30 to 176648a Compare March 3, 2026 13:11
@rwmjones

rwmjones commented Mar 3, 2026

Copy link
Copy Markdown
Member Author

In this update, I run pnputil using the full path, and I've removed the logging code so now logs go straight into log.txt and not wherever else they were going before.

I did not squash the additional patches yet, and this is still a draft. However it appears to work, although I'm not sure if it is removing the correct drivers. It says it's removing a bunch of drivers called stuff like oem3.inf. Is that OK?

@vrozenfe please see if the log below looks correct:

running "C:\Program Files\Guestfs\Firstboot\scripts\5000-0006-remove-VMware-driv
ers.bat"

===============================================================
  Remove VMware Driver Packages Script
===============================================================

 Searching for VMware drivers and packages
Filtering lines with Published Name and VMware...

===== VMware Drivers Found =====
Found VMware INF: oem3.inf
Found VMware INF: oem5.inf
Found VMware INF: oem9.inf
Found VMware INF: oem7.inf
Found VMware INF: oem6.inf
Found VMware INF: oem8.inf
Found VMware INF: oem4.inf
Remove each VMware driver package
Removing oem3.inf ...
Microsoft PnP Utility

Driver package uninstalled.
Driver package deleted successfully.
Done.
Removing oem5.inf ...
Microsoft PnP Utility

Driver package uninstalled.
Driver package deleted successfully.
Done.
Removing oem9.inf ...
Microsoft PnP Utility

Driver package uninstalled.
Driver package deleted successfully.
Done.
Removing oem7.inf ...
Microsoft PnP Utility

Driver package uninstalled.
Driver package deleted successfully.
System reboot is needed to complete unconfiguration operations!
Done.
Removing oem6.inf ...
Microsoft PnP Utility

Driver package uninstalled.
Driver package deleted successfully.
Done.
Removing oem8.inf ...
Microsoft PnP Utility

Driver package uninstalled.
Driver package deleted successfully.
Done.
Removing oem4.inf ...
Microsoft PnP Utility

Driver package uninstalled.
Driver package deleted successfully.
Done.
Clean up temporary files

 VMware driver removal process finished
A system reboot is required to complete the removal.
.... exit code 0
Script succeeded, moving to scripts-done
        1 file(s) moved.

@vrozenfe

vrozenfe commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

@rwmjones Looks good to me. Are you going to add the VMW services removal code as well? Best, Vadim.

@rwmjones

rwmjones commented Mar 5, 2026

Copy link
Copy Markdown
Member Author

@rwmjones Looks good to me. Are you going to add the VMW services removal code as well? Best, Vadim.

I don't know - which actual script is that?

@rwmjones

rwmjones commented Mar 5, 2026

Copy link
Copy Markdown
Member Author

@vrozenfe:
I guess that's: https://github.com/virtio-win/vmwremover/blob/main/services/remove_vmware_services.bat
It seems invasive.

Other questions about the current patch:

  • How do we get it to print the actual driver name, not oemX.inf
  • Is the path to pnputil correct? Why do we need the path to pnputil?
  • I have removed the rebooting code (since firstboot always reboots between scripts), is that correct?

@vrozenfe

Copy link
Copy Markdown
Contributor

@rwmjones Hi Richard.
You are right that
https://github.com/virtio-win/vmwremover/blob/main/services/remove_vmware_services.bat

is somewhat aggressive. We could make it less invasive by only stopping and disabling the relevant services rather than deleting them.

Regarding printing the actual driver name instead of just oemX.inf: I assume you are referring to the output section such as:
===== VMware Drivers Found =====
Found VMware INF: oem3.inf

We can extend the parsing logic to also capture the Original Name field from pnputil /enum-drivers. That would allow us to print something like:
===== VMware Drivers Found =====
Found VMware INF: vmmouse.inf (oem3.inf)

set COUNT=0
set LAST_PUBLISHED=
set LAST_ORIGINAL=

for /f "tokens=1,* delims=:" %%A in (%temp%\vmware_drivers.txt) do (
set LINE=%%A
set VALUE=%%B
set VALUE=!VALUE: =!

if /i "!LINE!"=="Published Name" (
    set LAST_PUBLISHED=!VALUE!
)

if /i "!LINE!"=="Original Name" (
    set LAST_ORIGINAL=!VALUE!
)

if /i "!LINE!"=="Provider Name" (
    echo !VALUE! | findstr /i "VMware" >nul
    if !errorlevel! == 0 (
        if not "!LAST_PUBLISHED!"=="" (
            echo Found VMware driver: !LAST_ORIGINAL! (!LAST_PUBLISHED!)
            set INF_LIST[!COUNT!]=!LAST_PUBLISHED!
            set /a COUNT+=1
        )
    )
    set LAST_PUBLISHED=
    set LAST_ORIGINAL=
)

)

Regarding the pnputil path: we need to use the same path handling as in the other calls. One important detail is that firstboot itself is a 32-bit process. When a 32-bit service runs on a 64-bit Windows system, any process it spawns is normally subject to WOW64 filesystem redirection, which means System32 is redirected to SysWOW64.
In our case we need to run the 64-bit pnputil.exe, but since it is being invoked from a 32-bit process, the only reliable way to access it is through the Sysnative alias, which bypasses the redirection mechanism.

Right, no reboot is needed as firstboot does it by itself.

Best,
Vadim.

@rwmjones

Copy link
Copy Markdown
Member Author

https://github.com/virtio-win/vmwremover/blob/main/services/remove_vmware_services.bat

So removing the uninstall permanently bit? (https://github.com/virtio-win/vmwremover/blob/6d70ce6830a57c3f6dc8b43a327260b2b20358db/services/remove_vmware_services.bat#L140)

I suspect it'd be better if all that went into a separate pull request rather than making this one more complex.

Thanks for the other explanations. I will see if I can change the current pull request to print the service name.

@rwmjones rwmjones force-pushed the 2026-remove-vmware-drivers branch from 0bc8984 to 1fa22e8 Compare March 16, 2026 12:43
@rwmjones

Copy link
Copy Markdown
Member Author

I just squashed the commits together and rebased on top of master. Still more work to be done here.

Since we want to use the full path of pnputil later, abstract out the
Windows path of this utility.  I also added an explanation of what we
understand to be going on with the path here.  This was originally
written by Vadim Rozenfeld in the comment linked below.

Link: libguestfs#144 (comment)
Thanks: Vadim Rozenfeld
@rwmjones

Copy link
Copy Markdown
Member Author

@vrozenfe I made this change to the script which appears completely innocuous. Yet when I make this change, the script no longer finds any drivers at all! What's going on?

@@ -569,11 +576,9 @@ echo Searching for VMware drivers and packages
 echo Filtering lines with Published Name and VMware...
 findstr /i /c:"Published Name" /c:"Provider Name" "%temp%\all_drivers.txt" > "%temp%\vmware_drivers.txt"
 
-echo.
-echo ===== VMware Drivers Found =====
-
 set COUNT=0
 set LAST_PUBLISHED=
+set LAST_ORIGINAL=
 
 for /f "tokens=1,* delims=:" %%A in (%temp%\vmware_drivers.txt) do (
     set LINE=%%A
@@ -584,17 +589,22 @@ for /f "tokens=1,* delims=:" %%A in (%temp%\vmware_drivers.txt) do (
         set LAST_PUBLISHED=!VALUE!
     )
 
+    if /i "!LINE!"=="Original Name" (
+        set LAST_ORIGINAL=!VALUE!
+    )
+
     if /i "!LINE!"=="Provider Name" (
         echo !VALUE! | findstr /i "VMware" >nul
         if !errorlevel! == 0 (
             REM This Published Name belongs to VMware
             if not "!LAST_PUBLISHED!"=="" (
-                echo Found VMware INF: !LAST_PUBLISHED!
+                echo Found VMware driver: !LAST_ORIGINAL! (!LAST_PUBLISHED!)
                 set INF_LIST[!COUNT!]=!LAST_PUBLISHED!
                 set /a COUNT+=1
             )
         )
         set LAST_PUBLISHED=
+        set LAST_ORIGINAL=
     )
 )

@rwmjones rwmjones force-pushed the 2026-remove-vmware-drivers branch from 1fa22e8 to d622039 Compare March 16, 2026 15:11
@rwmjones

Copy link
Copy Markdown
Member Author

@vrozenfe Please see comments above, plus in the latest version it seems like the final for loop doesn't ever remove the drivers, and I have no idea why.

Searching for VMware drivers and packages
Filtering lines with Published Name and VMware...
Removing 7 VMware driver package(s)      <---- 7 drivers in INF list
Clean up temporary files   <---- why is nothing printed before this line?!

VMware driver removal process finished
.... exit code 0

@vrozenfe

Copy link
Copy Markdown
Contributor

@rwmjones Let me check it, and sorry for the inconvenience.

@vrozenfe

Copy link
Copy Markdown
Contributor

@rwmjones Hi Richard. It should be something like this:
diff --git a/drivers/remove_vmware_driver_packages.bat b/drivers/remove_vmware_driver_packages.bat
index 46d7ebb..3365da6 100644
--- a/drivers/remove_vmware_driver_packages.bat
+++ b/drivers/remove_vmware_driver_packages.bat
@@ -40,7 +40,7 @@ pnputil /enum-drivers > "%temp%\all_drivers.txt"

:: --- Filter for VMware drivers ---
echo Filtering lines with Published Name and VMware...
-findstr /i /c:"Published Name" /c:"Provider Name" "%temp%\all_drivers.txt" > "%temp%\vmware_drivers.txt"
+findstr /i /c:"Published Name" /c:"Original Name" /c:"Provider Name" "%temp%\all_drivers.txt" > "%temp%\vmware_drivers.txt"

echo.
echo ===== VMware Drivers Found =====
@@ -48,6 +48,7 @@ echo ===== VMware Drivers Found =====
:: --- Initialize variables ---
set COUNT=0
set LAST_PUBLISHED=
+set LAST_ORIGINAL=

:: --- Parse driver list for VMware providers ---
for /f "tokens=1,* delims=:" %%A in (%temp%\vmware_drivers.txt) do (
@@ -59,17 +60,22 @@ for /f "tokens=1,* delims=:" %%A in (%temp%\vmware_drivers.txt) do (
set LAST_PUBLISHED=!VALUE!
)

  • if /i "!LINE!"=="Original Name" (
  •    set LAST_ORIGINAL=!VALUE!
    
  • )
  • if /i "!LINE!"=="Provider Name" (
    echo !VALUE! | findstr /i "VMware" >nul
    if !errorlevel! == 0 (
    REM This Published Name belongs to VMware
    if not "!LAST_PUBLISHED!"=="" (
  •            echo Found VMware INF: !LAST_PUBLISHED!
    
  •            echo Found VMware driver: !LAST_ORIGINAL! ^(!LAST_PUBLISHED!^)
               set INF_LIST[!COUNT!]=!LAST_PUBLISHED!
               set /a COUNT+=1
           )
       )
       set LAST_PUBLISHED=
    
  •    set LAST_ORIGINAL=
    
    )
    )

I tested it briefly, since I don't have a proper VMware-converted image at the moment.

We essentially expect that uninstalling VMware drivers will fail
(because the VMware uninstaller is broken).  Therefore add a firstboot
script which does the next best thing, removing VMware drivers by hand.

This requires Microsoft pnputil which is present in Windows >= Vista.

Most of the hard work was done by and all of the batch file was
written by Vadim Rozenfeld.

Thanks: Vadim Rozenfeld
Fixes: https://issues.redhat.com/browse/RHEL-112249
Related: https://github.com/virtio-win/vmwremover/blob/main/drivers/remove_vmware_driver_packages.bat
@rwmjones rwmjones force-pushed the 2026-remove-vmware-drivers branch from d622039 to 38287ab Compare March 16, 2026 21:00
@rwmjones

Copy link
Copy Markdown
Member Author

Thanks, I think it was the addition of /c:"Original Name" that was required. After that change the output is:

Filtering lines with Published Name and VMware...
Found VMware driver: efifw.inf (oem3.inf)
Found VMware driver: pvscsi.inf (oem5.inf)
Found VMware driver: vmci.inf (oem9.inf)
Found VMware driver: vmmouse.inf (oem7.inf)
Found VMware driver: vmusbmouse.inf (oem6.inf)
Found VMware driver: vm3d.inf (oem8.inf)
Found VMware driver: vmxnet3.inf (oem4.inf)
Removing 7 VMware driver package(s)
Removing oem3.inf ...
Microsoft PnP Utility

Driver package uninstalled.
Driver package deleted successfully.
Done.
Removing oem5.inf ...
[etc]

@rwmjones rwmjones marked this pull request as ready for review March 16, 2026 21:00
@vrozenfe

Copy link
Copy Markdown
Contributor

Actually, there were two issues: a missing /c:"Original Name" and (!LAST_PUBLISHED!), which should be ^(!LAST_PUBLISHED!^) (the ")" in the batch if statement needs to be escaped as "^)" ).

@rwmjones

Copy link
Copy Markdown
Member Author

Thanks, I got both in the latest version.

@rwmjones

Copy link
Copy Markdown
Member Author

The current status is that mxie tested this and found that although drivers are removed, some left over Windows Registry information remains. The effect of this information is that the Windows driverquery command still shows the drivers as being present. Basically yet another bug/weirdness with Windows.

Removing the Windows Registry information is possible, but registry changes in general are invasive and completely beyond what Microsoft would recommend or support.

There are some scripts in the vmwremover repo for removing stuff from the Registry (eg: https://github.com/virtio-win/vmwremover/tree/main/reg) but I don't know which one is needed and they're all pretty invasive. We also don't know if they work across all versions of Windows or what side effects they have.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants