#requires -Version 5.1 #requires -RunAsAdministrator <# .SYNOPSIS RUVDS bootstrap for IIS migration from windows-recovery-host. .DESCRIPTION Run on RUVDS in PowerShell as Administrator (RDP session). Steps: 1. Install IIS (Web-Server + sub-features + Management Tools). 2. Verify .NET Framework 4.8 (Release >= 528040). 3. Install URL Rewrite Module 2.1. 4. Open Defender Firewall: HTTP/80, HTTPS/443. 5. Create C:\sites + SMB share, scoped to source IP 46.151.25.64. 6. Print summary. Idempotent. Transcript: C:\bootstrap-log.txt #> [CmdletBinding()] param( [string]$SourceIp = '46.151.25.64', [string]$SiteRoot = 'C:\sites', [string]$ShareName = 'sites' ) $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' Start-Transcript -Path C:\bootstrap-log.txt -Append -Force | Out-Null function Step($name) { Write-Host "`n=== $name ===" -ForegroundColor Cyan } function Ok($msg) { Write-Host " [OK] $msg" -ForegroundColor Green } function Skip($msg) { Write-Host " [SKIP] $msg" -ForegroundColor Yellow } function Fail($msg) { Write-Host " [FAIL] $msg" -ForegroundColor Red } try { Step '1. Install IIS' $iis = Get-WindowsFeature Web-Server if ($iis.Installed) { Skip "Web-Server already installed" } else { Install-WindowsFeature Web-Server -IncludeAllSubFeature -IncludeManagementTools -Restart:$false | Out-Null Ok "Web-Server installed" } $extras = @('Web-Asp-Net45','Web-Net-Ext45','Web-ISAPI-Ext','Web-ISAPI-Filter','Web-Windows-Auth','Web-Mgmt-Console') foreach ($f in $extras) { $st = Get-WindowsFeature $f if ($st.Installed) { Skip "$f already installed" } else { Install-WindowsFeature $f -Restart:$false | Out-Null Ok "$f installed" } } Step '2. Verify .NET Framework 4.8' $ndp = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\' -ErrorAction SilentlyContinue if ($ndp -and $ndp.Release -ge 528040) { Ok ".NET 4.8 detected (Release=$($ndp.Release))" } else { Fail ".NET 4.8 NOT found (Release=$($ndp.Release)). Win Server 2025 normally pre-bundles 4.8 -- check Optional Features." Write-Host " Hint: DISM /Online /Add-Capability /CapabilityName:NetFx4.8~~~~" -ForegroundColor Yellow throw "Bootstrap aborted: .NET 4.8 missing" } Step '3. Install URL Rewrite Module 2.1' $rewriteInstalled = Test-Path 'HKLM:\SOFTWARE\Microsoft\IIS Extensions\URL Rewrite' if ($rewriteInstalled) { Skip "URL Rewrite already installed" } else { $msiUrl = 'https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi' $msiPath = "$env:TEMP\rewrite_amd64_en-US.msi" if (-not (Test-Path $msiPath)) { Write-Host " Downloading $msiUrl ..." Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath -UseBasicParsing Ok "downloaded ($([math]::Round((Get-Item $msiPath).Length / 1MB, 2)) MB)" } Write-Host " Installing..." $p = Start-Process msiexec.exe -ArgumentList "/i `"$msiPath`" /quiet /norestart" -Wait -PassThru if ($p.ExitCode -ne 0) { throw "msiexec exit $($p.ExitCode)" } Ok "URL Rewrite installed" } Step '4. Open Defender Firewall (HTTP/80, HTTPS/443)' foreach ($port in @(80,443)) { $name = "iis-http-$port" $existing = Get-NetFirewallRule -DisplayName $name -ErrorAction SilentlyContinue if ($existing) { Skip "FW rule $name already exists" } else { New-NetFirewallRule -DisplayName $name -Direction Inbound -Protocol TCP -LocalPort $port -Action Allow -Profile Any | Out-Null Ok "FW rule $name added" } } Step '5. Open SMB inbound + create share' if (-not (Test-Path $SiteRoot)) { New-Item -ItemType Directory -Path $SiteRoot -Force | Out-Null Ok "Created $SiteRoot" } else { Skip "$SiteRoot already exists" } $fileSharingRules = Get-NetFirewallRule -DisplayGroup 'File and Printer Sharing' -ErrorAction SilentlyContinue | Where-Object Enabled -eq 'False' if ($fileSharingRules) { $cnt = $fileSharingRules.Count $fileSharingRules | Set-NetFirewallRule -Enabled True Ok "Enabled built-in 'File and Printer Sharing' group ($cnt rules)" } else { Skip "'File and Printer Sharing' rules already enabled" } $smbRule = Get-NetFirewallRule -DisplayName 'smb-from-source' -ErrorAction SilentlyContinue if ($smbRule) { Skip "smb-from-source FW rule already exists" } else { New-NetFirewallRule -DisplayName 'smb-from-source' ` -Direction Inbound -Protocol TCP -LocalPort 445 ` -RemoteAddress $SourceIp ` -Action Allow -Profile Any | Out-Null Ok "smb-from-source FW rule added (source=$SourceIp)" } $share = Get-SmbShare -Name $ShareName -ErrorAction SilentlyContinue if ($share) { Skip "SMB share '$ShareName' already exists (path=$($share.Path))" } else { New-SmbShare -Name $ShareName -Path $SiteRoot -FullAccess Administrator | Out-Null Ok "SMB share '$ShareName' created -> $SiteRoot" } Step '6. Summary' Write-Host "" Write-Host " IIS (Web-Server): $((Get-WindowsFeature Web-Server).Installed)" Write-Host " ASP.NET 4.5/4.8: $((Get-WindowsFeature Web-Asp-Net45).Installed)" Write-Host " URL Rewrite 2.1: $(Test-Path 'HKLM:\SOFTWARE\Microsoft\IIS Extensions\URL Rewrite')" Write-Host " FW HTTP/80: $([bool](Get-NetFirewallRule -DisplayName 'iis-http-80' -ErrorAction SilentlyContinue))" Write-Host " FW HTTPS/443: $([bool](Get-NetFirewallRule -DisplayName 'iis-http-443' -ErrorAction SilentlyContinue))" Write-Host " FW smb-from-source: $([bool](Get-NetFirewallRule -DisplayName 'smb-from-source' -ErrorAction SilentlyContinue))" Write-Host " SMB share '$ShareName': $([bool](Get-SmbShare -Name $ShareName -ErrorAction SilentlyContinue)) -> $SiteRoot" Write-Host " Disk C: free: $([math]::Round((Get-PSDrive C).Free / 1GB, 2)) GB" Write-Host "" Write-Host "Transcript: C:\bootstrap-log.txt" -ForegroundColor DarkGray } catch { Fail $_.Exception.Message Write-Host $_.ScriptStackTrace -ForegroundColor DarkRed exit 1 } finally { Stop-Transcript | Out-Null }