Summary: Customize a Windows PE environment to contain Windows PowerShell and DISM modules.
Honorary Scripting Guy, Sean Kearney, is here again today with some early holiday gifts! A little PowerShell in a mean, lean green environment!
Note This is Part 2 in a five-part series. Before you start reading this post, see:
Build a PowerShell-Enabled Windows PE Key: Part 1
Now that we have the necessary software installed in Windows to build out a Windows PE environment, let’s take a look at building it.
The Windows PE environment is pretty neat because most of the actual boot environment is ready for you. But the actual “live environment” is built into a WIM file that loads into memory after boot.
A WIM file is a “Windows Imaging Format” file, which is really a specialized archive that holds all of the files for the Windows operating system.
The WIM file for Windows PE is located in one of two folders, depending on whether you’re working with the 32-bit or the 64-bit version. We’ll be dealing with the 64-bit version, but the process is identical for the 32-bit version.
The WIM file we need is located in this folder:
C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us
In this folder, there is only one file called WinPE.wim. We’ll be making a copy of this file to work with.
First we’ll store the location of the Windows PE media in a PowerShell variable called $WinAdk to make things more readable. We’ll take advantage of the Get-ArchitectureString function that we created yesterday to ensure the path is always correct for our parent operating system.
$WinADK=”C:\Program Files$(Get-ArchitectureString)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\en-us”
We will then create a structure to hold the Windows PE WIM file and a place to temporarily mount the WIM file:
$WinPETemp=’C:\TempPE’
New-Item -ItemType Directory -Path “$WinPETemp\Media” -force
Copy-Item -path "$WinAdk\en-us\winpe.wim" -Destination "$WinPETemp\Media\boot.wim"
New-Item -ItemType Directory -Path "$WinPETemp\Mount" –Force
Now that we have the WIM file, we can mount it with PowerShell by using the Mount-WindowsImage cmdlet. This will open the WIM file for editing. It will extract the structure to a target folder where we can add files and content.
Mount-WindowsImage -ImagePath "$WinPETemp\Media\boot.wim" -Index 1 –path "$WinPETemp\Mount"
At this point, we need to add a series of packages to the WIM file to enhance its capabilities. To find the list and names of packages that are available for Windows PE, we can use this article from TechNet: WinPE: Add packages (Optional Components Reference). It describes all the current pacakges, including dependencies.
The list of these packages (OCS files) can be found in the WinPE_OCS folder.
In our environment, we will not only be adding Windows PowerShell but also the storage and DISM cmdlets.
For each component we need to add, we provide the CAB file of the optional component in Windows PE and the folder where we “mounted” the WIM file. You’ll need to add not only the OCS package but also its language equivalent for everything to work properly.
To do this, we use the Add-WindowsPackage cmdlet. Here’s an example of using this cmdlet to apply the WMI capability to a Windows PE environment:
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\WinPE-WMI.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\en-us\WinPE-WMI_en-us.cab" -Path "$WinPeTemp\Mount" -IgnoreCheck
To populate all of our components, the script looks like this:
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\WinPE-WMI.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\en-us\WinPE-WMI_en-us.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\WinPE-NetFx.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\en-us\WinPE-NetFx_en-us.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\WinPE-Scripting.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\en-us\WinPE-Scripting_en-us.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\WinPE-PowerShell.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\en-us\WinPE-PowerShell_en-us.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\WinPE-DismCmdlets.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\en-us\WinPE-DismCmdlets_en-us.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\WinPE-EnhancedStorage.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\en-us\WinPE-EnhancedStorage_en-us.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\WinPE-StorageWMI.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Add-WindowsPackage -PackagePath "$($WinAdk)\Winpe_OCS\en-us\WinPE-StorageWMI_en-us.cab" -Path "$WinPeTemp\Mount" –IgnoreCheck
Now that we’ve updated our WIM file, we can dismount and save the image:
Dismount-WindowsImage -path "$WinPETemp\Mount"
Let’s back up this file so we can use it later:
$Destination=’C:\Pewim’
New-Item -Path $Destination -ItemType Directory –Force
Copy-Item -path "$WinPETemp\Media\boot.wim" -destination "$Destination\"
At this point, we have a WIM file for Windows PE that is packed with the bits for Windows PowerShell 5.0!
Stay tuned! Tomorrow we’ll use Windows PowerShell to create a bootable USB key.
I invite you to follow the Scripting Guys on Twitter and Facebook. If you have any questions, send email to them at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then always remember that with great PowerShell comes great responsibility.
Sean Kearney, Honorary Scripting Guy, Cloud and Datacenter Management MVP