Saturday, December 2, 2017

Migrating %ProgramFiles% off of %SystemDrive%

Do not do this! I just had to do a fresh install of Windows 10 to finally get everything working again. Full disk format and install.

Yesterday I noticed a concerning state on my computer:
For a moment I wondered how I could have possibly filled that drive all the way up this fast. I just received this system in mid-October!

Oh yeah. I have games on here. Very, very large games. But I have that huge D. That should be able to relieve the pressure. So I set about copying both of my Program Files directories over.
 This took a while, as those two directories weigh in at 116 GB on disk for me right now. Once they were all copied I was left with another large problem: Windows uses stuff out of Program Files! There are open handles all over and so you cannot just move the directories. I needed to have access to my hard drives without Windows running. In the past (Windows XP days) this would have meant booting from an install media or booting up a Linux distro.

Thankfully, this is 2017 and I'm running Windows 10. There is now native support for rebooting into a diagnostic state that is not using your normal partitions. I followed the instructions documented by DigitalCitizen. Just pop open the Start menu and type Settings.

Click thru Update & Security and select Recovery.


 Once I was in the Advanced Startup screen I booted into Command Prompt.

For some reason my D: was mapped to C: and my normal C: was mapped to D:. It was a little weird. What I wanted to set up was NTFS junction points (symbolic links) at what my normal operating system thought was C:\Program Files and C:\Program Files (x86).

First, I made backup copies.
cd /d D:
move "\Program Files" "\_Program Files"
move "\Program Files (x86)" "\_Program Files (x86)"

And then I made the symbolic links... including with a bug!

mklink /D "\Program Files" "D:\InstalledSoftware\Program Files"
mklink /D "\Program Files (x86)" "D:\InstalledSoftware\Program Files"

Since the destination path is stored in the NTFS partition, I could point it at a location that didn't make any sense in the state I was at right there. Once I rebooted everything should work out fine.

I exited out to the Advanced Startup and allowed the system to continue into Windows 10. The first thing I noticed was that the system successfully booted. Once I logged in though I saw a bunch of my icons were broken. Just the shortcuts to 32 bit programs though. I compared the contents of D:\InstalledSoftware\Program Files (x86)\ and C:\Program Files (x86)\ and found that they didn't match. Strange. It looked more like C:\Program Files (x86)\ contained my 64 bit applications. Which it did.

A quick jaunt back to the Boot to Command Prompt let me fix it:
cd /d D:
rmdir "\Program Files (x86)"
mklink /D "\Program Files (x86)" "D:\InstalledSoftware\Program Files (x86)"

Excellent. On reboot all my icons looked find. Time to do a quick spot check of the file system before I delete the backups on C:
The file view in the C drive backup
The file view in C:\Program Files
Oh no! I broke all of the file system security settings by setting everything to be owned by Administrators. Is it even possible to restore a file to TrustedInstaller?! Turns out it is and it has been blogged about. And so I set about fixing a few directories.
Security Tab of File Properties on my directory
You cannot search for the TrustedInstaller account, but it is there.
Apply the changes down the whole tree.
Finally I had a directory restored! Yay! Now on to the next... 116 GB worth?! No. There had to be a way to script this. And so Powershell to the rescue.

Function Copy-ACL {
    Param (
        [string]$SrcPath,
        [string]$DestPath
    )
 
    $BaseACL = Get-ACL -LiteralPath $SrcPath
    Set-ACL -LiteralPath $DestPath -AclObject $BaseACL
 
    ForEach ($ChildItem in Get-ChildItem -LiteralPath $SrcPath -Recurse)
    {
        $DestItem = $ChildItem.FullName.replace($SrcPath, $DestPath)
        $SrcACL = Get-ACL -LiteralPath $ChildItem.FullName       
        if (Test-Path $DestItem)
        {
            Set-ACL -LiteralPath $DestItem -AclObject $SrcACL
        }     
    }
}
Now I could fix both trees.
Copy-ACL 'C:\_Program Files\' 'D:\InstalledSoftware\Program Files\'
Copy-ACL 'C:\_Program Files (x86)\' 'D:\InstalledSoftware\Program Files (x86)\'

Now... off to the races!
What is this? Oh, just rmdir /s /q %programfiles% ¯\_(ツ)_/¯
Thank you for coming on this journey with me. Next week I will blog about the total destruction I just made by massively modifying my workstation from 1am to 6am. I hope you enjoyed reading about it.
Free ALL the space!

No comments:

Post a Comment