Senaryo: IK'dan 50 Yeni Çalışan Listesi Geldi

Manuel olarak admin portal'dan tek tek 50 kullanıcı oluşturmak ~3 saat sürer. PowerShell ile 5 dakikada oluşur, hatasız + raporlu + lisanslı.

1) CSV Şablonu Hazırla

IK'dan gelen bilgileri standardize edin. Örnek new_users.csv:

FirstName,LastName,Username,Department,JobTitle,Manager,License
Ahmet,Yılmaz,ahmet.yilmaz,Pazarlama,Pazarlama Uzmanı,gulay@firmaniz.com,O365_BUSINESS_ESSENTIALS
Ayşe,Demir,ayse.demir,Finans,Muhasebe Uzmanı,osman@firmaniz.com,O365_BUSINESS_PREMIUM
Mehmet,Kaya,mehmet.kaya,IT,Yazılım Geliştirici,emre@firmaniz.com,O365_BUSINESS_PREMIUM

UTF-8 kaydet (Türkçe karakter için). Excel'de "CSV UTF-8 (.csv)" formatı.

2) PowerShell Modülleri

Install-Module Microsoft.Graph -Scope CurrentUser
Connect-MgGraph -Scopes "User.ReadWrite.All", "Group.ReadWrite.All", "Organization.Read.All"

3) SKU Map (Lisans Adı → ID)

$skuMap = @{}
Get-MgSubscribedSku -All | ForEach-Object {
  $skuMap[$_.SkuPartNumber] = $_.SkuId
}

# Kontrol
$skuMap | Format-Table

4) Toplu Oluşturma Scripti

$csv = Import-Csv .\new_users.csv -Encoding UTF8
$domain = "firmaniz.com"
$report = @()

foreach ($row in $csv) {
  $upn = "$($row.Username)@$domain"

  # Aynı UPN var mı kontrol
  try {
    $existing = Get-MgUser -UserId $upn -ErrorAction Stop
    Write-Warning "$upn zaten var, atlandı."
    $report += [PSCustomObject]@{
      User = $upn; Status = "EXISTS"; Password = ""; Error = ""
    }
    continue
  } catch {
    # Yok — devam
  }

  # Geçici parola üret
  $pass = -join ((33..126) | Get-Random -Count 14 | ForEach-Object {[char]$_})
  $pass = $pass -replace "[\\""]", "X"  # quote/backslash temizliği

  $params = @{
    AccountEnabled = $true
    DisplayName = "$($row.FirstName) $($row.LastName)"
    GivenName = $row.FirstName
    Surname = $row.LastName
    MailNickname = $row.Username
    UserPrincipalName = $upn
    PasswordProfile = @{
      Password = $pass
      ForceChangePasswordNextSignIn = $true
    }
    UsageLocation = "TR"
    JobTitle = $row.JobTitle
    Department = $row.Department
  }

  try {
    $newUser = New-MgUser -BodyParameter $params -ErrorAction Stop

    # Lisans ata
    if ($row.License -and $skuMap.ContainsKey($row.License)) {
      Set-MgUserLicense -UserId $upn `
        -AddLicenses @(@{ SkuId = $skuMap[$row.License] }) `
        -RemoveLicenses @() -ErrorAction Stop
    }

    # Manager ata
    if ($row.Manager) {
      try {
        $mgr = Get-MgUser -UserId $row.Manager -ErrorAction Stop
        $managerRef = @{ "@odata.id" = "https://graph.microsoft.com/v1.0/users/$($mgr.Id)" }
        Set-MgUserManagerByRef -UserId $upn -BodyParameter $managerRef
      } catch {
        Write-Warning "Manager atanamadı: $($row.Manager)"
      }
    }

    Write-Host "✓ $upn oluşturuldu" -ForegroundColor Green
    $report += [PSCustomObject]@{
      User = $upn; Status = "OK"; Password = $pass; Error = ""
    }

  } catch {
    Write-Host "✗ $upn hata: $($_.Exception.Message)" -ForegroundColor Red
    $report += [PSCustomObject]@{
      User = $upn; Status = "FAIL"; Password = ""; Error = $_.Exception.Message
    }
  }
}

# Rapor CSV (parolaları içerir, güvenli sakla)
$report | Export-Csv .\import_report.csv -NoTypeInformation -Encoding UTF8
Write-Host "`nRapor: import_report.csv ($($report.Count) kullanıcı)"
Write-Host "  Başarılı: $(($report | Where Status -eq 'OK').Count)"
Write-Host "  Mevcut: $(($report | Where Status -eq 'EXISTS').Count)"
Write-Host "  Hata: $(($report | Where Status -eq 'FAIL').Count)"

5) Departman Bazlı Otomatik Grup Atama

"Pazarlama" departmanına yeni eklenenler otomatik "Pazarlama-Grubu"na girsin:

$deptGroupMap = @{
  "Pazarlama" = "Pazarlama-Grubu"
  "Finans" = "Finans-Grubu"
  "IT" = "IT-Grubu"
}

foreach ($row in $csv) {
  $upn = "$($row.Username)@$domain"
  $groupName = $deptGroupMap[$row.Department]
  if (-not $groupName) { continue }

  $grp = Get-MgGroup -Filter "displayName eq \u0027$groupName\u0027"
  $user = Get-MgUser -UserId $upn

  if ($grp -and $user) {
    try {
      New-MgGroupMember -GroupId $grp.Id -DirectoryObjectId $user.Id -ErrorAction Stop
      Write-Host "  → $upn $groupName grubuna eklendi"
    } catch {
      Write-Warning "Grup eklenemedi: $($_.Exception.Message)"
    }
  }
}

6) Hoşgeldin Maili Gönder

foreach ($r in ($report | Where Status -eq "OK")) {
  $body = @"
Merhaba,

Microsoft 365 hesabınız oluşturuldu:
  Kullanıcı: $($r.User)
  Geçici parola: $($r.Password)

İlk girişte parolanızı değiştirmeniz istenecektir.
MFA kurulumu için: https://aka.ms/mfasetup

İyi çalışmalar.
IT Ekibi
"@

  Send-MgUserMail -UserId admin@firmaniz.com -BodyParameter @{
    Message = @{
      Subject = "Microsoft 365 Hesabınız Hazır"
      Body = @{ ContentType = "Text"; Content = $body }
      ToRecipients = @(@{ EmailAddress = @{ Address = $r.User } })
    }
  }
}

Yaygın 5 Hata

1. "Property usageLocation is required for assigning licenses"

Lisans atamadan önce UsageLocation ayarlanmalı. Yukarıdaki script'te zaten "TR".

2. "Insufficient privileges"

Connect-MgGraph'ta eksik scope. User.ReadWrite.All yerine User.Read.All denmiş olabilir.

3. UPN dublike

"ahmet.yilmaz" zaten var. CSV'de kontrol et veya numerik suffix ekle (ahmet.yilmaz2).

4. Lisans bitti — "Could not assign license"

Tenant'ta yeterli lisans yok. Get-MgSubscribedSku ile ConsumedUnits / PrepaidUnits.Enabled kontrol et.

5. Türkçe karakter "?" oldu

CSV UTF-8 olmalı. Notepad'de aç → Save As → Encoding: UTF-8.

Sonraki Adımlar (Manuel veya Ek Otomasyon)

  • Out-of-office mesajı (yeni gelen için "Yeni katıldım" şablonu)
  • Mailbox quota / signature deployment (Exchange Online cmdlets)
  • Intune cihaz enrollment davetiyesi
  • Teams kanal davetleri

SSS

Parola güçlülük şartları?

Microsoft 365: 8+ karakter, 3 farklı sınıf (büyük/küçük/sayı/sembol), eski parolalardan farklı. Yukarıdaki random generator karşılar.

UPN suffix .onmicrosoft.com mu, custom mu?

Custom domain doğrulanmışsa onu kullan (ahmet@firmaniz.com). Aksi halde tenant default (ahmet@firmaniz.onmicrosoft.com).

Aynı script'i Active Directory için kullanabilir miyim?

Hayır — AD on-prem için New-ADUser (RSAT modülü). Senkronize ediliyorsa AD'de oluştur, AD Connect Cloud'a iter. AD Connect vs Cloud Sync.

Manager attribute neden önemli?

Approval workflow'lar (PIM, expense), org chart, yokluğunda mailing rules için.

Geçici parolalar e-postayla nasıl gönderilir güvenli?

İdeal: KOBİ için manager'a tek e-posta + telefonla parola söyleme. Büyük ölçek: Authenticator'ı self-service onboard et, parolasız.

Toplu kullanıcı oluşturma + onboarding paketi için bize ulaşın → CSV şablonu + script + ilk-gün otomasyonu.