PowerShell ile Active Directory Kullanıcı Sorgulama

Active Directory ortamında kullanıcı yönetimi, bir sysadmin’in günlük rutininin ayrılmaz bir parçası. “Şu kullanıcı neden sisteme giremedi?”, “Hangi hesaplar 90 gündür aktif değil?”, “Bu kişi hangi gruplara üye?” gibi sorular günde onlarca kez karşınıza çıkabilir. GUI üzerinden tek tek bu bilgilere ulaşmaya çalışmak hem zaman kaybıdır hem de hata yapma ihtimalini artırır. PowerShell ile bu işlemleri dakikalar içinde, tekrarlanabilir ve otomatize edilebilir şekilde yapmak mümkün. Bu yazıda AD kullanıcı sorgulama konusunu gerçek dünya senaryolarıyla ele alacağız.

Başlamadan Önce: Gereksinimler

PowerShell ile Active Directory komutlarını kullanabilmek için birkaç şeyin yerli yerinde olması gerekiyor.

RSAT (Remote Server Administration Tools) kurulu olmalı. Windows 10/11 üzerinde bunu şu şekilde yükleyebilirsiniz:

# Windows 10/11 üzerinde RSAT AD araçlarını yüklemek
Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0

Sunucu üzerinde çalışıyorsanız ve AD DS rolü kuruluysa modül zaten gelmiş olabilir. Kontrol etmek için:

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

# Modülü import et
Import-Module ActiveDirectory

Yetkiler konusunda dikkatli olun. Domain Admin olmak zorunda değilsiniz, ama en azından Domain Users üzerinde okuma yetkisine sahip bir hesapla çalışmalısınız. Üretim ortamında sorgulama işlemleri için ayrı bir “readonly” servis hesabı oluşturmak iyi bir pratiktir.

Get-ADUser ile Temel Sorgular

Her şey Get-ADUser komutuyla başlıyor. Bu cmdlet, AD’deki kullanıcı objelerini sorgulamanın temel yolu. En basit kullanımı şu şekilde:

# Tek bir kullanıcıyı SAMAccountName ile sorgula
Get-ADUser -Identity "jdoe"

# Tüm özellikleri getir (varsayılan olarak sınırlı özellik gelir)
Get-ADUser -Identity "jdoe" -Properties *

# Belirli özellikleri getir
Get-ADUser -Identity "jdoe" -Properties DisplayName, EmailAddress, LastLogonDate, PasswordLastSet, Department, Title

Burada önemli bir nokta var: Get-ADUser varsayılan olarak yalnızca birkaç temel özelliği döndürür. LastLogonDate, PasswordLastSet gibi kritik bilgileri görmek için ya -Properties kullanmanız ya da ihtiyacınız olan özellikleri açıkça belirtmeniz gerekiyor. Tüm özellikleri çekmek (-Properties ) büyük ortamlarda performans sorununa yol açabilir, bu yüzden yalnızca ihtiyacınız olanları listeleyin.

Filter Parametresi ile Akıllı Sorgulama

Gerçek gücü Filter parametresiyle görüyorsunuz. Binlerce kullanıcı arasından belirli kriterlere uyanları saniyeler içinde bulabilirsiniz.

# Aktif olmayan (disabled) tüm hesapları listele
Get-ADUser -Filter {Enabled -eq $false} -Properties DisplayName, LastLogonDate |
    Select-Object Name, SamAccountName, LastLogonDate, Enabled

# Belirli bir departmandaki kullanıcıları bul
Get-ADUser -Filter {Department -eq "Muhasebe"} -Properties Department, Title, EmailAddress |
    Select-Object DisplayName, Title, EmailAddress

# Adı "Ahmet" ile başlayan kullanıcıları bul
Get-ADUser -Filter {GivenName -like "Ahmet*"} |
    Select-Object DisplayName, SamAccountName

Filter parametresinde dikkat etmeniz gereken bir husus var: Buradaki syntax SQL veya normal PowerShell karşılaştırması değil, AD’nin kendi query dili. String değerleri tırnak içine alın, boolean değerler için $true ve $false kullanın.

SearchBase parametresi de çok işe yarıyor. Tüm domain yerine belirli bir OU altında arama yapmanıza olanak tanıyor:

# Belirli bir OU altındaki kullanıcıları getir
Get-ADUser -Filter * -SearchBase "OU=Istanbul,OU=Kullanicilar,DC=sirket,DC=local" `
    -Properties Department |
    Select-Object DisplayName, Department

Gerçek Dünya Senaryosu 1: 90 Gündür Giriş Yapmayan Hesaplar

Bu senaryo her ortamda karşılaşılan klasik bir güvenlik gereksinimidir. “Kıdemli yöneticilerimiz eski hesapların kapatılmasını istiyor” dediğinizde çalıştıracağınız script tam olarak bu:

# 90 gündür giriş yapmayan aktif hesapları bul
$tarih = (Get-Date).AddDays(-90)

Get-ADUser -Filter {
    LastLogonDate -lt $tarih -and
    Enabled -eq $true
} -Properties DisplayName, LastLogonDate, Department, EmailAddress, Manager |
    Select-Object `
        DisplayName,
        SamAccountName,
        @{Name="LastLogon"; Expression={$_.LastLogonDate}},
        Department,
        EmailAddress,
        @{Name="Yonetici"; Expression={(Get-ADUser $_.Manager -ErrorAction SilentlyContinue).DisplayName}} |
    Sort-Object LastLogon |
    Export-Csv -Path "C:RaporlarAtil_Hesaplar.csv" -NoTypeInformation -Encoding UTF8

Write-Host "Rapor oluşturuldu: C:RaporlarAtil_Hesaplar.csv"

Bu scripti çalıştırdıktan sonra elinizde CSV formatında, yöneticiye de gösterebileceğiniz, temiz bir rapor oluyor. Manager alanında LDAP distinguished name geldiği için onu kullanıcı adına çeviriyoruz.

Gerçek Dünya Senaryosu 2: Parola Süresi Dolacak Hesapları Tespit Etme

Kullanıcılar parolaları dolduğunda IT’ye koşmadan önce onları uyarabilirseniz çok daha az şikayet alırsınız. Aşağıdaki script önümüzdeki 7 gün içinde parolası dolacak hesapları listeler:

# Parola süresi 7 gün içinde dolacak kullanıcıları bul
$bugun = Get-Date
$maxParolaYasi = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days

Get-ADUser -Filter {
    Enabled -eq $true -and
    PasswordNeverExpires -eq $false -and
    PasswordLastSet -gt 0
} -Properties PasswordLastSet, EmailAddress, DisplayName |
    ForEach-Object {
        $parola_bitis = $_.PasswordLastSet.AddDays($maxParolaYasi)
        $kalan_gun = ($parola_bitis - $bugun).Days

        if ($kalan_gun -ge 0 -and $kalan_gun -le 7) {
            [PSCustomObject]@{
                KullaniciAdi    = $_.DisplayName
                SAMAccount      = $_.SamAccountName
                Email           = $_.EmailAddress
                ParolaBitis     = $parola_bitis.ToString("dd.MM.yyyy")
                KalanGun        = $kalan_gun
            }
        }
    } |
    Sort-Object KalanGun |
    Format-Table -AutoSize

Bu çıktıyı alıp basit bir Send-MailMessage komutuyla kullanıcılara otomatik bildirim göndermek de mümkün. Ama o konu ayrı bir yazının konusu.

Grup Üyeliklerini Sorgulama

Bir kullanıcının hangi gruplara üye olduğunu bilmek, özellikle yetki sorunlarını giderirken hayat kurtarıcı oluyor.

# Kullanıcının üye olduğu tüm grupları listele
Get-ADUser -Identity "jdoe" -Properties MemberOf |
    Select-Object -ExpandProperty MemberOf |
    ForEach-Object { (Get-ADGroup $_).Name } |
    Sort-Object

# Nested grupları da dahil ederek tam üyelik listesi
# (Get-ADPrincipalGroupMembership recursive desteklemez, bu yüzden farklı yaklaşım)
function Get-ADGroupMembershipRecursive {
    param([string]$Username)

    $user = Get-ADUser -Identity $Username -Properties MemberOf
    $gruplar = @()

    foreach ($grup in $user.MemberOf) {
        $adGrup = Get-ADGroup $grup
        $gruplar += $adGrup.Name
        # Alt grup üyeliklerini de al
        $altGruplar = Get-ADGroupMember -Identity $adGrup -Recursive |
            Where-Object {$_.objectClass -eq "group"}
    }

    return $gruplar | Sort-Object -Unique
}

Get-ADGroupMembershipRecursive -Username "jdoe"

Kilitlenen Hesapları Bulma ve Yönetme

“Hesabım kilitlendi” çağrısı aldığınızda hızlıca hareket etmek gerekiyor. Üstelik hangi DC’de kilitlendiğini bulmak da ayrı bir dert olabiliyor.

# Kilitli hesapları listele
Search-ADAccount -LockedOut |
    Select-Object Name, SamAccountName, LockedOut, LastLogonDate |
    Format-Table -AutoSize

# Belirli bir kullanıcının kilit durumunu kontrol et
Get-ADUser -Identity "jdoe" -Properties LockedOut, BadLogonCount, BadPasswordTime, LockedOut |
    Select-Object Name, LockedOut, BadLogonCount,
        @{Name="SonHataliGiris"; Expression={[datetime]::FromFileTime($_.BadPasswordTime)}}

# Hesabın kilidini aç
Unlock-ADAccount -Identity "jdoe"
Write-Host "jdoe hesabının kilidi açıldı."

# Toplu kilit açma (dikkatli kullanın!)
Search-ADAccount -LockedOut | Unlock-ADAccount -PassThru |
    Select-Object Name, SamAccountName

Search-ADAccount cmdlet’i kilitli hesaplar için harika bir araç. Ama Unlock-ADAccount ile birleştirirken dikkatli olun, üretim ortamında önce listeyi gözden geçirip sonra toplu işlem yapmak daha güvenli.

Gerçek Dünya Senaryosu 3: Yeni Çalışan Onboarding Doğrulaması

İnsan kaynakları size “Yeni çalışanların hesapları açıldı mı?” diye sorduğunda, bir liste gelir elinize ve hepsini tek tek kontrol edersiniz. Bunu otomatize etmek hem zaman kazandırır hem de gözden kaçanları engeller.

# CSV dosyasından kullanıcı listesi okuyup hesap durumlarını kontrol et
# CSV formatı: SamAccountName, DisplayName

$kullanicilar = Import-Csv -Path "C:Raporlaryeni_calisanlar.csv"

$sonuclar = foreach ($kullanici in $kullanicilar) {
    try {
        $adUser = Get-ADUser -Identity $kullanici.SamAccountName `
            -Properties Enabled, LastLogonDate, PasswordLastSet, EmailAddress, Department `
            -ErrorAction Stop

        [PSCustomObject]@{
            AdSoyad         = $adUser.DisplayName
            KullaniciAdi    = $adUser.SamAccountName
            HesapDurumu     = if ($adUser.Enabled) {"Aktif"} else {"Devre Disi"}
            Email           = $adUser.EmailAddress
            Departman       = $adUser.Department
            ParolaOlusturma = $adUser.PasswordLastSet
            SonGiris        = $adUser.LastLogonDate
            Durum           = "Bulundu"
        }
    }
    catch {
        [PSCustomObject]@{
            AdSoyad         = $kullanici.DisplayName
            KullaniciAdi    = $kullanici.SamAccountName
            HesapDurumu     = "Bilinmiyor"
            Email           = ""
            Departman       = ""
            ParolaOlusturma = $null
            SonGiris        = $null
            Durum           = "BULUNAMADI - Kontrol Gerekli"
        }
    }
}

$sonuclar | Format-Table -AutoSize
$sonuclar | Export-Csv "C:Raporlaronboarding_kontrol.csv" -NoTypeInformation -Encoding UTF8

Bu script hem bulunan hem de bulunamayan hesapları raporluyor. IK ile paylaşabileceğiniz temiz bir çıktı elde ediyorsunuz.

LDAP Filter ile Gelişmiş Sorgular

-Filter parametresi bazı karmaşık sorgularda yetersiz kalabiliyor. Bu durumda -LDAPFilter parametresi devreye giriyor. LDAP syntax biraz farklı ama çok daha güçlü.

# LDAP filter ile birden fazla koşul
# Son 30 günde oluşturulan ve belirli bir OU'da olan hesaplar
$tarih30Gun = (Get-Date).AddDays(-30).ToFileTime()

Get-ADUser -LDAPFilter "(&(objectClass=user)(whenCreated>=$((Get-Date).AddDays(-30).ToString('yyyyMMddHHmmss.0Z'))))" `
    -Properties whenCreated, Department |
    Select-Object DisplayName, SamAccountName, whenCreated, Department |
    Sort-Object whenCreated -Descending

# Telefon numarası girilmemiş kullanıcıları bul
Get-ADUser -LDAPFilter "(&(objectClass=user)(!(telephoneNumber=*)))" `
    -Properties Department |
    Where-Object {$_.Enabled -eq $true} |
    Select-Object DisplayName, SamAccountName, Department |
    Export-Csv "C:Raporlartelefon_eksik.csv" -NoTypeInformation -Encoding UTF8

LDAP filter syntax’ında & AND, | OR, ! NOT anlamına gelir. Parantezlere dikkat etmek gerekiyor, yanlış parantez tüm sorguyu bozar.

Çıktıyı Biçimlendirme ve Raporlama

Ham sorgu sonuçlarını olduğu gibi vermek yerine daha okunabilir hale getirmek için birkaç pratik yöntem:

# Format-Table ile konsolda düzenli görüntüleme
Get-ADUser -Filter {Department -eq "IT"} -Properties Department, Title, EmailAddress |
    Select-Object DisplayName, SamAccountName, Title, EmailAddress |
    Format-Table -AutoSize -Wrap

# Out-GridView ile interaktif pencere (GUI ortamında kullanışlı)
Get-ADUser -Filter {Enabled -eq $true} -Properties Department, LastLogonDate |
    Select-Object DisplayName, SamAccountName, Department, LastLogonDate |
    Out-GridView -Title "Aktif AD Kullanıcıları"

# HTML raporu oluşturma
$htmlBaslik = "<style>body{font-family:Arial;} table{border-collapse:collapse;width:100%} th,td{border:1px solid #ddd;padding:8px;} th{background-color:#4472C4;color:white;}</style>"

Get-ADUser -Filter {Enabled -eq $true} `
    -Properties DisplayName, Department, LastLogonDate, EmailAddress |
    Select-Object DisplayName, SamAccountName, Department, EmailAddress,
        @{Name="SonGiris"; Expression={if($_.LastLogonDate){$_.LastLogonDate.ToString("dd.MM.yyyy")}else{"Hic giris yapilmadi"}}} |
    ConvertTo-Html -Head $htmlBaslik -Title "AD Kullanici Raporu" `
        -PreContent "<h2>Active Directory Kullanici Raporu - $(Get-Date -Format 'dd.MM.yyyy')</h2>" |
    Out-File "C:Raporlarad_kullanici_raporu.html" -Encoding UTF8

Write-Host "HTML rapor oluşturuldu."

HTML raporunu yöneticilere mail ile göndermek ya da bir iç portala koymak çok daha profesyonel duruyor.

Performans İpuçları

Büyük AD ortamlarında (10.000+ kullanıcı) sorgular yavaşlayabilir. Birkaç önemli nokta:

-Properties * kullanmaktan kaçının. Her özelliği çekmek gereksiz ağ trafiği ve bellek tüketimi yaratır. Sadece ihtiyacınız olan özellikleri listeleyin.

-SearchBase kullanın. Mümkün olduğunda tüm domain yerine ilgili OU’da arama yapın.

-SearchScope parametresi de işe yarar:

  • Base: Yalnızca belirtilen objeyi sorgular
  • OneLevel: Yalnızca doğrudan alt objeleri sorgular
  • Subtree: Tüm alt ağacı sorgular (varsayılan)
# Sadece bir OU'nun doğrudan altındaki kullanıcıları getir (nested OU'ları dahil etme)
Get-ADUser -Filter * `
    -SearchBase "OU=Istanbul,OU=Kullanicilar,DC=sirket,DC=local" `
    -SearchScope OneLevel `
    -Properties Department |
    Select-Object DisplayName, Department

Where-Object yerine -Filter kullanın. Where-Object tüm kullanıcıları çekip PowerShell tarafında filtreler. -Filter parametresi ise filtrelemeyi AD tarafında yapar, çok daha hızlıdır.

Hata Yönetimi ve Loglama

Script yazarken hata yönetimine dikkat etmek, özellikle toplu işlemlerde kritik öneme sahip:

# Hata yönetimi ile kullanıcı sorgulama
function Get-KullaniciBilgi {
    param(
        [string[]]$KullaniciListesi,
        [string]$LogDosya = "C:Logsad_sorgu.log"
    )

    $tarih = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

    foreach ($kullanici in $KullaniciListesi) {
        try {
            $user = Get-ADUser -Identity $kullanici `
                -Properties DisplayName, EmailAddress, Department, Enabled, LastLogonDate `
                -ErrorAction Stop

            "$tarih - BASARILI: $kullanici sorgulandı" | Out-File $LogDosya -Append
            $user | Select-Object DisplayName, SamAccountName, EmailAddress, Department, Enabled, LastLogonDate
        }
        catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
            "$tarih - HATA: $kullanici bulunamadı" | Out-File $LogDosya -Append
            Write-Warning "$kullanici AD'de bulunamadı."
        }
        catch {
            "$tarih - BEKLENMEDIK HATA: $kullanici - $($_.Exception.Message)" | Out-File $LogDosya -Append
            Write-Error "Beklenmedik hata: $_"
        }
    }
}

# Kullanımı
$hesaplar = @("jdoe", "asmith", "var_olmayan_kullanici", "mjones")
Get-KullaniciBilgi -KullaniciListesi $hesaplar

Sık Kullanılan Parametreler Özeti

Get-ADUser ve ilgili cmdlet’lerin sık kullanılan parametrelerini hatırlamak için:

Get-ADUser parametreleri:

  • -Identity: SAMAccountName, UPN, DN veya GUID ile tek kullanıcı sorgular
  • -Filter: Koşullu sorgulama için (AD tarafında filtreleme)
  • -LDAPFilter: Raw LDAP syntax ile gelişmiş sorgulama
  • -Properties: Getirilecek ek özellikleri belirtir
  • -SearchBase: Aramanın başlayacağı OU’nun DN’i
  • -SearchScope: Arama derinliği (Base, OneLevel, Subtree)
  • -Server: Sorgulanacak DC’yi belirtir (multi-site ortamlarda kullanışlı)

Yardımcı cmdlet’ler:

  • Search-ADAccount: Kilitli, süresi dolmuş, pasif hesaplar için özel sorgular
  • Get-ADPrincipalGroupMembership: Kullanıcının grup üyelikleri
  • Unlock-ADAccount: Hesap kilidini açar
  • Get-ADDefaultDomainPasswordPolicy: Domain parola politikasını getirir

Sonuç

PowerShell ile AD kullanıcı sorgulama, başta karmaşık görünse de birkaç temel cmdlet’i öğrendikten sonra günlük işlerinizi ciddi ölçüde hızlandırıyor. Get-ADUser, Search-ADAccount ve birkaç yardımcı cmdlet ile atıl hesap tespitinden onboarding doğrulamasına, parola süresi kontrolünden grup üyeliği analizine kadar pek çok işi otomatize edebilirsiniz.

En önemli tavsiyem: Bu scriptleri doğrudan üretim ortamında çalıştırmadan önce test ortamında ya da WhatIf parametresiyle deneyin. Özellikle toplu işlemler söz konusu olduğunda önce listeyi çıkartın, gözden geçirin, sonra aksiyona geçin. Ve her önemli scriptinizi kayıt altına alın, hem ne yaptığınızı belgelemek hem de sorun çıktığında geri dönebilmek için log tutma alışkanlığı edinin.

Bu konuyu daha da derinleştirmek isteyenler için sonraki adımlar arasında AD grup yönetimi, bilgisayar objesi sorgulama ve zamanlanmış görevlerle otomatik raporlama konularına bakabilirsiniz. PowerShell’in Active Directory modülü oldukça geniş, keşfedilecek çok şey var.

Yorum yapın