Created
March 2, 2026 14:29
-
-
Save ciekawy/f0a8b83c7cc838fc139b27a5a5845f0a to your computer and use it in GitHub Desktop.
WEB-9: Unified Windows Server 2022 init script (network + packages + SSH + .NET)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Windows Server 2022 Unified Init Script - WEB-9 | |
| # Run in Administrator PowerShell after fresh Windows install | |
| # | |
| # Usage: irm <tinyurl> | iex | |
| # | |
| # This script handles the complete post-installation setup: | |
| # 1. VirtIO network driver (if CD drive mounted) | |
| # 2. DNS configuration | |
| # 3. Chocolatey + packages (.NET SDK, Git, PowerShell 7) | |
| # 4. OpenSSH Server with key-based authentication | |
| # 5. Test .NET project creation | |
| # | |
| # Requires: Administrator privileges, internet access (or VirtIO ISO for network) | |
| param( | |
| [string]$SshPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO9VR+9HrxMs+2NxN2h8Td6rCDP8eupti1BtqFK1pSdX coder@myfirst" | |
| ) | |
| $ErrorActionPreference = "Continue" | |
| Set-ExecutionPolicy Bypass -Scope Process -Force | |
| function Write-Step { | |
| param([string]$Step, [string]$Message) | |
| Write-Host "`n[$Step] $Message" -ForegroundColor Cyan | |
| } | |
| function Write-Ok { param([string]$Message) Write-Host " OK: $Message" -ForegroundColor Green } | |
| function Write-Warn { param([string]$Message) Write-Host " WARN: $Message" -ForegroundColor Yellow } | |
| function Write-Err { param([string]$Message) Write-Host " ERROR: $Message" -ForegroundColor Red } | |
| Write-Host "=== Windows Server 2022 Unified Init ===" -ForegroundColor Green | |
| Write-Host "Starting at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Gray | |
| # --- Step 1: Network --- | |
| Write-Step "1/6" "Checking network..." | |
| $adapter = Get-NetAdapter -ErrorAction SilentlyContinue | |
| if (-not $adapter) { | |
| Write-Warn "No network adapter found. Looking for VirtIO driver ISO..." | |
| $cdDrives = Get-Volume | Where-Object { $_.DriveType -eq 'CD-ROM' -and $_.DriveLetter } | |
| foreach ($drive in $cdDrives) { | |
| $letter = $drive.DriveLetter | |
| $driverPath = "${letter}:\NetKVM\2k22\amd64" | |
| if (Test-Path $driverPath) { | |
| Write-Host " Installing VirtIO network driver from ${letter}:\" -ForegroundColor Yellow | |
| pnputil /add-driver "${driverPath}\*.inf" /install | |
| Start-Sleep -Seconds 5 | |
| break | |
| } | |
| } | |
| $adapter = Get-NetAdapter -ErrorAction SilentlyContinue | |
| if (-not $adapter) { | |
| Write-Err "No network adapter found even after VirtIO install!" | |
| Write-Host " Attach VirtIO ISO from Linux: hcloud server attach-iso <vm> 116716" -ForegroundColor Yellow | |
| Write-Host " Then re-run this script." -ForegroundColor Yellow | |
| exit 1 | |
| } | |
| } | |
| Write-Ok "Network adapter: $($adapter.Name) ($($adapter.Status))" | |
| # Configure DNS | |
| $adapterAlias = $adapter.Name | |
| Set-DnsClientServerAddress -InterfaceAlias $adapterAlias -ServerAddresses ("8.8.8.8","8.8.4.4") | |
| Write-Ok "DNS set to 8.8.8.8, 8.8.4.4" | |
| # Test connectivity | |
| $ping = Test-NetConnection 8.8.8.8 -WarningAction SilentlyContinue | |
| if ($ping.TcpTestSucceeded -or $ping.PingSucceeded) { | |
| Write-Ok "Internet connectivity confirmed" | |
| } else { | |
| Write-Warn "Ping failed but continuing (ICMP may be blocked)" | |
| } | |
| # --- Step 2: Chocolatey --- | |
| Write-Step "2/6" "Installing Chocolatey..." | |
| if (Get-Command choco -ErrorAction SilentlyContinue) { | |
| Write-Ok "Chocolatey already installed" | |
| } else { | |
| [System.Net.ServicePointManager]::SecurityProtocol = 3072 | |
| Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) | |
| $env:PATH = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") | |
| Write-Ok "Chocolatey installed" | |
| } | |
| # --- Step 3: Packages --- | |
| Write-Step "3/6" "Installing packages (this takes ~10 minutes)..." | |
| choco install -y powershell-core dotnet-8.0-sdk git 2>&1 | Out-Null | |
| $env:PATH = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") | |
| # Verify installs using full paths | |
| $dotnetPath = "C:\Program Files\dotnet\dotnet.exe" | |
| $gitPath = "C:\Program Files\Git\cmd\git.exe" | |
| if (Test-Path $dotnetPath) { Write-Ok ".NET SDK: $(& $dotnetPath --version)" } | |
| else { Write-Err ".NET SDK not found at $dotnetPath" } | |
| if (Test-Path $gitPath) { Write-Ok "Git: $(& $gitPath --version)" } | |
| else { Write-Err "Git not found at $gitPath" } | |
| $pwshPath = "C:\Program Files\PowerShell\7\pwsh.exe" | |
| if (Test-Path $pwshPath) { Write-Ok "PowerShell 7 installed" } | |
| else { Write-Warn "PowerShell 7 not found (non-blocking)" } | |
| # --- Step 4: OpenSSH --- | |
| Write-Step "4/6" "Configuring SSH..." | |
| # Use Windows built-in OpenSSH (more reliable than Chocolatey version) | |
| $sshCapability = Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Server*' | |
| if ($sshCapability.State -ne 'Installed') { | |
| Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 | Out-Null | |
| Write-Ok "OpenSSH Server installed via Windows Capability" | |
| } else { | |
| Write-Ok "OpenSSH Server already installed" | |
| } | |
| # Write minimal sshd_config | |
| $sshdConfig = @" | |
| PubkeyAuthentication yes | |
| PasswordAuthentication no | |
| Match Group administrators | |
| AuthorizedKeysFile C:/ProgramData/ssh/administrators_authorized_keys | |
| "@ | |
| $sshdConfig | Set-Content -Path "C:\ProgramData\ssh\sshd_config" -Force | |
| Write-Ok "sshd_config written" | |
| # Start service | |
| Start-Service sshd -ErrorAction SilentlyContinue | |
| Set-Service -Name sshd -StartupType Automatic -ErrorAction SilentlyContinue | |
| $sshService = Get-Service sshd -ErrorAction SilentlyContinue | |
| if ($sshService -and $sshService.Status -eq 'Running') { | |
| Write-Ok "SSH service running" | |
| } else { | |
| Write-Err "SSH service failed to start! Check: Get-EventLog -LogName Application -Source sshd -Newest 5" | |
| } | |
| # Firewall rule | |
| New-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -DisplayName "OpenSSH Server" ` | |
| -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 ` | |
| -ErrorAction SilentlyContinue | Out-Null | |
| Write-Ok "Firewall rule configured" | |
| # --- Step 5: SSH Key --- | |
| Write-Step "5/6" "Adding SSH public key..." | |
| $authorizedKeysFile = "C:\ProgramData\ssh\administrators_authorized_keys" | |
| New-Item -Path $authorizedKeysFile -ItemType File -Force -Value $SshPublicKey | Out-Null | |
| icacls.exe $authorizedKeysFile /inheritance:r | Out-Null | |
| icacls.exe $authorizedKeysFile /grant "SYSTEM:(F)" | Out-Null | |
| icacls.exe $authorizedKeysFile /grant "BUILTIN\Administrators:(F)" | Out-Null | |
| Restart-Service sshd -ErrorAction SilentlyContinue | |
| Write-Ok "SSH key added and service restarted" | |
| # --- Step 6: Test Project --- | |
| Write-Step "6/6" "Creating test .NET project..." | |
| if (Test-Path $dotnetPath) { | |
| New-Item -ItemType Directory -Path C:\Projects -Force | Out-Null | |
| Set-Location C:\Projects | |
| if (-not (Test-Path "C:\Projects\HelloWindows")) { | |
| & $dotnetPath new console -n HelloWindows -o HelloWindows 2>&1 | Out-Null | |
| } | |
| Set-Location HelloWindows | |
| $buildResult = & $dotnetPath build 2>&1 | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Ok "HelloWindows project built successfully" | |
| } else { | |
| Write-Err "Build failed: $buildResult" | |
| } | |
| } else { | |
| Write-Warn "Skipping test project (.NET SDK not available)" | |
| } | |
| # --- Summary --- | |
| Write-Host "`n=== Setup Complete ===" -ForegroundColor Green | |
| Write-Host "Finished at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Gray | |
| $ip = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notlike "*Loopback*" } | Select-Object -First 1).IPAddress | |
| Write-Host "`nConnection Info:" -ForegroundColor Cyan | |
| Write-Host " SSH: ssh -i ~/.ssh/id_windows_poc Administrator@$ip" -ForegroundColor White | |
| Write-Host " .NET build: ssh ... `"cd C:\Projects\HelloWindows & \`"C:\Program Files\dotnet\dotnet.exe\`" build`"" -ForegroundColor White | |
| Write-Host "`nInstalled:" -ForegroundColor Cyan | |
| if (Test-Path $dotnetPath) { Write-Host " .NET SDK $(& $dotnetPath --version)" } | |
| if (Test-Path $gitPath) { Write-Host " Git $(& $gitPath --version)" } | |
| if (Test-Path $pwshPath) { Write-Host " PowerShell 7" } | |
| Write-Host " OpenSSH Server ($(Get-Service sshd -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Status))" | |
| Write-Host "`n✅ Ready for remote development!" -ForegroundColor Green |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment