Active Directory Yönetimi: Temel Kavramlar ve En İyi Uygulamalar

Yeni bir Windows Server ortamına Active Directory kuruyorsunuz ve “bu sefer doğru yapayım” diyorsunuz. Güzel niyet. Ama Active Directory yönetimi sadece kurulumdan ibaret değil; kullanıcı yönetimi, grup politikaları, OU yapısı, replikasyon sağlığı… Bunların hepsini bir arada düşünmek gerekiyor. Bu yazıda, gerçek dünyada karşılaşacağınız senaryolar üzerinden Active Directory yönetimini PowerShell ile nasıl verimli hale getireceğinizi anlatacağım.

Active Directory’e Neden PowerShell ile Yaklaşmalısınız?

GUI üzerinden Active Directory yönetmek başlangıçta mantıklı gelir. Tek bir kullanıcı ekleyeceksiniz, birkaç tıklama yeterli. Ama 200 kullanıcıyı aynı anda onboard etmeniz gerektiğinde ya da tüm şirket bilgisayarlarına bir GPO uygulamanız gerektiğinde fare ile uğraşmak işkenceye dönüşür. PowerShell bu noktada hem zaman kazandırır hem de tekrarlanabilir, hatasız işlemler yapmanızı sağlar.

Windows Server 2019 ve üzeri sürümlerde RSAT (Remote Server Administration Tools) paketinin kurulu olduğundan emin olun. Aksi halde AD modüllerini kullanamazsınız.

# AD PowerShell modülünü yükleme (Windows 10/11 istemci makinelerde)
Add-WindowsFeature RSAT-AD-PowerShell

# Modülün yüklü olup olmadığını kontrol etme
Get-Module -ListAvailable -Name ActiveDirectory

# Modülü aktif etme
Import-Module ActiveDirectory

Organizational Unit (OU) Yapısını Doğru Kurmak

OU yapısı, Active Directory’nin iskeletidir. Yanlış kurulmuş bir OU yapısı, ilerleyen dönemde GPO uygulamalarını, kullanıcı yönetimini ve yetki delegasyonunu kabusa çevirir. Gerçek dünyada çalıştığım bir kurumda tüm kullanıcılar tek bir OU altına yığılmıştı. GPO uygulamak neredeyse imkansız hale gelmişti çünkü farklı departmanlar için farklı politikalar uygulanmak isteniyordu.

İyi bir OU yapısı genellikle coğrafi ya da departman bazlı olur. Küçük ve orta ölçekli şirketler için departman bazlı yaklaşım daha mantıklıdır.

# Temel OU yapısını oluşturma
$domainDN = "DC=sirket,DC=local"

# Ana OU'ları oluşturma
New-ADOrganizationalUnit -Name "Kullanicilar" -Path $domainDN -ProtectedFromAccidentalDeletion $true
New-ADOrganizationalUnit -Name "Bilgisayarlar" -Path $domainDN -ProtectedFromAccidentalDeletion $true
New-ADOrganizationalUnit -Name "Gruplar" -Path $domainDN -ProtectedFromAccidentalDeletion $true
New-ADOrganizationalUnit -Name "Servis_Hesaplari" -Path $domainDN -ProtectedFromAccidentalDeletion $true

# Departman bazlı alt OU'lar oluşturma
$kullanicilarOU = "OU=Kullanicilar,$domainDN"
New-ADOrganizationalUnit -Name "BilgiIslem" -Path $kullanicilarOU
New-ADOrganizationalUnit -Name "Muhasebe" -Path $kullanicilarOU
New-ADOrganizationalUnit -Name "Insan_Kaynaklari" -Path $kullanicilarOU
New-ADOrganizationalUnit -Name "Satis" -Path $kullanicilarOU

Write-Host "OU yapisi basariyla olusturuldu." -ForegroundColor Green

-ProtectedFromAccidentalDeletion parametresini mutlaka kullanın. Yanlışlıkla silinen bir OU, altındaki tüm objeleri de götürür. Bu parametreyi aktif etmek sizi bu felaketten korur.

Toplu Kullanıcı Oluşturma

Şirkete 50 yeni çalışan katılıyor ve her birini ayrı ayrı GUI üzerinden oluşturacaksınız. Bu hem zaman kaybı hem de hata riski demek. PowerShell ile CSV dosyasından kullanıcı oluşturmak işin doğal çözümüdür.

Önce CSV dosyanızın formatını tanımlayalım. Dosyanın başlık satırı şu şekilde olmalı:

Ad,Soyad,Departman,Unvan,Telefon,Email

# CSV'den toplu kullanıcı olusturma
$csvDosyasi = "C:Tempyeni_kullanicilar.csv"
$varsayilanSifre = ConvertTo-SecureString "Sirket2024!" -AsPlainText -Force
$domainDN = "DC=sirket,DC=local"

Import-Csv $csvDosyasi | ForEach-Object {
    $kullaniciAdi = ($_.Ad.Substring(0,1) + $_.Soyad).ToLower()
    $ouYolu = "OU=$($_.Departman),OU=Kullanicilar,$domainDN"
    
    try {
        New-ADUser `
            -Name "$($_.Ad) $($_.Soyad)" `
            -GivenName $_.Ad `
            -Surname $_.Soyad `
            -SamAccountName $kullaniciAdi `
            -UserPrincipalName "[email protected]" `
            -Path $ouYolu `
            -Title $_.Unvan `
            -Department $_.Departman `
            -OfficePhone $_.Telefon `
            -EmailAddress $_.Email `
            -AccountPassword $varsayilanSifre `
            -Enabled $true `
            -ChangePasswordAtLogon $true
        
        Write-Host "$kullaniciAdi kullanicisi basariyla olusturuldu." -ForegroundColor Green
    }
    catch {
        Write-Host "Hata: $kullaniciAdi olusturulamadi. $($_.Exception.Message)" -ForegroundColor Red
    }
}

Burada dikkat etmeniz gereken birkaç nokta var. -ChangePasswordAtLogon $true parametresi, kullanıcının ilk girişte şifresini değiştirmesini zorunlu kılar. Bu güvenlik açısından önemli. Ayrıca hata yönetimi için try-catch bloğu kullandık; bu sayede bir kullanıcı oluşturulamazsa diğerleri etkilenmez.

Grup Yönetimi ve Üyelik Operasyonları

Active Directory grupları iki temel amaç için kullanılır: kaynaklara erişim yetkisi vermek ve GPO kapsamını belirlemek. Grupları doğru tipte oluşturmak kritik önem taşır.

  • Domain Local: Aynı domain içindeki kaynaklara erişim için
  • Global: Aynı domain’deki kullanıcıları bir araya getirmek için
  • Universal: Forest genelinde kullanım için
# Güvenlik grubu olusturma
New-ADGroup `
    -Name "GRP_Muhasebe_Yazilim" `
    -GroupScope Global `
    -GroupCategory Security `
    -Path "OU=Gruplar,DC=sirket,DC=local" `
    -Description "Muhasebe yazilimina erisim grubu"

# Gruba birden fazla kullanici ekleme
$kullanicilar = @("ahmetk", "merves", "fatmaa", "muratd")
Add-ADGroupMember -Identity "GRP_Muhasebe_Yazilim" -Members $kullanicilar

# Grup uyeliklerini listeleme
Get-ADGroupMember -Identity "GRP_Muhasebe_Yazilim" | 
    Select-Object Name, SamAccountName, ObjectClass |
    Format-Table -AutoSize

# Bir kullanicinin ait oldugu tum gruplari listeleme
$kullanici = "ahmetk"
Get-ADPrincipalGroupMembership -Identity $kullanici | 
    Select-Object Name, GroupScope, GroupCategory |
    Sort-Object Name

Şirketlerde sıkça karşılaştığım bir senaryo şudur: IT ekibi grupların içinde kimin olduğunu bilmiyor ve zamanla gruplar şişiyor. Ayrılan çalışanların hesapları gruplarda kalmaya devam ediyor. Bunu önlemek için periyodik temizlik scriptleri yazılmalı.

# 90 gundir giris yapmamis ve hala aktif olan kullanicilari bulma
$sinirTarih = (Get-Date).AddDays(-90)

Get-ADUser -Filter {
    Enabled -eq $true -and 
    LastLogonDate -lt $sinirTarih
} -Properties LastLogonDate, Department, Manager | 
    Select-Object Name, SamAccountName, Department, LastLogonDate |
    Sort-Object LastLogonDate |
    Export-Csv "C:Raporlarinaktif_kullanicilar.csv" -NoTypeInformation -Encoding UTF8

Write-Host "Rapor olusturuldu: C:Raporlarinaktif_kullanicilar.csv"

Group Policy Object (GPO) Yönetimi

GPO yönetimi Active Directory’nin en güçlü özelliklerinden biridir ve aynı zamanda en çok karıştırılan kısmıdır. GPO’lar OU’lara bağlanır ve o OU’daki kullanıcı ve bilgisayarlara uygulanır. GPMC (Group Policy Management Console) modülü olmadan PowerShell ile GPO yönetmek mümkün ama sınırlıdır.

Önce GPMC modülünü yükleyelim:

# GPMC modülünü yükleme
Add-WindowsFeature GPMC

# Mevcut GPO'ları listeleme
Get-GPO -All | Select-Object DisplayName, GpoStatus, CreationTime, ModificationTime

# Yeni GPO olusturma ve OU'ya baglama
$gpoAdi = "POL_Muhasebe_Masaustu"
$ouYolu = "OU=Muhasebe,OU=Kullanicilar,DC=sirket,DC=local"

New-GPO -Name $gpoAdi -Comment "Muhasebe departmani masaustu politikalari"
New-GPLink -Name $gpoAdi -Target $ouYolu -LinkEnabled Yes

# GPO raporunu HTML olarak alma
Get-GPOReport -Name $gpoAdi -ReportType HTML -Path "C:Raporlar$gpoAdi.html"

Write-Host "GPO olusturuldu ve $ouYolu'e baglandi." -ForegroundColor Green

Pratik bir ipucu: GPO’ları isimlendirirken bir standart belirleyin. Ben genellikle POL_[Hedef]_[Kapsam] formatını kullanıyorum. Örneğin POL_PasswordPolicy_TumKullanicilar ya da POL_USBEngel_Muhasebe. Bu sayede onlarca GPO arasında neyin ne olduğunu anında anlarsınız.

Şifre Politikası ve Fine-Grained Password Policy

Varsayılan domain şifre politikası tüm kullanıcılara uygulanır. Ama ya servis hesaplarının daha karmaşık şifreler kullanması gerekiyorsa ya da yöneticiler için farklı bir politika istiyorsanız? Bu durumda Fine-Grained Password Policy (FGPP) devreye girer.

# Fine-Grained Password Policy olusturma
New-ADFineGrainedPasswordPolicy `
    -Name "PSO_Yoneticiler" `
    -Precedence 10 `
    -MinPasswordLength 14 `
    -PasswordHistoryCount 24 `
    -ComplexityEnabled $true `
    -ReversibleEncryptionEnabled $false `
    -MinPasswordAge "1.00:00:00" `
    -MaxPasswordAge "60.00:00:00" `
    -LockoutThreshold 5 `
    -LockoutDuration "0.00:30:00" `
    -LockoutObservationWindow "0.00:30:00" `
    -Description "Yoneticiler icin guclendirilmis sifre politikasi"

# Politikayı gruba uygulama
Add-ADFineGrainedPasswordPolicySubject `
    -Identity "PSO_Yoneticiler" `
    -Subjects "Domain Admins"

# Uygulanan politikayi kontrol etme
Get-ADUserResultantPasswordPolicy -Identity "adminkullanici"

Precedence değeri önemli. Düşük sayı daha yüksek öncelik anlamına gelir. Birden fazla FGPP bir kullanıcıya uygulanıyorsa, en düşük Precedence değerine sahip olan kazanır.

Domain Controller Sağlık Kontrolü

Production ortamında DC’lerin sağlığını düzenli olarak kontrol etmek zorundasınız. Replikasyon sorunları, DNS hataları ya da SYSVOL sorunları fark edilmeden büyüyebilir ve authentication problemlerine, GPO uygulanmama hatalarına yol açabilir.

# DC saglik kontrol scripti
$domainDC = (Get-ADDomainController -Discover).HostName

Write-Host "=== Domain Controller Saglik Raporu ===" -ForegroundColor Cyan
Write-Host "Tarih: $(Get-Date)" -ForegroundColor Gray

# Tum DC'leri listele
Write-Host "`n[DC Listesi]" -ForegroundColor Yellow
Get-ADDomainController -Filter * | 
    Select-Object Name, IPv4Address, Site, IsGlobalCatalog, OperationMasterRoles

# Replikasyon durumunu kontrol et
Write-Host "`n[Replikasyon Durumu]" -ForegroundColor Yellow
$replikasyon = repadmin /replsummary
$replikasyon | Where-Object { $_ -match "FAIL|ERROR" } | 
    ForEach-Object { Write-Host $_ -ForegroundColor Red }

# FSMO rollerini kontrol et
Write-Host "`n[FSMO Rolleri]" -ForegroundColor Yellow
$domain = Get-ADDomain
$forest = Get-ADForest

Write-Host "PDC Emulator: $($domain.PDCEmulator)"
Write-Host "RID Master: $($domain.RIDMaster)"
Write-Host "Infrastructure Master: $($domain.InfrastructureMaster)"
Write-Host "Schema Master: $($forest.SchemaMaster)"
Write-Host "Domain Naming Master: $($forest.DomainNamingMaster)"

# Servis durumlarini kontrol et
Write-Host "`n[Kritik Servisler]" -ForegroundColor Yellow
$kritikServisler = @("ADWS", "DNS", "KDC", "Netlogon", "NTDS", "W32Time")
foreach ($servis in $kritikServisler) {
    $durum = Get-Service -Name $servis -ErrorAction SilentlyContinue
    if ($durum.Status -eq "Running") {
        Write-Host "$servis : Calisiyor" -ForegroundColor Green
    } else {
        Write-Host "$servis : DURDU!" -ForegroundColor Red
    }
}

Bu scripti görev zamanlayıcıya ekleyin ve çıktıyı log dosyasına yazdırın. Haftalık ya da günlük çalıştırılması, sorunları erken yakalamanızı sağlar.

Yetki Delegasyonu

Her küçük işlem için Domain Admin yetkisi vermek büyük bir güvenlik sorunudur. Active Directory’de yetki delegasyonu ile örneğin Help Desk ekibinin sadece kullanıcı şifrelerini sıfırlayabilmesini, ama başka hiçbir şeyi değiştiremeyeceğini ayarlayabilirsiniz.

# Yetki delegasyonu - sadece sifre sifirlama yetkisi verme
# Hedef OU
$ouYolu = "OU=Kullanicilar,DC=sirket,DC=local"
$helpDeskGrubu = "GRP_HelpDesk"

# ACL nesnesini al
$acl = Get-ACL "AD:$ouYolu"

# Sifre sifirlama hakki icin GUID degerler
$resetPasswordGUID = [GUID]"00299570-246d-11d0-a768-00aa006e0529"
$userAccountGUID = [GUID]"bf967aba-0de6-11d0-a285-00aa003049e2"

# Help Desk grubunun SID'ini al
$helpDeskSID = New-Object System.Security.Principal.SecurityIdentifier (
    (Get-ADGroup $helpDeskGrubu).SID
)

# Sifre sifirlama iznini olustur
$hakki = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $helpDeskSID,
    "ExtendedRight",
    "Allow",
    $resetPasswordGUID,
    "Descendents",
    $userAccountGUID
)

$acl.AddAccessRule($hakki)
Set-ACL "AD:$ouYolu" -AclObject $acl

Write-Host "$helpDeskGrubu grubuna sifre sifirlama yetkisi verildi." -ForegroundColor Green

Delegasyon yaparken en az yetki ilkesini her zaman uygulayın. Birine ihtiyacından fazla yetki vermek, güvenlik açıkları oluşturur ve olay incelemelerini zorlaştırır.

Stale Object Temizliği

Zamanla Active Directory şişer. Devre dışı bırakılmamış eski bilgisayar hesapları, kullanılmayan gruplar, silinmemiş kullanıcılar bunların hepsi AD’yi kirletir ve yönetimi zorlaştırır. Bu temizliği periyodik yapmak zorundasınız.

# Eski bilgisayar hesaplarini bulma ve deaktif etme
$sinirTarih = (Get-Date).AddDays(-180)
$hedefOU = "OU=Deaktif_Bilgisayarlar,DC=sirket,DC=local"

# 180 gundir gorunmeyen bilgisayarlari bul
$eskiBilgisayarlar = Get-ADComputer -Filter {
    LastLogonDate -lt $sinirTarih -and Enabled -eq $true
} -Properties LastLogonDate, OperatingSystem, Description

Write-Host "Bulunan eski bilgisayar sayisi: $($eskiBilgisayarlar.Count)" -ForegroundColor Yellow

foreach ($bilgisayar in $eskiBilgisayarlar) {
    try {
        # Once deaktif et
        Disable-ADAccount -Identity $bilgisayar.SamAccountName
        
        # Aciklama ekle
        Set-ADComputer -Identity $bilgisayar.SamAccountName `
            -Description "Deaktif edildi: $(Get-Date -Format 'yyyy-MM-dd') - Otomatik temizlik"
        
        # Hedef OU'ya tasi
        Move-ADObject -Identity $bilgisayar.DistinguishedName -TargetPath $hedefOU
        
        Write-Host "$($bilgisayar.Name) deaktif edildi ve tasindi." -ForegroundColor Green
    }
    catch {
        Write-Host "Hata: $($bilgisayar.Name) islemi basarisiz. $($_.Exception.Message)" -ForegroundColor Red
    }
}

Temizlik scriptlerinde dikkat etmeniz gereken önemli nokta: doğrudan silmek yerine önce deaktif etmek ve taşımak. 30-60 gün bekleyin, kimse şikayetçi olmazsa o zaman silin. Yanlışlıkla silinen bir objeyi geri getirmek hem zaman alır hem de her zaman mümkün olmaz.

Active Directory Audit Logları

Kimin ne zaman ne yaptığını izlemek compliance açısından zorunludur ve güvenlik olaylarını araştırırken de hayat kurtarır. AD audit politikasını etkinleştirmeden önce Event Log boyutunu artırmanızı öneririm.

# AD audit loglarini sorgulama - son 24 saatteki kullanici olusturma olaylarini bul
$baslangic = (Get-Date).AddHours(-24)
$sonuc = Get-WinEvent -FilterHashtable @{
    LogName   = 'Security'
    Id        = 4720
    StartTime = $baslangic
} -ErrorAction SilentlyContinue

if ($sonuc) {
    $sonuc | ForEach-Object {
        $xml = [xml]$_.ToXml()
        $yeniKullanici = $xml.Event.EventData.Data | 
            Where-Object { $_.Name -eq "TargetUserName" } | 
            Select-Object -ExpandProperty '#text'
        $olusturanKisi = $xml.Event.EventData.Data | 
            Where-Object { $_.Name -eq "SubjectUserName" } | 
            Select-Object -ExpandProperty '#text'
        
        Write-Host "[$($_.TimeCreated)] $olusturanKisi tarafindan $yeniKullanici hesabi olusturuldu."
    }
} else {
    Write-Host "Son 24 saatte yeni kullanici olusturma olayı bulunamadi." -ForegroundColor Gray
}

Kritik Event ID’leri bilmek önemli:

  • 4720: Kullanıcı hesabı oluşturuldu
  • 4740: Kullanıcı hesabı kilitlendi
  • 4625: Başarısız giriş denemesi
  • 4728: Global gruba üye eklendi
  • 4776: Domain Controller kimlik doğrulamayı denedi
  • 4771: Kerberos ön kimlik doğrulama başarısız

Sonuç

Active Directory yönetimi, GUI tıklamalarından ibaret değildir. Ölçeklenebilir, güvenli ve yönetilebilir bir AD altyapısı için PowerShell scriptleri ve otomasyonun kaçınılmaz bir yeri vardır. Doğru OU yapısı, temiz grup politikaları, periyodik sağlık kontrolleri ve audit loglarının düzenli incelenmesi, sizi hem olası felaketlerden korur hem de denetim süreçlerinde rahat ettirer.

Anlattığım scriptleri kendi ortamınıza uyarlarken her zaman test ortamında deneyin. Production AD’de yapılan bir hata, tüm kullanıcıların etkilenmesine neden olabilir. Küçük adımlarla ilerlemenizi, her değişikliği loglamanızı ve geri alma planınızın her zaman hazır olmasını öneririm. Sonuçta iyi bir sysadmin yalnızca sorunları çözmez; sorunların oluşmaması için önlemler alan kişidir.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir