diff options
| author | 5an7y <[email protected]> | 2026-03-31 15:14:04 -0700 |
|---|---|---|
| committer | 5an7y <[email protected]> | 2026-03-31 16:22:25 -0700 |
| commit | e021472d548bb26ff390b6b90b42caf21def7024 (patch) | |
| tree | 43d798fe90b5e95346f0f22c780497f128b347d2 | |
| parent | 35d8855033e29e7025c3794c73093df24f506640 (diff) | |
Extract environment helper functions into BuildEnvironment.ps1
Move Get-VsInstallationsWithWdk, Select-VsInstallation, Initialize-DevShell,
Assert-MsBuildAvailable, and Resolve-BuildEnvironment out of Build-Samples.ps1
into a new BuildEnvironment.ps1 helper file. Build-Samples.ps1 dot-sources it
via PSScriptRoot, consistent with the existing ListAllSamples.ps1 pattern.
Reduces Build-Samples.ps1 from 733 to 565 lines with no behaviour change.
Co-authored-by: Copilot <[email protected]>
| -rw-r--r-- | Build-Samples.ps1 | 189 | ||||
| -rw-r--r-- | BuildEnvironment.ps1 | 192 |
2 files changed, 193 insertions, 188 deletions
diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index 9cefe67e..3dcbaa94 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -96,194 +96,7 @@ param( # Helper Functions # ============================================================================= -function Get-VsInstallationsWithWdk { - <# - .SYNOPSIS - Returns all Visual Studio installations that have the WDK component installed. - .DESCRIPTION - Uses vswhere.exe (from its fixed install location under Program Files (x86)) to - enumerate VS installations that carry the Microsoft.Windows.DriverKit component. - If vswhere.exe is not found at the expected path the installed VS version is too - old to be supported and the script exits with an error. - #> - $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" - if (-not (Test-Path $vswhere)) { - Write-Error "vswhere.exe was not found at '$vswhere'. Visual Studio 2017 or later is required." - exit 1 - } - - $json = & $vswhere -all -format json -requires Microsoft.Windows.DriverKit 2>$null - $installations = $json | ConvertFrom-Json - return $installations | ForEach-Object { - [PSCustomObject]@{ - DisplayName = $_.displayName - InstallationPath = $_.installationPath - } - } -} - -function Select-VsInstallation { - <# - .SYNOPSIS - Chooses a Visual Studio installation from the list returned by Get-VsInstallationsWithWdk. - .DESCRIPTION - - 0 found : error + exit - - 1 found : verbose log, return it - - 2+ found : display a numbered menu and prompt the user to choose - #> - param([object[]]$Installations) - - if (-not $Installations -or $Installations.Count -eq 0) { - Write-Error "No Visual Studio installation with the required WDK media was found. Ensure the WDK Visual Studio component is installed." - exit 1 - } - - if ($Installations.Count -eq 1) { - Write-Verbose "Found Visual Studio installation with required WDK media: $($Installations[0].DisplayName) at $($Installations[0].InstallationPath)" - return $Installations[0] - } - - # Multiple installations — let the user choose - Write-Output "" - Write-Output "The following Visual Studio installations were found with the required WDK media:" - for ($i = 0; $i -lt $Installations.Count; $i++) { - Write-Output " [$($i + 1)] $($Installations[$i].DisplayName) — $($Installations[$i].InstallationPath)" - } - Write-Output "" - - do { - $choice = Read-Host "Select the installation to use [1-$($Installations.Count)]" - $index = [int]$choice - 1 - } while ($index -lt 0 -or $index -ge $Installations.Count) - - return $Installations[$index] -} - -function Initialize-DevShell { - <# - .SYNOPSIS Imports the Visual Studio Developer PowerShell if not already active. - #> - param([string]$ReturnToDirectory) - - if ($env:VSCMD_VER) { - Write-Verbose "VS Developer Shell already active (VSCMD_VER=$env:VSCMD_VER)." - return - } - - $vsInstall = Select-VsInstallation (Get-VsInstallationsWithWdk) - - $devShellDll = Join-Path $vsInstall.InstallationPath 'Common7\Tools\Microsoft.VisualStudio.DevShell.dll' - if (-not (Test-Path $devShellDll)) { - Write-Error "Visual Studio Developer Shell module not found at '$devShellDll'." - exit 1 - } - - Import-Module $devShellDll - Enter-VsDevShell -VsInstallPath $vsInstall.InstallationPath - Set-Location $ReturnToDirectory -} - -function Assert-MsBuildAvailable { - <# - .SYNOPSIS Verifies msbuild.exe is on PATH. Exits with error if not found. - #> - $savedPref = $ErrorActionPreference - $ErrorActionPreference = 'Stop' - try { - Get-Command 'msbuild' | Out-Null - } - catch { - Write-Error "msbuild cannot be called from current environment. Ensure it is on PATH (run from VS Developer Command Prompt or EWDK)." - exit 1 - } - finally { - $ErrorActionPreference = $savedPref - } -} - -function Resolve-BuildEnvironment { - <# - .SYNOPSIS - Detects or resolves the active build environment and returns metadata. - .DESCRIPTION - When RunMode is 'Auto', checks in priority order: NuGet, EWDK, WDK. - When RunMode is 'Github', behaves identically to 'NuGet' and sets IsGithubMode. - When RunMode is explicitly set to WDK/NuGet/EWDK, skips detection and uses that mode. - Returns a hashtable: Name, BuildNumber (int), NuGetVersion, WdkVsComponentVersion, IsGithubMode. - #> - param( - [string]$RepoRoot, - [string]$RunMode = 'Auto' - ) - - $result = @{ - Name = '' - BuildNumber = [int]0 - NuGetVersion = '' - WdkVsComponentVersion = '' - IsGithubMode = $false - } - - # Resolve effective mode for Github (same path as NuGet) - $effectiveMode = if ($RunMode -eq 'Github') { 'NuGet' } else { $RunMode } - if ($RunMode -eq 'Github') { $result.IsGithubMode = $true } - - # --- Resolve build environment --- - if ($effectiveMode -eq 'NuGet' -or - ($effectiveMode -eq 'Auto' -and (Test-Path "$RepoRoot\packages\*"))) { - if ($effectiveMode -eq 'NuGet' -and -not (Test-Path "$RepoRoot\packages\*")) { - Write-Error "RunMode is 'NuGet' but no packages were found under '$RepoRoot\packages\'. Ensure NuGet restore has been run." - exit 1 - } - $result.Name = 'NuGet' - $wdkPackage = Get-ChildItem "$RepoRoot\packages\*WDK.x64*" -Name -ErrorAction SilentlyContinue - $result.NuGetVersion = ([regex]'(?<=x64\.)(\d+\.){3}\d+').Match($wdkPackage).Value - $result.BuildNumber = [int]($result.NuGetVersion.Split('.')[2]) - } - elseif ($effectiveMode -eq 'EWDK' -or - ($effectiveMode -eq 'Auto' -and $env:BuildLab -match '^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$')) { - if ($effectiveMode -eq 'EWDK') { - # Forced EWDK: require BuildLab to be set - if ($env:BuildLab -notmatch '^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$') { - Write-Error "RunMode is 'EWDK' but the EWDK environment variable BuildLab is not set. Ensure the EWDK is mounted and the environment is initialised." - exit 1 - } - } - $result.Name = "EWDK.$($Matches.branch).$($Matches.build).$($Matches.qfe)" - $result.BuildNumber = [int]$Matches.build - } - elseif ($effectiveMode -eq 'WDK' -or - ($effectiveMode -eq 'Auto' -and $env:UCRTVersion -match '10\.0\.(?<build>\d+)\.0')) { - if ($effectiveMode -eq 'WDK' -and $env:UCRTVersion -notmatch '10\.0\.(?<build>\d+)\.0') { - Write-Error "RunMode is 'WDK' but UCRTVersion ('$env:UCRTVersion') is not set or does not match the expected format. Ensure the VS Developer Shell is active." - exit 1 - } - $result.Name = 'WDK' - $result.BuildNumber = [int]$Matches.build - } - else { - Write-Output "Environment variables {" - Get-ChildItem env:* | Sort-Object Name - Write-Output "Environment variables }" - Write-Error "Could not determine build environment. Ensure EWDK, WDK, or NuGet packages are configured." - exit 1 - } - - # WDK VS component version (EWDK does not ship this metadata) - if ($result.Name -match '^EWDK') { - $result.WdkVsComponentVersion = '(not available for EWDK builds)' - } - else { - $vsComponent = Get-ChildItem "${env:ProgramData}\Microsoft\VisualStudio\Packages\Microsoft.Windows.DriverKit,version=*" -ErrorAction SilentlyContinue - if (-not $vsComponent) { - Write-Error "WDK Visual Studio Component not found. Ensure the WDK Component is installed." - exit 1 - } - $result.WdkVsComponentVersion = [regex]::Match($vsComponent.Name, '(\d+\.){3}\d+').Value - } - - return $result -} +. (Join-Path $PSScriptRoot 'BuildEnvironment.ps1') function Import-SampleExclusions { <# diff --git a/BuildEnvironment.ps1 b/BuildEnvironment.ps1 new file mode 100644 index 00000000..b0b03ee1 --- /dev/null +++ b/BuildEnvironment.ps1 @@ -0,0 +1,192 @@ +# BuildEnvironment.ps1 +# Helper functions for detecting and initialising the build environment. +# Dot-sourced by Build-Samples.ps1. + +function Get-VsInstallationsWithWdk { + <# + .SYNOPSIS + Returns all Visual Studio installations that have the WDK component installed. + .DESCRIPTION + Uses vswhere.exe (from its fixed install location under Program Files (x86)) to + enumerate VS installations that carry the Microsoft.Windows.DriverKit component. + If vswhere.exe is not found at the expected path the installed VS version is too + old to be supported and the script exits with an error. + #> + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vswhere)) { + Write-Error "vswhere.exe was not found at '$vswhere'. Visual Studio 2017 or later is required." + exit 1 + } + + $json = & $vswhere -all -format json -requires Microsoft.Windows.DriverKit 2>$null + $installations = $json | ConvertFrom-Json + return $installations | ForEach-Object { + [PSCustomObject]@{ + DisplayName = $_.displayName + InstallationPath = $_.installationPath + } + } +} + +function Select-VsInstallation { + <# + .SYNOPSIS + Chooses a Visual Studio installation from the list returned by Get-VsInstallationsWithWdk. + .DESCRIPTION + - 0 found : error + exit + - 1 found : verbose log, return it + - 2+ found : display a numbered menu and prompt the user to choose + #> + param([object[]]$Installations) + + if (-not $Installations -or $Installations.Count -eq 0) { + Write-Error "No Visual Studio installation with the required WDK media was found. Ensure the WDK Visual Studio component is installed." + exit 1 + } + + if ($Installations.Count -eq 1) { + Write-Verbose "Found Visual Studio installation with required WDK media: $($Installations[0].DisplayName) at $($Installations[0].InstallationPath)" + return $Installations[0] + } + + # Multiple installations — let the user choose + Write-Output "" + Write-Output "The following Visual Studio installations were found with the required WDK media:" + for ($i = 0; $i -lt $Installations.Count; $i++) { + Write-Output " [$($i + 1)] $($Installations[$i].DisplayName) — $($Installations[$i].InstallationPath)" + } + Write-Output "" + + do { + $choice = Read-Host "Select the installation to use [1-$($Installations.Count)]" + $index = [int]$choice - 1 + } while ($index -lt 0 -or $index -ge $Installations.Count) + + return $Installations[$index] +} + +function Initialize-DevShell { + <# + .SYNOPSIS Imports the Visual Studio Developer PowerShell if not already active. + #> + param([string]$ReturnToDirectory) + + if ($env:VSCMD_VER) { + Write-Verbose "VS Developer Shell already active (VSCMD_VER=$env:VSCMD_VER)." + return + } + + $vsInstall = Select-VsInstallation (Get-VsInstallationsWithWdk) + + $devShellDll = Join-Path $vsInstall.InstallationPath 'Common7\Tools\Microsoft.VisualStudio.DevShell.dll' + if (-not (Test-Path $devShellDll)) { + Write-Error "Visual Studio Developer Shell module not found at '$devShellDll'." + exit 1 + } + + Import-Module $devShellDll + Enter-VsDevShell -VsInstallPath $vsInstall.InstallationPath + Set-Location $ReturnToDirectory +} + +function Assert-MsBuildAvailable { + <# + .SYNOPSIS Verifies msbuild.exe is on PATH. Exits with error if not found. + #> + $savedPref = $ErrorActionPreference + $ErrorActionPreference = 'Stop' + try { + Get-Command 'msbuild' | Out-Null + } + catch { + Write-Error "msbuild cannot be called from current environment. Ensure it is on PATH (run from VS Developer Command Prompt or EWDK)." + exit 1 + } + finally { + $ErrorActionPreference = $savedPref + } +} + +function Resolve-BuildEnvironment { + <# + .SYNOPSIS + Detects or resolves the active build environment and returns metadata. + .DESCRIPTION + When RunMode is 'Auto', checks in priority order: NuGet, EWDK, WDK. + When RunMode is 'Github', behaves identically to 'NuGet' and sets IsGithubMode. + When RunMode is explicitly set to WDK/NuGet/EWDK, skips detection and uses that mode. + Returns a hashtable: Name, BuildNumber (int), NuGetVersion, WdkVsComponentVersion, IsGithubMode. + #> + param( + [string]$RepoRoot, + [string]$RunMode = 'Auto' + ) + + $result = @{ + Name = '' + BuildNumber = [int]0 + NuGetVersion = '' + WdkVsComponentVersion = '' + IsGithubMode = $false + } + + # Resolve effective mode for Github (same path as NuGet) + $effectiveMode = if ($RunMode -eq 'Github') { 'NuGet' } else { $RunMode } + if ($RunMode -eq 'Github') { $result.IsGithubMode = $true } + + # --- Resolve build environment --- + if ($effectiveMode -eq 'NuGet' -or + ($effectiveMode -eq 'Auto' -and (Test-Path "$RepoRoot\packages\*"))) { + if ($effectiveMode -eq 'NuGet' -and -not (Test-Path "$RepoRoot\packages\*")) { + Write-Error "RunMode is 'NuGet' but no packages were found under '$RepoRoot\packages\'. Ensure NuGet restore has been run." + exit 1 + } + $result.Name = 'NuGet' + $wdkPackage = Get-ChildItem "$RepoRoot\packages\*WDK.x64*" -Name -ErrorAction SilentlyContinue + $result.NuGetVersion = ([regex]'(?<=x64\.)(\d+\.){3}\d+').Match($wdkPackage).Value + $result.BuildNumber = [int]($result.NuGetVersion.Split('.')[2]) + } + elseif ($effectiveMode -eq 'EWDK' -or + ($effectiveMode -eq 'Auto' -and $env:BuildLab -match '^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$')) { + if ($effectiveMode -eq 'EWDK') { + # Forced EWDK: require BuildLab to be set + if ($env:BuildLab -notmatch '^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$') { + Write-Error "RunMode is 'EWDK' but the EWDK environment variable BuildLab is not set. Ensure the EWDK is mounted and the environment is initialised." + exit 1 + } + } + $result.Name = "EWDK.$($Matches.branch).$($Matches.build).$($Matches.qfe)" + $result.BuildNumber = [int]$Matches.build + } + elseif ($effectiveMode -eq 'WDK' -or + ($effectiveMode -eq 'Auto' -and $env:UCRTVersion -match '10\.0\.(?<build>\d+)\.0')) { + if ($effectiveMode -eq 'WDK' -and $env:UCRTVersion -notmatch '10\.0\.(?<build>\d+)\.0') { + Write-Error "RunMode is 'WDK' but UCRTVersion ('$env:UCRTVersion') is not set or does not match the expected format. Ensure the VS Developer Shell is active." + exit 1 + } + $result.Name = 'WDK' + $result.BuildNumber = [int]$Matches.build + } + else { + Write-Output "Environment variables {" + Get-ChildItem env:* | Sort-Object Name + Write-Output "Environment variables }" + Write-Error "Could not determine build environment. Ensure EWDK, WDK, or NuGet packages are configured." + exit 1 + } + + # WDK VS component version (EWDK does not ship this metadata) + if ($result.Name -match '^EWDK') { + $result.WdkVsComponentVersion = '(not available for EWDK builds)' + } + else { + $vsComponent = Get-ChildItem "${env:ProgramData}\Microsoft\VisualStudio\Packages\Microsoft.Windows.DriverKit,version=*" -ErrorAction SilentlyContinue + if (-not $vsComponent) { + Write-Error "WDK Visual Studio Component not found. Ensure the WDK Component is installed." + exit 1 + } + $result.WdkVsComponentVersion = [regex]::Match($vsComponent.Name, '(\d+\.){3}\d+').Value + } + + return $result +} |
