PowerShell ile Windows Lisans Yönetimi: slmgr Komutları

Windows ortamlarında lisans yönetimi, özellikle büyük ölçekli dağıtımlarda elle yapılamayacak kadar karmaşık bir hal alıyor. Yüzlerce sunucu veya iş istasyonunun lisans durumunu tek tek kontrol etmek, aktivasyon sorunlarını gidermek ya da KMS altyapısını yönetmek; doğru araçlar olmadan gerçek bir kabus olabiliyor. İşte tam bu noktada PowerShell ile slmgr.vbs kombinasyonu hayat kurtarıcı oluyor. Bu yazıda, Windows lisans yönetimini PowerShell üzerinden nasıl otomatize edeceğini, toplu aktivasyon işlemlerini nasıl yöneteceğini ve üretim ortamlarında işe yarayan gerçek senaryoları ele alacağız.

slmgr Nedir ve Neden PowerShell ile Kullanmalısın?

slmgr.vbs (Software Licensing Manager), Windows’un yerleşik lisans yönetim aracıdır. VBScript tabanlı bu araç, lisans aktivasyonu, KMS yapılandırması, lisans durumu sorgulama gibi işlemleri komut satırından yapmanı sağlar. Tek başına kullanılabilir ama PowerShell ile entegre ettiğinde asıl gücü ortaya çıkıyor.

Neden PowerShell? Çünkü slmgr.vbs‘yi doğrudan çağırabilirsin, çıktıları işleyebilirsin, döngüler yazabilirsin, uzak makinelere bağlanabilirsin ve tüm süreci loglayabilirsin. Ayrıca WMI/CIM üzerinden lisans bilgilerine doğrudan erişim de mümkün. Bu da sana hem slmgr komutlarını hem de daha derin bir sorgu mekanizması sunuyor.

Temel slmgr Parametreleri

Önce slmgr.vbs‘nin temel parametrelerini PowerShell bağlamında nasıl kullandığımıza bakalım. Bu parametreler her Windows yöneticisinin ezbere bilmesi gereken şeyler.

-dli: Temel lisans bilgilerini gösterir. Ürün adı, aktivasyon kimliği, lisans durumu gibi özet bilgiler verir.

-dlv: Detaylı lisans bilgilerini gösterir. KMS sunucu bilgileri, aktivasyon sayaçları, lisans süresi gibi kapsamlı veriler içerir.

-xpr: Lisansın süresini kontrol eder. Makinenin ne zaman yeniden aktivasyon gerektireceğini gösterir.

-ipk: Yeni bir ürün anahtarı yükler. Parametrenin ardından ürün anahtarı belirtilir.

-upk: Mevcut ürün anahtarını kaldırır.

-ato: Aktivasyon işlemini başlatır.

-skms: KMS sunucusunu ve portunu belirler.

-ckms: Yapılandırılmış KMS sunucusunu temizler.

-rearm: Değerlendirme süresini sıfırlar. Dikkatli kullanılmalıdır.

-dti: KMS aktivasyonu için gerekli Kurulum Kimliğini alır.

-atp: Telefon aktivasyonu için Onay Kimliği girer.

Lisans Durumunu Kontrol Etmek

En temel senaryodan başlayalım: Tek bir makinenin lisans durumunu sorgulamak.

# Temel lisans bilgisi
cscript C:WindowsSystem32slmgr.vbs -dli

# Detayli lisans bilgisi
cscript C:WindowsSystem32slmgr.vbs -dlv

# Lisans suresi
cscript C:WindowsSystem32slmgr.vbs -xpr

Bu komutlar bir pencere açarak sonucu gösterir. Ama PowerShell scriptlerinde bunu otomatize etmek için çıktıyı yakalamanız ve işlemeniz gerekir. Bunun için WMI/CIM yolu çok daha temiz:

# WMI uzerinden lisans durumu sorgulama
$LisansBilgisi = Get-WmiObject -Class SoftwareLicensingProduct `
    -Filter "Name like 'Windows%'" | 
    Where-Object { $_.PartialProductKey -ne $null }

foreach ($lisans in $LisansBilgisi) {
    Write-Host "Urun Adi: $($lisans.Name)"
    Write-Host "Aktivasyon Durumu: $($lisans.LicenseStatus)"
    Write-Host "Kismi Anahtar: $($lisans.PartialProductKey)"
    Write-Host "KMS Sunucusu: $($lisans.DiscoveredKeyManagementServiceMachineName)"
    Write-Host "---"
}

LicenseStatus değerleri şu anlama gelir:

  • 0: Lisanssız
  • 1: Lisanslı (Aktif)
  • 2: OOB Grace (Kutu dışı tolerans süresi)
  • 3: OOT Grace (Tolerans süresi dolmak üzere)
  • 4: Non-Genuine Grace (Orijinal olmayan)
  • 5: Bildirim modu
  • 6: Genişletilmiş Grace

Toplu Lisans Durumu Sorgulama Scripti

Gerçek hayatta tek bir makinenin durumunu elle kontrol etmiyorsun. Onlarca, belki yüzlerce sunucuyu kontrol etmen gerekiyor. İşte bunun için kullanabileceğin kapsamlı bir script:

# Toplu lisans kontrolu - makine listesinden okuma
param(
    [string]$MakinelListesi = "C:Scriptssunucular.txt",
    [string]$LogDosyasi = "C:Scriptslisans_raporu_$(Get-Date -Format 'yyyyMMdd').csv"
)

# Durum kodlarini insan okuyabilir formata cevir
function Get-LisansDurumu {
    param([int]$KodDeger)
    switch ($KodDeger) {
        0 { return "Lisanssiz" }
        1 { return "Aktif" }
        2 { return "Grace Suresi (OOB)" }
        3 { return "Grace Suresi Bitmek Uzere" }
        4 { return "Orijinal Degil" }
        5 { return "Bildirim Modu" }
        6 { return "Uzatilmis Grace" }
        default { return "Bilinmiyor ($KodDeger)" }
    }
}

$Sonuclar = @()
$Makineler = Get-Content $MakinelListesi

foreach ($Makine in $Makineler) {
    Write-Host "Kontrol ediliyor: $Makine" -ForegroundColor Cyan
    
    try {
        $LisansVerisi = Get-WmiObject -Class SoftwareLicensingProduct `
            -ComputerName $Makine `
            -Filter "Name like 'Windows%'" `
            -ErrorAction Stop |
            Where-Object { $_.PartialProductKey -ne $null }
        
        foreach ($veri in $LisansVerisi) {
            $Sonuclar += [PSCustomObject]@{
                Makine        = $Makine
                UrunAdi       = $veri.Name
                Durum         = Get-LisansDurumu $veri.LicenseStatus
                KismiAnahtar  = $veri.PartialProductKey
                KMSSunucu     = $veri.DiscoveredKeyManagementServiceMachineName
                KMSPort       = $veri.DiscoveredKeyManagementServiceMachinePort
                SorguZamani   = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
                Hata          = ""
            }
        }
    }
    catch {
        Write-Warning "HATA - $Makine : $($_.Exception.Message)"
        $Sonuclar += [PSCustomObject]@{
            Makine        = $Makine
            UrunAdi       = "N/A"
            Durum         = "Erisim Hatasi"
            KismiAnahtar  = "N/A"
            KMSSunucu     = "N/A"
            KMSPort       = "N/A"
            SorguZamani   = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            Hata          = $_.Exception.Message
        }
    }
}

# CSV olarak kaydet
$Sonuclar | Export-Csv -Path $LogDosyasi -NoTypeInformation -Encoding UTF8
Write-Host "`nRapor kaydedildi: $LogDosyasi" -ForegroundColor Green

# Ozet goster
$Sonuclar | Group-Object Durum | 
    Select-Object Name, Count | 
    Format-Table -AutoSize

Bu script, bir metin dosyasından sunucu isimlerini okur, her birinin lisans durumunu sorgular ve sonuçları CSV dosyasına kaydeder. Haftalık zamanlanmış görev olarak çalıştırdığında lisans altyapının sürekli takibini yapabilirsin.

KMS Yapılandırması ve Yönetimi

Kurumsal ortamlarda büyük ihtimalle KMS (Key Management Service) kullanıyorsunuzdur. KMS yapılandırmasını PowerShell ile yönetmek hem hızlı hem de tutarlı sonuçlar veriyor.

# KMS sunucusunu yapilandir
function Set-KMSYapılandirmasi {
    param(
        [string]$KMSSunucu,
        [int]$Port = 1688,
        [string[]]$HedefMakineler
    )
    
    foreach ($Makine in $HedefMakineler) {
        Write-Host "KMS yapilandiriliyor: $Makine" -ForegroundColor Yellow
        
        try {
            # Uzak makinede KMS sunucusunu ayarla
            $SonucKMS = Invoke-Command -ComputerName $Makine -ScriptBlock {
                param($Sunucu, $PortNo)
                
                # Mevcut KMS temizle
                cscript C:WindowsSystem32slmgr.vbs -ckms | Out-Null
                
                # Yeni KMS sunucusu ayarla
                cscript C:WindowsSystem32slmgr.vbs -skms "$Sunucu`:$PortNo" | Out-Null
                
                # Aktivasyonu baslat
                $AtoSonuc = cscript C:WindowsSystem32slmgr.vbs -ato 2>&1
                
                return $AtoSonuc
            } -ArgumentList $KMSSunucu, $Port -ErrorAction Stop
            
            Write-Host "Basarili: $Makine - $SonucKMS" -ForegroundColor Green
        }
        catch {
            Write-Error "Hata: $Makine - $($_.Exception.Message)"
        }
    }
}

# Kullanim ornegi
$SunucuListesi = @("SUNUCU01", "SUNUCU02", "SUNUCU03")
Set-KMSYapılandirmasi -KMSSunucu "kms.sirket.local" -Port 1688 -HedefMakineler $SunucuListesi

Ürün Anahtarı Yükleme ve Değiştirme

Lisans anahtarı değiştirmek gerektiğinde, özellikle toplu işlemlerde, aşağıdaki yaklaşım çok işe yarıyor. Dikkat: Ürün anahtarlarını script içine düz metin olarak yazma. Güvenli bir yerden oku ya da SecureString kullan.

# Guvenli urun anahtari yukleme
function Install-UrunAnahtari {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Makine,
        [Parameter(Mandatory=$true)]
        [string]$UrunAnahtari
    )
    
    # Anahtar formatini dogrula (XXXXX-XXXXX-XXXXX-XXXXX-XXXXX)
    $AnahtarPattern = '^([A-Z0-9]{5}-){4}[A-Z0-9]{5}$'
    if ($UrunAnahtari -notmatch $AnahtarPattern) {
        Write-Error "Gecersiz anahtar formati: $UrunAnahtari"
        return $false
    }
    
    try {
        $Sonuc = Invoke-Command -ComputerName $Makine -ScriptBlock {
            param($Anahtar)
            
            # Eski anahtari kaldir
            cscript C:WindowsSystem32slmgr.vbs -upk | Out-Null
            Start-Sleep -Seconds 2
            
            # Yeni anahtari yukle
            $YukleSonuc = cscript C:WindowsSystem32slmgr.vbs -ipk $Anahtar 2>&1
            
            # Aktivasyonu baslat
            $AktivasySonuc = cscript C:WindowsSystem32slmgr.vbs -ato 2>&1
            
            return @{
                Yukleme     = $YukleSonuc -join " "
                Aktivasyon  = $AktivasySonuc -join " "
            }
        } -ArgumentList $UrunAnahtari -ErrorAction Stop
        
        Write-Host "Anahtar yuklendi: $Makine" -ForegroundColor Green
        Write-Host "Aktivasyon: $($Sonuc.Aktivasyon)" -ForegroundColor Cyan
        return $true
    }
    catch {
        Write-Error "Anahtar yuklenemedi - $Makine : $($_.Exception.Message)"
        return $false
    }
}

Aktivasyon Sorunlarını Otomatik Giderme

Prodüksiyon ortamında en çok karşılaştığım senaryolardan biri: sabah iş başında bir grup makinenin aktivasyon durumunun bozulmuş olduğunu fark etmek. Bunun için proaktif bir izleme ve otomatik düzeltme scripti kullanıyorum:

# Aktivasyon sorunlarini tespit ve otomatik duzelt
param(
    [string[]]$Makineler,
    [string]$KMSSunucu = "kms.sirket.local",
    [switch]$OtomatikDuzelt,
    [string]$RaporYolu = "C:ScriptsRaporlar"
)

if (-not (Test-Path $RaporYolu)) {
    New-Item -ItemType Directory -Path $RaporYolu | Out-Null
}

$SorunluMakineler = @()
$RaporZamani = Get-Date -Format "yyyyMMdd_HHmmss"

foreach ($Makine in $Makineler) {
    try {
        $LisansBilgi = Get-WmiObject -Class SoftwareLicensingProduct `
            -ComputerName $Makine `
            -Filter "Name like 'Windows%'" |
            Where-Object { $_.PartialProductKey -ne $null }
        
        $Durum = $LisansBilgi.LicenseStatus
        
        if ($Durum -ne 1) {
            Write-Warning "$Makine - Sorunlu durum: $Durum"
            $SorunluMakineler += $Makine
            
            if ($OtomatikDuzelt) {
                Write-Host "Duzeltme deneniyor: $Makine" -ForegroundColor Yellow
                
                Invoke-Command -ComputerName $Makine -ScriptBlock {
                    param($KMS)
                    # KMS sunucusunu yeniden ayarla
                    cscript C:WindowsSystem32slmgr.vbs -ckms | Out-Null
                    cscript C:WindowsSystem32slmgr.vbs -skms $KMS | Out-Null
                    cscript C:WindowsSystem32slmgr.vbs -ato | Out-Null
                    
                    # Lisanslama servisini yeniden baslat
                    Restart-Service -Name "sppsvc" -Force
                    Start-Sleep -Seconds 5
                    cscript C:WindowsSystem32slmgr.vbs -ato | Out-Null
                } -ArgumentList $KMSSunucu
                
                # Duzeltme sonrasinda tekrar kontrol et
                Start-Sleep -Seconds 10
                $YeniDurum = (Get-WmiObject -Class SoftwareLicensingProduct `
                    -ComputerName $Makine `
                    -Filter "Name like 'Windows%'" |
                    Where-Object { $_.PartialProductKey -ne $null }).LicenseStatus
                
                if ($YeniDurum -eq 1) {
                    Write-Host "Duzeltildi: $Makine" -ForegroundColor Green
                    $SorunluMakineler = $SorunluMakineler | Where-Object { $_ -ne $Makine }
                }
                else {
                    Write-Error "Duzeltilemedi: $Makine (Durum: $YeniDurum)"
                }
            }
        }
        else {
            Write-Host "$Makine - OK" -ForegroundColor Green
        }
    }
    catch {
        Write-Error "Erisim hatasi: $Makine - $($_.Exception.Message)"
        $SorunluMakineler += $Makine
    }
}

# Sorunlu makine raporu kaydet
if ($SorunluMakineler.Count -gt 0) {
    $RaporDosyasi = Join-Path $RaporYolu "sorunlu_makineler_$RaporZamani.txt"
    $SorunluMakineler | Out-File -FilePath $RaporDosyasi -Encoding UTF8
    Write-Host "`nSorunlu makine sayisi: $($SorunluMakineler.Count)" -ForegroundColor Red
    Write-Host "Rapor kaydedildi: $RaporDosyasi" -ForegroundColor Yellow
}
else {
    Write-Host "`nTum makineler aktif!" -ForegroundColor Green
}

KMS Sunucu Durumunu İzlemek

KMS sunucunun sağlığını izlemek de kritik bir görev. Yeterli aktivasyon sayısına ulaşılıp ulaşılmadığını ve sunucunun düzgün çalışıp çalışmadığını düzenli kontrol etmelisin:

# KMS sunucu durumu ve aktivasyon sayaci kontrolu
function Get-KMSSunucuDurumu {
    param([string]$KMSSunucu)
    
    try {
        $KMSVerisi = Get-WmiObject -Class SoftwareLicensingProduct `
            -ComputerName $KMSSunucu `
            -Filter "ApplicationId='55c92734-d682-4d71-983e-d6ec3f16059f' AND LicenseIsAddon=False" `
            -ErrorAction Stop
        
        foreach ($urun in $KMSVerisi | Where-Object { $_.LicenseStatus -eq 1 }) {
            Write-Host "=== KMS Sunucu Bilgisi ===" -ForegroundColor Cyan
            Write-Host "Sunucu: $KMSSunucu"
            Write-Host "Urun: $($urun.Name)"
            
            # Mevcut aktivasyon sayisi
            $AktivasyonSayaci = Invoke-Command -ComputerName $KMSSunucu -ScriptBlock {
                $kayit = Get-ItemProperty "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionSoftwareProtectionPlatform" `
                    -ErrorAction SilentlyContinue
                return $kayit
            }
            
            Write-Host "KMS Port: 1688"
            Write-Host "Durum: Aktif"
        }
    }
    catch {
        Write-Error "KMS sunucuya erisim hatasi: $($_.Exception.Message)"
    }
    
    # Portun acik olup olmadigini kontrol et
    $PortKontrol = Test-NetConnection -ComputerName $KMSSunucu -Port 1688 -WarningAction SilentlyContinue
    if ($PortKontrol.TcpTestSucceeded) {
        Write-Host "KMS Port 1688: ACIK" -ForegroundColor Green
    }
    else {
        Write-Host "KMS Port 1688: KAPALI - Guvvenlik duvari kuralini kontrol edin!" -ForegroundColor Red
    }
}

Get-KMSSunucuDurumu -KMSSunucu "kms.sirket.local"

Zamanlanmış Görev ile Otomatik Lisans Takibi

Bu scriptlerin hepsini zamanlanmış görev olarak çalıştırmanı öneririm. Aşağıdaki script, günlük lisans kontrolü için zamanlanmış görev oluşturuyor:

# Zamanlanmis gorev olustur - gunluk lisans kontrolu
$GorevAdi = "GunlukLisansKontrolu"
$ScriptYolu = "C:Scriptslisans_kontrolu.ps1"
$ZamanlanmisZaman = "07:00"

# Gorev ayarlari
$Eylem = New-ScheduledTaskAction `
    -Execute "PowerShell.exe" `
    -Argument "-NonInteractive -NoProfile -ExecutionPolicy Bypass -File `"$ScriptYolu`""

$Tetikleyici = New-ScheduledTaskTrigger `
    -Daily `
    -At $ZamanlanmisZaman

$Ayarlar = New-ScheduledTaskSettingsSet `
    -ExecutionTimeLimit (New-TimeSpan -Hours 2) `
    -RestartCount 3 `
    -RestartInterval (New-TimeSpan -Minutes 10) `
    -StartWhenAvailable

$Eleman = New-ScheduledTaskPrincipal `
    -UserId "DOMAINServiceHesabi" `
    -LogonType Password `
    -RunLevel Highest

# Gorevi kaydet
Register-ScheduledTask `
    -TaskName $GorevAdi `
    -Action $Eylem `
    -Trigger $Tetikleyici `
    -Settings $Ayarlar `
    -Principal $Eleman `
    -Description "Gunluk Windows lisans durum kontrolu ve raporlama" `
    -Force

Write-Host "Zamanlanmis gorev olusturuldu: $GorevAdi" -ForegroundColor Green
Write-Host "Calisma saati: $ZamanlanmisZaman" -ForegroundColor Cyan

Pratik İpuçları ve Dikkat Edilmesi Gerekenler

Yıllarca bu araçlarla çalıştıktan sonra öğrendiğim bazı önemli noktalar var.

WMI yerine CIM tercih et: Yeni ortamlarda Get-WmiObject yerine Get-CimInstance kullanmaya başla. Hem daha hızlı hem de PowerShell 6+ ile uyumlu.

cscript ile çalıştır: slmgr.vbs‘yi her zaman cscript ile çağır, wscript ile değil. wscript GUI penceresi açar, cscript konsola çıktı verir; scriptlerde işlenebilir.

Güvenlik duvarı kurallarını unutma: Uzak makinelerde WMI sorgusu yapabilmek için 135 portunu ve dinamik RPC portlarını açman gerekiyor. Aksi halde “Access Denied” veya timeout hataları alırsın.

Servis hesabı yetkilerini kontrol et: Lisans yönetimi işlemleri için Administrator yetkisi gerekiyor. Uzak makinelerde bu işlemleri yapacak servis hesabının domain admin veya lokal admin olması şart.

rearm işlemini acil durumlar için sakla: slmgr.vbs -rearm komutu değerlendirme süresini uzatır ama sınırlı sayıda kullanılabilir. Bunu rutin bir işlem haline getirme.

Log yönetimini ihmal etme: Lisans değişiklikleri denetim açısından kritik. Her aktivasyon, anahtar değişikliği ve hata mutlaka loglanmalı. Event Log’a da yazmayı düşün:

# Olay gunlugune lisans degisikligini kaydet
function Write-LisansOlayi {
    param(
        [string]$Mesaj,
        [string]$OlayTuru = "Information"
    )
    
    $KaynakAdi = "LisansYonetimi"
    
    if (-not [System.Diagnostics.EventLog]::SourceExists($KaynakAdi)) {
        New-EventLog -LogName Application -Source $KaynakAdi
    }
    
    Write-EventLog -LogName Application `
        -Source $KaynakAdi `
        -EventId 1000 `
        -EntryType $OlayTuru `
        -Message $Mesaj
}

Write-LisansOlayi -Mesaj "KMS aktivasyonu tamamlandi: SUNUCU01" -OlayTuru "Information"

GVLK anahtarlarını bilmek: KMS aktivasyonu için Generic Volume License Key (GVLK) anahtarları gereklidir. Bu anahtarlar Microsoft’un dokümantasyonunda halka açık paylaşılmıştır; üretim anahtarı değildir, sadece KMS aktivasyonunu tetiklemek için kullanılır.

Test ortamında dene: Özellikle toplu anahtar değiştirme veya rearm işlemlerini üretim ortamına uygulamadan önce mutlaka test ortamında dene.

Sonuç

PowerShell ile Windows lisans yönetimi, büyük ölçekli ortamlarda hem zamandan tasarruf sağlıyor hem de tutarlılığı garantiliyor. slmgr.vbs komutlarını PowerShell döngüleriyle, WMI/CIM sorgulamalarıyla ve hata yönetimi mekanizmalarıyla bir araya getirdiğinde; yüzlerce makinenin lisans durumunu dakikalar içinde görebilir, sorunları otomatik olarak düzeltebilir ve tüm süreci izlenebilir hale getirebilirsin.

Bu yazıdaki scriptleri doğrudan kopyalayıp yapıştırma. Kendi ortamına göre uyarla, özellikle KMS sunucu adlarını, makine listelerini ve servis hesaplarını değiştir. Test ortamında çalıştır, logları incele ve ancak ondan sonra prodüksiyona al. Lisans yönetimi kritik bir süreç; otomasyonun faydalarından yararlanırken dikkatli ve sistematik olmak gerekiyor. Herhangi bir adımda takılırsan event log ve slmgr -dlv çıktısı genellikle sana doğru yönü gösterir.

Yorum yapın