private/Step-BuildBootInstallWinPEAppSysinternals.ps1
|
#Requires -PSEdition Core function Step-BuildBootInstallWinPEAppSysinternals { <# .SYNOPSIS Downloads, caches, and injects configured Sysinternals tools into WinPE .DESCRIPTION Creates or reuses the Sysinternals cache, then enumerates the configured tools in global OSDeployModule.BootImage.winpeapps.sysinternals. Tools without a URL for global BuildMedia.Architecture are skipped. Missing binaries are downloaded with curl.exe when available and Invoke-WebRequest otherwise. Each available cached binary is copied to its configured name under Windows\System32 in the mounted image. The tool name is then appended to global BuildMedia.InstalledApps. Download failures and missing cached files produce warnings. .EXAMPLE PS> Step-BuildBootInstallWinPEAppSysinternals Caches and injects each configured tool for the current build architecture. .INPUTS None. This function does not accept pipeline input. .OUTPUTS None. Native download output is silent and web requests write directly to files. .NOTES Author: David Segura Company: Recast Software Version: 0.1.0 Date: 2026-08-28 Requires global BuildMedia with Architecture, MountPath, and InstalledApps properties; global OSDeployModule.BootImage.winpeapps.sysinternals; and script OSDeployCorePath. Requires network access for cache misses. Modifies the shared cache, mounted image, and global InstalledApps collection. #> [CmdletBinding()] param () $Architecture = $global:BuildMedia.Architecture $MountPath = $global:BuildMedia.MountPath $WinPEAppsPath = Join-Path $Script:OSDeployCorePath 'cache' 'winpe-apps' $CacheDir = Join-Path $WinPEAppsPath 'microsoft-sysinternals' $sysinternals = $global:OSDeployModule.BootImage.winpeapps.sysinternals if (-not (Test-Path -Path $CacheDir)) { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Creating Sysinternals cache: $CacheDir" New-Item -Path $CacheDir -ItemType Directory -Force | Out-Null } else { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Using Sysinternals cache: $CacheDir" } foreach ($tool in $sysinternals.PSObject.Properties) { $toolName = $tool.Name $toolConfig = $tool.Value # Select arch-appropriate URL; skip tool entirely if absent/empty for this arch $DownloadUri = $toolConfig.$Architecture if ([string]::IsNullOrEmpty($DownloadUri)) { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Skipping Sysinternals $toolName (no $Architecture URL)" continue } $CachedFile = Join-Path $CacheDir (Split-Path -Leaf $DownloadUri) if (-not (Test-Path -Path $CachedFile)) { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Downloading Sysinternals $toolName ($Architecture): $DownloadUri" try { if (Get-Command 'curl.exe' -ErrorAction SilentlyContinue) { & curl.exe --silent --location --retry 5 --continue-at - --output $CachedFile $DownloadUri } else { Invoke-WebRequest -UseBasicParsing -Uri $DownloadUri -OutFile $CachedFile } } catch { Write-Warning "[$(Get-Date -Format s)] Failed to download Sysinternals $toolName ($Architecture): $_" continue } } if (-not (Test-Path -Path $CachedFile)) { Write-Warning "[$(Get-Date -Format s)] Sysinternals $toolName binary not found at $CachedFile" continue } $Destination = Join-Path $MountPath "Windows\System32\$($toolConfig.destination)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Injecting $($toolConfig.destination) into WinPE" Copy-Item -Path $CachedFile -Destination $Destination -Force $global:BuildMedia.InstalledApps += $toolName } } |