Microsoft 365 admin'iniz için tek bir cheat sheet — kullanıcı oluşturmadan Power Platform DLP'ye kadar 19 hazır PowerShell senaryosu. Microsoft 365 admin merkezi (admin.microsoft.com) günlük işlerin %90'ını çözer; ancak toplu işlemler, raporlama, audit, migration, compliance, SharePoint provisioning, Teams policy, Defender ve Power Platform governance için PowerShell vazgeçilmezdir. Bu yazıda 6 farklı PowerShell modülünü, 19 sık kullanılan senaryoyu kategorilere ayırarak ve örnek komutlarla sunuyoruz — bookmark'lanacak bir referans.

6 Modül Kurulum + Bağlantı

M365 PowerShell ekosistemi 6 ana modülden oluşur. Her birinin kendi bağlantısı vardır:

# PowerShell'i yönetici olarak başlatın

# 1) Microsoft Graph — Kullanıcı, Lisans, MFA, CA, Audit
Install-Module Microsoft.Graph -Scope CurrentUser -Force
Connect-MgGraph -Scopes "User.ReadWrite.All","Group.ReadWrite.All","Directory.ReadWrite.All",`
  "AuditLog.Read.All","Policy.ReadWrite.ConditionalAccess",`
  "UserAuthenticationMethod.Read.All","IdentityRiskyUser.Read.All"

# 2) Exchange Online — Mailbox, Distribution Group, Migration
Install-Module ExchangeOnlineManagement -Scope CurrentUser -Force
Connect-ExchangeOnline -UserPrincipalName admin@sirketim.com.tr

# 3) Security & Compliance — Litigation Hold, DLP, Anti-Phishing
Connect-IPPSSession -UserPrincipalName admin@sirketim.com.tr

# 4) SharePoint Online
Install-Module Microsoft.Online.SharePoint.PowerShell -Scope CurrentUser -Force
Connect-SPOService -Url https://sirketim-admin.sharepoint.com

# 5) Microsoft Teams
Install-Module MicrosoftTeams -Scope CurrentUser -Force
Connect-MicrosoftTeams

# 6) Power Platform Admin (DLP, Environment)
Install-Module Microsoft.PowerApps.Administration.PowerShell -Scope CurrentUser -Force
Add-PowerAppsAccount
Eski modüllerden vazgeçin: MSOnline ve AzureAD modülleri Mart 2024 sonrası kademeli kapatma altında. Yeni script'lerinizde mutlaka Microsoft.Graph kullanın. Get-MsolUserGet-MgUser, Get-AzureADUserGet-MgUser.

19 Senaryo Özet Tablo (9 Kategori)

Kategori#SenaryoModül
Kullanıcı1Yeni kullanıcı oluşturMicrosoft.Graph
2Lisans ataMicrosoft.Graph
3Parola sıfırlaMicrosoft.Graph
4CSV ile toplu kullanıcı oluşturMicrosoft.Graph
Mailbox5Mailbox istatistikleri (tek)ExchangeOnline
6Tüm mailbox boyutları (CSV)ExchangeOnline
7Distribution group oluştur + üye ekleExchangeOnline
Audit8MFA durum raporuMicrosoft.Graph
9Sign-in / login geçmişiMicrosoft.Graph
10Auto-forward audit (BEC önleme)ExchangeOnline
Migration11Hybrid mailbox migration batchExchangeOnline
Identity12Conditional Access (basic MFA template)Microsoft.Graph
13Conditional Access (risk-based + location-based)Microsoft.Graph
Compliance14Litigation HoldExchangeOnline
15DLP politikası (TC Kimlik / Kart No)IPPSSession
SharePoint16SharePoint Online site oluşturSharePoint Online
Teams17Teams policy (Messaging/Meeting/Calling)MicrosoftTeams
Defender18Anti-Phishing C-level impersonation korumaIPPSSession
Power Platform19Power Platform DLP (connector classification)PowerApps Admin

Senaryo Örnekleri — Her Kategoriden 1-2 Komut

Kullanıcı: Lisans Ata (Microsoft.Graph)

# Önce SKU listesini gör (organizasyonunuzdaki mevcut SKU'lar)
Get-MgSubscribedSku | Select SkuPartNumber, ConsumedUnits, ActiveUnits, SkuId

# Kullanıcıya Microsoft 365 Business Premium ata
$sku = Get-MgSubscribedSku | Where-Object { $_.SkuPartNumber -eq "SPB" }

Set-MgUserLicense `
    -UserId "ahmet@sirket.com" `
    -AddLicenses @(@{SkuId = $sku.SkuId}) `
    -RemoveLicenses @()

# Sonuç doğrulama
Get-MgUserLicenseDetail -UserId "ahmet@sirket.com" | Select SkuPartNumber, ServicePlans

Yaygın SKU PartNumber'lar:

  • O365_BUSINESS_ESSENTIALS = Business Basic
  • O365_BUSINESS_PREMIUM = Business Standard (eski isim, hâlâ kullanılıyor)
  • SPB = Business Premium
  • ENTERPRISEPACK = Office 365 E3
  • SPE_E5 = Microsoft 365 E5
  • EXCHANGESTANDARD = Exchange Online Plan 1
  • EXCHANGEENTERPRISE = Exchange Online Plan 2
  • SPE_F1 = Microsoft 365 F1
  • DESKLESSPACK = Microsoft 365 F3

Mailbox: Tüm Mailbox Boyutları CSV (ExchangeOnline)

# Tüm mailbox boyutları, en büyükten küçüğe sıralı
$report = Get-Mailbox -ResultSize Unlimited |
    Get-MailboxStatistics |
    Sort-Object -Property TotalItemSize -Descending |
    Select DisplayName,
           ItemCount,
           @{N='SizeGB';E={[math]::Round($_.TotalItemSize.Value.ToBytes() / 1GB, 2)}},
           @{N='SizeMB';E={[math]::Round($_.TotalItemSize.Value.ToBytes() / 1MB, 0)}},
           LastLogonTime,
           DeletedItemCount

# Konsola yaz
$report | Format-Table -AutoSize

# CSV'ye export (Türkçe karakter için UTF8)
$report | Export-Csv -Path "C:\reports\mailbox-sizes.csv" -NoTypeInformation -Encoding UTF8

# 50 GB'ı geçen kullanıcıları belirle (Plan 1 kotası kontrolü)
$report | Where-Object { $_.SizeGB -ge 50 } | Format-Table

Audit: MFA Durum Raporu (Microsoft.Graph)

# MFA durum raporu — Microsoft'un built-in raporunu kullan (hızlı yöntem)
$report = Get-MgReportAuthenticationMethodUserRegistrationDetail -All |
    Select UserPrincipalName,
           UserDisplayName,
           IsMfaRegistered,
           IsMfaCapable,
           IsAdmin,
           DefaultMfaMethod,
           @{N='RegisteredMethods';E={ ($_.MethodsRegistered -join ', ') }}

$report | Format-Table -AutoSize
$report | Export-Csv -Path "C:\reports\mfa-report.csv" -NoTypeInformation -Encoding UTF8

# Özet
$total = $report.Count
$mfaOn = ($report | Where-Object { $_.IsMfaRegistered }).Count
Write-Host "MFA aktif: $mfaOn / $total ($([math]::Round($mfaOn/$total*100, 1))%)" -ForegroundColor Cyan

# MFA olmayan admin'leri tespit et (KRİTİK)
$report | Where-Object { $_.IsAdmin -and -not $_.IsMfaRegistered } |
    Select UserPrincipalName, UserDisplayName |
    Format-Table

Audit: Auto-Forward Audit — BEC Saldırı Önleme (ExchangeOnline)

# Tüm mailbox'larda gizli auto-forward kuralı tespit et
# BEC (Business Email Compromise) saldırılarında ele geçirilen hesaba forward konur

# Yöntem 1: Mailbox-level forwarding
$mailboxFwd = Get-Mailbox -ResultSize Unlimited |
    Where-Object { $_.ForwardingSmtpAddress -ne $null -or $_.ForwardingAddress -ne $null } |
    Select Name, PrimarySmtpAddress, ForwardingSmtpAddress, ForwardingAddress

# Yöntem 2: Inbox kuralları (gizli filtre — admin görünmez)
$ruleFwd = @()
Get-Mailbox -ResultSize Unlimited | ForEach-Object {
    $rules = Get-InboxRule -Mailbox $_.UserPrincipalName -ErrorAction SilentlyContinue |
        Where-Object { $_.ForwardTo -or $_.RedirectTo }
    foreach ($r in $rules) {
        $ruleFwd += [PSCustomObject]@{
            Mailbox = $_.UserPrincipalName
            RuleName = $r.Name
            Enabled = $r.Enabled
            ForwardTo = ($r.ForwardTo -join '; ')
            RedirectTo = ($r.RedirectTo -join '; ')
        }
    }
}

Write-Host "Mailbox-level forwarding: $($mailboxFwd.Count)" -ForegroundColor Yellow
Write-Host "Inbox rule forwarding: $($ruleFwd.Count)" -ForegroundColor Yellow
Write-Host "→ Şüpheli forward'ları gözden geçir. Yetkisiz olanlar BEC saldırı göstergesidir." -ForegroundColor Red

Identity: Risk-Based Conditional Access (Microsoft.Graph)

Microsoft Entra Identity Protection sinyalleriyle adaptif politika. Önemli not: Sign-in risk medium → MFA + high → BLOK için iki ayrı politika gerekir (tek politikada hem MFA hem BLOK olmaz).

# Politika 1: Sign-in risk MEDIUM → MFA
$breakGlass = Get-MgUser -Filter "userPrincipalName eq 'breakglass@sirket.onmicrosoft.com'"

$conditions1 = @{
    Users = @{ IncludeUsers = @("All"); ExcludeUsers = @($breakGlass.Id) }
    Applications = @{ IncludeApplications = @("All") }
    SignInRiskLevels = @("medium")
    ClientAppTypes = @("all")
}
$grantControls1 = @{ Operator = "OR"; BuiltInControls = @("mfa") }

New-MgIdentityConditionalAccessPolicy `
    -DisplayName "CA010-Risk-MEDIUM-MFA" `
    -State "enabledForReportingButNotEnforced" `
    -Conditions $conditions1 `
    -GrantControls $grantControls1

# Politika 2: Sign-in risk HIGH → BLOK
$conditions2 = $conditions1.Clone()
$conditions2.SignInRiskLevels = @("high")
$grantControls2 = @{ Operator = "OR"; BuiltInControls = @("block") }

New-MgIdentityConditionalAccessPolicy `
    -DisplayName "CA011-Risk-HIGH-BLOCK" `
    -State "enabledForReportingButNotEnforced" `
    -Conditions $conditions2 `
    -GrantControls $grantControls2

# Microsoft Entra ID P2 (E5 dahil veya P2 add-on $9) zorunlu
Write-Host "→ Sign-in logs > CA tab'da etkilenenleri 2-3 hafta izle, sonra 'enabled'a çevir" -ForegroundColor Cyan

Compliance: Litigation Hold (ExchangeOnline)

# Tek mailbox litigation hold (KVKK Madde 7 + hukuki süreç için)
Set-Mailbox -Identity "ahmet@sirket.com" `
    -LitigationHoldEnabled $true `
    -LitigationHoldDuration 2555 `
    -LitigationHoldOwner "legal@sirket.com" `
    -RetentionComment "2026-LIT-001 — XYZ davası"

# Departman bazlı (örn. Hukuk departmanı)
$mailboxes = Get-User -ResultSize Unlimited -Filter "Department -eq 'Hukuk'" |
    ForEach-Object { Get-Mailbox -Identity $_.UserPrincipalName -ErrorAction SilentlyContinue }

foreach ($mb in $mailboxes) {
    Set-Mailbox -Identity $mb.UserPrincipalName `
        -LitigationHoldEnabled $true `
        -LitigationHoldDuration 2555 `
        -LitigationHoldOwner "legal@sirket.com" `
        -RetentionComment "Hukuk departmanı blanket hold"
    Write-Host "✓ Hold: $($mb.UserPrincipalName)" -ForegroundColor Green
}

# Doğrulama
Get-Mailbox -ResultSize Unlimited |
    Where-Object { $_.LitigationHoldEnabled } |
    Select Name, LitigationHoldDate, LitigationHoldDuration, LitigationHoldOwner |
    Format-Table -AutoSize

SharePoint: Site Oluştur (SharePoint Online)

# YOL 1: Klasik Team Site (M365 Group YOK)
Connect-SPOService -Url https://sirketim-admin.sharepoint.com

New-SPOSite `
    -Url "https://sirketim.sharepoint.com/sites/proje-x" `
    -Owner "admin@sirketim.com.tr" `
    -StorageQuota 5000 `
    -Title "Proje X Çalışma Alanı" `
    -Template "STS#3" `
    -LocaleId 1055 `
    -TimeZoneId 13  # (UTC+03:00) Istanbul

# YOL 2 (Önerilen): M365 Group bağlı modern Team Site
# Microsoft Graph üzerinden grup oluştur, SharePoint sitesi otomatik gelir
Connect-MgGraph -Scopes "Group.ReadWrite.All"

$groupParams = @{
    DisplayName = "Proje X Çalışma Alanı"
    MailNickname = "proje-x"
    Description = "Proje X — Microsoft 365 Group bağlı SharePoint sitesi"
    GroupTypes = @("Unified")
    MailEnabled = $true
    SecurityEnabled = $false
    Visibility = "Private"
    "Owners@odata.bind" = @("https://graph.microsoft.com/v1.0/users('admin@sirketim.com.tr')")
}

$group = New-MgGroup -BodyParameter $groupParams
Write-Host "M365 Group + SharePoint sitesi 1-3 dakika içinde hazır olur" -ForegroundColor Green

Teams: Strict Messaging Policy (MicrosoftTeams)

# Compliance/finans/hukuk için sıkı messaging policy
Connect-MicrosoftTeams

New-CsTeamsMessagingPolicy -Identity "Strict-Compliance" `
    -AllowGiphy $false `
    -AllowMemes $false `
    -AllowStickers $false `
    -AllowUrlPreviews $true `
    -AllowOwnerDeleteMessage $true `
    -AllowUserDeleteMessage $false `
    -AllowUserEditMessage $false `
    -AllowImmersiveReader $true `
    -ChannelsInChatListEnabledType DisabledUserOverride

# Tek kullanıcıya ata
Grant-CsTeamsMessagingPolicy -Identity "ahmet@sirket.com" -PolicyName "Strict-Compliance"

# Toplu atama (Hukuk departmanı)
Get-CsOnlineUser -Filter {Department -eq "Hukuk"} | ForEach-Object {
    Grant-CsTeamsMessagingPolicy -Identity $_.UserPrincipalName -PolicyName "Strict-Compliance"
    Write-Host "✓ Atandı: $($_.UserPrincipalName)" -ForegroundColor Green
}

Defender: Anti-Phishing C-Level Koruma (IPPSSession)

# BEC (Business Email Compromise) önleme — CEO/CFO impersonation koruması
Connect-IPPSSession

# 1) Anti-phishing politikasını oluştur
New-AntiPhishPolicy -Name "C-Level-Impersonation-Protection" `
    -EnableTargetedUserProtection $true `
    -TargetedUsersToProtect @(
        "ceo@sirket.com:Ahmet Yılmaz",
        "cfo@sirket.com:Ayşe Demir",
        "coo@sirket.com:Mehmet Kaya"
    ) `
    -TargetedUserProtectionAction Quarantine `
    -EnableTargetedDomainsProtection $true `
    -TargetedDomainsToProtect @("sirket.com") `
    -TargetedDomainProtectionAction Quarantine `
    -EnableMailboxIntelligence $true `
    -EnableMailboxIntelligenceProtection $true `
    -MailboxIntelligenceProtectionAction Quarantine `
    -PhishThresholdLevel 2 `
    -EnableSpoofIntelligence $true

# 2) Politikayı bağla
New-AntiPhishRule -Name "C-Level-Rule" `
    -AntiPhishPolicy "C-Level-Impersonation-Protection" `
    -RecipientDomainIs "sirket.com" `
    -Priority 0

# Microsoft Defender for Office 365 Plan 1 (E3 dahil değil) gerek

Power Platform: DLP (PowerApps Admin)

# Connector classification — Business / Non-Business / Blocked
Add-PowerAppsAccount

# Politika oluştur (tüm ortamlar, default Non-Business)
$dlp = New-DlpPolicy -DisplayName "TR-KVKK-Production-DLP" `
    -EnvironmentType "AllEnvironments" `
    -DefaultGroup "NonBusiness"

# Business connector'lar (iş verisine erişebilir)
$businessConnectors = @(
    "shared_office365",
    "shared_sharepointonline",
    "shared_onedriveforbusiness",
    "shared_microsoftteams",
    "shared_excelonlinebusiness"
)
foreach ($c in $businessConnectors) {
    Add-CustomConnectorToPolicy -PolicyName $dlp.PolicyName `
        -ConnectorId $c -GroupName "Business" -ConnectorType "Microsoft" -ErrorAction SilentlyContinue
}

# Yasaklı connector'lar (KVKK Madde 9 yurtdışı aktarım koruması)
$blockedConnectors = @(
    "shared_twitter",
    "shared_dropbox",
    "shared_facebook",
    "shared_telegram"
)
foreach ($c in $blockedConnectors) {
    Add-CustomConnectorToPolicy -PolicyName $dlp.PolicyName `
        -ConnectorId $c -GroupName "Blocked" -ConnectorType "Microsoft" -ErrorAction SilentlyContinue
}

Write-Host "DLP aktif. Mevcut Power Apps/Flow'lar etkilenebilir — admin merkezde uyarı kontrol et" -ForegroundColor Yellow

Production'da Güvenli Çalıştırma — Kontrol Listesi

  1. Test ortamında deneyin. Yeni script'leri ilk önce test tenant'ında çalıştırın.
  2. -WhatIf parametresi ile dry-run. Komutun gerçek etkisini uygulamadan ne yapacağını gösterir. Geri dönülmez işlemlerde mutlaka.
  3. Toplu işlemleri batch'leyin. 1000 kullanıcılı toplu lisans atamasını 10 batch × 100 olarak çalıştırın; tek seferde olası throttling riski azalır.
  4. Logging ekleyin. Start-Transcript -Path "C:\Logs\m365-$(Get-Date -Format 'yyyy-MM-dd-HHmm').log" ile tüm output'u dosyaya kaydedin.
  5. Hatalarda durdurun. $ErrorActionPreference = 'Stop' veya komutlara -ErrorAction Stop ekleyin.
  6. Just-in-Time admin (PIM). Sürekli Global Admin yerine PIM ile geçici (saatlik) yetki alın. Microsoft Entra ID P2 ile gelir.
  7. Service Principal (App Registration) kullanın. İnsan hesabı yerine, sınırlı izinlere sahip uygulama hesabı ile otomatize edin. Azure Automation Runbook ile kombinasyon ideal.

PIM + Service Principal — Güvenli Admin Modeli

Sürekli Global Admin yetkisi büyük güvenlik riski. Modern best practice:

  1. Privileged Identity Management (PIM): Microsoft Entra ID P2 ile gelir. İnsan admin'ler "eligible" rolde tutulur, gerektiğinde aktive eder, 4-8 saat sonra otomatik düşer. Tüm rol aktivasyonu loglanır.
  2. Service Principal (App Registration): Otomatik script'ler için insan hesabı yerine. Azure portal → App Registrations → New → Microsoft Graph API izinleri ver → certificate-based authentication.
  3. Azure Automation Runbook: Service Principal + PowerShell script + zamanlama. Örnek: aylık inactive user raporu, haftalık MFA audit.
  4. Conditional Access ile yönetici hesaplarını koru: trusted location'dan + corporate cihazdan + MFA zorunlu.

Sıradaki Adım: Form-Tabanlı Komut Üretici

M365 PowerShell Komut Üretici — 19 Senaryo Form-Tabanlı

Yukarıdaki 19 senaryoyu form doldurarak özelleştirin — UPN, lisans, parola, hold süresi gibi parametreleri girin, kopyalanabilir PowerShell komutu üretsin. .ps1 olarak indirebilirsiniz.

PowerShell Komut Üretici Aracını Aç →

Microsoft Yetkili Çözüm Ortağı (CSP) olarak onboarding/offboarding otomasyonu + periyodik audit script'leri + Service Principal yapılandırması + Power Automate entegrasyonu hizmetlerini sunuyoruz. WhatsApp 0216 344 15 59.

Sıkça Sorulan Sorular

Microsoft Graph PowerShell ile MSOnline / AzureAD modülü arasında ne fark var?

MSOnline ve AzureAD modülleri Microsoft tarafından deprecated edilmiştir; Mart 2024 sonrası fonksiyonelliği kademeli olarak kapatılıyor. Yeni standart Microsoft Graph PowerShell (Microsoft.Graph modülü) — Microsoft Graph API üzerinden çalışır, modern auth destekler, daha geniş işlevsellik sunar. Tüm yeni script'lerinizde Microsoft.Graph kullanın.

PowerShell 7 mi Windows PowerShell 5.1 mi?

PowerShell 7 (cross-platform, modern .NET tabanlı) önerilir. Daha hızlı, daha az hata, paralel ForEach desteği. Microsoft.Graph ve ExchangeOnlineManagement modülleri her ikisinde de çalışır. Windows PowerShell 5.1 sadece Windows'a özel, eski .NET Framework tabanlı, yeni özellikler eklenmiyor.

Connect-MgGraph hangi izinleri istemeli?

İhtiyacınız olan minimum scope'ları belirtin. Yaygın scope'lar: 'User.ReadWrite.All' (kullanıcı CRUD), 'Group.ReadWrite.All' (grup yönetimi), 'Directory.ReadWrite.All' (lisans atama), 'AuditLog.Read.All' (sign-in geçmişi), 'Policy.ReadWrite.ConditionalAccess' (CA), 'UserAuthenticationMethod.Read.All' (MFA raporu), 'IdentityRiskyUser.Read.All' (risk-based CA için).

-WhatIf parametresi nedir?

-WhatIf, komutun gerçek etkisini uygulamadan ne yapacağını gösterir. Toplu silme, lisans kaldırma gibi geri dönülmez işlemlerde mutlaka önce -WhatIf ile test edin. Örnek: Remove-MgUser -UserId 'user@sirket.com' -WhatIf çıktısı "What if: Performing the operation Remove on target..." der ama gerçek silme yapmaz.

CSV toplu işlemde encoding sorunu yaşıyorum, ne yapmalıyım?

Türkçe karakterli (ç,ğ,ı,ö,ş,ü) CSV'leri Excel UTF-8 BOM ile kaydedilmelidir. PowerShell'de okurken: Import-Csv users.csv -Encoding UTF8. Ayrıca CSV'deki sütun adları PowerShell parametreleri ile eşleşmeli (örn: DisplayName, UserPrincipalName, Password).

MFA raporu komutu çok yavaş çalışıyor, hızlandırmak için ne yapabilirim?

Get-MgUser -All ile birlikte ForEach-Object yerine ForEach -Parallel (PowerShell 7) kullanın: 1000+ kullanıcı için 10× hızlanır. Ya da Get-MgReportAuthenticationMethodUserRegistrationDetail komutu — Microsoft'un built-in rapor API'si, çok daha hızlı.

Connect-MgGraph 'AADSTS50059' hatası alıyorum, ne yapmalıyım?

Bu genelde tenant adı bozulması veya conditional access engellemesi. Çözümler: (1) Connect-MgGraph -TenantId 'sirketim.onmicrosoft.com' ile tenant'ı açıkça belirtin, (2) Conditional Access politikalarınızda Microsoft Graph PowerShell client uygulamasının izinli olduğundan emin olun, (3) Hesap MFA gerektiriyorsa modern auth devrede mi kontrol edin. AADSTS hata kodu lookup aracımız 20+ kod için detaylı çözüm verir.

Kaynaklar