PowerShell ile Windows Registry Düzenleme ve Yönetimi

Registry düzenlemesi denince çoğu sysadmin’in aklına hemen regedit.exe gelir. Ama production ortamında yüzlerce makineye aynı registry değişikliğini uygulamanız gerektiğinde, fareyle tıklaya tıklaya saçlarınızın döküleceğini çok geçmeden fark edersiniz. PowerShell, registry yönetimini hem hızlı hem de tekrarlanabilir hale getiren araçlarla dolu. Bu yazıda registry’nin PowerShell ile nasıl yönetileceğini, gerçek dünya senaryolarıyla birlikte ele alacağız.

Registry’yi PowerShell Gözüyle Anlamak

PowerShell, registry’ye dosya sistemi gibi davranır. Bu yaklaşım son derece zekice tasarlanmış çünkü cmdlet’leri zaten biliyorsunuz: Get-Item, Set-Item, New-Item, Remove-Item. Registry sürücüleri (PSDrive) sayesinde HKLM ve HKCU gibi hive’lara doğrudan erişebilirsiniz.

PowerShell’in varsayılan olarak tanımladığı registry sürücülerini görmek için:

Get-PSDrive -PSProvider Registry

Bu komut size HKLM (HKEY_LOCAL_MACHINE) ve HKCU (HKEY_CURRENT_USER) sürücülerini gösterir. Fakat dikkat, HKEY_CLASSES_ROOT, HKEY_USERS ve HKEY_CURRENT_CONFIG gibi hive’lara erişmek için bunları önce mount etmeniz gerekir:

New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT
New-PSDrive -Name HKU  -PSProvider Registry -Root HKEY_USERS

Bu sürücüler PowerShell oturumu kapandığında kaybolur. Kalıcı olmasını istiyorsanız -Persist parametresini ekleyin.

Temel Registry Okuma İşlemleri

Key ve Value Okumak

Bir registry key’ini listelemek için Get-Item kullanırsınız. Ama dikkat, Get-Item key’i döndürür, içindeki value’ları değil. Value’ları okumak için ya Get-ItemProperty ya da Get-ItemPropertyValue tercih edilir.

# Bir key'in tüm property'lerini oku
Get-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersion"

# Sadece belirli bir value'yu oku
Get-ItemPropertyValue -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersion" -Name "ProductName"

# Bir key altındaki tüm subkey'leri listele
Get-ChildItem -Path "HKLM:SOFTWAREMicrosoftWindowsCurrentVersionRun"

Gerçek dünyada sıkça kullanılan bir senaryo: Domain’deki tüm makinelerde hangi uygulamaların “Run” key’ine eklendiğini kontrol etmek. Birisi izinsiz bir şey eklemiş mi? Hemen anlarsınız.

Registry Value Tiplerini Anlamak

Registry’de farklı veri tipleri var ve PowerShell bu tipleri doğru şekilde yönetmenizi bekliyor:

  • String (REG_SZ): Normal metin değerleri
  • ExpandString (REG_EXPAND_SZ): %SystemRoot% gibi ortam değişkeni içeren değerler
  • Binary (REG_BINARY): Ham binary veri
  • DWord (REG_DWORD): 32-bit integer
  • QWord (REG_QWORD): 64-bit integer
  • MultiString (REG_MULTI_SZ): Çok satırlı string dizisi

Değer Yazma ve Güncelleme

Yeni Değer Oluşturmak

New-ItemProperty cmdlet’i yeni bir registry value oluşturur. Tip belirtmezseniz PowerShell bunu String olarak oluşturur, bu yüzden her zaman -PropertyType parametresini kullanın:

# Basit string değer ekle
New-ItemProperty -Path "HKLM:SOFTWAREMyApp" `
    -Name "InstallPath" `
    -Value "C:Program FilesMyApp" `
    -PropertyType String `
    -Force

# DWORD değer ekle (örneğin bir feature flag)
New-ItemProperty -Path "HKLM:SOFTWAREMyApp" `
    -Name "EnableFeatureX" `
    -Value 1 `
    -PropertyType DWord `
    -Force

-Force parametresi çok önemli: Key yoksa oluşturur, value zaten varsa üzerine yazar. Bunu kullanmazsanız var olan değerde hata alırsınız.

Mevcut Değeri Güncellemek

# Var olan değeri güncelle
Set-ItemProperty -Path "HKLM:SOFTWAREMyApp" `
    -Name "Version" `
    -Value "2.1.0"

# Çoklu değerleri tek seferde güncelle
$settings = @{
    "EnableLogging" = 1
    "LogLevel"      = "Verbose"
    "MaxRetry"      = 3
}

foreach ($key in $settings.Keys) {
    Set-ItemProperty -Path "HKLM:SOFTWAREMyAppSettings" `
        -Name $key `
        -Value $settings[$key]
}

Key Oluşturma ve Silme

Yeni Key Oluşturmak

New-Item cmdlet’i registry key oluşturur. İç içe geçmiş key’leri oluştururken dikkatli olun; üst key yoksa hata alırsınız:

# Tek key oluştur
New-Item -Path "HKLM:SOFTWAREMyCompany" -Force

# İç içe key'leri tek seferde oluştur
New-Item -Path "HKLM:SOFTWAREMyCompanyMyAppSettings" -Force

# Key oluştur ve hemen value ekle
New-Item -Path "HKLM:SOFTWAREMyCompanyMyApp" -Force |
    New-ItemProperty -Name "Version" -Value "1.0" -PropertyType String

Key ve Value Silmek

# Bir value'yu sil
Remove-ItemProperty -Path "HKLM:SOFTWAREMyApp" -Name "OldSetting"

# Bir key'i ve içindeki her şeyi sil
Remove-Item -Path "HKLM:SOFTWAREMyAppOldFeature" -Recurse -Force

# Birden fazla value'yu sil
"Setting1", "Setting2", "Setting3" | ForEach-Object {
    Remove-ItemProperty -Path "HKLM:SOFTWAREMyApp" -Name $_ -ErrorAction SilentlyContinue
}

Gerçek Dünya Senaryosu 1: Toplu Makine Konfigürasyonu

Diyelim ki 50 Windows Server’da IE Enhanced Security Configuration’ı devre dışı bırakmanız gerekiyor. Bu klasik bir senaryo ve elle yapmak saatler alır.

$servers = Get-Content "C:servers.txt"
$adminIESCPath = "HKLM:SOFTWAREMicrosoftActive SetupInstalled Components{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}"
$userIESCPath  = "HKLM:SOFTWAREMicrosoftActive SetupInstalled Components{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}"

foreach ($server in $servers) {
    try {
        Invoke-Command -ComputerName $server -ScriptBlock {
            param($adminPath, $userPath)
            
            # Admin için IESC kapat
            Set-ItemProperty -Path $adminPath -Name "IsInstalled" -Value 0 -Type DWord
            # User için IESC kapat
            Set-ItemProperty -Path $userPath -Name "IsInstalled" -Value 0 -Type DWord
            
            Write-Host "[$env:COMPUTERNAME] IESC devre disi birakildi" -ForegroundColor Green
        } -ArgumentList $adminIESCPath, $userIESCPath -ErrorAction Stop
    }
    catch {
        Write-Warning "[$server] Hata: $($_.Exception.Message)"
    }
}

Bu script, Invoke-Command ile remote makinelerde registry değişikliği yapıyor. WinRM’in aktif olduğundan emin olun tabii.

Gerçek Dünya Senaryosu 2: Registry Backup ve Restore

Production’da değişiklik yapmadan önce her zaman backup alın. PowerShell ile registry export/import işlemi:

function Backup-RegistryKey {
    param(
        [string]$KeyPath,
        [string]$BackupFolder = "C:RegBackups"
    )
    
    # Backup klasörü yoksa oluştur
    if (-not (Test-Path $BackupFolder)) {
        New-Item -ItemType Directory -Path $BackupFolder | Out-Null
    }
    
    # Tarihli backup dosyası oluştur
    $timestamp  = Get-Date -Format "yyyyMMdd_HHmmss"
    $keyName    = ($KeyPath -split "\")[-1]
    $backupFile = Join-Path $BackupFolder "$keyName`_$timestamp.reg"
    
    # reg.exe ile export al (PowerShell'in native export'undan daha güvenilir)
    $regPath = $KeyPath -replace "HKLM:\", "HKEY_LOCAL_MACHINE" `
                        -replace "HKCU:\", "HKEY_CURRENT_USER"
    
    reg export $regPath $backupFile /y 2>&1
    
    if ($LASTEXITCODE -eq 0) {
        Write-Host "Backup alindi: $backupFile" -ForegroundColor Green
        return $backupFile
    } else {
        Write-Error "Backup alinamadi!"
        return $null
    }
}

# Kullanim
$backupFile = Backup-RegistryKey -KeyPath "HKLM:SOFTWAREMyApp"

# Restore etmek icin
# reg import $backupFile

Registry’de Arama Yapmak

Registry içinde belirli bir değer veya key aramak için Get-ChildItem ile recursive gezinme kullanılır. Ama dikkat, bu işlem çok yavaş olabilir, özellikle HKLM’nin tamamında arama yapıyorsanız:

function Search-Registry {
    param(
        [string]$StartPath,
        [string]$SearchValue,
        [switch]$SearchInNames,
        [switch]$SearchInValues
    )
    
    Get-ChildItem -Path $StartPath -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
        $key = $_
        
        try {
            $properties = Get-ItemProperty -Path $key.PSPath -ErrorAction SilentlyContinue
            
            if ($properties) {
                $properties.PSObject.Properties | Where-Object {
                    $_.Name -notmatch "^PS" # Built-in PS property'leri atla
                } | ForEach-Object {
                    $match = $false
                    
                    if ($SearchInNames -and $_.Name -like "*$SearchValue*") {
                        $match = $true
                    }
                    if ($SearchInValues -and $_.Value -like "*$SearchValue*") {
                        $match = $true
                    }
                    
                    if ($match) {
                        [PSCustomObject]@{
                            KeyPath  = $key.PSPath
                            Name     = $_.Name
                            Value    = $_.Value
                        }
                    }
                }
            }
        }
        catch { }
    }
}

# Belirli bir uygulamanin kurulum yolunu ara
Search-Registry -StartPath "HKLM:SOFTWARE" `
    -SearchValue "MyApp" `
    -SearchInNames `
    -SearchInValues

Registry ACL Yönetimi

Registry key’lerinde yetki yönetimi de bazen gerekli olur. Özellikle uygulamaların registry’ye yazabilmesi için gereken izinleri PowerShell ile ayarlayabilirsiniz:

# Mevcut ACL'yi gör
$acl = Get-Acl -Path "HKLM:SOFTWAREMyApp"
$acl.Access | Select-Object IdentityReference, RegistryRights, AccessControlType

# Yeni izin ekle (örneğin "DOMAINAppServiceAccount" hesabına okuma/yazma)
$acl = Get-Acl -Path "HKLM:SOFTWAREMyApp"

$identity = "DOMAINAppServiceAccount"
$rights   = [System.Security.AccessControl.RegistryRights]::ReadKey -bor `
            [System.Security.AccessControl.RegistryRights]::WriteKey

$inheritanceFlags  = [System.Security.AccessControl.InheritanceFlags]::ContainerInherit
$propagationFlags  = [System.Security.AccessControl.PropagationFlags]::None
$type              = [System.Security.AccessControl.AccessControlType]::Allow

$rule = New-Object System.Security.AccessControl.RegistryAccessRule(
    $identity, $rights, $inheritanceFlags, $propagationFlags, $type
)

$acl.SetAccessRule($rule)
Set-Acl -Path "HKLM:SOFTWAREMyApp" -AclObject $acl

Write-Host "Registry izni basariyla ayarlandi." -ForegroundColor Green

Gerçek Dünya Senaryosu 3: Registry ile Uygulama Envanteri

Kurulu uygulamaların listesini çıkarmak, özellikle lisanslama ve güvenlik audit’leri için kritik. Windows, kurulu uygulamaları birkaç farklı registry path’inde tutar:

function Get-InstalledSoftware {
    param(
        [string[]]$ComputerName = $env:COMPUTERNAME
    )
    
    $uninstallPaths = @(
        "HKLM:SOFTWAREMicrosoftWindowsCurrentVersionUninstall*",
        "HKLM:SOFTWAREWOW6432NodeMicrosoftWindowsCurrentVersionUninstall*"
    )
    
    foreach ($computer in $ComputerName) {
        if ($computer -eq $env:COMPUTERNAME) {
            foreach ($path in $uninstallPaths) {
                Get-ItemProperty -Path $path -ErrorAction SilentlyContinue |
                    Where-Object { $_.DisplayName } |
                    Select-Object @{N="Computer";E={$computer}},
                                  DisplayName,
                                  DisplayVersion,
                                  Publisher,
                                  InstallDate
            }
        } else {
            Invoke-Command -ComputerName $computer -ScriptBlock {
                param($paths)
                foreach ($path in $paths) {
                    Get-ItemProperty -Path $path -ErrorAction SilentlyContinue |
                        Where-Object { $_.DisplayName } |
                        Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
                }
            } -ArgumentList (, $uninstallPaths) |
                Select-Object @{N="Computer";E={$computer}},
                              DisplayName, DisplayVersion, Publisher, InstallDate
        }
    }
}

# Tum sunucularda kurulu yazilim envanteri al
$servers  = "Server01", "Server02", "Server03"
$software = Get-InstalledSoftware -ComputerName $servers
$software | Export-Csv -Path "C:ReportsSoftwareInventory.csv" -NoTypeInformation -Encoding UTF8

Write-Host "Toplam $($software.Count) uygulama kaydi bulundu." -ForegroundColor Cyan

Registry ile Windows Ayarlarını Otomatize Etmek

Sık yapılan Windows güvenlik ayarlarını registry üzerinden otomatize eden bir script:

function Set-WindowsHardening {
    param(
        [switch]$WhatIf
    )
    
    $settings = @(
        # SMBv1'i devre disi birak
        @{
            Path  = "HKLM:SYSTEMCurrentControlSetServicesLanmanServerParameters"
            Name  = "SMB1"
            Value = 0
            Type  = "DWord"
            Desc  = "SMBv1 devre disi"
        },
        # RDP Network Level Authentication
        @{
            Path  = "HKLM:SYSTEMCurrentControlSetControlTerminal ServerWinStationsRDP-Tcp"
            Name  = "UserAuthentication"
            Value = 1
            Type  = "DWord"
            Desc  = "NLA zorunlu kilindi"
        },
        # Autorun devre disi
        @{
            Path  = "HKLM:SOFTWAREMicrosoftWindowsCurrentVersionPoliciesExplorer"
            Name  = "NoDriveTypeAutoRun"
            Value = 255
            Type  = "DWord"
            Desc  = "Autorun devre disi"
        }
    )
    
    foreach ($setting in $settings) {
        if ($WhatIf) {
            Write-Host "[WhatIf] $($setting.Desc) uygulanacak: $($setting.Path)" -ForegroundColor Yellow
            continue
        }
        
        try {
            # Key yoksa olustur
            if (-not (Test-Path $setting.Path)) {
                New-Item -Path $setting.Path -Force | Out-Null
            }
            
            Set-ItemProperty -Path $setting.Path `
                             -Name $setting.Name `
                             -Value $setting.Value `
                             -Type $setting.Type `
                             -ErrorAction Stop
            
            Write-Host "[OK] $($setting.Desc)" -ForegroundColor Green
        }
        catch {
            Write-Warning "[HATA] $($setting.Desc): $($_.Exception.Message)"
        }
    }
}

# Once WhatIf ile test et
Set-WindowsHardening -WhatIf

# Sonra gercekten uygula
# Set-WindowsHardening

Registry Değişikliklerini İzlemek

Kritik registry key’lerinde yapılan değişiklikleri gerçek zamanlı izlemek için WMI veya FileSystemWatcher‘ın registry muadili olan RegistryKey.OpenSubKey ile monitoring yapabilirsiniz. Basit ama etkili bir yöntem şöyle:

function Watch-RegistryKey {
    param(
        [string]$KeyPath = "HKLM:SOFTWAREMyApp",
        [int]$IntervalSeconds = 30,
        [int]$Duration = 300
    )
    
    $snapshot = @{}
    $endTime  = (Get-Date).AddSeconds($Duration)
    
    Write-Host "Registry izleme basliyor: $KeyPath" -ForegroundColor Cyan
    Write-Host "Sure: $Duration saniye, Kontrol araligi: $IntervalSeconds saniye`n"
    
    while ((Get-Date) -lt $endTime) {
        $current = Get-ItemProperty -Path $KeyPath -ErrorAction SilentlyContinue
        
        if ($current) {
            $current.PSObject.Properties | Where-Object { $_.Name -notmatch "^PS" } | ForEach-Object {
                $name  = $_.Name
                $value = $_.Value
                
                if ($snapshot.ContainsKey($name)) {
                    if ($snapshot[$name] -ne $value) {
                        $changeTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
                        Write-Warning "[$changeTime] DEGISIKLIK TESPIT EDILDI!"
                        Write-Host "  Key  : $KeyPath" -ForegroundColor Red
                        Write-Host "  Name : $name" -ForegroundColor Red
                        Write-Host "  Eski : $($snapshot[$name])" -ForegroundColor Yellow
                        Write-Host "  Yeni : $value" -ForegroundColor Green
                    }
                }
                $snapshot[$name] = $value
            }
        }
        
        Start-Sleep -Seconds $IntervalSeconds
    }
    
    Write-Host "`nIzleme tamamlandi." -ForegroundColor Cyan
}

Watch-RegistryKey -KeyPath "HKLM:SOFTWAREMyApp" -IntervalSeconds 10 -Duration 600

Dikkat Edilmesi Gereken Noktalar

Registry ile çalışırken bazı tuzaklardan kaçınmak gerekir:

  • 64-bit vs 32-bit: 64-bit Windows’ta 32-bit uygulamalar HKLM:SOFTWAREWOW6432Node altına yazılır. Hangi uygulamaya hitap ettiğinizi bilin.
  • Yetki sorunları: HKLM altındaki bazı key’ler için Administrator yetkisi gerekir. Script’lerinizi “Run as Administrator” ile çalıştırın.
  • Remote Registry servisi: Uzak makinelerde Invoke-Command yerine doğrudan HKLM path’i kullanıyorsanız Remote Registry servisinin çalışıyor olması lazım.
  • Test Et, Sonra Uygula: -WhatIf ve -Confirm parametrelerini kullanın. Production’da deneme yanılma yapamazsınız.
  • Backup: Her değişiklikten önce backup alın. Yukarıdaki Backup-RegistryKey fonksiyonunu kullanma alışkanlığı edinin.
  • ErrorAction: Registry’de olmayan bir path okumaya çalışmak hata fırlatır. ErrorAction SilentlyContinue veya Test-Path ile kontrol edin.

Sonuç

PowerShell ile registry yönetimi, başlangıçta karmaşık görünse de temelde dosya sistemi mantığına benziyor. Get-Item, Set-Item, New-Item, Remove-Item gibi bildiğiniz cmdlet’leri zaten kullanıyorsunuz. Asıl güç, bu işlemleri scriptlerle otomatize edip onlarca veya yüzlerce makineye aynı anda uygulayabilmekten geliyor.

Gerçek hayatta en çok kullandığım senaryolar şunlar: toplu güvenlik hardening, uygulama envanteri çıkarma, deploy sonrası konfigürasyon doğrulama ve audit amaçlı registry snapshot alma. Bu yazıdaki fonksiyonları kendi ortamınıza uyarlayıp iç toolbox’ınıza ekleyebilirsiniz.

Son olarak şunu hatırlatmakta fayda var: Registry, Windows’un kalbidir. Yanlış bir değişiklik sistemi kullanılamaz hale getirebilir. Her zaman backup alın, önce test ortamında deneyin ve değişikliklerinizi dokümante edin. PowerShell’in gücünü sorumlu şekilde kullandığınızda, registry yönetimi artık korkulacak bir şey olmaktan çıkıp elinizin altındaki güçlü bir araca dönüşür.

Yorum yapın