#Requires -RunAsAdministrator <# .SYNOPSIS Removes unsupported Microsoft .NET Core / ASP.NET Core / Windows Desktop Runtime / SDK 3.1.x components. .DESCRIPTION Queries HKLM uninstall registry locations (64-bit and 32-bit) for .NET 3.1.x components, executes quiet uninstallation for both MSI and Executable/Bundle bootstrappers, cleans orphaned runtime directories, and verifies removal. #> $ErrorActionPreference = "Continue" Write-Host "Starting .NET Core 3.1 remediation..." -ForegroundColor Cyan $registryPaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" ) # Search pattern targeting 3.1.x runtimes, SDKs, targeting packs, and hosting bundles $targetApps = foreach ($path in$registryPaths) { Get-ItemProperty $path -ErrorAction SilentlyContinue | Where-Object { ( $_.DisplayName -match "Microsoft .*\b3\.1\.\d+\b" -or $_.DisplayName -match "Microsoft \.NET (Core|SDK|Runtime|Windows Desktop|ASP\.NET Core).*3\.1" ) -and ($_.UninstallString -or$_.QuietUninstallString) } } if (-not $targetApps) { Write-Host "No .NET Core 3.1 components found. System is clean." -ForegroundColor Green exit 0 } Write-Host "Found $($targetApps.Count) .NET Core 3.1 component(s) to remove:" -ForegroundColor Yellow foreach ($app in$targetApps) { Write-Host " - $($app.DisplayName) ($($app.DisplayVersion))" -ForegroundColor Yellow } foreach ($app in$targetApps) { Write-Host "`nAttempting to remove: $($app.DisplayName)..." -ForegroundColor Cyan $uninstallCmd = if ($app.QuietUninstallString) { $app.QuietUninstallString } else { $app.UninstallString } if ($uninstallCmd -match "\{[A-Fa-f0-9\-]{36}\}") { # Standard MSI Uninstall $productCode = $Matches[0] Write-Host "Executing MSI uninstall for GUID: $productCode" -ForegroundColor Gray $proc = Start-Process -FilePath "msiexec.exe" -ArgumentList "/x $productCode /qn /norestart" -Wait -PassThru -NoNewWindow } else { # Executable / WiX Burn Bootstrapper Uninstall Write-Host "Executing Bootstrapper EXE uninstall..." -ForegroundColor Gray # Parse EXE path and arguments safely if ($uninstallCmd -match '^"([^"]+)"(.*)$') { $exePath = $Matches[1] $exeArgs = "$($Matches[2]) /uninstall /quiet /norestart".Trim() } elseif ($uninstallCmd -match '^(\S+)(.*)$') { $exePath = $Matches[1] $exeArgs = "$($Matches[2]) /uninstall /quiet /norestart".Trim() } else { $exePath = $uninstallCmd $exeArgs = "/uninstall /quiet /norestart" } $proc = Start-Process -FilePath $exePath -ArgumentList $exeArgs -Wait -PassThru -NoNewWindow -ErrorAction SilentlyContinue } # Evaluate return codes (0 = Success, 3010 = Success, reboot required) if ($proc.ExitCode -in @(0, 3010)) { Write-Host "Successfully processed uninstall for $($app.DisplayName)." -ForegroundColor Green } else { Write-Host "Warning: Uninstall process returned exit code $($proc.ExitCode) for $($app.DisplayName)." -ForegroundColor Yellow } } # Clean residual 3.1.x folder remnants from dotnet installation directories $dotnetPaths = @( "$env:ProgramFiles\dotnet", "${env:ProgramFiles(x86)}\dotnet" ) foreach ($basePath in $dotnetPaths) { if (Test-Path $basePath) { Get-ChildItem -Path $basePath -Recurse -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "3.1.*" } | ForEach-Object { Write-Host "Removing leftover directory: $($_.FullName)" -ForegroundColor Yellow Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue } } } # Final Verification Write-Host "`nVerifying remaining .NET Core 3.1 components..." -ForegroundColor Cyan $remainingApps = foreach ($path in$registryPaths) { Get-ItemProperty $path -ErrorAction SilentlyContinue | Where-Object { ( $_.DisplayName -match "Microsoft .*\b3\.1\.\d+\b" -or $_.DisplayName -match "Microsoft \.NET (Core|SDK|Runtime|Windows Desktop|ASP\.NET Core).*3\.1" ) -and ($_.UninstallString -or$_.QuietUninstallString) } } if ($remainingApps) { Write-Host "ERROR: Some .NET Core 3.1 components remain installed:" -ForegroundColor Red $remainingApps | ForEach-Object { Write-Host " - $($_.DisplayName) ($($_.DisplayVersion))" -ForegroundColor Red } exit 1 } else { Write-Host ".NET Core 3.1 remediation completed successfully." -ForegroundColor Green exit 0 }