PowerShell ile Yazıcı Yönetimi ve Sorun Giderme

Yazıcı yönetimi, sysadmin’lerin en çok zaman harcadığı konulardan biri olmasa da en çok baş ağrıtan konuların kesinlikle başında gelir. “Yazıcı çalışmıyor” şikayeti ofiste panik yaratır, kullanıcılar sinirlenmiştir ve genellikle sabahın erken saatlerinde gelir. PowerShell, bu kaotik anlarda sizi kurtarabilecek güçlü bir araçtır. Hem günlük yönetim işlerini otomatize edebilir, hem de sorun gidermeyi çok daha hızlı yapabilirsiniz. Bu yazıda gerçek dünya senaryoları üzerinden PowerShell ile yazıcı yönetimini ele alacağız.

Temel Kavramlar ve Gereksinimler

PowerShell ile yazıcı yönetimi için iki temel modül kullanırız:

  • PrintManagement modülü: Windows 8/Server 2012 ile birlikte geldi, modern yazıcı yönetiminin ana aracı
  • WMI/CIM sınıfları: Eski sistemlerle uyumluluk gerektiğinde başvurduğumuz yöntem

PrintManagement modülünün yüklü olup olmadığını kontrol etmekle başlayalım:

# Modül kontrolü
Get-Module -ListAvailable -Name PrintManagement

# Modülü yükle (gerekirse)
Import-Module PrintManagement

# Mevcut cmdlet'leri listele
Get-Command -Module PrintManagement

Eğer uzak bir sunucuyu veya print server’ı yönetiyorsanız, PowerShell remoting aktif olmalı. Ayrıca “Print and Document Services” rolü kurulu bir Windows Server üzerinde çalışıyorsanız tüm özellikler kullanılabilir durumdadır.

Yazıcıları Listeleme ve Bilgi Alma

En temel işlemden başlayalım. Sunucudaki tüm yazıcıları listelemek için:

# Tüm yazıcıları listele
Get-Printer

# Belirli bir yazıcı hakkında detaylı bilgi
Get-Printer -Name "HP_LaserJet_4015" | Format-List *

# Sadece belirli özellikleri göster
Get-Printer | Select-Object Name, DriverName, PortName, PrinterStatus, Shared, ShareName

# Uzak sunucudaki yazıcıları listele
Get-Printer -ComputerName "PRINTSERVER01"

# Paylaşılan yazıcıları filtrele
Get-Printer | Where-Object { $_.Shared -eq $true }

# Offline veya sorunlu yazıcıları bul
Get-Printer | Where-Object { $_.PrinterStatus -ne "Normal" }

Gerçek dünyada en sık ihtiyaç duyduğum şeylerden biri, tüm print server’lardaki yazıcıların durumunu tek seferde görmek. Şöyle bir şey yazabilirsiniz:

# Birden fazla print server'daki yazıcı durumlarını raporla
$printServers = @("PRINTSERVER01", "PRINTSERVER02", "PRINTSERVER03")

$allPrinters = foreach ($server in $printServers) {
    Get-Printer -ComputerName $server | Select-Object Name, 
        @{Name="Server"; Expression={$server}},
        PrinterStatus, 
        Shared, 
        ShareName,
        DriverName
}

$allPrinters | Where-Object { $_.PrinterStatus -ne "Normal" } | 
    Format-Table -AutoSize

# Sonuçları CSV'ye aktar
$allPrinters | Export-Csv -Path "C:RaporlarYaziciDurumu_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding UTF8

Bu scripti her sabah çalışacak şekilde Task Scheduler’a eklerseniz, güne yazıcı sorunlarına hazırlıklı başlarsınız.

Yazıcı Sürücüleri Yönetimi

Yazıcı sorunlarının büyük çoğunluğu sürücüden kaynaklanır. Sürücüleri yönetmek için şu komutları kullanabilirsiniz:

# Yüklü tüm yazıcı sürücülerini listele
Get-PrinterDriver

# Belirli bir sürücünün detaylarına bak
Get-PrinterDriver -Name "HP Universal Printing PCL 6" | Format-List *

# Uzak sunucudaki sürücüleri listele
Get-PrinterDriver -ComputerName "PRINTSERVER01"

# Yeni sürücü ekle (sürücü INF dosyasının olduğu klasörden)
Add-PrinterDriver -Name "HP Universal Printing PCL 6 (v6.7.0)" -InfPath "C:DriversHPhpcu270u.inf"

# Sürücüyü kaldır
Remove-PrinterDriver -Name "HP LaserJet 4 Plus/4M Plus PS"

# Sürücü deposunu listele
Get-PrinterDriver | Select-Object Name, DriverVersion, PrinterEnvironment | Sort-Object Name

Büyük ortamlarda sürücü versiyonlarını takip etmek başlı başına bir iş haline gelir. Şöyle bir kontrol scripti işe yarar:

# Tüm sunuculardaki sürücü versiyonlarını karşılaştır
$printServers = @("PRINTSERVER01", "PRINTSERVER02")
$referenceServer = "PRINTSERVER01"

$refDrivers = Get-PrinterDriver -ComputerName $referenceServer | 
    Select-Object Name, DriverVersion

foreach ($server in $printServers | Where-Object { $_ -ne $referenceServer }) {
    $serverDrivers = Get-PrinterDriver -ComputerName $server | 
        Select-Object Name, DriverVersion
    
    $comparison = Compare-Object -ReferenceObject $refDrivers -DifferenceObject $serverDrivers -Property Name, DriverVersion
    
    if ($comparison) {
        Write-Host "FARK BULUNDU: $server - $referenceServer arasinda:" -ForegroundColor Yellow
        $comparison | Format-Table
    } else {
        Write-Host "$server - Suruculer eslesıyor." -ForegroundColor Green
    }
}

Yazıcı Port Yönetimi

IP tabanlı yazıcı portları yanlış yapılandırıldığında yazıcı görünür ama iş gönderilemez. Port yönetimi için:

# Tüm portları listele
Get-PrinterPort

# Sadece TCP/IP portlarını filtrele
Get-PrinterPort | Where-Object { $_.Description -like "*TCP*" }

# Yeni TCP/IP port ekle
Add-PrinterPort -Name "IP_192.168.10.50" -PrinterHostAddress "192.168.10.50"

# Port sil
Remove-PrinterPort -Name "IP_192.168.10.99"

# Port bilgilerini detaylı gör
Get-PrinterPort -Name "IP_192.168.10.50" | Format-List *

Gerçek dünya senaryosu: Şirkette 50 yazıcının IP adresi değişti ve hepsinin portunu tek tek güncellemek gerekiyor. Elle yapmak yerine şöyle bir script çalıştırabilirsiniz:

# IP değişikliklerini toplu uygula - CSV'den oku
# CSV formatı: EskiIP, YeniIP, YaziciAdi

$degisiklikler = Import-Csv -Path "C:ip_degisiklikleri.csv" -Encoding UTF8

foreach ($kayit in $degisiklikler) {
    $eskiPort = "IP_$($kayit.EskiIP)"
    $yeniPort = "IP_$($kayit.YeniIP)"
    
    try {
        # Yeni port oluştur
        Add-PrinterPort -Name $yeniPort -PrinterHostAddress $kayit.YeniIP -ErrorAction Stop
        
        # Yazıcıyı yeni porta ata
        Set-Printer -Name $kayit.YaziciAdi -PortName $yeniPort -ErrorAction Stop
        
        # Eski portu sil
        Remove-PrinterPort -Name $eskiPort -ErrorAction SilentlyContinue
        
        Write-Host "BASARILI: $($kayit.YaziciAdi) - $($kayit.EskiIP) -> $($kayit.YeniIP)" -ForegroundColor Green
    }
    catch {
        Write-Host "HATA: $($kayit.YaziciAdi) - $($_.Exception.Message)" -ForegroundColor Red
    }
}

Yazıcı Kurulumu ve Kaldırma

Toplu yazıcı kurulumu, özellikle yeni ofis açılışlarında veya sunucu geçişlerinde kritik öneme sahip:

# Temel yazıcı kurulumu
Add-Printer -Name "Muhasebe_HP4015" `
            -DriverName "HP LaserJet P4015 PCL6" `
            -PortName "IP_192.168.1.100" `
            -Shared `
            -ShareName "MuhasebeHP" `
            -Comment "Muhasebe departmani ana yazicisi" `
            -Location "Kat 2, Oda 201"

# Yazıcıyı kaldır
Remove-Printer -Name "Muhasebe_HP4015"

# Mevcut yazıcı ayarlarını güncelle
Set-Printer -Name "Muhasebe_HP4015" `
            -Comment "Muhasebe - yonetici onayladi" `
            -Location "Kat 2, Oda 205"

Toplu kurulum senaryosu için şu script işe yarar. Diyelim ki yeni bir ofis açıyorsunuz ve 20 yazıcı kuracaksınız:

# Toplu yazıcı kurulum scripti
# Gerekli sürücülerin önceden yüklenmiş olduğu varsayılır

$yazicilar = @(
    @{Ad="Recepsiyon_Canon"; IP="192.168.5.10"; Surucu="Canon Generic Plus UFR II"; Paylasim="Recepsiyon"},
    @{Ad="Toplanti_A_HP"; IP="192.168.5.11"; Surucu="HP Universal Printing PCL 6"; Paylasim="TopantiA"},
    @{Ad="BT_Xerox"; IP="192.168.5.20"; Surucu="Xerox Global Print Driver PCL6"; Paylasim="BT_Yazici"}
)

$hatalar = @()
$basarilar = @()

foreach ($yazici in $yazicilar) {
    $portAdi = "IP_$($yazici.IP)"
    
    try {
        # Port yoksa oluştur
        if (-not (Get-PrinterPort -Name $portAdi -ErrorAction SilentlyContinue)) {
            Add-PrinterPort -Name $portAdi -PrinterHostAddress $yazici.IP
            Write-Host "Port olusturuldu: $portAdi" -ForegroundColor Cyan
        }
        
        # Yazıcıyı kur
        Add-Printer -Name $yazici.Ad `
                    -DriverName $yazici.Surucu `
                    -PortName $portAdi `
                    -Shared `
                    -ShareName $yazici.Paylasim `
                    -ErrorAction Stop
        
        $basarilar += $yazici.Ad
        Write-Host "KURULDU: $($yazici.Ad)" -ForegroundColor Green
    }
    catch {
        $hatalar += "$($yazici.Ad): $($_.Exception.Message)"
        Write-Host "HATA: $($yazici.Ad) - $($_.Exception.Message)" -ForegroundColor Red
    }
}

# Özet rapor
Write-Host "`n=== KURULUM OZETI ===" -ForegroundColor Yellow
Write-Host "Basarili: $($basarilar.Count)" -ForegroundColor Green
Write-Host "Hatali: $($hatalar.Count)" -ForegroundColor Red
if ($hatalar.Count -gt 0) {
    $hatalar | ForEach-Object { Write-Host "  - $_" -ForegroundColor Red }
}

Print Queue Yönetimi ve Sorun Giderme

Takılı kalan print job’lar, sysadmin’in en sevmediği konulardan biri. Bazen Spooler servisi tamamen donmuş olur:

# Print queue'daki işleri listele
Get-PrintJob -PrinterName "Muhasebe_HP4015"

# Tüm yazıcılardaki bekleyen işleri gör
Get-Printer | ForEach-Object {
    $jobs = Get-PrintJob -PrinterName $_.Name
    if ($jobs) {
        Write-Host "`nYazici: $($_.Name)" -ForegroundColor Yellow
        $jobs | Select-Object Id, DocumentName, UserName, JobStatus, Size, SubmittedTime | Format-Table
    }
}

# Belirli bir işi sil
Remove-PrintJob -PrinterName "Muhasebe_HP4015" -ID 3

# Bir yazıcının tüm queue'sunu temizle
Get-PrintJob -PrinterName "Muhasebe_HP4015" | Remove-PrintJob

# Tüm yazıcıların queue'larını temizle (dikkatli kullanın!)
Get-Printer | ForEach-Object {
    Get-PrintJob -PrinterName $_.Name | Remove-PrintJob
    Write-Host "Temizlendi: $($_.Name)"
}

Spooler servisi tamamen yanıt vermez hale geldiğinde kullandığım klasik sorun giderme scripti:

# Yazici Spooler tamamen yeniden baslatma scripti
# Takili kalmis print joblar icin

function Reset-PrintSpooler {
    param (
        [string]$ComputerName = $env:COMPUTERNAME,
        [switch]$ClearJobs
    )
    
    Write-Host "[$ComputerName] Spooler yeniden baslatiliyor..." -ForegroundColor Yellow
    
    try {
        # Spooler'i durdur
        $spooler = Get-Service -Name Spooler -ComputerName $ComputerName
        Stop-Service -InputObject $spooler -Force
        Start-Sleep -Seconds 3
        
        if ($ClearJobs) {
            # Spooler klasorunu temizle
            $spoolPath = "\$ComputerNameC$WindowsSystem32spoolPRINTERS"
            
            if (Test-Path $spoolPath) {
                $dosyalar = Get-ChildItem -Path $spoolPath -File
                $dosyalar | Remove-Item -Force
                Write-Host "[$ComputerName] $($dosyalar.Count) dosya silindi." -ForegroundColor Cyan
            }
        }
        
        # Spooler'i başlat
        Start-Service -InputObject $spooler
        Start-Sleep -Seconds 2
        
        $durum = (Get-Service -Name Spooler -ComputerName $ComputerName).Status
        Write-Host "[$ComputerName] Spooler durumu: $durum" -ForegroundColor Green
        
        return $true
    }
    catch {
        Write-Host "[$ComputerName] HATA: $($_.Exception.Message)" -ForegroundColor Red
        return $false
    }
}

# Kullanım örnekleri
Reset-PrintSpooler
Reset-PrintSpooler -ComputerName "PRINTSERVER01" -ClearJobs

Yazıcı İzinleri ve Güvenlik Yönetimi

Hangi kullanıcının hangi yazıcıyı kullanabileceği, büyük ortamlarda önemli bir konu:

# Yazıcı ACL bilgisini al
$yaziciAdi = "Muhasebe_HP4015"
$yazici = Get-Printer -Name $yaziciAdi -Full
$yazici.PermissionSDDL

# Mevcut izinleri daha okunabilir formatta görüntüle
$sd = New-Object System.Security.AccessControl.RawSecurityDescriptor($yazici.PermissionSDDL)
$sd.DiscretionaryAcl | ForEach-Object {
    $sid = $_.SecurityIdentifier
    try {
        $hesap = $sid.Translate([System.Security.Principal.NTAccount])
        Write-Host "$($hesap.Value) - Maske: $($_.AccessMask)"
    }
    catch {
        Write-Host "$sid - Maske: $($_.AccessMask)"
    }
}

Yazıcı Konfigürasyonunu Yedekleme ve Geri Yükleme

Sunucu geçişlerinde veya felaket kurtarma senaryolarında hayat kurtaran script:

# Tüm yazıcı konfigürasyonunu yedekle
function Backup-PrinterConfig {
    param (
        [string]$ComputerName = $env:COMPUTERNAME,
        [string]$YedekKlasoru = "C:PrinterBackup"
    )
    
    $tarih = Get-Date -Format "yyyyMMdd_HHmm"
    $yedekDizin = "$YedekKlasoru$ComputerName$tarih"
    New-Item -ItemType Directory -Path $yedekDizin -Force | Out-Null
    
    # Yazıcıları yedekle
    Get-Printer -ComputerName $ComputerName | 
        Export-Clixml -Path "$yedekDizinYazicilar.xml"
    
    # Sürücüleri yedekle
    Get-PrinterDriver -ComputerName $ComputerName | 
        Export-Clixml -Path "$yedekDizinSuruculer.xml"
    
    # Portları yedekle
    Get-PrinterPort -ComputerName $ComputerName | 
        Export-Clixml -Path "$yedekDizinPortlar.xml"
    
    Write-Host "Yedek alindi: $yedekDizin" -ForegroundColor Green
    
    # Yedek özeti
    $yaziciSayisi = (Import-Clixml "$yedekDizinYazicilar.xml").Count
    $surucuSayisi = (Import-Clixml "$yedekDizinSuruculer.xml").Count
    $portSayisi = (Import-Clixml "$yedekDizinPortlar.xml").Count
    
    Write-Host "Yedeklenen: $yaziciSayisi yazici, $surucuSayisi surucu, $portSayisi port" -ForegroundColor Cyan
}

Backup-PrinterConfig -ComputerName "PRINTSERVER01" -YedekKlasoru "D:YedeklerYazici"

Monitoring ve Otomatik Uyarı

Yazıcı sorunlarını kullanıcılar bildirmeden önce fark etmek, iyi bir sysadmin’in hedefidir:

# Yazıcı durum monitoring scripti - Task Scheduler ile her 15 dakikada bir calistir
$printServers = @("PRINTSERVER01", "PRINTSERVER02")
$emailGonderici = "[email protected]"
$emailAlici = "[email protected]"
$smtpSunucu = "mail.sirket.com"

$sorunlar = @()

foreach ($server in $printServers) {
    $yazicilar = Get-Printer -ComputerName $server
    
    foreach ($yazici in $yazicilar) {
        # Durum kontrolü
        if ($yazici.PrinterStatus -ne "Normal") {
            $sorunlar += [PSCustomObject]@{
                Sunucu = $server
                Yazici = $yazici.Name
                Durum = $yazici.PrinterStatus
                Zaman = Get-Date -Format "dd.MM.yyyy HH:mm"
            }
        }
        
        # Uzun suren print job kontrolü
        $eskiIsler = Get-PrintJob -PrinterName $yazici.Name | 
            Where-Object { 
                $_.SubmittedTime -lt (Get-Date).AddMinutes(-30) -and 
                $_.JobStatus -ne "Printed" 
            }
        
        if ($eskiIsler) {
            $sorunlar += [PSCustomObject]@{
                Sunucu = $server
                Yazici = "$($yazici.Name) - 30 dakikadan uzun beken is"
                Durum = "StuckJob"
                Zaman = Get-Date -Format "dd.MM.yyyy HH:mm"
            }
        }
    }
}

# Sorun varsa mail at
if ($sorunlar.Count -gt 0) {
    $govde = "Asagidaki yazici sorunlari tespit edildi:`n`n"
    $sorunlar | ForEach-Object {
        $govde += "- [$($_.Sunucu)] $($_.Yazici) - Durum: $($_.Durum) ($($_.Zaman))`n"
    }
    
    try {
        Send-MailMessage -From $emailGonderici `
                         -To $emailAlici `
                         -Subject "UYARI: Yazici Sorunu Tespit Edildi" `
                         -Body $govde `
                         -SmtpServer $smtpSunucu `
                         -Encoding UTF8
        Write-Host "Uyari maili gonderildi." -ForegroundColor Yellow
    }
    catch {
        Write-Host "Mail gonderilemedi: $($_.Exception.Message)" -ForegroundColor Red
    }
}

WMI ile Eski Sistemlerde Çalışma

Bazen PowerShell 2.0 çalışan eski bir sunucu veya Windows Server 2008 ile muhatap olursunuz. O zaman WMI kullanmak zorunda kalırsınız:

# WMI ile yazıcıları listele (eski sistemler için)
Get-WmiObject -Class Win32_Printer -ComputerName "ESKISUNUCU" | 
    Select-Object Name, Status, Default, Network, ShareName

# CIM ile (daha modern yaklaşım, eski sistemlerde de çalışır)
Get-CimInstance -ClassName Win32_Printer -ComputerName "ESKISUNUCU" | 
    Where-Object { $_.Status -ne "OK" }

# WMI ile print job'ları gör
Get-WmiObject -Class Win32_PrintJob | 
    Select-Object Name, Document, Status, Size, Owner

# WMI ile yazıcı sürücülerini listele
Get-WmiObject -Class Win32_PrinterDriver | 
    Select-Object Name, Version, SupportedPlatform

Sık Karşılaşılan Sorunlar ve Hızlı Çözümler

Gerçek hayatta en sık karşılaştığım sorunlar ve PowerShell çözümleri:

“Yazıcı görünüyor ama iş gitmiyor”

  • Port IP adresini kontrol et: Get-PrinterPort -Name "IP_xxx.xxx.xxx.xxx" | Format-List *
  • Test baskı gönder ve queue’yu izle
  • Güvenlik duvarında port 9100’ü kontrol et

“Spooler servisi sürekli çöküyor”

  • Bozuk sürücüyü tespit et: Olay görüntüleyicisinde “PrintService” loguna bak
  • İzole etmek için: Get-EventLog -LogName System -Source "Print" -Newest 50

“Kullanıcı yazıcı bulamıyor”

  • Paylaşım durumunu kontrol et: Get-Printer -Name "XXX" | Select-Object Shared, ShareName
  • net view \PRINTSERVER01 ile paylaşımları doğrula

“Yazıcı orada ama offline görünüyor”

  • Test-Connection -ComputerName "192.168.1.100" -Count 2 ile bağlantı testi
  • SNMP portunu kontrol et, bazı yazıcılarda devre dışı olabilir

Sonuç

PowerShell ile yazıcı yönetimi, başta karmaşık görünse de doğru scriptleri bir kez yazıp düzenli kullandığınızda işinizi inanılmaz kolaylaştırır. Bu yazıda anlattığım senaryolar, yıllar içinde gerçek sorunlarla uğraşırken biriktirdiğim çözümlerden oluşuyor.

En önemli önerilerim şunlar:

  • Değişiklik yapmadan önce yedek al: Backup-PrinterConfig scriptini alışkanlık haline getirin
  • Monitoring kurun: Kullanıcılar sorun bildirmeden önce siz fark edin
  • Script kütüphanesi oluşturun: Her çözdüğünüz sorunu script olarak kaydedin
  • Test ortamında deneyin: Toplu değişiklikleri direkt production’da uygulamayın
  • Loglama ekleyin: Scriptlerinize her zaman log yazma ekleyin, ileride neyin ne zaman değiştiğini bilmeniz kritik

Yazıcılar hiçbir zaman tamamen sorunsuz olmayacak, bu iş böyle. Ama hazırlıklı olmak ve sorunları hızla çözmek, iyi bir sysadmin’i ortalamadan ayırt eden şeydir. Bu scriptleri kendi ortamınıza uyarlayın, geliştirin ve gerektiğinde kullanıma hazır bulundurun.

Yorum yapın