#Requires -RunAsAdministrator <# .SYNOPSIS Windows Post-Installation Automation Script .DESCRIPTION Automates software installation via Chocolatey and applies Windows customizations. Fully automated - no prompts or user interaction required. .PARAMETER dev Include development-specific software (Docker Desktop) .EXAMPLE .\post_install.ps1 .\post_install.ps1 -dev #> param( [switch]$dev ) # ============================================================================ # CONFIGURATION # ============================================================================ $cacheFolder = "c:\temp\chocolatey_cache" $logFolder = "c:\temp" $chocoLogFile = Join-Path $logFolder "chocolatey_main.log" # Software packages to install (same on every machine) $software = @( # Browsers & Internet "vivaldi", # Web browser (replaced Firefox) # Security & Privacy "keepassxc", # Password manager # File Management & Transfer "winscp", # SFTP/FTP client (replaced FileZilla) "7zip", # File compression # Development Tools "vscode", # Code editor "python", # Python runtime "nodejs", "git", # Version control "gow", # GNU utilities for Windows # Media & Creative "vlc", # Media player "foobar", # Media player "plex", # Media server "audacity", # Audio editor "blender", # 3D creation suite "ffmpeg", # Media processing "yt-dlp", # Video downloader "imagemagick", # Gaming "steam", # Game platform "geforce-experience", # NVIDIA GPU management # Utilities "powertoys", # Microsoft PowerToys "qbittorrent", # Torrent client "zerotier-one", # Virtual networking # System "wsl2" # Windows Subsystem for Linux ) # Development-specific software (only with -dev switch) $devSoftware = @() if ($dev) { $devSoftware = @( "docker-desktop" # Container platform ) } # Combine all software $allSoftware = $software + $devSoftware # ============================================================================ # ERROR HANDLING & VALIDATION # ============================================================================ # Set error action preference $ErrorActionPreference = "Stop" Write-Host "`n========================================" -ForegroundColor Cyan Write-Host " Windows Post-Installation Script" -ForegroundColor Cyan Write-Host "========================================`n" -ForegroundColor Cyan # Check internet connectivity Write-Host "[1/6] Checking internet connectivity..." -ForegroundColor Yellow try { $null = Test-Connection -ComputerName chocolatey.org -Count 1 -Quiet -ErrorAction Stop Write-Host " Internet connection OK`n" -ForegroundColor Green } catch { Write-Host " ERROR: No internet connection detected!" -ForegroundColor Red Write-Host " Cannot proceed with installations.`n" -ForegroundColor Red exit 1 } # ============================================================================ # SETUP DIRECTORIES # ============================================================================ Write-Host "[2/6] Setting up directories..." -ForegroundColor Yellow try { if (!(Test-Path -Path $cacheFolder)) { New-Item -ItemType Directory -Force -Path $cacheFolder | Out-Null } if (!(Test-Path -Path $logFolder)) { New-Item -ItemType Directory -Force -Path $logFolder | Out-Null } Set-Location -Path $logFolder Write-Host " Cache: $cacheFolder" -ForegroundColor Gray Write-Host " Logs: $logFolder`n" -ForegroundColor Gray } catch { Write-Host " ERROR: Failed to create directories: $_`n" -ForegroundColor Red exit 1 } # ============================================================================ # INSTALL CHOCOLATEY # ============================================================================ Write-Host "[3/6] Checking Chocolatey installation..." -ForegroundColor Yellow try { $choco = Get-Command -Name "choco" -ErrorAction SilentlyContinue if (!$choco) { Write-Host " Chocolatey not found. Installing..." -ForegroundColor Yellow Set-ExecutionPolicy Bypass -Scope Process -Force [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) # Refresh environment to get choco in PATH $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") # Verify installation $choco = Get-Command -Name "choco" -ErrorAction SilentlyContinue if (!$choco) { throw "Chocolatey installation failed - choco command not found after install" } Write-Host " Chocolatey installed successfully" -ForegroundColor Green } else { Write-Host " Chocolatey already installed" -ForegroundColor Green } # Enable global confirmation (no prompts) $result = choco feature enable -n allowGlobalConfirmation 2>&1 Write-Host " Auto-confirmation enabled`n" -ForegroundColor Gray } catch { Write-Host " ERROR: Chocolatey installation failed: $_`n" -ForegroundColor Red exit 1 } # ============================================================================ # CHECK INSTALLED PACKAGES # ============================================================================ Write-Host "[4/6] Scanning for already-installed packages..." -ForegroundColor Yellow try { # Get list of installed packages $installedList = choco list --local-only --limit-output 2>&1 | Out-String $installedPackages = $installedList -split "`n" | ForEach-Object { if ($_ -match '^([^|]+)\|') { $matches[1].Trim() } } | Where-Object { $_ } # Filter out already-installed packages $packagesToInstall = @() $skippedPackages = @() foreach ($pkg in $allSoftware) { if ($installedPackages -contains $pkg) { $skippedPackages += $pkg } else { $packagesToInstall += $pkg } } Write-Host " Found $($installedPackages.Count) total installed packages" -ForegroundColor Gray Write-Host " Skipping $($skippedPackages.Count) already-installed packages" -ForegroundColor Cyan Write-Host " Will install $($packagesToInstall.Count) new packages`n" -ForegroundColor Green if ($skippedPackages.Count -gt 0) { Write-Host " Already installed:" -ForegroundColor Gray foreach ($pkg in $skippedPackages) { Write-Host " - $pkg" -ForegroundColor DarkGray } Write-Host "" } } catch { Write-Host " WARNING: Could not check installed packages: $_" -ForegroundColor Yellow Write-Host " Proceeding with all packages...`n" -ForegroundColor Yellow $packagesToInstall = $allSoftware } # ============================================================================ # INSTALL PACKAGES # ============================================================================ if ($packagesToInstall.Count -eq 0) { Write-Host "[5/6] All packages already installed - nothing to do!`n" -ForegroundColor Green } else { Write-Host "[5/6] Installing $($packagesToInstall.Count) packages..." -ForegroundColor Yellow Write-Host " This may take a while. Logging to individual files in $logFolder`n" -ForegroundColor Gray $successful = @() $failed = @() $total = $packagesToInstall.Count $current = 0 foreach ($pkg in $packagesToInstall) { $current++ $percent = [math]::Round(($current / $total) * 100) # Display progress Write-Host " [$current/$total] " -NoNewline -ForegroundColor Cyan Write-Host "$pkg " -NoNewline -ForegroundColor White Write-Progress -Activity "Installing Chocolatey Packages" -Status "$pkg ($current of $total)" -PercentComplete $percent try { # Install package with individual log file $pkgLogFile = Join-Path $logFolder "$pkg.log" $output = choco install $pkg -y --cache=$cacheFolder --log-file=$pkgLogFile 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host "[OK]" -ForegroundColor Green $successful += $pkg } else { Write-Host "[FAILED - see $pkg.log]" -ForegroundColor Red $failed += $pkg } } catch { Write-Host "[ERROR: $_]" -ForegroundColor Red $failed += $pkg } } Write-Progress -Activity "Installing Chocolatey Packages" -Completed Write-Host "" } # ============================================================================ # WINDOWS CUSTOMIZATIONS # ============================================================================ Write-Host "[6/6] Applying Windows customizations..." -ForegroundColor Yellow try { # Restore old Windows 10 File Explorer context menu (removes "Show more options") reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve 2>&1 | Out-Null Write-Host " Windows 10 context menu enabled`n" -ForegroundColor Green } catch { Write-Host " WARNING: Failed to apply registry customization: $_`n" -ForegroundColor Yellow } # ============================================================================ # SUMMARY # ============================================================================ Write-Host "========================================" -ForegroundColor Cyan Write-Host " INSTALLATION SUMMARY" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan if ($packagesToInstall.Count -gt 0) { Write-Host "Successful: " -NoNewline -ForegroundColor Green Write-Host "$($successful.Count)/$total" -ForegroundColor White if ($failed.Count -gt 0) { Write-Host "Failed: " -NoNewline -ForegroundColor Red Write-Host "$($failed.Count)/$total" -ForegroundColor White Write-Host "`nFailed packages:" -ForegroundColor Red foreach ($pkg in $failed) { Write-Host " - $pkg (check $logFolder\$pkg.log)" -ForegroundColor Red } } } else { Write-Host "No new packages installed" -ForegroundColor Green } if ($skippedPackages.Count -gt 0) { Write-Host "Skipped: " -NoNewline -ForegroundColor Cyan Write-Host "$($skippedPackages.Count) (already installed)" -ForegroundColor White } Write-Host "`nLogs saved to: $logFolder" -ForegroundColor Gray Write-Host "`nNOTE: Some packages may require a system restart to function properly." -ForegroundColor Yellow Write-Host "========================================`n" -ForegroundColor Cyan # Exit with error code if any packages failed if ($failed.Count -gt 0) { exit 1 } else { exit 0 }