Skip to content

Instantly share code, notes, and snippets.

@michaelsstuff
Created August 23, 2025 10:11
Show Gist options
  • Select an option

  • Save michaelsstuff/d3408f8d001f21caa4f288a184eb5855 to your computer and use it in GitHub Desktop.

Select an option

Save michaelsstuff/d3408f8d001f21caa4f288a184eb5855 to your computer and use it in GitHub Desktop.
Install script
<#
Fresh Windows bootstrap script
- Enables WSL, Virtual Machine Platform, optional Windows Sandbox
- Installs chosen applications with winget (idempotent)
- Optional sets: mobile / gaming
- Privacy tweaks (optional), logging, reboot detection
- Re-runnable: skips already enabled features & installed packages
Execution Policy / First Run:
Windows may block direct execution (Restricted / AllSigned). Launch one of these from an elevated PowerShell:
1) One-shot bypass:
powershell -NoProfile -ExecutionPolicy Bypass -File .\!install.ps1
2) Current session only:
Set-ExecutionPolicy -Scope Process Bypass -Force; .\!install.ps1
3) Unblock downloaded file (removes MOTW):
Unblock-File .\!install.ps1
Or use the helper batch launcher (run-install.cmd) created alongside this script.
#>
#[CmdletBinding()] + param must appear before any executable statements (like Set-StrictMode)
[CmdletBinding()]
param(
[switch] $SkipRebootCheck,
[switch] $IgnoreStalePendingFileRenames,
[switch] $MobileDevice,
[switch] $ApplyPrivacyTweaks,
[switch] $GamingDevice
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
### --- Helper Functions --- ###
function Test-IsAdmin {
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).
IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Get-RebootPendingReasons {
<# Returns an array of reason strings; empty array => no reboot required (best effort). #>
$reasons = @()
try {
if (Test-Path 'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending') { $reasons += 'CBS:RebootPending' }
if (Test-Path 'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired') { $reasons += 'WU:RebootRequired' }
$sess = 'HKLM:SYSTEM\CurrentControlSet\Control\Session Manager'
$pfr = (Get-ItemProperty -Path $sess -Name PendingFileRenameOperations -ErrorAction SilentlyContinue).PendingFileRenameOperations
if ($pfr) {
# Normalize (drop blanks)
$raw = @()
foreach ($e in $pfr) { if ($e -and -not [string]::IsNullOrWhiteSpace([string]$e)) { $raw += [string]$e } }
Set-Variable -Name PendingFileRenameOperationsRaw -Value $raw -Scope Script
# PendingFileRenameOperations is an array of pairs (source, destination). Destination can be empty -> delete.
$entries = @()
for ($i = 0; $i -lt $raw.Count; $i += 2) {
$src = $raw[$i]
$dst = if ($i + 1 -lt $raw.Count) { $raw[$i + 1] } else { '' }
if (-not $src) { continue }
$entries += [pscustomobject]@{ Source=$src; Destination=$dst }
}
function _CleanPath([string]$p) {
if (-not $p) { return $null }
# Remove leading *<n>\??\ prefix if present
$c = $p -replace '^\*[0-9]+\\\?\?\\',''
# Remove leading \\?\ (extended path) if present
$c = $c -replace '^\\\\\?\\',''
return $c
}
$ignorePatterns = @(
'(?i)\\Windows\\Temp\\',
'(?i)\\Windows\\SystemTemp\\',
'(?i)\\AppData\\Local\\Temp\\'
)
function _IsIgnorableEntry($entry) {
$paths = @($entry.Source, $entry.Destination) | Where-Object { $_ }
if ($paths.Count -eq 0) { return $true }
# Quick pattern-based ignore (temp locations, .tmp files)
foreach ($p in $paths) {
foreach ($pat in $ignorePatterns) { if ($p -match $pat) { return $true } }
if ($p -match '(?i)\.tmp$') { return $true }
}
if ($IgnoreStalePendingFileRenames) {
# If all referenced paths (after cleaning) do NOT exist, treat as stale -> ignore
$existing = 0
foreach ($p in $paths) {
$clean = _CleanPath $p
if ($clean -and (Test-Path $clean)) { $existing++ }
}
if ($existing -eq 0) { return $true }
}
return $false
}
$meaningful = $entries | Where-Object { -not (_IsIgnorableEntry $_) }
if ($meaningful.Count -gt 0) {
$reasons += "SessionManager:PendingFileRenameOperations($($meaningful.Count))"
Set-Variable -Name PendingFileRenameOperationsMeaningful -Value $meaningful -Scope Script
} else {
Set-Variable -Name PendingFileRenameOperationsMeaningful -Value @() -Scope Script
}
}
$updateExeVolatile = (Get-ItemProperty -Path 'HKLM:SOFTWARE\Microsoft\Updates' -Name UpdateExeVolatile -ErrorAction SilentlyContinue).UpdateExeVolatile
if ($updateExeVolatile -and $updateExeVolatile -ne 0) { $reasons += "Updates:UpdateExeVolatile=$updateExeVolatile" }
} catch {
Write-Verbose "Get-RebootPendingReasons error: $($_.Exception.Message)"
}
return $reasons
}
function Enable-FeatureIfNeeded {
param(
[Parameter(Mandatory)] [string]$Name
)
$feature = Get-WindowsOptionalFeature -Online -FeatureName $Name -ErrorAction SilentlyContinue
if ($feature -and $feature.State -eq 'Enabled') {
Write-Host "[WSL] Feature '$Name' already enabled" -ForegroundColor DarkGray
} else {
Write-Host "[WSL] Enabling feature '$Name'..." -ForegroundColor Cyan
dism.exe /online /enable-feature /featurename:$Name /all /norestart | Out-Null
}
}
function Enable-WindowsSandboxIfAvailable {
<# Attempts to enable Windows Sandbox (Containers-DisposableClientVM) if the feature exists on this SKU / architecture.
Skips quietly on unsupported editions (e.g. Home) or when the optional feature is absent.
#>
$featureName = 'Containers-DisposableClientVM'
try {
# Quick architecture / OS checks
if (-not [Environment]::Is64BitOperatingSystem) {
Write-Host '[Sandbox] Not a 64-bit OS; skipping.' -ForegroundColor DarkGray; return
}
$cv = Get-ItemProperty -Path 'HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction Stop
$edition = $cv.EditionID
$eligible = 'Professional','ProfessionalN','Enterprise','EnterpriseN','Education','EducationN','Pro','ProN'
if ($eligible -notcontains $edition) {
# Still attempt detection of feature presence; some custom editions might allow it
Write-Host "[Sandbox] Edition '$edition' not in standard eligible list; probing feature anyway..." -ForegroundColor DarkGray
}
$feature = Get-WindowsOptionalFeature -Online -FeatureName $featureName -ErrorAction SilentlyContinue
if (-not $feature) {
Write-Host '[Sandbox] Optional feature not found on this system; skipping.' -ForegroundColor DarkGray; return
}
if ($feature.State -eq 'Enabled') {
Write-Host '[Sandbox] Windows Sandbox already enabled.' -ForegroundColor DarkGray; return
}
if ($feature.State -eq 'Disabled') {
Write-Host '[Sandbox] Enabling Windows Sandbox...' -ForegroundColor Cyan
dism.exe /online /enable-feature /featurename:$featureName /all /norestart | Out-Null
} else {
Write-Host "[Sandbox] Feature present but state '$($feature.State)' (no action)." -ForegroundColor Yellow
}
} catch {
Write-Host "[Sandbox] Unable to query/enable Windows Sandbox: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
function Install-App {
param(
[Parameter(Mandatory)] [string]$Id
)
Write-Host "----> $Id" -ForegroundColor Yellow
# Check if installed
$listOutput = winget list --id $Id -e --accept-source-agreements 2>$null | Out-String
if ($listOutput -notmatch 'No installed package found' -and $listOutput -match [Regex]::Escape($Id)) {
Write-Host "Already installed: $Id" -ForegroundColor DarkGray
return
}
try {
winget install --id $Id -e --silent --accept-package-agreements --accept-source-agreements
} catch {
Write-Warning "Failed to install $Id : $($_.Exception.Message)"
}
}
function Ensure-Winget {
Write-Host 'Checking for winget...' -ForegroundColor Cyan
$wingetCmd = Get-Command winget -ErrorAction SilentlyContinue
if ($wingetCmd) {
try { $v = winget --version 2>$null; Write-Host "winget present (version $v)" -ForegroundColor DarkGray } catch { Write-Host 'winget present.' -ForegroundColor DarkGray }
return $true
}
# Fallback: check App Installer (Store package) which provides winget
$appInstaller = Get-AppxPackage -Name 'Microsoft.DesktopAppInstaller' -ErrorAction SilentlyContinue
if ($appInstaller) {
Write-Host 'App Installer package found; winget should become available after shell restart.' -ForegroundColor Yellow
return $false
}
Write-Warning 'winget not found. Attempting to trigger Microsoft Store App Installer installation.'
$storeUri = 'ms-windows-store://pdp/?productid=9NBLGGH4NNS1'
try {
Start-Process $storeUri
Write-Host 'Please install "App Installer" from the Store window that opened, then re-run this script.' -ForegroundColor Magenta
} catch {
Write-Warning "Failed to open Microsoft Store. Install App Installer manually (ProductId 9NBLGGH4NNS1). Error: $($_.Exception.Message)"
}
return $false
}
function Invoke-AppxRemoval {
Write-Host 'Removing bundled AppX packages...' -ForegroundColor Cyan
$packages = @(
'Microsoft.BingWeather',
'Microsoft.BingNews',
'Microsoft.GetHelp',
'Microsoft.Getstarted',
'MicrosoftTeams',
'Microsoft.MicrosoftSolitaireCollection',
'Microsoft.MicrosoftOfficeHub',
'Microsoft.People',
'Microsoft.Todos',
'Microsoft.WindowsAlarms',
'microsoft.windowscommunicationsapps',
'Microsoft.WindowsCamera',
'Microsoft.WindowsSoundRecorder',
'Microsoft.WindowsMaps',
'Microsoft.WindowsFeedbackHub'
)
foreach ($p in $packages) {
try {
$found = Get-AppxPackage -Name $p -ErrorAction SilentlyContinue
if ($found) {
Write-Host "Removing AppX: ${p}" -ForegroundColor Yellow
$found | Remove-AppxPackage -ErrorAction SilentlyContinue
} else {
Write-Host "Not installed (skip): ${p}" -ForegroundColor DarkGray
}
} catch { Write-Warning "Failed removing ${p} (user packages): $($_.Exception.Message)" }
try {
$prov = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -eq $p }
if ($prov) {
Write-Host "Removing provisioned package: ${p}" -ForegroundColor Yellow
$prov | Remove-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue | Out-Null
}
} catch { Write-Warning "Failed removing provisioned ${p}: $($_.Exception.Message)" }
}
Write-Host 'AppX removal phase complete.' -ForegroundColor Green
}
function Invoke-PrivacyTweaks {
<#
Applies a curated set of Windows 11 privacy / de-bloat style registry settings to reduce telemetry,
targeted ads, suggestions, consumer experiences, and activity tracking.
A backup of previous values is written to %USERPROFILE%\privacy-backup-<timestamp>.json so changes can be reverted manually.
NOTE: Some settings only take effect after sign-out or reboot. Use responsibly; enterprise policies or managed devices
may override or conflict with these keys. This is intentionally conservative (avoids disabling Windows Update or Defender).
#>
Write-Host 'Applying privacy & ad/telemetry reduction tweaks...' -ForegroundColor Cyan
$timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$backupPath = Join-Path $env:USERPROFILE "privacy-backup-$timestamp.json"
$backup = @()
function Backup-And-Set {
param(
[Parameter(Mandatory)] [string]$Path,
[Parameter(Mandatory)] [string]$Name,
[Parameter(Mandatory)] [object]$Value,
[ValidateSet('DWord','String')] [string]$Type = 'DWord'
)
try {
if (-not (Test-Path $Path)) { New-Item -Path $Path -Force | Out-Null }
$existing = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue
$old = if ($existing) { $existing.$Name } else { $null }
$backup += [pscustomobject]@{ Path=$Path; Name=$Name; OldValue=$old; NewValue=$Value; Type=$Type }
if ($Type -eq 'DWord') {
New-ItemProperty -Path $Path -Name $Name -Value $Value -PropertyType DWord -Force | Out-Null
} else {
New-ItemProperty -Path $Path -Name $Name -Value $Value -PropertyType String -Force | Out-Null
}
} catch {
Write-Warning "Failed setting $Path : $Name -> $Value ($Type) : $($_.Exception.Message)"
}
}
# Telemetry level (0 = Security on Enterprise/Education, best-effort on other SKUs)
Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\DataCollection' -Name 'AllowTelemetry' -Value 0
# Advertising ID off
Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\AdvertisingInfo' -Name 'Disabled' -Value 1
# Consumer features / suggestions / spotlight
$cloudContentLM = 'HKLM:SOFTWARE\Policies\Microsoft\Windows\CloudContent'
Backup-And-Set -Path $cloudContentLM -Name 'DisableConsumerFeatures' -Value 1
Backup-And-Set -Path $cloudContentLM -Name 'DisableSoftLanding' -Value 1
Backup-And-Set -Path $cloudContentLM -Name 'DisableTailoredExperiencesWithDiagnosticData' -Value 1
Backup-And-Set -Path $cloudContentLM -Name 'DisableWindowsSpotlightFeatures' -Value 1
Backup-And-Set -Path $cloudContentLM -Name 'DisableSpotlightCollection' -Value 1
# Activity history
Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\System' -Name 'PublishUserActivities' -Value 0
Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\System' -Name 'UploadUserActivities' -Value 0
# Feedback frequency (0 = no prompts) under current user
Backup-And-Set -Path 'HKCU:Software\Microsoft\Siuf\Rules' -Name 'NumberOfSIUFInPeriod' -Value 0
Backup-And-Set -Path 'HKCU:Software\Microsoft\Siuf\Rules' -Name 'PeriodInNanoSeconds' -Value 0
# Cortana / Search
Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\Windows Search' -Name 'AllowCortana' -Value 0
Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\Windows Search' -Name 'DisableWebSearch' -Value 1
Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\Windows Search' -Name 'ConnectedSearchUseWeb' -Value 0
# Location services off (policy) - skip if mobile device flagged
if (-not $script:IsMobileDevice) {
Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\LocationAndSensors' -Name 'DisableLocation' -Value 1
} else {
Write-Host '[Privacy] Skipping location disable (mobile device).' -ForegroundColor DarkGray
}
# OneDrive (optional) - comment out if you rely on OneDrive
# Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\OneDrive' -Name 'DisableFileSyncNGSC' -Value 1
# Windows Tips (Current User)
Backup-And-Set -Path 'HKCU:Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' -Name 'SubscribedContent-338389Enabled' -Value 0
Backup-And-Set -Path 'HKCU:Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' -Name 'SubscribedContent-353694Enabled' -Value 0
Backup-And-Set -Path 'HKCU:Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' -Name 'SubscribedContent-353696Enabled' -Value 0
Backup-And-Set -Path 'HKCU:Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' -Name 'SubscribedContent-280815Enabled' -Value 0
# Store suggestions (turn off app suggestions)
Backup-And-Set -Path 'HKLM:SOFTWARE\Policies\Microsoft\Windows\CloudContent' -Name 'DisableThirdPartySuggestions' -Value 1
try { $backup | ConvertTo-Json -Depth 4 | Set-Content -Path $backupPath -Encoding UTF8 } catch {
Write-Warning "Failed to write backup file: $($_.Exception.Message)"
}
Write-Host "Privacy tweaks applied. Backup saved to: $backupPath" -ForegroundColor Green
}
function Disable-FastStartup {
Write-Host 'Disabling Windows Fast Startup (Hybrid Boot)...' -ForegroundColor Cyan
$path = 'HKLM:SYSTEM\CurrentControlSet\Control\Session Manager\Power'
try {
if (-not (Test-Path $path)) { New-Item -Path $path -Force | Out-Null }
$old = (Get-ItemProperty -Path $path -Name HiberbootEnabled -ErrorAction SilentlyContinue).HiberbootEnabled
New-ItemProperty -Path $path -Name HiberbootEnabled -Value 0 -PropertyType DWord -Force | Out-Null
Write-Host "Fast Startup disabled (old value: $old)" -ForegroundColor Green
} catch {
Write-Warning "Failed to set HiberbootEnabled: $($_.Exception.Message)"
}
# To also disable hibernation (and remove hiberfil.sys) uncomment the line below:
# try { powercfg /hibernate off | Out-Null; Write-Host 'Hibernation disabled.' -ForegroundColor Green } catch { Write-Warning "Failed disabling hibernation: $($_.Exception.Message)" }
}
### --- Pre-flight --- ###
if (-not (Test-IsAdmin)) {
Write-Warning 'This script must be run as Administrator. Right-click PowerShell and choose "Run as administrator".'
break
}
try { Start-Transcript -Path (Join-Path $env:USERPROFILE "install-log-$(Get-Date -Format yyyyMMdd_HHmmss).txt") -ErrorAction Stop } catch {}
Write-Host "Starting bootstrap @ $(Get-Date)" -ForegroundColor Green
if (Ensure-Winget) {
Write-Host 'Updating winget sources...' -ForegroundColor Cyan
try { winget source update --accept-source-agreements | Out-Null } catch { Write-Warning 'Winget source update failed.' }
} else {
Write-Warning 'Skipping winget source update because winget is not currently available.'
}
### --- Feature enablement (WSL2) --- ###
Enable-FeatureIfNeeded -Name Microsoft-Windows-Subsystem-Linux
Enable-FeatureIfNeeded -Name VirtualMachinePlatform
Enable-WindowsSandboxIfAvailable
if (-not $SkipRebootCheck) {
$rebootReasons = @(Get-RebootPendingReasons)
if ($rebootReasons.Count -gt 0) {
Write-Host "A reboot is reported pending (reasons: $($rebootReasons -join ', '))." -ForegroundColor Magenta
if ($script:PendingFileRenameOperationsRaw) {
Write-Host 'Raw PendingFileRenameOperations entries (for diagnostics):' -ForegroundColor DarkGray
$script:PendingFileRenameOperationsRaw | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray }
}
$choice = Read-Host 'Reboot now before continuing? (y=Reboot / s=Skip this time / i=Ignore future PFR stale entries)'
switch -Regex ($choice) {
'^[Yy]$' {
Write-Host 'Rebooting...' -ForegroundColor Magenta
Stop-Transcript | Out-Null 2>$null
Restart-Computer -Force; return
}
'^[Ii]$' {
Write-Host 'Ignoring stale PendingFileRenameOperations for this run.' -ForegroundColor DarkGray
$IgnoreStalePendingFileRenames = $true
}
}
} else {
Write-Host 'No reboot indicators detected.' -ForegroundColor DarkGray
}
} else {
Write-Host 'Reboot check skipped via parameter.' -ForegroundColor DarkGray
}
### --- WSL Distribution --- ###
$desiredDistro = 'openSUSE-Tumbleweed'
Write-Host "Ensuring WSL distro '$desiredDistro' installed..." -ForegroundColor Cyan
$existingDistros = (wsl -l -q 2>$null) | ForEach-Object { $_.Trim() } | Where-Object { $_ }
if ($existingDistros -contains $desiredDistro) {
Write-Host "WSL distro already present: $desiredDistro" -ForegroundColor DarkGray
} else {
# Set default version to 2 (only if supported)
try { wsl --set-default-version 2 2>$null } catch {}
wsl --install -d $desiredDistro
Write-Host 'If the install triggered a reboot, rerun this script afterwards to continue application installs.' -ForegroundColor Magenta
}
### --- Fast Startup Disable (always) --- ###
Disable-FastStartup
### --- Application Lists & Prompts --- ###
$apps = @(
'7zip.7zip',
'AppWork.JDownloader',
'Balena.Etcher',
'Brave.Brave',
'CPUID.CPU-Z',
'Deezer.Deezer',
'Discord.Discord',
'Docker.DockerDesktop',
'Git.Git',
'GitHub.cli',
'GnuPG.Gpg4win',
'AgileBits.1Password',
'WinSCP.WinSCP',
'Malwarebytes.Malwarebytes',
'Microsoft.PowerToys',
'Microsoft.VisualStudioCode',
'OpenMedia.4KVideoDownloader',
'OpenWhisperSystems.Signal',
'Plex.PlexMediaPlayer',
'PointPlanck.FileBot',
'Postman.Postman',
'Python.Python.3.13',
'Rufus.Rufus',
'VideoLAN.VLC',
'WhatsApp.WhatsApp',
'WireGuard.WireGuard',
'WiresharkFoundation.Wireshark',
'Yubico.YubikeyManager',
'Inkscape.Inkscape',
'GlavSoft.RemoteRipple',
'hadolint.hadolint',
'mvdan.shfmt'
)
$mobileApps = @(
'Cloudflare.Warp',
'Proton.ProtonVPN',
'Citrix.Workspace',
'9WZDNCRDJ8LH' # Cisco AnyConnect (msstore ProductId)
)
$gamingApps = @('EpicGames.EpicGamesLauncher','GOG.Galaxy','NexusMods.Vortex','Valve.Steam')
$MobileDeviceAnswer = $MobileDevice
$GamingDeviceAnswer = $GamingDevice
if (-not $PSBoundParameters.ContainsKey('MobileDevice')) { $MobileDeviceAnswer = (Read-Host 'Is this a mobile device? (y/n)').Trim() }
if ($MobileDeviceAnswer -or $MobileDevice) {
if ($MobileDeviceAnswer -match '^[Yy]$' -or $MobileDevice) {
Write-Host 'Adding mobile software...' -ForegroundColor Cyan
$apps += $mobileApps
}
}
# Gaming device prompt / inclusion
if (-not $PSBoundParameters.ContainsKey('GamingDevice')) { $GamingDeviceAnswer = (Read-Host 'Is this a gaming device? (y/n)').Trim() }
if ($GamingDeviceAnswer -or $GamingDevice) {
if ($GamingDeviceAnswer -match '^[Yy]$' -or $GamingDevice) {
Write-Host 'Adding gaming software (stores / mod manager)...' -ForegroundColor Cyan
$apps += $gamingApps
}
}
$apps = $apps | Sort-Object -Unique
# Record mobile device choice for later conditional tweaks
$script:IsMobileDevice = ($MobileDeviceAnswer -match '^[Yy]$' -or $MobileDevice)
### --- Optional Privacy Tweaks (after prompts so we know if mobile) --- ###
if ($ApplyPrivacyTweaks) {
Invoke-PrivacyTweaks
} else {
$applyAns = Read-Host 'Apply Windows privacy/ads/telemetry reduction tweaks? (y/n)'
if ($applyAns -match '^[Yy]$') { Invoke-PrivacyTweaks }
}
Write-Host "Total packages queued: $($apps.Count)" -ForegroundColor Green
### --- Remove Built-in AppX Packages Before Installing --- ###
Invoke-AppxRemoval
### --- Install Loop --- ###
$sw = [System.Diagnostics.Stopwatch]::StartNew()
foreach ($id in $apps) {
Install-App -Id $id
}
$sw.Stop()
Write-Host "Completed in $([int]$sw.Elapsed.TotalMinutes)m $(($sw.Elapsed.Seconds))s" -ForegroundColor Green
try { Stop-Transcript | Out-Null } catch {}
Write-Host 'All done.' -ForegroundColor Green
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment