@@ -67,37 +67,6 @@ function Select-VsInstallation {
6767 return $Installations [$index ]
6868}
6969
70- function Initialize-DevShell {
71- <#
72- . SYNOPSIS
73- Imports the Visual Studio Developer PowerShell if not already active.
74- . OUTPUTS
75- Returns the selected VS installation object ({ DisplayName, InstallationPath,
76- WdkVsComponentVersion }), or $null if the shell was already active.
77- Callers should pass the returned object to Resolve-BuildEnvironment so VS
78- selection happens exactly once.
79- #>
80- param ([string ]$ReturnToDirectory )
81-
82- if ($env: VSCMD_VER ) {
83- Write-Verbose " VS Developer Shell already active (VSCMD_VER=$env: VSCMD_VER )."
84- return $null
85- }
86-
87- $vsInstall = Select-VsInstallation (Get-VsInstallationsWithWdk )
88-
89- $devShellDll = Join-Path $vsInstall.InstallationPath ' Common7\Tools\Microsoft.VisualStudio.DevShell.dll'
90- if (-not (Test-Path $devShellDll )) {
91- Write-Error " Visual Studio Developer Shell module not found at '$devShellDll '."
92- exit 1
93- }
94-
95- Import-Module $devShellDll
96- Enter-VsDevShell - VsInstallPath $vsInstall.InstallationPath
97- Set-Location $ReturnToDirectory
98- return $vsInstall
99- }
100-
10170function Assert-MsBuildAvailable {
10271 <#
10372 .SYNOPSIS Verifies msbuild.exe is on PATH. Exits with error if not found.
@@ -119,20 +88,21 @@ function Assert-MsBuildAvailable {
11988function Resolve-BuildEnvironment {
12089 <#
12190 . SYNOPSIS
122- Detects or resolves the active build environment and returns metadata.
91+ Detects the active build environment, opens a VS Developer Shell when needed,
92+ and returns metadata about the environment.
12393 . DESCRIPTION
124- When RunMode is 'Auto', checks in priority order: EWDK, NuGet, WDK.
125- EWDK is checked first because $env:BuildLab is an active, explicit signal
126- whereas the packages\ folder is a passive disk artifact that may linger.
127- When RunMode is explicitly set to WDK/NuGet/EWDK, skips detection and uses that mode.
128- Pass the VsInstallation returned by Initialize-DevShell to avoid prompting the user
129- a second time when multiple VS installations are present.
94+ Handles the full setup sequence in one place:
95+ 1. Detect mode: EWDK → NuGet → WDK (Auto), or use the explicitly supplied RunMode.
96+ 2. For NuGet / WDK: open a VS Developer Shell if one is not already active,
97+ prompting the user to choose if multiple VS installations with the required
98+ WDK media are found. If the shell is already active, the matching installation
99+ is located via $env:VSINSTALLDIR.
100+ 3. For EWDK: skip VS detection entirely ($env:BuildLab is the authoritative signal).
130101 Returns a hashtable: Name, BuildNumber (int), NuGetVersion, WdkVsComponentVersion.
131102 #>
132103 param (
133104 [string ]$RepoRoot ,
134- [string ]$RunMode = ' Auto' ,
135- [object ]$VsInstallation = $null
105+ [string ]$RunMode = ' Auto'
136106 )
137107
138108 $result = @ {
@@ -142,63 +112,98 @@ function Resolve-BuildEnvironment {
142112 WdkVsComponentVersion = ' '
143113 }
144114
145- $effectiveMode = $RunMode
115+ # -------------------------------------------------------------------------
116+ # Step 1 – Detect / validate build mode
117+ # -------------------------------------------------------------------------
146118
147- # --- Resolve build environment ---
148- if ($effectiveMode -eq ' EWDK' -or
149- ($effectiveMode -eq ' Auto' -and $env: BuildLab -match ' ^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$' )) {
150- if ($effectiveMode -eq ' EWDK' ) {
151- # Forced EWDK: require BuildLab to be set
152- if ($env: BuildLab -notmatch ' ^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$' ) {
153- Write-Error " RunMode is 'EWDK' but the EWDK environment variable BuildLab is not set. Ensure the EWDK is mounted and the environment is initialised."
154- exit 1
155- }
156- }
157- $result.Name = " EWDK.$ ( $Matches.branch ) .$ ( $Matches.build ) .$ ( $Matches.qfe ) "
158- $result.BuildNumber = [int ]$Matches.build
159- }
160- elseif ($effectiveMode -eq ' NuGet' -or
161- ($effectiveMode -eq ' Auto' -and (Test-Path " $RepoRoot \packages\*" ))) {
162- if ($effectiveMode -eq ' NuGet' -and -not (Test-Path " $RepoRoot \packages\*" )) {
163- Write-Error " RunMode is 'NuGet' but no packages were found under '$RepoRoot \packages\'. Ensure NuGet restore has been run."
119+ # EWDK: checked first. $env:BuildLab is an active, explicit signal that
120+ # disappears when you close the EWDK prompt, unlike the packages\ folder.
121+ if ($RunMode -eq ' EWDK' -or
122+ ($RunMode -eq ' Auto' -and $env: BuildLab -match ' ^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$' )) {
123+
124+ if ($RunMode -eq ' EWDK' -and
125+ $env: BuildLab -notmatch ' ^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$' ) {
126+ Write-Error " RunMode is 'EWDK' but the EWDK environment variable BuildLab is not set. Ensure the EWDK is mounted and the environment is initialised."
164127 exit 1
165128 }
166- $result.Name = ' NuGet'
167- $wdkPackage = Get-ChildItem " $RepoRoot \packages\*WDK.x64*" - Name - ErrorAction SilentlyContinue
168- $result.NuGetVersion = ([regex ]' (?<=x64\.)(\d+\.){3}\d+' ).Match($wdkPackage ).Value
169- $result.BuildNumber = [int ]($result.NuGetVersion.Split (' .' )[2 ])
129+ # Re-run the match to populate $Matches (the Auto branch already matched above;
130+ # the forced-EWDK branch needs an explicit match after the validation guard).
131+ $null = $env: BuildLab -match ' ^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$'
132+ $result.Name = " EWDK.$ ( $Matches.branch ) .$ ( $Matches.build ) .$ ( $Matches.qfe ) "
133+ $result.BuildNumber = [int ]$Matches.build
134+ $result.WdkVsComponentVersion = ' (not available for EWDK builds)'
135+ return $result
170136 }
171- elseif ($effectiveMode -eq ' WDK' -or
172- ($effectiveMode -eq ' Auto' -and $env: UCRTVersion -match ' 10\.0\.(?<build>\d+)\.0' )) {
173- if ($effectiveMode -eq ' WDK' -and $env: UCRTVersion -notmatch ' 10\.0\.(?<build>\d+)\.0' ) {
174- 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."
137+
138+ $isNuGet = ($RunMode -eq ' NuGet' ) -or
139+ ($RunMode -eq ' Auto' -and (Test-Path " $RepoRoot \packages\*" ))
140+
141+ if ($RunMode -eq ' NuGet' -and -not (Test-Path " $RepoRoot \packages\*" )) {
142+ Write-Error " RunMode is 'NuGet' but no packages were found under '$RepoRoot \packages\'. Ensure NuGet restore has been run."
143+ exit 1
144+ }
145+
146+ # If not EWDK and not NuGet, assume WDK. VS Dev Shell setup below will validate
147+ # the environment; if no VS with WDK media is found, Select-VsInstallation errors out.
148+
149+ # -------------------------------------------------------------------------
150+ # Step 2 – Set up VS Developer Shell
151+ # -------------------------------------------------------------------------
152+
153+ $vsInstall = $null
154+
155+ if (-not $env: VSCMD_VER ) {
156+ # Dev Shell not active – open one now.
157+ $vsInstall = Select-VsInstallation (Get-VsInstallationsWithWdk )
158+ $devShellDll = Join-Path $vsInstall.InstallationPath ' Common7\Tools\Microsoft.VisualStudio.DevShell.dll'
159+ if (-not (Test-Path $devShellDll )) {
160+ Write-Error " Visual Studio Developer Shell module not found at '$devShellDll '."
175161 exit 1
176162 }
177- $result.Name = ' WDK'
178- $result.BuildNumber = [int ]$Matches.build
163+ Import-Module $devShellDll
164+ Enter-VsDevShell - VsInstallPath $vsInstall.InstallationPath
165+ Set-Location $RepoRoot
179166 }
180167 else {
181- Write-Output " Environment variables {"
182- Get-ChildItem env:* | Sort-Object Name
183- Write-Output " Environment variables }"
184- Write-Error " Could not determine build environment. Ensure EWDK, WDK, or NuGet packages are configured."
185- exit 1
168+ Write-Verbose " VS Developer Shell already active (VSCMD_VER=$env: VSCMD_VER )."
169+ # Locate the matching installation via VSINSTALLDIR so we can read its
170+ # WdkVsComponentVersion without prompting the user again.
171+ # Normalize trailing backslash: VSINSTALLDIR ends with '\', vswhere paths do not.
172+ $normalizedVsInstallDir = $env: VSINSTALLDIR.TrimEnd (' \' )
173+ $vsInstall = Get-VsInstallationsWithWdk |
174+ Where-Object { $_.InstallationPath.TrimEnd (' \' ) -eq $normalizedVsInstallDir } |
175+ Select-Object - First 1
176+ if (-not $vsInstall ) {
177+ Write-Error " The active Visual Studio Developer Shell ('$env: VSINSTALLDIR ') does not have the required WDK media installed. Ensure the WDK Visual Studio component is installed."
178+ exit 1
179+ }
186180 }
187181
188- # WDK VS component version (EWDK does not ship this metadata)
189- if ($result.Name -match ' ^EWDK' ) {
190- $result.WdkVsComponentVersion = ' (not available for EWDK builds)'
182+ # -------------------------------------------------------------------------
183+ # Step 3 – Fill mode-specific fields (Dev Shell is now guaranteed active)
184+ # -------------------------------------------------------------------------
185+
186+ if ($isNuGet ) {
187+ $result.Name = ' NuGet'
188+ $wdkPackage = Get-ChildItem " $RepoRoot \packages\*WDK.x64*" - Name - ErrorAction SilentlyContinue
189+ $result.NuGetVersion = ([regex ]' (?<=x64\.)(\d+\.){3}\d+' ).Match($wdkPackage ).Value
190+ $result.BuildNumber = [int ]($result.NuGetVersion.Split (' .' )[2 ])
191191 }
192192 else {
193- # Re-use the installation selected during Initialize-DevShell if available,
194- # otherwise query vswhere again (e.g. when the Dev Shell was already active).
195- $vsInstall = if ($VsInstallation ) { $VsInstallation } else { Select-VsInstallation (Get-VsInstallationsWithWdk ) }
196- if (-not $vsInstall.WdkVsComponentVersion ) {
197- Write-Error " Could not determine WDK component version for '$ ( $vsInstall.DisplayName ) '. Ensure the WDK Visual Studio component is installed."
193+ # WDK – Dev Shell is now active, UCRTVersion must be set.
194+ if ($env: UCRTVersion -notmatch ' 10\.0\.(?<build>\d+)\.0' ) {
195+ Write-Error " UCRTVersion ('$env: UCRTVersion ') is not set or does not match the expected format. Ensure the VS Developer Shell is active."
198196 exit 1
199197 }
200- $result.WdkVsComponentVersion = $vsInstall.WdkVsComponentVersion
198+ $result.Name = ' WDK'
199+ $result.BuildNumber = [int ]$Matches.build
200+ }
201+
202+ if (-not $vsInstall.WdkVsComponentVersion ) {
203+ Write-Error " Could not determine WDK component version for '$ ( $vsInstall.DisplayName ) '. Ensure the WDK Visual Studio component is installed."
204+ exit 1
201205 }
206+ $result.WdkVsComponentVersion = $vsInstall.WdkVsComponentVersion
202207
203208 return $result
204209}
0 commit comments