private/WinpeStartup/Initialize-WinpeStartupEnvironment.ps1
|
#requires -Version 5.1 function Initialize-WinpeStartupEnvironment { <# .SYNOPSIS Initializes the WinPE shell environment for OS deployment .DESCRIPTION Creates required shell profile folders, sets process-level environment variables, and writes registry keys needed by Windows PE before any PowerShell modules or deployment scripts run. This function is the PowerShell equivalent of the environment-setup section in startnet.cmd / ReStartnet.cmd and should be called early in the WinPE boot sequence. Actions performed: - Imports X:\WinpeStartup\core\*\*.env into the process environment - Creates shell profile directories under SystemDrive - Sets APPDATA, HOMEDRIVE, HOMEPATH, LOCALAPPDATA, USERPROFILE - Writes the USERDATA registry value to the Session Manager Environment key - Sets the PowerShell execution policy to Bypass via registry - Imports X:\WinpeStartup\core\*\winpe-reg\*.reg using reg.exe import - Adds X:\WinpeStartup\core\*\winpe-root-cer\*.cer to the machine Root store Core files, including hidden files named .env, are loaded from immediate Core subfolders in sorted full-path order. Later assignments overwrite earlier values. Shell profile variables, selected-profile JSON environment values, and then selected-profile environment files are applied afterward and take precedence over Core values. Entries use literal, single-line NAME=VALUE syntax. Blank lines and full-line # comments are ignored. Surrounding whitespace and matching outer quotes are removed; embedded equals signs are preserved. Expressions, variable references, escape sequences, and inline comments are not expanded. Multiline values and export syntax are not supported. Empty values use the current runtime's process environment semantics (removal on PS 5.1). Invalid entries and file failures warn and continue without logging values. Missing Core content is allowed. Imported values are not persisted. Environment import output is summarized by one pass or fail message when files are discovered or discovery fails. After built-in registry setup, Core registry files are imported, followed by root certificates using certutil.exe -addstore root. Each file type is processed in sorted full-path order, including hidden files, without searching deeper folders. Missing import folders are allowed. Discovery, process launch, and nonzero exit-code failures warn and continue with remaining files. Registry imports may overwrite existing keys; certificates are trusted in the local machine Root store for the current WinPE instance. Registry and certificate tool output is suppressed and summarized by one pass or fail message for each file type. Core asset discovery and imports require a valid Recast license (Get-OSDCoreLicense IsValid). Missing or invalid licenses skip assets without errors, warnings, or asset summaries. Built-in shell setup remains available regardless of license state. .EXAMPLE PS> Initialize-WinpeStartupEnvironment Imports Core environment files, creates shell folders, sets environment variables, and writes registry keys for the current WinPE session. .EXAMPLE PS> Initialize-WinpeStartupEnvironment -Verbose Runs the full environment initialization with detailed progress output. .INPUTS None. This function does not accept pipeline input. .OUTPUTS None. .NOTES Author: David Segura Company: Recast Software Version: 1.0.0 Date: 2026-10-06 Module: OSDCloud Runs only when SystemDrive is X:. Core imports require reg.exe and certutil.exe and permission to modify the WinPE registry and local machine certificate store. .LINK https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/reg-import .LINK https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/certutil #> [CmdletBinding()] [OutputType([void])] param () begin { $skipExecution = $false if ($env:SystemDrive -ne 'X:') { Write-Warning 'Initialize-WinpeStartupEnvironment: Not running in WinPE (SystemDrive is not X:). Exiting.' $skipExecution = $true return } Write-Verbose 'Initialize-WinpeStartupEnvironment: Starting WinPE environment initialization' $systemDrive = $env:SystemDrive $profileRoot = Join-Path -Path $systemDrive -ChildPath 'windows\system32\config\systemprofile' } process { if ($skipExecution) { return } Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Initialize WinpeStartup" $corePath = Join-Path -Path $systemDrive -ChildPath 'WinpeStartup\core' $coreFolders = @() $coreDiscoverySucceeded = $true $canImportAssets = Test-WinpeStartupAssetLicense if ($canImportAssets) { try { if (Test-Path -LiteralPath $corePath -PathType Container -ErrorAction Stop) { $coreFolders = @(Get-ChildItem -LiteralPath $corePath -Directory -Force -ErrorAction Stop) } } catch { $coreDiscoverySucceeded = $false Write-Warning "Initialize-WinpeStartupEnvironment: Failed to discover Core folders in '$corePath'." } $assetPaths = @($coreFolders | ForEach-Object { $_.FullName }) Import-WinpeStartupAssets -Path $assetPaths -AssetType Environment -DiscoverySucceeded $coreDiscoverySucceeded -SystemDrive $systemDrive } # ── Shell Folders ─────────────────────────────────────────────── $shellFolders = @( Join-Path -Path $systemDrive -ChildPath 'Program Files\WindowsPowerShell\Scripts' Join-Path -Path $profileRoot -ChildPath 'AppData\Local' Join-Path -Path $profileRoot -ChildPath 'AppData\Roaming' Join-Path -Path $profileRoot -ChildPath 'Desktop' Join-Path -Path $profileRoot -ChildPath 'Documents\WindowsPowerShell' Join-Path -Path $systemDrive -ChildPath 'windows\system32\WindowsPowerShell\v1.0\Scripts' ) foreach ($folder in $shellFolders) { New-Item -Path $folder -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null # Write-Verbose "Created folder: $folder" } # ── Environment Variables (process scope) ─────────────────────── $env:APPDATA = Join-Path -Path $profileRoot -ChildPath 'AppData\Roaming' $env:HOMEDRIVE = $systemDrive $env:HOMEPATH = '\windows\system32\config\systemprofile' $env:LOCALAPPDATA = Join-Path -Path $profileRoot -ChildPath 'AppData\Local' $env:USERPROFILE = $profileRoot Write-Verbose "Set APPDATA = $env:APPDATA" Write-Verbose "Set HOMEDRIVE = $env:HOMEDRIVE" Write-Verbose "Set HOMEPATH = $env:HOMEPATH" Write-Verbose "Set LOCALAPPDATA = $env:LOCALAPPDATA" Write-Verbose "Set USERPROFILE = $env:USERPROFILE" # ── Registry: USERDATA environment variable ───────────────────── $userDataPath = Join-Path -Path $systemDrive -ChildPath 'Windows\System32\Config\SystemProfile' $envRegKeyPath = 'HKLM:\SYSTEM\ControlSet001\Control\Session Manager\Environment' Set-ItemProperty -Path $envRegKeyPath -Name 'USERDATA' -Value $userDataPath -Type String -Force Write-Verbose "Set registry USERDATA = $userDataPath" # ── Registry: PowerShell execution policy ─────────────────────── $psRegKeyPath = 'HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell' Set-ItemProperty -Path $psRegKeyPath -Name 'ExecutionPolicy' -Value 'Bypass' -Type String -Force Write-Verbose 'Set registry ExecutionPolicy = Bypass' if ($canImportAssets) { Import-WinpeStartupAssets -Path $assetPaths -AssetType Registry, Certificate -DiscoverySucceeded $coreDiscoverySucceeded -SystemDrive $systemDrive } } end { if ($skipExecution) { return } Write-Verbose 'Initialize-WinpeStartupEnvironment: Complete' } } |