Active Directory ortamında çalışırken, uzun süren scriptleri veya görevleri çalıştırırken terminal penceresini kapatamama ya da başka işlemler yapamama durumuna düşmüşsünüzdür. İşte tam bu noktada Linux dünyasından aşina olduğumuz & operatörü ve süreç arka plana alma kavramı devreye giriyor. Windows Server ortamında PowerShell ile AD yönetimi yaparken bu teknikler hem zaman kazandırıyor hem de iş akışınızı ciddi ölçüde iyileştiriyor.
Süreç Arka Plana Alma Neden Önemli?
Düşünün: Sabah 08:00’de Domain Controller üzerinde büyük bir AD temizlik scripti başlattınız. 50.000 kullanıcılık bir OU yapısında devre dışı hesapları bulmak, raporlamak ve belirli gruplara taşımak için yazdığınız script çalışmaya başladı. Ama siz bu süreçte bekleyemezsiniz. Başka ticket’lar var, başka DC’lere bağlanmanız gerekiyor, log dosyalarını kontrol etmeniz lazım.
Linux’ta & ile bir komutu arka plana atmak son derece doğal bir refleks haline gelmiştir sistem yöneticileri için. Windows PowerShell dünyasında ise bu iş biraz farklı çalışıyor ancak aynı derecede güçlü araçlar mevcut.
Arka plan işlemlerin AD yönetiminde kritik olduğu durumlar:
- Büyük OU yapılarında toplu kullanıcı işlemleri
- Tüm domain’e yayılacak Group Policy güncellemeleri
- AD replikasyon durumu izleme scriptleri
- Binlerce bilgisayar hesabı üzerinde yapılan temizlik operasyonları
- Scheduled task yerine anlık çalıştırılan ama uzun süren raporlama işleri
Linux’ta & Operatörü: Temel Kullanım
Önce Linux tarafında nasıl çalıştığını anlayalım, çünkü birçok sysadmin karma ortamlarda çalışıyor ve kavramın temeli buradan geliyor.
# Basit bir komutu arka plana at
ldapsearch -x -H ldap://dc01.example.com -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" "(objectClass=user)" > /tmp/ad_users.txt &
# Arka plandaki işlemi görüntüle
jobs
# Arka plan işlemini ön plana getir
fg %1
# Çalışan arka plan işlemini kontrol et
jobs -l
Burada & işareti komutun sonuna ekleniyor ve shell hemen bir sonraki komuta geçiyor. Aynı zamanda size bir PID numarası veriyor.
# nohup ile birlikte kullanım - terminal kapansa bile devam eder
nohup ./ad_bulk_modify.sh > /var/log/ad_bulk_modify.log 2>&1 &
# PID'i kaydet
echo $! > /var/run/ad_bulk_modify.pid
# Durumunu kontrol et
ps aux | grep ad_bulk_modify
nohup + & kombinasyonu özellikle SSH ile uzaktan bağlandığınızda ve bağlantı kopsa bile işlemin devam etmesini istediğinizde altın değerinde.
PowerShell’de Arka Plan İşlemleri: Jobs Kavramı
Windows Server ve Active Directory dünyasına geçtiğimizde, PowerShell’in Background Jobs sistemi & operatörünün karşılığı olarak karşımıza çıkıyor. Ama PowerShell 7 ile birlikte gerçek anlamda & operatörüne benzer bir sözdizimi de geldi.
Start-Job ile Klasik Yöntem
# Basit bir AD sorgusunu arka plana al
$job = Start-Job -ScriptBlock {
Import-Module ActiveDirectory
Get-ADUser -Filter {Enabled -eq $false} -SearchBase "OU=Users,DC=example,DC=com" |
Select-Object Name, SamAccountName, LastLogonDate |
Export-Csv "C:Reportsdisabled_users.csv" -NoTypeInformation
}
Write-Host "Job başlatıldı. ID: $($job.Id)"
Write-Host "Başka işlerinize devam edebilirsiniz..."
# Job durumunu kontrol et
Get-Job
# Job tamamlanana kadar bekle ve sonucu al
Wait-Job $job
Receive-Job $job
Bu yöntemde dikkat edilmesi gereken önemli bir nokta var: Start-Job ile başlatılan bir işlem ayrı bir PowerShell process’i olarak çalışır. Bu yüzden mevcut session’ınızda yüklü modüller veya tanımlı değişkenler otomatik olarak aktarılmaz.
AD Yönetiminde Gerçek Senaryo: Toplu Kullanıcı İşlemi
Diyelim ki 3000 kullanıcının şifre politikasını güncelleyeceksiniz ve bu işlem sırasında başka DC’lerle de ilgilenmeniz gerekiyor.
# Değişkenleri job'a aktarmak için -ArgumentList kullanıyoruz
$targetOU = "OU=Employees,DC=example,DC=com"
$logPath = "C:ADLogspassword_policy_update.log"
$passwordJob = Start-Job -ScriptBlock {
param($OU, $Log)
Import-Module ActiveDirectory
$users = Get-ADUser -Filter * -SearchBase $OU -Properties PasswordNeverExpires
$counter = 0
foreach ($user in $users) {
try {
Set-ADUser -Identity $user -PasswordNeverExpires $false
$counter++
Add-Content -Path $Log -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - OK: $($user.SamAccountName)"
}
catch {
Add-Content -Path $Log -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - HATA: $($user.SamAccountName) - $_"
}
}
return "Toplam $counter kullanıcı güncellendi."
} -ArgumentList $targetOU, $logPath
Write-Host "Toplu güncelleme arka planda çalışıyor. Job ID: $($passwordJob.Id)"
Write-Host "Log dosyasını izlemek için: Get-Content $logPath -Wait"
Şimdi bu job çalışırken siz başka bir PowerShell penceresi açıp DC replikasyon durumunu kontrol edebilir, Group Policy güncellemesi yapabilir ya da sadece bir fincan kahve içebilirsiniz.
PowerShell 7’de Gerçek & Operatörü
PowerShell 7 ile birlikte Linux’takine çok daha yakın bir sözdizimi geldi. Eğer ortamınızda PS7 kullanıyorsanız bu özellik işinizi çok kolaylaştıracak.
# PowerShell 7 - & ile arka plana alma
$job = & {
Import-Module ActiveDirectory
Get-ADComputer -Filter {OperatingSystem -like "*Windows 7*"} -Properties * |
Select-Object Name, IPv4Address, LastLogonDate |
Export-Csv "C:Reportswin7_machines.csv" -NoTypeInformation
} &
# Aynı anda başka iş yap
Write-Host "Windows 7 makine taraması arka planda..."
Get-ADDomainController -Filter * | Select-Object Name, Site, IsGlobalCatalog
Bu sözdizimi PowerShell script bloğunun sonundaki & işaretiyle arka plan job’u başlatıyor. Çok daha temiz ve Linux sysadmin’lerine tanıdık geliyor.
Birden Fazla Job ile Paralel AD Yönetimi
İşte gerçek güç burada ortaya çıkıyor. Birden fazla OU veya birden fazla domain üzerinde eş zamanlı işlem yapabilirsiniz.
# Farklı OU'lar için paralel temizlik işlemi
$ouList = @(
"OU=Finance,DC=example,DC=com",
"OU=HR,DC=example,DC=com",
"OU=IT,DC=example,DC=com",
"OU=Sales,DC=example,DC=com"
)
$jobs = @()
foreach ($ou in $ouList) {
$jobs += Start-Job -ScriptBlock {
param($targetOU)
Import-Module ActiveDirectory
# 90 günden fazla giriş yapmayan hesapları bul
$cutoffDate = (Get-Date).AddDays(-90)
$staleUsers = Get-ADUser -Filter {
LastLogonDate -lt $cutoffDate -and Enabled -eq $true
} -SearchBase $targetOU -Properties LastLogonDate
return [PSCustomObject]@{
OU = $targetOU
StaleUserCount = $staleUsers.Count
Users = $staleUsers | Select-Object SamAccountName, LastLogonDate
}
} -ArgumentList $ou
Write-Host "Job başlatıldı: $ou"
}
Write-Host "`nTüm joblar çalışıyor. Tamamlanması bekleniyor..."
# Tüm jobların bitmesini bekle
$results = $jobs | Wait-Job | Receive-Job
# Sonuçları göster
foreach ($result in $results) {
Write-Host "`nOU: $($result.OU)"
Write-Host "Eski hesap sayısı: $($result.StaleUserCount)"
}
# Temizlik
$jobs | Remove-Job
Bu yaklaşım, 4 OU’yu sırayla işlemek yerine hepsini aynı anda taramanızı sağlıyor. Özellikle büyük domainlerde bu zaman farkı çok ciddi boyutlara ulaşabiliyor.
Job Monitoring ve Yönetimi
Arka plan işlemleri başlattınız, peki bunları nasıl takip edeceksiniz?
# Tüm çalışan jobları listele
Get-Job | Format-Table Id, Name, State, HasMoreData -AutoSize
# Belirli bir job'ın detaylı durumu
Get-Job -Id 3 | Select-Object *
# Job çalışırken gerçek zamanlı log izleme (ayrı pencerede)
Get-Content "C:ADLogspassword_policy_update.log" -Wait -Tail 20
# Hata veren jobları filtrele
Get-Job | Where-Object {$_.State -eq "Failed"} | Receive-Job
# Tamamlanan jobları temizle
Get-Job | Where-Object {$_.State -eq "Completed"} | Remove-Job
Job Durumları ve Anlamları
- Running: Job şu an çalışıyor
- Completed: Job başarıyla tamamlandı
- Failed: Job bir hatayla sonlandı
- Stopped: Job manuel olarak durduruldu
- Suspended: Job askıya alındı (Workflow job’larında)
- Disconnected: Bağlantı koptu ama job hala çalışıyor olabilir
Invoke-Command ile Remote Job’lar
Active Directory yönetiminin önemli bir parçası da remote DC’ler üzerinde işlem yapabilmektir. Invoke-Command ile -AsJob parametresi bu ihtiyacı karşılıyor.
# Birden fazla DC üzerinde arka planda bilgi topla
$domainControllers = @("DC01", "DC02", "DC03")
$dcJobs = Invoke-Command -ComputerName $domainControllers -AsJob -ScriptBlock {
$dcInfo = [PSCustomObject]@{
ComputerName = $env:COMPUTERNAME
ReplicationStatus = (Get-Command repadmin) ? (repadmin /showrepl 2>&1 | Select-String "error" | Measure-Object).Count : "N/A"
ADServiceStatus = (Get-Service NTDS).Status
DFSRStatus = (Get-Service DFSR).Status
FreeSpaceSysvol = [math]::Round((Get-PSDrive C).Free / 1GB, 2)
LastBootTime = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
}
return $dcInfo
}
Write-Host "DC bilgileri toplanıyor... Arka planda çalışıyor."
Write-Host "Bu arada başka işlemlerinizi yapabilirsiniz.`n"
# Sonuçları al
$dcResults = $dcJobs | Wait-Job | Receive-Job
foreach ($dc in $dcResults) {
Write-Host "DC: $($dc.ComputerName)"
Write-Host " AD Servisi: $($dc.ADServiceStatus)"
Write-Host " DFSR Servisi: $($dc.DFSRStatus)"
Write-Host " Replikasyon Hataları: $($dc.ReplicationStatus)"
Write-Host " C: Boş Alan: $($dc.FreeSpaceSysvol) GB"
Write-Host ""
}
$dcJobs | Remove-Job
Arka Plan İşlemlerinde Hata Yönetimi
Arka planda çalışan işlemlerde hataları yakalamak ve yönetmek ayrı bir dikkat gerektiriyor.
# Sağlam hata yönetimiyle AD gruplarını arka planda yeniden yapılandır
$groupMigrationJob = Start-Job -Name "GroupMigration" -ScriptBlock {
Import-Module ActiveDirectory
$errorList = @()
$successList = @()
try {
$legacyGroups = Get-ADGroup -Filter {Name -like "Legacy_*"} -Properties Members
foreach ($group in $legacyGroups) {
try {
$newGroupName = $group.Name -replace "^Legacy_", "DEPT_"
# Yeni grup var mi kontrol et
if (-not (Get-ADGroup -Filter {Name -eq $newGroupName} -ErrorAction SilentlyContinue)) {
New-ADGroup -Name $newGroupName `
-GroupScope Global `
-GroupCategory Security `
-Path "OU=Groups,DC=example,DC=com" `
-Description "Migrated from $($group.Name)"
# Eski grup üyelerini yeni gruba ekle
if ($group.Members.Count -gt 0) {
Add-ADGroupMember -Identity $newGroupName -Members $group.Members
}
$successList += $group.Name
}
}
catch {
$errorList += [PSCustomObject]@{
GroupName = $group.Name
Error = $_.Exception.Message
}
}
}
}
catch {
Write-Error "Kritik hata: $_"
throw
}
return [PSCustomObject]@{
SuccessCount = $successList.Count
SuccessGroups = $successList
ErrorCount = $errorList.Count
Errors = $errorList
}
}
# Job durumunu periyodik olarak izle
do {
$status = Get-Job -Name "GroupMigration"
Write-Host "$(Get-Date -Format 'HH:mm:ss') - Job durumu: $($status.State)"
Start-Sleep -Seconds 10
} while ($status.State -eq "Running")
# Sonucu al
$migrationResult = Receive-Job -Name "GroupMigration"
Write-Host "`nMigrasyon tamamlandi!"
Write-Host "Basarili: $($migrationResult.SuccessCount) grup"
Write-Host "Basarisiz: $($migrationResult.ErrorCount) grup"
if ($migrationResult.ErrorCount -gt 0) {
Write-Host "`nHatali gruplar:"
$migrationResult.Errors | ForEach-Object {
Write-Host " - $($_.GroupName): $($_.Error)"
}
}
Remove-Job -Name "GroupMigration"
Workflow Jobs ve Scheduled Jobs
Bazı senaryolarda işinizin PowerShell oturumu kapansa bile devam etmesi gerekebilir. Bunun için Register-ScheduledJob kullanabilirsiniz.
# Scheduled job olarak kaydet - oturum kapansa bile çalışmaya devam eder
$trigger = New-JobTrigger -Once -At (Get-Date).AddMinutes(5)
Register-ScheduledJob -Name "ADHealthCheck" -ScriptBlock {
Import-Module ActiveDirectory
$report = @()
# Domain Controller kontrolü
$dcs = Get-ADDomainController -Filter *
foreach ($dc in $dcs) {
$report += [PSCustomObject]@{
Type = "DomainController"
Name = $dc.Name
Site = $dc.Site
IsOnline = (Test-Connection -ComputerName $dc.Name -Count 1 -Quiet)
IsGC = $dc.IsGlobalCatalog
}
}
# Kilitli hesap kontrolü
$lockedAccounts = Search-ADAccount -LockedOut | Where-Object {$_.ObjectClass -eq "user"}
$report | Export-Csv "C:Reportsad_health_$(Get-Date -Format 'yyyyMMdd_HHmm').csv" -NoTypeInformation
if ($lockedAccounts.Count -gt 0) {
Send-MailMessage -To "[email protected]" `
-From "[email protected]" `
-Subject "AD Uyarı: $($lockedAccounts.Count) kilitli hesap" `
-Body ($lockedAccounts | ConvertTo-Html | Out-String) `
-BodyAsHtml `
-SmtpServer "smtp.example.com"
}
} -Trigger $trigger
Write-Host "Scheduled job kaydedildi. 5 dakika sonra çalışacak."
Write-Host "Oturumu kapatsanız bile job çalışmaya devam edecek."
Pratik İpuçları ve Dikkat Edilmesi Gerekenler
Yıllar içinde edindiğim deneyimle, arka plan işlemleri kullanırken dikkat etmeniz gereken birkaç önemli noktayı paylaşayım:
Job çıktılarını mutlaka kaydedin: Receive-Job komutu varsayılan olarak job çıktısını temizler. Eğer bir job’ın çıktısına birden fazla kez erişmeniz gerekiyorsa -Keep parametresini kullanın.
# Çıktıyı temizleme, birden fazla erişime izin ver
Receive-Job -Id 5 -Keep
Çok fazla paralel job açmayın: Her job ayrı bir PowerShell process’i oluşturur. DC üzerinde 20-30 paralel job açmak bellek ve CPU basıncı yaratabilir. Genellikle 5-10 arası paralel job iyi bir denge noktasıdır.
Job isimlerini anlamlı verin:
Start-Job -Name "DisabledUserCleanup_$(Get-Date -Format 'yyyyMMdd')" -ScriptBlock {...}
Orphan job’ları düzenli temizleyin:
# Tamamlanmış tüm jobları temizle
Get-Job | Where-Object {$_.State -in @("Completed","Failed","Stopped")} | Remove-Job
Sonuç
Active Directory yönetiminde arka plan işlemleri kullanmak, salt teknik bir beceri değil, aynı zamanda bir verimlilik ve profesyonellik göstergesidir. Start-Job, -AsJob, PowerShell 7’deki & sözdizimi ve Register-ScheduledJob ile elinizde son derece güçlü bir araç seti var.
Linux’taki & operatörünün sadeliğini özleyenler için müjde: PowerShell 7 bu sadeliği Windows dünyasına taşıdı. Ama klasik Windows Server ortamlarında da Start-Job ekosistemi, Linux’taki job control mekanizmalarıyla boy ölçüşebilecek kapasite sunuyor.
Bu teknikleri benimsediğinizde, büyük AD operasyonları sizi bir terminal penceresine mahkum etmeyecek. Sabah başlattığınız toplu kullanıcı güncellemesi arka planda çalışırken siz DC’lerin replikasyon sağlığını kontrol edebilir, öğleden sonra raporunuzu Receive-Job ile alabilirsiniz. Büyük ortamlarda bu esneklik gerçek anlamda oyun değiştirici oluyor.
Son olarak, her arka plan işlemi için mutlaka log tutun, hata yönetimini ihmal etmeyin ve üretim ortamında önce test ortamında deneyin. Arka planda çalışan bir script’in verdiği hasarı fark etmek bazen çok geç olabiliyor.