Windows 10

Windows PE: Why so big? Make it smaller.

I was working on some Windows PE images the other day and noticed something odd: The size of those images really didn’t make sense. I started off with just a few simple optional components to support scripting (scripting, wmi, securestartup), and ended up with sizes that I’m fairly used to:

PlatformScripting size

I then added .NET Framework and PowerShell (netfx, powershell, storagewmi) because I wanted to move on from the 90’s. But the new sizes weren’t quite in line:

PlatformScripting sizePowerShell sizePercent increase

OK, wait a minute, how can arm64 only grow 5%, while x64 (what most people want to use) grows 42%? And is the issue with .NET Framework, PowerShell, or both? To figure that out, let’s do a “middle step” of just adding the .NET Framework without PowerShell:

PlatformScripting size.NET Framework sizePercent increase

So that explains part of it: The .NET Framework component for ARM64 is broken in the 2004 version of the ADK — basically, it’s just an empty stub. (The HTA component is missing too, as I covered in my previous blog.) So it’s rather pointless to compare against anything ARM64 at this point. On the bright side, the current preview version of the ADK for Windows Server 2022 appears to fix that as the optional component (winpe-netfx) goes from 216KB to 94MB, so something to look forward to in that release (but still no HTA support, I guess they have no plans to port IE to ARM64 to support that).

So most of the bloat comes from the .NET Framework, not from PowerShell itself. Maybe at some point the version of PowerShell and .NET Framework in the ADK will be upgraded, but I wouldn’t hold your breath on that one.

So what can we do to reduce the size on Windows PE x64, if nothing else to get it closer to the size of the x86 version? First up would be whacking the “C:\Windows\SysWOW64” folder, since Windows PE doesn’t support WOW64 (running x86 code on an x64 OS). That would get rid of about 43MB or so — but only if the corresponding “C:\Windows\WinSXS\wow64_*” and “C:\Windows\WinSXS\x86_*” folders were also removed. Then there is “C:\Windows\Microsoft.NET\Framework64” vs. “C:\Windows\Microsoft.NET\Framework” — in theory, the Framework folder isn’t needed on x64, so that’s another 191MB that might be removable. And it’s probably not necessary to have a “C:\Windows\Microsoft.NET\assembly\GAC_32” folder, since Windows PE should only be using GAC_64. (The sizes don’t take into account duplicate files, file compression, etc. so the resulting savings are likely to be less.) What’s the worst that can happen? Windows PE won’t work. Seems worth a try at least.

With some PowerShell scripting to whack the (theoretically) unneeded stuff, the resulting x64 WIM file was 330MB. Compared to the original 396MB, that’s a savings of 66MB. So that makes the “penalty” of PowerShell + .NET Framework as a 20% increase in side, instead of a 40% increase. But does it work?

PlatformScripting sizePowerShell sizeWhacked sizeSavings

Using the ISOPrep.ps1 script from this post, I created an ISO and used it to boot a VM:

So far so good. (I love that PowerShell teases you in Windows PE, suggesting that you run a newer version of PowerShell. If only…) There’s a reasonable set of modules:

There are a few modules that won’t load:

But it’s quite possible that’s a normal situation. If I boot from a “non-whacked” x64 Windows PE boot ISO, I see exactly the same list of modules and the same errors when importing, a good sign. And a spot check of various cmdlets (e.g. Get-ComputerInfo, which makes a bunch of WMI calls) looks good too. So while that doesn’t qualify as “thorough testing” I still consider this a success.

So what are the downsides of this? You probably can’t service Windows PE any more (no big deal, just rebuild it from scratch) and you’ll get no support (so if you run into an issue that you can reproduce on a “full” x64 boot image, you’re good, but otherwise, you’re on your own).

If you want to try this out yourself, see the modified PEPrep.ps1 script in the attached zip file. Don’t blame me if it doesn’t work. (The logic in the script to remove the TrustedInstaller-protected files is probably overkill, just haven’t taken the time to validate a significantly simpler option — this was a PowerShell port of older MDT VBScript logic.)


Categories: Windows 10

2 replies »

  1. Would you be able to create a guide to adding PowerShell to WinPE? (I haven’t googled it yet but seems you know it extremely well and from such people it’s always a pleasure to learn).


    • The key is in the PEPrep.ps1 script that is attached to this blog. If you compare the “adding package” list from this file against the one in the previous post, you’ll see the difference:

      (“winpe-scripting”, “winpe-wmi”, “winpe-securestartup”, “winpe-netfx”, “winpe-powershell”, “winpe-storagewmi”) | % {

      This is the list of optional components to put into Windows PE. The last three add .NET Framework, PowerShell, and storage cmdlets (there are a few other cmdlet components you might want). If you are using MDT, these are just checkboxes in the deployment share’s properties.