#Requires -Version 5.1 # win.ps1 - fresh-Windows bootstrap for 759705.cc # # Purpose : Get a new Windows machine to a usable baseline by installing a # short list of everyday tools through winget. # Usage : irm https://759705.cc/win.ps1 | iex # Idempotent: yes. Each package is checked with `winget list` first and is only # installed when it is genuinely absent, so re-running changes nothing. # Dry run : $env:HUB_DRY_RUN = '1' prints each command instead of running it. # $env:HUB_DRY_RUN = '1'; irm https://759705.cc/win.ps1 | iex # Local test: $env:HUB_BASE overrides the base URL used in printed links. # # Installs only; never uninstalls, never deletes, never edits the registry. # Contains no secrets and no internal hostnames; safe to serve publicly. # # Note: the whole script is wrapped in a function so that `irm | iex` cannot be # terminated by a stray `exit` - early returns leave your session alive. $ErrorActionPreference = 'Stop' function Write-HubLog { param([Parameter(Mandatory = $true)][string] $Message) Write-Host "==> $Message" } function Write-HubOk { param([Parameter(Mandatory = $true)][string] $Message) Write-Host "ok $Message" } function Write-HubNote { param([Parameter(Mandatory = $true)][string] $Message) Write-Host " $Message" } # Invoke-HubStep runs an action, or prints it when -DryRun is set. function Invoke-HubStep { param( [Parameter(Mandatory = $true)][string] $Description, [Parameter(Mandatory = $true)][scriptblock] $Action, [switch] $DryRun ) if ($DryRun) { Write-Host "DRY $Description" return } Write-HubLog $Description & $Action } # Test-HubWingetPackage returns $true when the package id is already installed. function Test-HubWingetPackage { param([Parameter(Mandatory = $true)][string] $PackageId) # winget writes progress and "no package found" text to stderr. Under # $ErrorActionPreference = 'Stop' that would throw, so relax it here. $previousPreference = $ErrorActionPreference $ErrorActionPreference = 'Continue' try { $output = (& winget list --id $PackageId --exact --accept-source-agreements 2>$null | Out-String) $code = $LASTEXITCODE } finally { $ErrorActionPreference = $previousPreference } # Exit code 0 alone is not enough on older winget builds, so also confirm # the id actually appears in the table. return (($code -eq 0) -and ($output -match [regex]::Escape($PackageId))) } function Invoke-HubWindowsBootstrap { [CmdletBinding()] param() # ----------------------------------------------------------------------- # Edit this ONE line to change which packages get installed. $packages = @('Git.Git', 'Microsoft.PowerShell', '7zip.7zip') # ----------------------------------------------------------------------- $hubBase = if ($env:HUB_BASE) { $env:HUB_BASE } else { 'https://759705.cc' } $dryRun = ($env:HUB_DRY_RUN -eq '1') $changed = 0 Write-HubLog "hub windows bootstrap - PowerShell $($PSVersionTable.PSVersion)" if ($dryRun) { Write-HubNote 'DRY RUN: commands are printed, not executed.' } Write-Host '' # --- Step 1: winget availability --------------------------------------- Write-HubLog 'Step 1/2 - winget (Windows Package Manager)' $winget = Get-Command -Name 'winget' -ErrorAction SilentlyContinue if (-not $winget) { Write-Warning 'winget was not found on PATH.' Write-HubNote 'Install "App Installer" from the Microsoft Store, then re-run this script:' Write-HubNote ' https://apps.microsoft.com/detail/9nblggh4nns1' Write-HubNote "Cheatsheet: $hubBase/commands/win/" return } $wingetVersion = (& winget --version 2>$null | Out-String).Trim() Write-HubOk "available - $wingetVersion" Write-Host '' # --- Step 2: default packages ------------------------------------------ Write-HubLog ("Step 2/2 - default packages: " + ($packages -join ', ')) foreach ($packageId in $packages) { if (Test-HubWingetPackage -PackageId $packageId) { Write-HubOk "$packageId already installed" continue } $currentId = $packageId Invoke-HubStep -DryRun:$dryRun -Description "winget install --id $currentId --exact --source winget" -Action { & winget install --id $currentId --exact --source winget ` --accept-package-agreements --accept-source-agreements if ($LASTEXITCODE -ne 0) { throw "winget install failed for $currentId (exit code $LASTEXITCODE)" } } $changed = $changed + 1 } # --- Summary ------------------------------------------------------------ Write-Host '' Write-HubLog 'Summary' if ($dryRun) { Write-HubNote 'Dry run - nothing was installed or modified.' } elseif ($changed -eq 0) { Write-HubNote 'Everything was already in place. No changes made.' } else { Write-HubNote "$changed package(s) installed." Write-HubNote 'Open a new terminal so the updated PATH is picked up.' } Write-HubNote "Cheatsheet: $hubBase/commands/win/" } Invoke-HubWindowsBootstrap