Public/Functions/OSDWinPE.ps1
|
if ($env:SystemDrive -eq 'X:') { <# .SYNOPSIS Common WinPE Commands using wpeutil and Microsoft DaRT RemoteRecovery .DESCRIPTION Common WinPE Commands using wpeutil and Microsoft DaRT RemoteRecovery .LINK https://github.com/OSDeploy/OSD/tree/master/docs .NOTES 19.10.1 David Segura @SeguraOSD #> function Get-OSDWinPE { <# .SYNOPSIS Gets OSDWinPE information. .DESCRIPTION Returns OSDWinPE data for the current system or OSD session context. .PARAMETER GetModules Specifies the GetModules to use when running Get-OSDWinPE. .PARAMETER GetScript Specifies the GetScript to use when running Get-OSDWinPE. .PARAMETER GetScripts Specifies the GetScripts to use when running Get-OSDWinPE. .PARAMETER InitializeNetwork Specifies the InitializeNetwork to use when running Get-OSDWinPE. .PARAMETER InitializeNetworkNoWait Specifies the InitializeNetworkNoWait to use when running Get-OSDWinPE. .PARAMETER WaitForNetwork Specifies the WaitForNetwork to use when running Get-OSDWinPE. .PARAMETER WaitForRemovableStorage Specifies the WaitForRemovableStorage to use when running Get-OSDWinPE. .PARAMETER DisableFirewall Specifies the DisableFirewall to use when running Get-OSDWinPE. .PARAMETER UpdateBootInfo Specifies the UpdateBootInfo to use when running Get-OSDWinPE. .PARAMETER RemoteRecovery Specifies the RemoteRecovery to use when running Get-OSDWinPE. .PARAMETER Reboot Specifies the Reboot to use when running Get-OSDWinPE. .PARAMETER Shutdown Specifies the Shutdown to use when running Get-OSDWinPE. .EXAMPLE Get-OSDWinPE -GetModules <value> Demonstrates a common way to run Get-OSDWinPE. .LINK https://github.com/OSDeploy/OSD/tree/master/docs .NOTES Author: David Segura - Recast Software 2026-07-13 - Initial help block created 2026-07-13 - Refined generated help text #> [CmdletBinding()] param ( #Find and Copy PowerShell Modules to WinPE #Searches all PSDrives for <drive>:\Modules directory #Searches all PSDrives for <drive>:\Content\Modules directory #Copies Modules to X:\Program Files\WindowsPowerShell\Modules [Alias('Modules','AddModules')] [System.Management.Automation.SwitchParameter]$GetModules, #Find and Run PowerShell Scripts #Searches all PSDrives for <drive>:\<$GetScript> #Searches all PSDrives for <drive>:\Content\Scripts\<$GetScript> #Calls found scripts in the current PS Session [Alias('Script','CallScript')] [string[]]$GetScripts, #wpeutil InitializeNetwork #Initializes network components and drivers and sets the computer name to a randomly-chosen value [Alias('Network')] [System.Management.Automation.SwitchParameter]$InitializeNetwork, #wpeutil InitializeNetwork /NoWait #Initializes network components and drivers and sets the computer name to a randomly-chosen value #The /NoWait option will skip the time where your PC would otherwise wait to acquire an IP address #If you don't use /NoWait, Windows PE will wait to acquire an address before it finishes loading your WinPE session #/NoWait is helpful for environments that don't use DHCP [Alias('NetworkNoWait')] [System.Management.Automation.SwitchParameter]$InitializeNetworkNoWait, #wpeutil WaitForNetwork #Waits for the network card to be initialized #Use this command when creating scripts to make sure that the network card has been fully initialized before continuing [Alias('WaitNetwork')] [System.Management.Automation.SwitchParameter]$WaitForNetwork, #wpeutil WaitForRemovableStorage #During the Windows PE startup sequence, this command will block startup until the removable storage devices, such as USB hard drives, are initialized [Alias('WaitUSB')] [System.Management.Automation.SwitchParameter]$WaitForRemovableStorage, #wpeutil DisableFirewall #Disables the Firewall [Alias('Disable')] [System.Management.Automation.SwitchParameter]$DisableFirewall, #wpeutil UpdateBootInfo #Populates the registry with information about how Windows PE boots #After you run this command, query the registry. For example: #reg query HKLM\System\CurrentControlSet\Control /v PEBootType #The results of this operation might change after loading additional driver support. #To determine where Windows PE is booted from, examine the following: # PEBootType: Error, Flat, Remote, Ramdisk:SourceIdentified Ramdisk:SourceUnidentified, Ramdisk:OpticalDrive # PEBootTypeErrorCode: HRESULT code # PEBootServerName: Windows Deployment Services server name # PEBootServerAddr: Windows Deployment Services server IP address # PEBootRamdiskSourceDrive: Source drive letter, if available. # PEFirmwareType: Firmware boot mode: 0x1 for BIOS, 0x2 for UEFI. #If you are not booting Windows Deployment Services, the best way to determine where Windows PE booted from is to first check for PEBootRamdiskSourceDrive registry key #If it is not present, scan the drives of the correct PEBootType and look for some kind of tag file that identifies the boot drive [Alias('Update')] [System.Management.Automation.SwitchParameter]$UpdateBootInfo, #RemoteRecovery.exe -nomessage #Microsoft Diagnostic and Recovery Toolset Remote Recovery [Alias('Remote')] [System.Management.Automation.SwitchParameter]$RemoteRecovery, #wpeutil Reboot #Reboots the computer [System.Management.Automation.SwitchParameter]$Reboot, #wpeutil Shutdown #Shutdown the computer [System.Management.Automation.SwitchParameter]$Shutdown ) #================================================= # Blocks #================================================= Block-WinOS #================================================= # Increase the Console Screen Buffer size #================================================= if (!(Test-Path "HKCU:\Console")) { Write-Verbose "OSDWinPE: Increase Console Screen Buffer" New-Item -Path "HKCU:\Console" -Force | Out-Null New-ItemProperty -Path HKCU:\Console ScreenBufferSize -Value 589889656 -PropertyType DWORD -Force | Out-Null } #================================================= # GetModules #================================================= if ($GetModules.IsPresent) { $GetPSDrive = Get-PSDrive -PSProvider 'FileSystem' foreach ($PSDrive in $GetPSDrive) { $OSDSearchPath = @("$($PSDrive.Root)Modules","$($PSDrive.Root)Content\Modules") foreach ($Item in $OSDSearchPath) { if (Test-Path "$Item") { Get-ChildItem "$Item" | ` Where-Object {$_.PSIsContainer} | ` ForEach-Object { Write-Verbose "Copying Module at $($_.FullName) to X:\Program Files\WindowsPowerShell\Modules" Copy-Item -Path "$($_.FullName)" -Destination "X:\Program Files\WindowsPowerShell\Modules" -Recurse -Force -ErrorAction SilentlyContinue Import-Module -Name "$($_.Name)" -Force -ErrorAction SilentlyContinue } } } } } #================================================= # GetScripts #================================================= if ($GetScripts) { $GetPSDrive = Get-PSDrive -PSProvider 'FileSystem' foreach ($Item in $GetScripts) { foreach ($PSDrive in $GetPSDrive) { $ScriptFullName = @("$($PSDrive.Root)$Item","$($PSDrive.Root)Content\Scripts\$Item") foreach ($ScriptName in $ScriptFullName) { if (Test-Path $ScriptName) { $FoundScript = Get-Item $ScriptName | Select-Object -Property FullName Write-Verbose "Executing PowerShell Script $($FoundScript.FullName)" & "$($FoundScript.FullName)" -ErrorAction SilentlyContinue } } } } } #================================================= # wpeutil #================================================= if ($InitializeNetwork.IsPresent) { Write-Verbose 'OSDWinPE: wpeutil InitializeNetwork' Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'InitializeNetwork' -Wait Start-Sleep -Seconds 10 } if ($InitializeNetworkNoWait.IsPresent) { Write-Verbose 'OSDWinPE: wpeutil InitializeNetwork /NoWait' Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList ('InitializeNetwork','/NoWait') } if ($WaitForNetwork.IsPresent) { Write-Verbose 'OSDWinPE: wpeutil WaitForNetwork' Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'WaitForNetwork' -Wait } if ($WaitForRemovableStorage.IsPresent) { Write-Verbose 'OSDWinPE: wpeutil WaitForRemovableStorage' Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'WaitForRemovableStorage' -Wait } if ($DisableFirewall.IsPresent) { Write-Verbose 'OSDWinPE: wpeutil DisableFirewall' Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'DisableFirewall' -Wait } if ($UpdateBootInfo.IsPresent) { Write-Verbose 'OSDWinPE: wpeutil UpdateBootInfo' Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'UpdateBootInfo' } #================================================= # Microsoft DaRT #================================================= if (($RemoteRecovery.IsPresent) -and (Test-Path "$env:windir\System32\RemoteRecovery.exe")) { Write-Verbose 'OSDWinPE: Microsoft DaRT Remote Recovery' Start-Process -WindowStyle Minimized -FilePath RemoteRecovery.exe -ArgumentList '-nomessage' } #================================================= # Reboot Shutdown #================================================= if ($Reboot.IsPresent) { Write-Verbose 'OSDWinPE: wpeutil Reboot' Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'Reboot' } if ($Shutdown.IsPresent) { Write-Verbose 'OSDWinPE: wpeutil Shutdown' Start-Process -WindowStyle Hidden -FilePath wpeutil -ArgumentList 'Shutdown' } } function Add-OfflineServicingWindowsDriver { <# .SYNOPSIS Configures drivers for offline servicing in Windows Setup .DESCRIPTION Creates and applies an unattend XML file to configure driver paths for offline servicing during Windows Setup. This allows drivers to be installed on both x86 and x64 architectures. .PARAMETER Path Path to the drivers directory. Default is C:\Drivers .EXAMPLE Add-OfflineServicingWindowsDriver Configures C:\Drivers for offline servicing .EXAMPLE Add-OfflineServicingWindowsDriver -Path 'E:\CustomDrivers' Configures E:\CustomDrivers for offline servicing .NOTES Author: David Segura - Recast Software 2026-07-10 - Added comment-based help .LINK https://github.com/OSDeploy/OSD/tree/master/docs #> [CmdletBinding()] param ( [string]$Path = 'C:\Drivers' ) $UnattendXml = @" <?xml version="1.0" encoding="utf-8"?> <unattend xmlns="urn:schemas-microsoft-com:unattend"> <settings pass="offlineServicing"> <component name="Microsoft-Windows-PnpCustomizationsNonWinPE" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <DriverPaths> <PathAndCredentials wcm:keyValue="1" wcm:action="add"> <Path>$Path</Path> </PathAndCredentials> </DriverPaths> </component> <component name="Microsoft-Windows-PnpCustomizationsNonWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <DriverPaths> <PathAndCredentials wcm:keyValue="1" wcm:action="add"> <Path>$Path</Path> </PathAndCredentials> </DriverPaths> </component> </settings> </unattend> "@ #================================================= # Block #================================================= Block-WinOS Block-WindowsVersionNe10 Block-PowerShellVersionLt5 #================================================= # Use-WindowsUnattend #================================================= $Random = Get-Random $UnattendXml | Out-File -FilePath "$env:TEMP\$Random.xml" -Encoding utf8 -Width 2000 -Force Use-WindowsUnattend -Path 'C:\' -UnattendPath "$env:TEMP\$Random.xml" #================================================= } function Use-WinPEContent { <# .SYNOPSIS Processes and integrates content into WinPE environment .DESCRIPTION Finds and processes WinPE content including drivers, files, modules, registry settings, and scripts from connected drives or USB media. This function searches for content in standardized directories and applies it to the WinPE system. .PARAMETER Content Type of content to process. Valid values are Drivers, Files, Modules, Registry, Scripts, or * for all. Default is all content types. .EXAMPLE Use-WinPEContent Processes all available content types in WinPE .EXAMPLE Use-WinPEContent -Content 'Drivers','Modules' Processes only drivers and modules .NOTES Author: David Segura - Recast Software 2026-07-10 - Added comment-based help .LINK https://github.com/OSDeploy/OSD/tree/master/docs #> [CmdletBinding()] param ( [ValidateSet('*','Drivers','Files','Modules','Registry','Scripts')] [string[]]$Content = '*' ) #================================================= # Blocks #================================================= Block-WinOS #================================================= # PSDrive #================================================= $GetPSDrive = Get-PSDrive -PSProvider 'FileSystem' foreach ($Item in $Content) { #================================================= # Drivers #================================================= if ($Item -eq '*' -or $Item -eq 'Drivers') { foreach ($PSDrive in $GetPSDrive) { $ContentPath = @("$($PSDrive.Root)Content\Drivers","$($PSDrive.Root)WinPE\Drivers") foreach ($ContentItem in $ContentPath) { if (Test-Path "$ContentItem") { Get-ChildItem "$ContentItem" *.inf -Recurse | ` ForEach-Object { Write-Verbose "Importing Driver $($_.FullName)" PNPUtil.exe /add-driver "$($_.FullName)" /install } } } } } #================================================= # Files #================================================= if ($Item -eq '*' -or $Item -eq 'Files') { foreach ($PSDrive in $GetPSDrive) { $ContentPath = @("$($PSDrive.Root)Content\Files","$($PSDrive.Root)WinPE\Files") foreach ($ContentItem in $ContentPath) { if (Test-Path "$ContentItem") { Write-Verbose "Copying Files at $ContentItem to X:\" robocopy "$ContentItem" X:\ *.* /e /ndl /b } } } } #================================================= # Modules #================================================= if ($Item -eq '*' -or $Item -eq 'Modules') { foreach ($PSDrive in $GetPSDrive) { $ContentPath = @("$($PSDrive.Root)Content\Modules","$($PSDrive.Root)WinPE\Modules") foreach ($ContentItem in $ContentPath) { if (Test-Path "$ContentItem") { Get-ChildItem "$ContentItem" | ` Where-Object {$_.PSIsContainer} | ` ForEach-Object { Write-Verbose "Copying Module at $($_.FullName) to X:\Program Files\WindowsPowerShell\Modules" Copy-Item -Path "$($_.FullName)" -Destination "X:\Program Files\WindowsPowerShell\Modules" -Recurse -Force -ErrorAction SilentlyContinue Import-Module -Name "$($_.Name)" -Force -ErrorAction SilentlyContinue } } } } } #================================================= # Registry #================================================= if ($Item -eq '*' -or $Item -eq 'Registry') { foreach ($PSDrive in $GetPSDrive) { $ContentPath = @("$($PSDrive.Root)Content\Registry","$($PSDrive.Root)WinPE\Registry") foreach ($ContentItem in $ContentPath) { if (Test-Path "$ContentItem") { Get-ChildItem "$ContentItem" *.reg -Recurse | ` ForEach-Object { Write-Verbose "Importing Registry File $($_.FullName)" reg import "$($_.FullName)" } } } } } #================================================= # Scripts #================================================= if ($Item -eq '*' -or $Item -eq 'Scripts') { foreach ($PSDrive in $GetPSDrive) { $ContentPath = @("$($PSDrive.Root)Content\Scripts","$($PSDrive.Root)WinPE\Scripts") foreach ($ContentItem in $ContentPath) { if (Test-Path "$ContentItem") { Get-ChildItem "$ContentItem" *.ps1 -Recurse | ` ForEach-Object { Write-Verbose "Executing PowerShell Script $($_.FullName)" & "$($_.FullName)" -ErrorAction SilentlyContinue } } } } } } } } |