11 January 2021

Automating the Deletion of Windows.old

It is the beginning of 2021 and my first project for the new year is upgrading all systems to Windows 10 20H2. At the end of the upgrades comes the cleanup and there is no clean way to do this for system admins. Cleanmgr.exe is now deprecated as of Windows 10 2004. There is not a PowerShell option for controlling storage sense. Cleanmgr.exe /AUTOCLEAN would open up cleanmgr.exe and then freeze. It never deleted the folder and was stuck at zero CPU usage. I also tried using PSEXEC to execute it with the same results. Another suggestion was using task scheduler. I also tried using Dism.exe /online /Cleanup-Image /StartComponentCleanup. The Windows.old folder was still present. The next option is to delete the folder. Here is a pic of the failure to clean up the Windows.old folder using a domain admin account and cmd.exe run as administrator.

NOTE: Once this folder has been deleted, Windows cannot be reverted back to the previous version. 

Once the upgrade has taken place, the Windows.old folder is present. It typically takes up 15+ GB of space. The upgraded OS is still actively using some files in the directory as I learned while exploring how to delete them. I found the files being used were drivers. This prevents you from deleting it while the OS is in memory. The alternative is to load WinPE so the OS is not in memory thereby freeing up the directory for deletion. Once the directory is deleted in WinPE and the system reboots, the OS reassociates the drivers it was using in the Windows.old directory to the Windows directory.

I first tried using PowerShell to delete the directory and there was a constant problem. PowerShell could not delete all files and directories, no matter what I tried. I consistently got the message "No mapping between account names and security IDs was done." Next, I tried RMDIR and it worked perfectly. I was able to use PowerShell to both find the drive in the WinPE environment and then execute the RMDIR command to delete the Windows.old directory on that drive. I tried this as a one-liner, but it was hit and miss with the RMDIR accepting the piped output instead of a variable. I found storing the path to the Windows.old directory in a variable was much more reliable. Here is the two-line code below:

 $Directory = (Get-Partition | Where-Object {((Test-Path ($_.DriveLetter + ':\Windows.old')) -eq $True)}).DriveLetter + ':\Windows.old'  
 cmd.exe /c rmdir /S /Q $Directory  

Here is a screenshot of the task sequence I used to deploy to the systems. The first restart is to load WinPE, the second sequence is the above PowerShell script, and the third sequence reboots the system back into the installed OS.



  1. This work really well! My only change would be to expand out from a one-liner to something easier to read or troubleshoot, a `multi-liner` if you will.

    My old peers at Wells wouldn't let us check in anything with one-liners!

    1. I ended up putting it into two lines. The one-liner didn’t work out in this scenario.

  2. I guess they're not the sharpest tools in the toolshed.