Azure Active Directory ile Kullanıcı Yönetimi

Kurumsal ortamlarda kullanıcı yönetimi her zaman can sıkıcı bir iş olmuştur. Onlarca, yüzlerce, hatta binlerce kullanıcıyı yönetmek, grupları düzenlemek, lisans atamak ve erişim haklarını kontrol etmek; bunların hepsini manuel yapmaya çalışırsanız hem zaman kaybedersiniz hem de hata yapma ihtimaliniz artar. Azure Active Directory (Azure AD) tam bu noktada devreye giriyor ve hayatınızı kolaylaştırıyor. Ancak “kolaylaştırıyor” derken kast ettiğim, doğru araçları doğru şekilde kullandığınızda. Yoksa portal üzerinden tıkla-tıkla yönetim yapmaya çalışırsanız, büyük ortamlarda bunun sonu gelmez.

Bu yazıda Azure AD kullanıcı yönetimini gerçek dünya senaryolarıyla ele alacağız. PowerShell ve Azure CLI komutlarına ağırlık vereceğiz, çünkü bir sysadmin olarak otomasyon olmadan ölçeklenebilir bir yapı kurmak mümkün değil.

Azure AD Kullanıcı Yönetimine Neden PowerShell ile Başlamalısınız?

Azure portalı güzel ve kullanışlı bir arayüze sahip, bunu inkar etmiyorum. Ama şunu düşünün: 200 kullanıcıya aynı anda lisans atamanız gerekiyor. Ya da bir departmandaki tüm kullanıcıların şifrelerini sıfırlamanız gerekiyor. Portalde bu işlemleri tek tek yapıyorsanız, bu iş akşama kadar sürer.

AzureAD ve Microsoft.Graph PowerShell modülleri, bu tür toplu işlemleri dakikalar içinde halletmenizi sağlar. Microsoft, AzureAD modülünü deprecated ettiğini açıkladı ve artık Microsoft Graph PowerShell SDK’ya geçiş öneriyor. O yüzden örneklerimizde her ikisine de yer vereceğiz.

Önce modülleri yükleyelim:

# Microsoft Graph PowerShell SDK kurulumu
Install-Module Microsoft.Graph -Scope CurrentUser -Force

# Eski AzureAD modülü (hala kullanılıyor ama geçiş planı yapın)
Install-Module AzureAD -Scope CurrentUser -Force

# Azure CLI kurulumu (Ubuntu/Debian)
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

Modülleri yükledikten sonra Azure’a bağlanmak için:

# Microsoft Graph ile bağlantı
Connect-MgGraph -Scopes "User.ReadWrite.All", "Group.ReadWrite.All", "Directory.ReadWrite.All"

# Azure CLI ile giriş
az login --tenant your-tenant-id

Kullanıcı Oluşturma ve Temel Yönetim

Tekil Kullanıcı Oluşturma

En temel operasyondan başlayalım. Yeni bir çalışan geldi, hesap açmanız gerekiyor:

# Microsoft Graph PowerShell ile kullanıcı oluşturma
$passwordProfile = @{
    Password = "TempPass@2024!"
    ForceChangePasswordNextSignIn = $true
}

New-MgUser `
    -DisplayName "Ahmet Yilmaz" `
    -GivenName "Ahmet" `
    -Surname "Yilmaz" `
    -UserPrincipalName "[email protected]" `
    -MailNickname "ahmet.yilmaz" `
    -Department "Yazilim Gelistirme" `
    -JobTitle "Senior Developer" `
    -UsageLocation "TR" `
    -PasswordProfile $passwordProfile `
    -AccountEnabled $true

Azure CLI ile aynı işlemi yapmak isterseniz:

az ad user create 
  --display-name "Ahmet Yilmaz" 
  --user-principal-name "[email protected]" 
  --password "TempPass@2024!" 
  --force-change-password-next-sign-in true 
  --job-title "Senior Developer" 
  --department "Yazilim Gelistirme"

Toplu Kullanıcı Oluşturma

Gerçek hayatta tek tek kullanıcı oluşturmak nadir bir durum. Şirkete 50 kişilik bir ekip katıldığında ne yaparsınız? CSV dosyasından okuyarak toplu oluşturma yaparsınız:

# kullanicilar.csv dosyası şu formatta olmalı:
# DisplayName,GivenName,Surname,UPN,Department,JobTitle
# Bu scripti çalıştırmadan önce Connect-MgGraph yapın

$kullanicilar = Import-Csv -Path "kullanicilar.csv" -Encoding UTF8

foreach ($kullanici in $kullanicilar) {
    $passwordProfile = @{
        Password = "Sirket2024!" + (Get-Random -Minimum 100 -Maximum 999)
        ForceChangePasswordNextSignIn = $true
    }
    
    try {
        $yeniKullanici = New-MgUser `
            -DisplayName $kullanici.DisplayName `
            -GivenName $kullanici.GivenName `
            -Surname $kullanici.Surname `
            -UserPrincipalName $kullanici.UPN `
            -MailNickname ($kullanici.UPN.Split("@")[0]) `
            -Department $kullanici.Department `
            -JobTitle $kullanici.JobTitle `
            -UsageLocation "TR" `
            -PasswordProfile $passwordProfile `
            -AccountEnabled $true
        
        Write-Host "Olusturuldu: $($kullanici.DisplayName)" -ForegroundColor Green
        
        # Sonuçları log dosyasına yaz
        "$($kullanici.UPN), Olusturuldu, $(Get-Date)" | 
            Out-File -FilePath "kullanici_log.txt" -Append
    }
    catch {
        Write-Host "HATA: $($kullanici.DisplayName) - $($_.Exception.Message)" -ForegroundColor Red
        "$($kullanici.UPN), HATA: $($_.Exception.Message), $(Get-Date)" | 
            Out-File -FilePath "kullanici_log.txt" -Append
    }
}

Write-Host "Islem tamamlandi. Log dosyasi: kullanici_log.txt"

Kullanıcı Sorgulama ve Raporlama

Yöneticilerin en sık ihtiyaç duyduğu şeylerden biri de mevcut durumu raporlamak. Hangi kullanıcılar aktif, hangileri devre dışı, son ne zaman giriş yapılmış gibi soruların cevapları kritik önem taşır.

# Son 30 gündür giriş yapmayan kullanıcıları bul
$tarihSiniri = (Get-Date).AddDays(-30).ToString("yyyy-MM-ddTHH:mm:ssZ")

$aktifOlmayanlar = Get-MgUser -All `
    -Filter "signInActivity/lastSignInDateTime le $tarihSiniri" `
    -Property "DisplayName,UserPrincipalName,AccountEnabled,SignInActivity,Department" |
    Where-Object { $_.AccountEnabled -eq $true } |
    Select-Object DisplayName, UserPrincipalName, Department,
        @{N="SonGiris"; E={$_.SignInActivity.LastSignInDateTime}}

$aktifOlmayanlar | Export-Csv -Path "aktif_olmayan_kullanicilar.csv" -NoTypeInformation -Encoding UTF8
Write-Host "Toplam $($aktifOlmayanlar.Count) kullanici bulundu"

Bu raporu aylık çalıştırmak için Task Scheduler veya Azure Automation’a ekleyebilirsiniz. Büyük organizasyonlarda aylık yapılan bu temizlik işlemi hem güvenlik açısından hem de lisans maliyetleri açısından çok önemli.

Grup Yönetimi

Azure AD’de gruplar, kullanıcı yönetiminin temel yapı taşlarından biridir. Uygulamalara erişim, lisans ataması ve politika uygulaması büyük ölçüde gruplara dayanır.

Dinamik Gruplar

Statik gruplarda kullanıcıları tek tek eklemek zorunda kalırsınız. Dinamik gruplar ise belirlediğiniz kurallara göre otomatik olarak üye ekler ve çıkarır. Bu özelliği doğru kullanırsanız hayatınız çok kolaylaşır.

# "Yazilim Gelistirme" departmanındaki tüm kullanıcıları otomatik ekleyen dinamik grup
$dinamikKural = '(user.department -eq "Yazilim Gelistirme")'

New-MgGroup `
    -DisplayName "GRP-Yazilim-Gelistirme" `
    -Description "Yazilim Gelistirme departmani - Dinamik grup" `
    -MailEnabled $false `
    -MailNickname "grp-yazilim-gelistirme" `
    -SecurityEnabled $true `
    -GroupTypes @("DynamicMembership") `
    -MembershipRule $dinamikKural `
    -MembershipRuleProcessingState "On"

Write-Host "Dinamik grup olusturuldu. Uyeler otomatik eklenecek."

Dinamik grup kuralları için bazı yaygın örnekler:

  • Departmana göre: (user.department -eq "Finans")
  • Ülkeye göre: (user.country -eq "TR")
  • Unvana göre: (user.jobTitle -contains "Manager")
  • Çoklu kural: (user.department -eq "IT") -and (user.country -eq "TR")

Gruba Toplu Üye Ekleme

# Bir CSV'den kullanıcıları mevcut bir gruba ekle
$grupID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$uyeler = Import-Csv -Path "eklenecek_uyeler.csv"

foreach ($uye in $uyeler) {
    try {
        $kullanici = Get-MgUser -Filter "UserPrincipalName eq '$($uye.UPN)'"
        
        if ($kullanici) {
            $body = @{
                "@odata.id" = "https://graph.microsoft.com/v1.0/users/$($kullanici.Id)"
            }
            
            New-MgGroupMemberByRef -GroupId $grupID -BodyParameter $body
            Write-Host "Eklendi: $($uye.UPN)" -ForegroundColor Green
        }
        else {
            Write-Host "Kullanici bulunamadi: $($uye.UPN)" -ForegroundColor Yellow
        }
    }
    catch {
        Write-Host "HATA: $($uye.UPN) - $($_.Exception.Message)" -ForegroundColor Red
    }
}

Lisans Yönetimi

Azure AD’de lisans yönetimi sysadminlerin en çok başının ağrıdığı konulardan biridir. Özellikle büyük organizasyonlarda hangi kullanıcıya hangi lisansın atandığını takip etmek kritik önem taşır.

Önemli not: Microsoft artık grup tabanlı lisanslama yöntemini öneriyor. Kullanıcılara tek tek lisans atamak yerine gruplara lisans atayın, kullanıcılar gruba girince lisansı otomatik alsın. Bu yaklaşım hem yönetimi kolaylaştırır hem de hata payını azaltır.

# Mevcut SKU'ları (lisans tiplerini) listele
Get-MgSubscribedSku | Select-Object SkuPartNumber, SkuId,
    @{N="Toplam"; E={$_.PrepaidUnits.Enabled}},
    @{N="Kullanilan"; E={$_.ConsumedUnits}},
    @{N="Bos"; E={$_.PrepaidUnits.Enabled - $_.ConsumedUnits}}

# Kullanıcıya lisans atama
$kullanici = Get-MgUser -Filter "UserPrincipalName eq '[email protected]'"
$sku = Get-MgSubscribedSku | Where-Object { $_.SkuPartNumber -eq "ENTERPRISEPREMIUM" }

Set-MgUserLicense -UserId $kullanici.Id `
    -AddLicenses @{SkuId = $sku.SkuId} `
    -RemoveLicenses @()

Write-Host "Lisans atandi: $($kullanici.DisplayName)"

Şifre Sıfırlama ve Güvenlik İşlemleri

Güvenlik olaylarında veya rutin operasyonlarda kullanıcı şifrelerini sıfırlamak, hesapları kilitlemek veya açmak sık yapılan işlemler arasında.

# Tek kullanıcı şifre sıfırlama
$kullanici = Get-MgUser -Filter "UserPrincipalName eq '[email protected]'"

$yeniSifre = @{
    Password = "YeniGecici@2024!"
    ForceChangePasswordNextSignIn = $true
}

Update-MgUser -UserId $kullanici.Id -PasswordProfile $yeniSifre
Write-Host "Sifre sifirlandi: $($kullanici.DisplayName)"

# Kullanıcı hesabını devre dışı bırakma (ör: işten çıkan çalışan)
Update-MgUser -UserId $kullanici.Id -AccountEnabled $false
Write-Host "Hesap devre disi birakildi: $($kullanici.DisplayName)"

# Tüm aktif oturumları sonlandırma (güvenlik ihlali durumunda)
Revoke-MgUserSignInSession -UserId $kullanici.Id
Write-Host "Tum oturumlar sonlandirildi"

Gerçek Dünya Senaryosu: İşten Çıkan Çalışan Offboarding

Bu senaryo sysadminlerin en sık karşılaştığı durumlardan biri. Bir çalışan işten ayrıldığında yapılması gereken işlemlerin listesi uzundur ve hepsinin eksiksiz yapılması güvenlik açısından kritiktir.

# Offboarding scripti - Kapsamlı kullanici deaktivasyonu
param(
    [Parameter(Mandatory=$true)]
    [string]$KullaniciUPN,
    
    [Parameter(Mandatory=$false)]
    [string]$YedekYonetici = "[email protected]"
)

Connect-MgGraph -Scopes "User.ReadWrite.All","Group.ReadWrite.All","Directory.ReadWrite.All"

$kullanici = Get-MgUser -Filter "UserPrincipalName eq '$KullaniciUPN'" -Property "Id,DisplayName,AccountEnabled"

if (-not $kullanici) {
    Write-Host "HATA: Kullanici bulunamadi: $KullaniciUPN" -ForegroundColor Red
    exit 1
}

Write-Host "Offboarding basliyor: $($kullanici.DisplayName)" -ForegroundColor Yellow

# 1. Hesabi devre disi birak
Update-MgUser -UserId $kullanici.Id -AccountEnabled $false
Write-Host "[OK] Hesap devre disi birakildi" -ForegroundColor Green

# 2. Tum oturumları sonlandir
Revoke-MgUserSignInSession -UserId $kullanici.Id
Write-Host "[OK] Aktif oturumlar sonlandirildi" -ForegroundColor Green

# 3. Tum gruplardan cikar
$gruplar = Get-MgUserMemberOf -UserId $kullanici.Id
foreach ($grup in $gruplar) {
    try {
        Remove-MgGroupMemberByRef -GroupId $grup.Id -DirectoryObjectId $kullanici.Id
        Write-Host "[OK] Gruptan cikarildi: $($grup.AdditionalProperties['displayName'])" -ForegroundColor Green
    }
    catch {
        Write-Host "[UYARI] Gruptan cikarilamadi: $($grup.AdditionalProperties['displayName'])" -ForegroundColor Yellow
    }
}

# 4. Lisanslari kaldir (maliyet optimizasyonu)
$mevcutLisanslar = Get-MgUserLicenseDetail -UserId $kullanici.Id
if ($mevcutLisanslar) {
    $kaldirilacakSKUlar = $mevcutLisanslar | Select-Object -ExpandProperty SkuId
    Set-MgUserLicense -UserId $kullanici.Id `
        -AddLicenses @() `
        -RemoveLicenses $kaldirilacakSKUlar
    Write-Host "[OK] Lisanslar kaldirildi" -ForegroundColor Green
}

# 5. Log kaydi
$logMesaji = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | OFFBOARDING | $KullaniciUPN | Tamamlandi"
$logMesaji | Out-File -FilePath "offboarding_log.txt" -Append
Write-Host "Offboarding tamamlandi: $($kullanici.DisplayName)" -ForegroundColor Cyan

Bu tür bir scripti çalıştırmadan önce mutlaka test ortamında deneyin ve her adım için onay mekanizması ekleyin. İşten çıkan kişi üst yöneticiyse ve siz yanlış hesabı devre dışı bırakırsanız, sonuçları hayal edin.

Koşullu Erişim Politikaları İzleme

Azure AD’nin en güçlü özelliklerinden biri Conditional Access. PowerShell ile mevcut politikaları sorgulamak ve raporlamak için:

# Tüm Conditional Access politikalarını listele
$politikalar = Get-MgIdentityConditionalAccessPolicy

foreach ($politika in $politikalar) {
    Write-Host "Politika: $($politika.DisplayName)" -ForegroundColor Cyan
    Write-Host "  Durum: $($politika.State)"
    Write-Host "  Olusturulma: $($politika.CreatedDateTime)"
    Write-Host "  Son Degisiklik: $($politika.ModifiedDateTime)"
    Write-Host ""
}

# Devre disi politikaları bul (güvenlik auditi için önemli)
$devreDisi = $politikalar | Where-Object { $_.State -eq "disabled" }
Write-Host "Devre disi politika sayisi: $($devreDisi.Count)" -ForegroundColor Yellow

$devreDisi | Select-Object DisplayName, State, CreatedDateTime |
    Export-Csv -Path "devre_disi_politikalar.csv" -NoTypeInformation -Encoding UTF8

Audit Log ve Güvenlik Raporlama

Azure AD, her işlemi loglar. Bu logları düzenli olarak incelemek, hem güvenlik hem de compliance açısından zorunludur.

# Son 24 saatteki kullanici olusturma ve silme islemlerini getir
$baslangic = (Get-Date).AddDays(-1).ToString("yyyy-MM-ddTHH:mm:ssZ")

$auditLoglari = Get-MgAuditLogDirectoryAudit `
    -Filter "activityDateTime ge $baslangic and (activityDisplayName eq 'Add user' or activityDisplayName eq 'Delete user')" `
    -Top 100 |
    Select-Object ActivityDateTime, ActivityDisplayName,
        @{N="YapilanKisi"; E={$_.InitiatedBy.User.UserPrincipalName}},
        @{N="HedefKullanici"; E={$_.TargetResources[0].UserPrincipalName}},
        Result

$auditLoglari | Format-Table -AutoSize
$auditLoglari | Export-Csv -Path "audit_log_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding UTF8

Yaygın Hatalar ve Çözümleri

Yıllar içinde Azure AD yönetiminde karşılaşılan tipik sorunlar ve çözümleri:

“Insufficient privileges” hatası: Graph API’de istediğiniz işlem için gereken scope’u Connect-MgGraph komutuna eklemediğinizde alırsınız. Hangi işlem için hangi iznin gerektiğini Microsoft Graph Explorer üzerinden kontrol edin.

Dinamik grup üyeliği gecikmesi: Dinamik gruplara üye eklenmesi anlık değildir, Azure arka planda işler. Bu süre birkaç dakikadan birkaç saate kadar uzayabilir. Kritik erişim senaryolarında buna güvenmeyin, manuel onay mekanizması ekleyin.

UsageLocation zorunluluğu: Kullanıcıya lisans atamadan önce UsageLocation alanının dolu olması şart. Bu alanı boş bırakırsanız lisans ataması başarısız olur.

Toplu işlemlerde throttling: Graph API’de saniye başına gönderebileceğiniz istek sayısı sınırlıdır. Büyük toplu işlemlerde Start-Sleep -Milliseconds 200 gibi bekleme süreleri ekleyin, yoksa 429 (Too Many Requests) hatası alırsınız.

B2B/Guest kullanıcı karışıklığı: Harici kullanıcıları (guest) yönetirken bazı özellikler farklı davranır. Özellikle grup üyeliği ve lisans atamasında dikkatli olun.

Azure CLI ile Hızlı Referans

Bazı sysadminler PowerShell yerine Azure CLI’yı tercih eder. Sık kullanılan komutlar:

# Kullanici listesi - belirli alanlarla
az ad user list --query "[].{Ad:displayName, UPN:userPrincipalName, Durum:accountEnabled}" -o table

# Kullanici detayi
az ad user show --id "[email protected]"

# Kullanici guncelleme
az ad user update 
  --id "[email protected]" 
  --job-title "Lead Developer" 
  --department "Platform Ekibi"

# Hesap devre disi birakma
az ad user update 
  --id "[email protected]" 
  --account-enabled false

# Gruba uye listesi
az ad group member list 
  --group "GRP-Yazilim-Gelistirme" 
  --query "[].userPrincipalName" -o tsv

Otomasyon ve Zamanlama

Bu scriptleri bir kere yazıp bırakmak yetmez. Düzenli çalışmaları için zamanlama yapmanız gerekir. Azure Automation Runbooks bu iş için ideal:

  • Aylık inaktif kullanıcı raporu
  • Haftalık lisans kullanım raporu
  • Günlük offboarding takip raporu
  • Anlık yeni çalışan onboarding otomasyonu

Azure Automation ile bu scriptleri bulutta çalıştırabilir, Managed Identity kullanarak kimlik bilgisi saklamadan güvenli bağlantı kurabilirsiniz. Ayrıca Logic Apps veya Power Automate ile HR sistemleriyle entegrasyon sağlamak da oldukça yaygın bir senaryo haline geldi.

Sonuç

Azure AD kullanıcı yönetimi, doğru araçları ve yaklaşımları benimsediğinizde organizasyonunuzda ciddi verimlilik artışı sağlar. Manuel, portal üzerinden yapılan işlemleri mümkün olduğunca otomasyona bağlamak hem hataları azaltır hem de zaman kazandırır.

Özetle dikkat etmeniz gereken kritik noktalar:

  • Microsoft Graph PowerShell SDK’ya geçiş planınızı yapın, eski AzureAD modülünün kullanım ömrü dolmak üzere
  • Grup tabanlı lisanslama kullanın, kullanıcı bazlı atamayı ölçeklenebilir değil
  • Dinamik grupları aktif olarak kullanın, departman ve rol bazlı üyelikler için idealdir
  • Offboarding sürecinizi scriptle otomatize edin, insan hatası kabul edilemez
  • Audit loglarını düzenli inceleyin ve raporlayın, hem güvenlik hem de compliance için zorunlu
  • Throttling limitlerini göz önünde bulundurarak toplu işlemlerinizi tasarlayın

Bu alanda ilerlemek istiyorsanız Microsoft’un resmi Graph API dokümantasyonunu ve Graph Explorer aracını sık kullanın. Her operasyon için önce Graph Explorer’da test edin, sonra scripte dökün. Bu alışkanlık, production ortamında karşılaşacağınız sürprizlerin önüne geçer.

Bir yanıt yazın

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