From 3c096107d23668caeec91ba27095c9f94d3792b5 Mon Sep 17 00:00:00 2001 From: Max Vilimpoc Date: Wed, 5 Aug 2026 11:48:21 +0200 Subject: [PATCH] dotfiles: Windows dev-box provisioning scripts Extracted from a native Windows project so the box setup can be reused and versioned on its own. setup-windows.bat runs the non-elevated half (winget installs, user PATH edits for WinMerge and BinSkim, global git config) and then launches setup-windows-with-uac.ps1 elevated, printing its transcript when the elevated window closes. setup-windows-with-uac.ps1 enables ssh-agent and installs Visual Studio 2022 Community in three labelled passes (base C++ workload, Clang/LLVM, v141 + Windows XP toolset), the WDK 10.0.26100, and the Windows Performance Toolkit. The global git identity is PLACEHOLDER_NAME / PLACEHOLDER_EMAIL and must be edited before the script is run. The runtime transcript (setup-windows-uac.log) is gitignored: it embeds local machine paths. Co-Authored-By: Claude Opus 5 (1M context) --- .gitignore | 3 + README.md | 54 +++++++ setup-windows-with-uac.ps1 | 300 +++++++++++++++++++++++++++++++++++++ setup-windows.bat | 82 ++++++++++ 4 files changed, 439 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 setup-windows-with-uac.ps1 create mode 100644 setup-windows.bat diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7213c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Transcript written by setup-windows-with-uac.ps1 next to the script at runtime. +# Contains local machine paths; regenerated on every run. +setup-windows-uac.log diff --git a/README.md b/README.md new file mode 100644 index 0000000..5fd8878 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# dotfiles + +Windows development-box provisioning scripts. + +`setup-windows.bat` takes a fresh Windows install to a working C++ / native +development environment: editors and shells, Python, the Visual Studio 2022 +toolchain (including the Clang and Windows XP targeting toolsets), the Windows +Driver Kit, and a handful of analysis tools (Sysinternals, OpenCppCoverage, +BinSkim, the Windows Performance Toolkit). + +## Files + +| File | Purpose | +| --- | --- | +| `setup-windows.bat` | Entry point. Runs the non-elevated, per-user half (winget installs, user `PATH` edits, global git config), then launches the elevated half and prints its log. | +| `setup-windows-with-uac.ps1` | The elevated half, started via UAC by the batch file. Enables `ssh-agent`, installs Visual Studio 2022 Community with the required components, the WDK, and the Windows Performance Toolkit. Can also be run directly from an Administrator prompt. | + +## Usage + +1. **Edit `setup-windows.bat` first.** The global git identity near the middle of + the file is placeholder text: + + ```bat + git config --global user.name "PLACEHOLDER_NAME" + git config --global user.email "PLACEHOLDER_EMAIL" + ``` + + Substitute your own name and email, or comment both lines out to keep your + identity per-repository. + +2. Run it from a normal (non-elevated) prompt: + + ```bat + setup-windows.bat + ``` + + It will raise a single UAC prompt for the elevated half. Accept it — declining + leaves Visual Studio and the WDK uninstalled, and the script says so. + +3. Restart your shell afterwards so the updated user `PATH` is picked up, and + reboot if a step reported that a restart was required. + +## Notes + +- The elevated half writes a transcript to `setup-windows-uac.log` next to the + script; the batch file prints it when the elevated window closes. The log is + gitignored, as it contains local paths. +- Both halves are idempotent — re-running skips anything already installed. +- Visual Studio is installed in three labelled passes (base workload, Clang/LLVM, + XP toolset) so a failure identifies which component group is responsible. +- The scripts were extracted from a native Windows project, so the component + selection is tuned for that: Spectre-mitigated runtimes, the v141/XP toolset, + and driver-kit headers. Trim the component lists in the `.ps1` if you don't + need them — each group is a plain array near the top. diff --git a/setup-windows-with-uac.ps1 b/setup-windows-with-uac.ps1 new file mode 100644 index 0000000..254db14 --- /dev/null +++ b/setup-windows-with-uac.ps1 @@ -0,0 +1,300 @@ +#Requires -RunAsAdministrator +<# + setup-windows-with-uac.ps1 + Elevated portion of BlockBox Windows provisioning. Invoked by setup-windows.bat + via Start-Process -Verb RunAs, or run manually from an Administrator prompt. + + What this installs / configures: + - ssh-agent set to automatic + started + - Visual Studio 2022 Community (C++ desktop workload, Spectre libs, WDK VSIX, + Win11 SDK 26100, Clang/LLVM, and the v141 + Windows XP targeting toolset) + - Windows Driver Kit 10.0.26100 + + Change $VsInstallerUrl below to the Professional or Enterprise bootstrapper if needed: + Professional : https://aka.ms/vs/17/release/vs_professional.exe + Enterprise : https://aka.ms/vs/17/release/vs_enterprise.exe +#> + +$ErrorActionPreference = 'Stop' + +function Write-Step([string]$Msg) { + Write-Host "`n==> $Msg" -ForegroundColor Cyan +} + +function Assert-ExitCode([int]$Code, [string]$Step) { + # 0 = success, 3010 = success + reboot required + if ($Code -notin @(0, 3010)) { + throw "$Step failed with exit code $Code" + } + if ($Code -eq 3010) { + Write-Host " [reboot required after $Step]" -ForegroundColor Yellow + } +} + +function Show-VsSetupLogs { + # The VS Installer writes dd_*.log to the invoking user's %TEMP%. Because + # this script runs elevated, that %TEMP% belongs to the elevated user and is + # readable here even when it is NOT readable by the non-elevated caller. Fold + # only the NEWEST installer + bootstrapper log into the transcript (the setup + # engine log is where per-component / product errors actually appear) and + # keep it short so the transcript stays readable. + Write-Host "`n==> Collecting VS Installer logs from $env:TEMP" -ForegroundColor Cyan + $recent = Get-ChildItem $env:TEMP -Filter 'dd_*.log' -ErrorAction SilentlyContinue | + Where-Object { $_.LastWriteTime -gt (Get-Date).AddMinutes(-15) } + $picks = @() + $picks += $recent | Where-Object { $_.Name -like 'dd_installer_*' } | Sort-Object LastWriteTime | Select-Object -Last 1 + $picks += $recent | Where-Object { $_.Name -like 'dd_bootstrapper_*' } | Sort-Object LastWriteTime | Select-Object -Last 1 + $picks = $picks | Where-Object { $_ } + if (-not $picks) { + Write-Host ' (no VS Installer logs modified in the last 15 minutes)' -ForegroundColor Yellow + return + } + foreach ($l in $picks) { + Write-Host "`n----- $($l.Name) (tail) -----" -ForegroundColor Yellow + Get-Content $l.FullName -Tail 40 + } +} + +function Invoke-VsModify { + # Run one VS install/modify pass for a named group of components. Splitting + # the install into separate passes makes it obvious WHICH group fails: each + # call prints its label and exit code before Assert-ExitCode throws. + param( + [string] $Label, + [string[]] $Ids + ) + Write-Step "VS2022: $Label" + $addStr = ($Ids | ForEach-Object { "--add $_" }) -join ' ' + # --installPath must be quoted: it contains spaces ("C:\Program Files\..."). + # Windows PowerShell 5.1's Start-Process does not quote array elements, so we + # hand-build a single string. Component IDs / flags have no spaces. + $common = '--includeRecommended --quiet --norestart --wait' + if ($script:InstallPath) { + $argString = "modify --installPath `"$script:InstallPath`" $addStr $common --force" + } else { + # No existing install yet -> this first pass performs the base install. + $argString = "$addStr $common" + } + Write-Host " > $script:VsBootstrapper $argString" -ForegroundColor DarkGray + $p = Start-Process -FilePath $script:VsBootstrapper -ArgumentList $argString -Wait -PassThru -NoNewWindow + Write-Host " exit code: $($p.ExitCode)" + Assert-ExitCode $p.ExitCode "VS2022 ($Label)" + + # After the first (fresh) install, re-detect the install path so subsequent + # passes use `modify`. + if (-not $script:InstallPath -and (Test-Path $script:VsWhere)) { + $script:InstallPath = & $script:VsWhere -products '*' -property installationPath -format value | + Select-Object -First 1 + } +} + +# --------------------------------------------------------------------------- +# This runs in a separate elevated window that closes the moment it exits, so +# the non-elevated caller (setup-windows.bat) can't see what happened. Mirror +# all output to a log next to the script and exit with a real code so the +# caller can detect success/failure and show the log. +# --------------------------------------------------------------------------- +$LogFile = Join-Path $PSScriptRoot 'setup-windows-uac.log' +$ExitCode = 0 +try { Start-Transcript -Path $LogFile -Force | Out-Null } catch {} + +try { + +# --------------------------------------------------------------------------- +# Base tools via winget +# --------------------------------------------------------------------------- +# --------------------------------------------------------------------------- +# SSH agent +# --------------------------------------------------------------------------- +Write-Step 'Enabling ssh-agent' +Set-Service -Name ssh-agent -StartupType Automatic +if ((Get-Service ssh-agent).Status -ne 'Running') { Start-Service ssh-agent } + +# --------------------------------------------------------------------------- +# Visual Studio 2022 Community +# --------------------------------------------------------------------------- +$TempDir = Join-Path $env:TEMP 'dev_install' +New-Item -ItemType Directory -Force -Path $TempDir | Out-Null + +# Component IDs split into independent groups so each can be installed in its +# own pass. The base group is the known-good set; Clang and the Windows XP +# toolset are layered on afterwards so a failure clearly identifies the culprit. +# Component reference: https://learn.microsoft.com/visualstudio/install/workload-component-id-vs-community +$BaseComponents = @( + # Core C++ desktop workload + 'Microsoft.VisualStudio.Workload.NativeDesktop' + + # Spectre-mitigated MSVC runtime libs + 'Microsoft.VisualStudio.Component.VC.Runtimes.x86.x64.Spectre' + 'Microsoft.VisualStudio.Component.VC.Runtimes.ARM64.Spectre' + + # Spectre-mitigated ATL (needed for many driver/COM projects) + 'Microsoft.VisualStudio.Component.VC.ATL.Spectre' + + # Windows 11 SDK — build number must match the WDK below + 'Microsoft.VisualStudio.Component.Windows11SDK.26100' + + # WDK Visual Studio extension (VSIX). The silent wdksetup.exe /quiet does NOT + # install this (it only prompts interactively), so it must be added here. + 'Component.Microsoft.Windows.DriverKit' +) + +# Clang/LLVM toolset (ClangCL, used in CMakePresets.json). Two parts: the Clang +# compiler itself, plus the MSBuild integration providing the "ClangCL" toolset. +$ClangComponents = @( + 'Microsoft.VisualStudio.Component.VC.Llvm.Clang' + 'Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset' +) + +# Windows XP targeting (v141_xp toolset, used in CMakePresets.json). The v141 +# (VS2017) build tools provide the 14.16 compiler that the XP toolset wraps; +# WinXP layers the XP-compatible CRT/SDK on top of it. +$XpComponents = @( + 'Microsoft.VisualStudio.Component.VC.v141.x86.x64' + 'Microsoft.VisualStudio.Component.WinXP' +) + +# Detect an existing VS install via vswhere (ships with the VS Installer). +# These are referenced by Invoke-VsModify via $script: scope. +$VsWhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe' +$InstallPath = $null +if (Test-Path $VsWhere) { + $InstallPath = & $VsWhere -products '*' -property installationPath -format value | + Select-Object -First 1 +} + +Write-Step 'Downloading VS2022 Community bootstrapper' +$VsInstallerUrl = 'https://aka.ms/vs/17/release/vs_community.exe' +$VsBootstrapper = Join-Path $TempDir 'vs_community.exe' +Invoke-WebRequest -Uri $VsInstallerUrl -OutFile $VsBootstrapper -UseBasicParsing + +# Install in three sequential passes. The base set is installed first (this is +# the configuration that previously worked); Clang and the XP toolset are added +# afterwards. If one fails, its label pinpoints which group is responsible. +Invoke-VsModify -Label 'base toolset + workload' -Ids $BaseComponents +Invoke-VsModify -Label 'Clang / LLVM' -Ids $ClangComponents +Invoke-VsModify -Label 'Windows XP (v141 + WinXP)' -Ids $XpComponents + +# --------------------------------------------------------------------------- +# Verify the v141 / XP toolset actually landed. Earlier runs silently skipped +# it and the failure only surfaced at build time, so check on disk and fail +# loudly here instead. +# --------------------------------------------------------------------------- +Write-Step 'Verifying v141 / XP toolset' +$InstallPath = & $VsWhere -products '*' -property installationPath -format value | + Select-Object -First 1 +$V141 = if ($InstallPath) { + Get-ChildItem (Join-Path $InstallPath 'VC\Tools\MSVC') -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.Name -like '14.16.*' } | Select-Object -First 1 +} +if ($V141) { + Write-Host " OK: v141 toolset present ($($V141.Name))" -ForegroundColor Green +} else { + Write-Warning 'v141 (14.16.x) toolset NOT found - the XP build presets will fail.' + Write-Warning 'Add it via Visual Studio Installer > Modify > Individual components:' + Write-Warning ' - MSVC v141 - VS 2017 C++ x64/x86 build tools (v14.16)' + Write-Warning ' - C++ Windows XP Support for VS 2017 (v141) tools' +} + +# --------------------------------------------------------------------------- +# Windows Driver Kit (WDK 10.0.26100) +# Build 26100 matches the Windows 11 SDK installed above. +# Provides IddCx (iddcx.h / iddcx.lib) and UMDF 2.x for Indirect Display Drivers. +# linkid=2335869 -> WDK 26100.6584 (per Microsoft "Other WDK Downloads"). +# --------------------------------------------------------------------------- +$WdkVersion = '10.0.26100' +$WdkInstalledRoot = (Get-ItemProperty 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots' ` + -ErrorAction SilentlyContinue).WdkBinRootVersioned + +if ($WdkInstalledRoot -and $WdkInstalledRoot -match [regex]::Escape($WdkVersion)) { + # Re-running wdksetup.exe for an already-present version returns exit code + # 2008 (maintenance mode / nothing to do), which is not a real failure. + Write-Step "WDK $WdkVersion already installed - skipping ($WdkInstalledRoot)" +} else { + Write-Step 'Downloading WDK installer' + $WdkUrl = 'https://go.microsoft.com/fwlink/?linkid=2335869' + $WdkInstaller = Join-Path $TempDir 'wdksetup.exe' + Invoke-WebRequest -Uri $WdkUrl -OutFile $WdkInstaller -UseBasicParsing + + Write-Step 'Installing WDK' + $proc = Start-Process -FilePath $WdkInstaller -ArgumentList '/quiet /norestart' -Wait -PassThru -NoNewWindow + Write-Host " WDK installer exit code: $($proc.ExitCode)" + if ($proc.ExitCode -eq 2008) { + # 2008 = the WDK is already present; the installer has nothing to do. + Write-Host ' [WDK already installed (exit 2008) - treating as success]' -ForegroundColor Yellow + } else { + Assert-ExitCode $proc.ExitCode 'WDK' + } +} + +# --------------------------------------------------------------------------- +# Windows Performance Toolkit (xperf / WPA / wpr) -- ETW CPU + loader profiling, +# used by the perf/ measurement scripts. WPT is an OPTIONAL Windows SDK feature +# that the VS "Windows 11 SDK" component does NOT select, so a fresh box lacks it. +# The Windows ADK bundles WPT and winget owns the (versioned) download URL, so it +# is the most reliable source. Idempotent (skips if xperf is already present in +# either the SDK or ADK location) and non-fatal so it never aborts provisioning. +# Lighter alternative if you don't want the full ADK: install the Windows SDK's +# "Windows Performance Toolkit" optional feature via winsdksetup.exe /features +# OptionId.WindowsPerformanceToolkit. +# --------------------------------------------------------------------------- +Write-Step 'Windows Performance Toolkit (xperf / WPA)' +$wptRoots = @( + (Join-Path ${env:ProgramFiles(x86)} 'Windows Kits\10\Windows Performance Toolkit\xperf.exe'), + (Join-Path $env:ProgramFiles 'Windows Kits\10\Windows Performance Toolkit\xperf.exe'), + (Join-Path ${env:ProgramFiles(x86)} 'Windows Kits\10\Assessment and Deployment Kit\Windows Performance Toolkit\xperf.exe') +) +$xperf = $wptRoots | Where-Object { Test-Path $_ } | Select-Object -First 1 +if ($xperf) { + Write-Host " OK: WPT already present ($xperf)" -ForegroundColor Green +} else { + try { + winget install --id Microsoft.WindowsADK --exact --silent --disable-interactivity ` + --accept-source-agreements --accept-package-agreements + Write-Host ' Windows ADK (includes Windows Performance Toolkit) installed.' + } catch { + Write-Warning "WPT install failed: $($_.Exception.Message)" + Write-Warning 'Install manually: winget install Microsoft.WindowsADK, or add the' + Write-Warning 'Windows SDK "Windows Performance Toolkit" optional feature.' + } +} + +# --------------------------------------------------------------------------- +Write-Host "`nAll done." -ForegroundColor Green +Write-Host 'If a reboot was flagged above, restart before opening VS or building drivers.' + +} +catch { + $ExitCode = 1 + Write-Host "`n==> SETUP FAILED: $($_.Exception.Message)" -ForegroundColor Red + if ($_.ScriptStackTrace) { Write-Host $_.ScriptStackTrace -ForegroundColor DarkGray } + # Only fold in the VS Installer logs when a VS step actually failed; for other + # steps (e.g. WDK) those logs are stale and misleading, so the message above + # is what matters. + if ($_.Exception.Message -match 'VS2022') { + try { Show-VsSetupLogs } catch {} + } +} +finally { + try { Stop-Transcript | Out-Null } catch {} + + # This log was created by the elevated (admin) process, so by default the + # non-elevated caller can't delete it (their token has Administrators marked + # deny-only). Grant BUILTIN\Users Modify rights so the user account that runs + # setup-windows.bat can remove the log later. S-1-5-32-545 is the well-known + # Users SID, used here so this is locale-independent. + try { + if (Test-Path $LogFile) { + $usersSid = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-545') + $acl = Get-Acl -Path $LogFile + $rule = New-Object System.Security.AccessControl.FileSystemAccessRule( + $usersSid, 'Modify', 'Allow') + $acl.AddAccessRule($rule) + Set-Acl -Path $LogFile -AclObject $acl + } + } catch { + Write-Host " [warning] could not relax ACL on $LogFile : $($_.Exception.Message)" -ForegroundColor Yellow + } +} + +exit $ExitCode diff --git a/setup-windows.bat b/setup-windows.bat new file mode 100644 index 0000000..b94922d --- /dev/null +++ b/setup-windows.bat @@ -0,0 +1,82 @@ +@echo off + +@rem --------------------------------------------------------------------------- +@rem setup-windows.bat - provision a fresh Windows box for BlockBox development +@rem --------------------------------------------------------------------------- + +@rem --- Non-admin (per-user) installs + git config --- +winget install Anthropic.ClaudeCode +winget install Git.Git +winget install Microsoft.PowerShell Microsoft.Sysinternals.ProcessExplorer Microsoft.Sysinternals.ProcessMonitor Microsoft.Sysinternals.SDelete Microsoft.VisualStudioCode Microsoft.WindowsTerminal +winget install Python.Python.3.13 +winget install WinMerge.WinMerge +winget install WiXToolset.WiXCLI + +@rem OpenCppCoverage: native (PE) line coverage for the C++ binaries. run-coverage-occ.py drives the +@rem pytest suite under it to produce an HTML report (BlockBox + the sandbox DLLs build with PDBs, +@rem which it reads). The installer elevates via UAC. +winget install OpenCppCoverage.OpenCppCoverage + +@rem --- Add WinMerge to the user PATH (persists to the HKCU environment) --- +@rem Runs non-elevated, so it updates THIS user's PATH (the elevated script runs +@rem as a different account). Idempotent: only appends if not already present. +powershell -NoProfile -Command "$c = @((Join-Path $env:ProgramFiles 'WinMerge'), (Join-Path ${env:ProgramFiles(x86)} 'WinMerge'), (Join-Path $env:LOCALAPPDATA 'Programs\WinMerge')); $d = $c | Where-Object { Test-Path (Join-Path $_ 'WinMergeU.exe') } | Select-Object -First 1; if (-not $d) { Write-Warning 'WinMerge not found; user PATH unchanged.'; exit 0 }; $u = [Environment]::GetEnvironmentVariable('Path','User'); if (-not $u) { $u = '' }; if (($u -split ';') -notcontains $d) { $new = if ($u.Trim()) { $u.TrimEnd(';') + ';' + $d } else { $d }; [Environment]::SetEnvironmentVariable('Path', $new, 'User'); Write-Host ('Added ' + $d + ' to user PATH (restart your shell to pick it up).') } else { Write-Host ($d + ' already in user PATH.') }" + +@rem --- BinSkim (binary hardening analyzer) - per-user install, no admin needed --- +@rem BinSkim checks the exact mitigations we enable in CMakeLists.txt (CFG/XFG, CET, +@rem ASLR/HighEntropyVA, DEP, /GS, stack cookies, DEPENDENTLOADFLAG, etc.). The +@rem Microsoft.CodeAnalysis.BinSkim NuGet package ships a self-contained win-x64 +@rem build, so this needs no .NET SDK/runtime: download the .nupkg (a zip), extract +@rem the win-x64 tool folder to %LOCALAPPDATA%\Programs\BinSkim, and add it to the +@rem user PATH. After restarting the shell: binskim analyze path\to\BlockBox.exe +@rem A failure here only warns (exit 0) so it never aborts the rest of provisioning. +powershell -NoProfile -Command "try { $ErrorActionPreference='Stop'; [Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12; $dest=Join-Path $env:LOCALAPPDATA 'Programs\BinSkim'; $tmp=Join-Path $env:TEMP ('binskim_'+[guid]::NewGuid().ToString('N')); New-Item -ItemType Directory -Force -Path $tmp | Out-Null; $zip=Join-Path $tmp 'binskim.zip'; Invoke-WebRequest -Uri 'https://www.nuget.org/api/v2/package/Microsoft.CodeAnalysis.BinSkim' -OutFile $zip; Expand-Archive -Path $zip -DestinationPath $tmp -Force; $exe=Get-ChildItem -Path $tmp -Recurse -Filter 'BinSkim.exe' | Where-Object { $_.FullName -match 'win-x64' } | Sort-Object FullName | Select-Object -Last 1; if (-not $exe) { throw 'BinSkim.exe (win-x64) not found in package.' }; if (Test-Path $dest) { Remove-Item -Recurse -Force $dest }; New-Item -ItemType Directory -Force -Path $dest | Out-Null; Copy-Item -Path (Join-Path $exe.Directory.FullName '*') -Destination $dest -Recurse -Force; Remove-Item -Recurse -Force $tmp; $u=[Environment]::GetEnvironmentVariable('Path','User'); if (-not $u) { $u='' }; if (($u -split ';') -notcontains $dest) { $new = if ($u.Trim()) { $u.TrimEnd(';')+';'+$dest } else { $dest }; [Environment]::SetEnvironmentVariable('Path',$new,'User'); Write-Host ('Added '+$dest+' to user PATH (restart your shell to pick it up).') } else { Write-Host ($dest+' already in user PATH.') }; Write-Host ('BinSkim installed to '+$dest) } catch { Write-Warning ('BinSkim install failed: '+$_.Exception.Message); exit 0 }" + +@rem --- Global git identity: EDIT THESE BEFORE RUNNING --- +@rem Replace the placeholders with your own name and email, or comment the two +@rem lines out and set your identity per-repository instead. +git config --global user.name "PLACEHOLDER_NAME" +git config --global user.email "PLACEHOLDER_EMAIL" +git config --global core.sshcommand C:/Windows/System32/OpenSSH/ssh.exe + +@rem --------------------------------------------------------------------------- +@rem No package manager needed for the Windows build +@rem +@rem Just: +@rem cd windows && cmake -B build -G "Visual Studio 17 2022" -A x64 && cmake --build build --config Release +@rem --------------------------------------------------------------------------- + +@rem --- Elevated installs (VS2022, WDK, system tools) --- +@rem The elevated script runs in its own window and logs to setup-windows-uac.log. +@rem -PassThru + $p.ExitCode propagates its real exit code back through to ERRORLEVEL. +set "UAC_LOG=%~dp0setup-windows-uac.log" +if exist "%UAC_LOG%" del "%UAC_LOG%" + +powershell -NoProfile -Command "$p = Start-Process powershell -Verb RunAs -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','""%~dp0setup-windows-with-uac.ps1""' -Wait -PassThru; exit $p.ExitCode" +set "UAC_RC=%ERRORLEVEL%" + +@rem --- Surface the elevated session's output (its window has already closed) --- +if exist "%UAC_LOG%" ( + echo. + echo ===== elevated setup log ^(%UAC_LOG%^) ===== + type "%UAC_LOG%" + echo ===== end of elevated setup log ===== +) else ( + echo [setup-windows] WARNING: no elevated log found at "%UAC_LOG%". + echo [setup-windows] The elevated window may have been cancelled at the UAC prompt. +) + +if not "%UAC_RC%"=="0" ( + echo. + echo [setup-windows] ELEVATED SETUP FAILED ^(exit code %UAC_RC%^). See log above. + exit /b %UAC_RC% +) +echo. +echo [setup-windows] Elevated setup completed successfully. + +@rem Removed: this doesn't work as well as I hoped, maybe try again later +@rem -- Install Headroom --- +@rem py -m pip install "headroom-ai[all]" +@rem npm install headroom-ai + +py -m pip install Pillow \ No newline at end of file -- 2.48.2