<# .SYNOPSIS Sistemdeki Microsoft SQL Server kurulumlarını kaldırmaya yardımcı betik: - Uninstall kayıtlarını kullanarak mümkünse uninstall çalıştırır - Servisleri durdurur ve siler (MSSQL*, SQLAgent*) - Registry'de SQL ile ilişkili anahtarları yedekleyip siler - İsteğe bağlı olarak Program Files altındaki SQL klasörlerini siler .NOTES - Yönetici olarak çalıştırın. - Önce test ortamında deneyin. #> param( [switch]$AutoConfirm, [switch]$ConfirmDeletion, [switch]$RemoveProgramFiles # Program Files içindeki SQL klasörlerini siler (isteğe bağlı) ) function Assert-Admin { $id = [Security.Principal.WindowsIdentity]::GetCurrent() $p = New-Object Security.Principal.WindowsPrincipal($id) if (-not $p.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) { Write-Error "Bu scripti Yönetici (Run as Administrator) olarak çalıştırın." exit 1 } } Assert-Admin # Hazırlık: yedek dizini $ts = Get-Date -Format "yyyyMMdd_HHmmss" $backupRoot = "C:\RegBackups_MicrosoftSQL_$ts" New-Item -Path $backupRoot -ItemType Directory -Force | Out-Null Write-Host "Yedek dizini: $backupRoot" -ForegroundColor Cyan # Helper: PSPath -> reg.exe uyumlu function Convert-PSPathToRegPath([string]$pspath) { $reg = $pspath -replace "Microsoft.PowerShell.Core\\Registry::","" $reg = $reg -replace "^HKLM:\\","HKLM\\" $reg = $reg -replace "^HKCU:\\","HKCU\\" return $reg.Trim('\') } # 1) Uninstall kayıtlarını bul (HKLM Uninstall + Wow6432Node Uninstall) $uninstallRoots = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" ) $uninstallEntries = @() foreach ($root in $uninstallRoots) { try { Get-ChildItem -Path $root -ErrorAction SilentlyContinue | ForEach-Object { try { $props = Get-ItemProperty -Path $_.PSPath -ErrorAction SilentlyContinue if ($props.DisplayName) { if ($props.DisplayName -match "Microsoft SQL Server" -or $props.DisplayName -match "^SQL Server" -or $props.Publisher -match "Microsoft") { # Daha kesin filtre için DisplayName kontrolü yeterli if ($props.DisplayName -match "SQL" -or $props.DisplayName -match "Microsoft SQL") { $uninstallEntries += [PSCustomObject]@{ PSPath = $_.PSPath DisplayName = $props.DisplayName UninstallString = $props.UninstallString QuietUninstallString = $props.QuietUninstallString GUID = $_.PSChildName } } } } } catch {} } } catch {} } $uninstallEntries = $uninstallEntries | Sort-Object -Unique -Property DisplayName if ($uninstallEntries.Count -gt 0) { Write-Host "`nBulunan 'SQL' uninstall girdileri:" -ForegroundColor Green $i=0; foreach ($e in $uninstallEntries) { $i++; Write-Host "$i) $($e.DisplayName)"; Write-Host " UninstallString: $($e.UninstallString)" } } else { Write-Host "`nUninstall kaydı bulunamadı." -ForegroundColor Yellow } # 2) Servisleri tespit et (MSSQL*, SQLAgent*, MSSQL$*) Write-Host "`nServis taraması yapılıyor..." -ForegroundColor Cyan $svcCandidates = Get-Service -ErrorAction SilentlyContinue | Where-Object { ($_.Name -match "^MSSQL") -or ($_.Name -match "^SQLAgent") -or ($_.DisplayName -match "SQL Server") -or ($_.DisplayName -match "SQL Server Agent") } if ($svcCandidates.Count -gt 0) { Write-Host "Bulunan SQL ilgili servisler:" $svcCandidates | ForEach-Object { Write-Host "- $($_.Name) : $($_.DisplayName) ($($_.Status))" } } else { Write-Host "SQL servisleri bulunamadı." -ForegroundColor Yellow } # 3) Registry içinde yaygın SQL anahtarlarını arama (SOFTWARE, Wow6432Node, SERVICES) $searchRoots = @( "HKLM:\SOFTWARE", "HKLM:\SOFTWARE\Wow6432Node", "HKLM:\SYSTEM\CurrentControlSet\Services" ) $foundKeys = [System.Collections.Generic.List[string]]::new() foreach ($root in $searchRoots) { try { # child items geniş olabilir; burada sadece anahtar isimlerinde SQL veya MSSQL geçenleri alıyoruz Get-ChildItem -Path $root -Recurse -ErrorAction SilentlyContinue | ForEach-Object { try { if ($_.PSChildName -match "MSSQL" -or $_.PSChildName -match "SQLServer" -or $_.PSChildName -match "SQL" -or $_.PSPath -match "Microsoft SQL Server") { $foundKeys.Add($_.PSPath) } } catch {} } } catch { Write-Warning "Tarama hatası: $root : $_" } } # Ayrıca bazı kesin anahtarları kesin ekle (default instance ve MSSQLServer kökleri) $explicitKeys = @( "HKLM:\SYSTEM\CurrentControlSet\Services\MSSQLSERVER", "HKLM:\SYSTEM\CurrentControlSet\Services\SQLSERVERAGENT", "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server", "HKLM:\SOFTWARE\Microsoft\MSSQLServer", "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server" ) foreach ($k in $explicitKeys) { if (Test-Path $k) { $foundKeys.Add($k) } } # Normalize unique $foundKeys = $foundKeys | Sort-Object -Unique if ($foundKeys.Count -eq 0) { Write-Host "`nRegistry içinde açıkça SQL ile eşleşen anahtar bulunamadı." -ForegroundColor Yellow } else { Write-Host "`nBulunan registry anahtarları (kısa):" -ForegroundColor Green $n=0; foreach ($k in $foundKeys | Select-Object -First 200) { $n++; Write-Host "$n) $k" } if ($foundKeys.Count -gt 200) { Write-Host "... ve daha fazla (toplam $($foundKeys.Count))" } } # Onay alma $doDelete = $false if ($AutoConfirm) { $doDelete = $true } elseif ($ConfirmDeletion) { $ans = Read-Host "Tüm bulunan SQL bileşenlerini silmeyi onaylıyor musunuz? (E/H)" if ($ans -match "^[EeYy]") { $doDelete = $true } } else { $ans = Read-Host "Bulunan girdiler yedeklenecek. Silme işlemini başlatmak istiyor musunuz? (E/H)" if ($ans -match "^[EeYy]") { $doDelete = $true } } if (-not $doDelete) { Write-Host "`nHiçbir silme işlemi yapılmadı. Yedekleme dizini: $backupRoot" -ForegroundColor Yellow exit 0 } # 4) Uninstall işlemleri: uninstall string varsa çalıştır Write-Host "`nUninstall işlemleri başlatılıyor..." -ForegroundColor Red foreach ($entry in $uninstallEntries) { try { $u = $entry.UninstallString $q = $entry.QuietUninstallString if ($q) { $cmd = $q } elseif ($u) { $cmd = $u } else { $cmd = $null } if ($cmd) { Write-Host "Çalıştırılıyor: $($entry.DisplayName)" # Bazı UninstallString içinde 'msiexec /I {GUID}' veya 'MsiExec.exe /X{GUID}' bulunur. Eğer /I ise /X ile kaldırmalıyız. $cmdToRun = $cmd if ($cmd -match "msiexec" -and $cmd -match "/I") { # /I ise /x ile dönüştür $cmdToRun = $cmd -replace "/I","/X" # ensure quiet if possible if ($cmdToRun -notmatch "/qn") { $cmdToRun += " /qn" } } # Eğer komut bir exe pathi ile parametreliyse uygun şekilde Start-Process kullan Write-Host "Komut: $cmdToRun" Start-Process -FilePath "cmd.exe" -ArgumentList "/c `"$cmdToRun`"" -Wait -NoNewWindow Write-Host "Uninstall tamamlanmış olabilir: $($entry.DisplayName)" } else { Write-Warning "UninstallString yok: $($entry.DisplayName)" } } catch { Write-Warning "Uninstall hatası: $($entry.DisplayName) : $_" } } # 5) Servisleri durdur ve sil Write-Host "`nServisleri durdurup siliyorum..." -ForegroundColor Red if ($svcCandidates.Count -gt 0) { foreach ($s in $svcCandidates) { try { if ($s.Status -eq 'Running') { Write-Host "Durduruluyor: $($s.Name)" Stop-Service -Name $s.Name -Force -ErrorAction SilentlyContinue } Write-Host "Servis siliniyor: $($s.Name)" sc.exe delete $s.Name | Out-Null } catch { Write-Warning "Servis silme hatası: $($s.Name) : $_" } } } else { Write-Host "Silinecek SQL servisi bulunamadı." -ForegroundColor Yellow } # 6) Registry yedekle ve sil Write-Host "`nRegistry yedekleme ve silme adımı..." -ForegroundColor Magenta $removeFailures = @() foreach ($k in $foundKeys) { try { $regPath = Convert-PSPathToRegPath $k $safeName = ($regPath -replace '[\\/:]','_') + ".reg" $outFile = Join-Path $backupRoot $safeName # Export $cmd = "reg.exe export `"$regPath`" `"$outFile`" /y" $res = cmd.exe /c $cmd 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host "Yedeklendi: $regPath -> $outFile" } else { Write-Warning "Yedekleme başarısız: $regPath -> $res" } # Silme Write-Host "Siliniyor: $regPath" # Önce PowerShell ile dene try { Remove-Item -Path $k -Recurse -Force -ErrorAction Stop Write-Host "Silindi (PS): $k" } catch { # fallback reg.exe delete $delCmd = "reg.exe delete `"$regPath`" /f" $out2 = cmd.exe /c $delCmd 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host "Silindi (reg.exe): $regPath" } else { Write-Warning "Reg delete başarısız: $regPath -> $out2" $removeFailures += "$regPath -> $out2" } } } catch { Write-Warning "Registry işlem hatası: $k : $_" $removeFailures += "$k -> $_" } } if ($removeFailures.Count -gt 0) { Write-Warning "`nBazı registry anahtarları silinemedi veya hata verdi:" $removeFailures | ForEach-Object { Write-Warning $_ } } # 7) Program Files içi klasörleri (isteğe bağlı) if ($RemoveProgramFiles) { $pf64 = "${env:ProgramFiles}\Microsoft SQL Server" $pf86 = "${env:ProgramFiles(x86)}\Microsoft SQL Server" $candidates = @($pf64, $pf86) | Where-Object { Test-Path $_ } if ($candidates.Count -gt 0) { Write-Host "`nProgram Files içindeki SQL klasörleri silinecek:" -ForegroundColor Cyan $candidates | ForEach-Object { Write-Host "- $_" } if (-not $AutoConfirm) { $a = Read-Host "Program Files klasörlerini silmeyi onaylıyor musunuz? (E/H)" if ($a -notmatch "^[EeYy]") { Write-Host "Program Files klasörleri silinmeyecek." } else { foreach ($d in $candidates) { try { Write-Host "Siliniyor: $d" Remove-Item -Path $d -Recurse -Force -ErrorAction Stop Write-Host "Silindi: $d" } catch { Write-Warning "Klasör silme hatası: $d : $_" } } } } else { foreach ($d in $candidates) { try { Write-Host "Siliniyor (Auto): $d" Remove-Item -Path $d -Recurse -Force -ErrorAction Stop Write-Host "Silindi: $d" } catch { Write-Warning "Klasör silme hatası: $d : $_" } } } } else { Write-Host "Silinecek Program Files SQL klasörü bulunamadı." } } # 8) Özet kaydı $summary = @( "Date: $(Get-Date -Format u)", "Backup folder: $backupRoot", "Uninstall entries processed: $($uninstallEntries.Count)", "Services processed: $($svcCandidates.Count)", "Registry keys processed: $($foundKeys.Count)", "RemoveProgramFiles: $RemoveProgramFiles" ) $summary | Out-File -FilePath (Join-Path $backupRoot "summary.txt") -Encoding UTF8 Write-Host "`nİşlem tamamlandı. Özet ve yedekler: $backupRoot" -ForegroundColor Green if ($removeFailures.Count -gt 0) { Write-Host "`nUYARI: Bazı öğeler silinemedi veya hata verdi. summary.txt ve *.reg dosyalarını kontrol edin." -ForegroundColor Yellow }