Exchange Çalışma Saatleri (Working Hours) Toplu Kontrol ve Düzeltme Script’i

Kurumsal ortamlarda Exchange kullanıcılarının takvim çalışma saatleri (Working Hours) çoğu zaman standart dışı olabiliyor.
Bazı kullanıcılar 17:00’da bitirirken, bazıları 17:30, bazıları ise tamamen farklı saatlerde görünebiliyor.
Bu durum özellikle toplantı planlama, Free/Busy ve otomatik randevu senaryolarında ciddi karışıklıklara yol açıyor.

Bu yazıda, Exchange Online / Exchange Management Shell üzerinde çalışan ve bu sorunu uçtan uca çözen bir PowerShell script’ini paylaşıyorum.


Script Ne Yapar?

Bu script:

  1. Çalışma saatlerini hardcode etmez
  2. Başlangıç ve bitiş saatini kullanıcıdan alır
  3. Tüm mailbox’ları sıfırdan tarar
  4. Girilen saatlere uymayan kullanıcıları altta listeler
  5. Kullanıcıya sorar:
    • “Bu hatalıları düzelteyim mi?”
  6. Onay verilirse (y) kalıcı olarak düzeltir
  7. Onay verilmezse (n) script’i kapatır

Yani hem kontrol, hem raporlama, hem de düzeltme tek script içindedir.


Neden Kullanıcıdan Saat Alıyor?

Her firmanın çalışma saatleri farklıdır.

  • 08:00 – 17:00
  • 08:30 – 17:30
  • 09:00 – 18:00

Bu yüzden script:

  • 08.00, 17.30 gibi formatları kabul eder
  • Nokta (.) veya iki nokta (:) farkını tolere eder
  • Yanlış format girilirse script’i durdurur

Bu sayede farklı ortamlarda tekrar tekrar düzenleme ihtiyacı olmaz.


Teknik Detaylar

  • Get-Mailbox ile tüm mailbox’lar taranır
  • Her kullanıcı için:
    • Get-MailboxCalendarConfiguration çağrılır
  • Hedef saatler ile karşılaştırma yapılır
  • Uymayanlar memory’de bir listeye alınır
  • Düzeltme aşamasında:
    • Set-MailboxCalendarConfiguration kullanılır
  • Değişiklik kalıcıdır, sadece PowerShell objesi değil Exchange tarafı güncellenir

Script, sadece RAM’de değişiklik yapıp tekrar taramada eski veriyi getiren hatalı yaklaşımlardan özellikle kaçınır.


Kimler İçin Uygun?

  • Exchange Online yöneten sistem ekipleri
  • Hybrid veya Cloud Exchange ortamları
  • Toplu kullanıcı yönetimi yapan IT ekipleri
  • Çalışma saatlerini standartlaştırmak isteyen firmalar

Sonuç

Bu script sayesinde:

  • Çalışma saatleri tek tek kontrol etmek zorunda kalmazsınız
  • Hatalı kullanıcıları net şekilde görürsünüz
  • Onay almadan otomatik değişiklik yapılmaz
  • Farklı firma saatlerine kolayca uyarlanır

İhtiyaca göre:

  • CSV export
  • Sadece UserMailbox filtreleme
  • Düzeltme sonrası otomatik yeniden tarama

gibi geliştirmeler de rahatlıkla eklenebilir.

# ========================= # Working Hours Audit + Fix # Exchange Online / EMS # ========================= function Convert-ToTimeSpan { param( [Parameter(Mandatory)] [string]$TimeText ) # Accept: 08.00 / 08:00 / 8.00 / 8:00 $t = $TimeText.Trim().Replace('.', ':') if ($t -notmatch '^\d{1,2}:\d{2}$') { throw "Saat formatı hatalı: '$TimeText' (örn: 08.00 veya 17.30)" } $parts = $t.Split(':') $h = [int]$parts[0] $m = [int]$parts[1] if ($h -lt 0 -or $h -gt 23 -or $m -lt 0 -or $m -gt 59) { throw "Saat değeri geçersiz: '$TimeText'" } return New-TimeSpan -Hours $h -Minutes $m } try { Write-Host "===== Working Hours TARAMA =====" -ForegroundColor Cyan $startInput = Read-Host "Başlangıç saati (örn. 08.00)" $endInput = Read-Host "Bitiş saati (örn. 17.30)" $targetStart = Convert-ToTimeSpan -TimeText $startInput $targetEnd = Convert-ToTimeSpan -TimeText $endInput Write-Host "" Write-Host "Hedef saatler: $($targetStart.ToString()) - $($targetEnd.ToString())" -ForegroundColor Green Write-Host "Tarama başlıyor..." -ForegroundColor Cyan Write-Host "" $hatalilar = New-Object System.Collections.Generic.List[object] Get-Mailbox -ResultSize Unlimited | ForEach-Object { $mbx = $_ try { $cal = Get-MailboxCalendarConfiguration -Identity $mbx.Identity -ErrorAction Stop $curStart = $cal.WorkingHoursStartTime $curEnd = $cal.WorkingHoursEndTime if ($curStart -ne $targetStart -or $curEnd -ne $targetEnd) { $hatalilar.Add([pscustomobject]@{ DisplayName = $mbx.DisplayName Identity = $mbx.Identity CurrentStart = $curStart CurrentEnd = $curEnd }) | Out-Null } } catch { # Okunamayanları da hatalı listeye düşürelim (yetki/nesne sorunu vs.) $hatalilar.Add([pscustomobject]@{ DisplayName = $mbx.DisplayName Identity = $mbx.Identity CurrentStart = "OKUNAMADI" CurrentEnd = "OKUNAMADI" }) | Out-Null } } Write-Host "" Write-Host "===== ❌ HATALILAR (Hedef: $($targetStart.ToString()) - $($targetEnd.ToString())) =====" -ForegroundColor Red if ($hatalilar.Count -eq 0) { Write-Host "Hatalı kullanıcı bulunmadı." -ForegroundColor Green return } # Altta topluca listele $hatalilar | Sort-Object DisplayName | Format-Table DisplayName, CurrentStart, CurrentEnd -AutoSize Write-Host "" $answer = Read-Host "Bu hatalıları düzelteyim mi? (y/n)" if ($answer.ToLower() -ne "y") { Write-Host "İşlem iptal edildi. Script kapanıyor." -ForegroundColor Yellow return } Write-Host "" Write-Host "===== 🔧 DÜZELTME BAŞLIYOR =====" -ForegroundColor Cyan foreach ($u in $hatalilar) { # OKUNAMADI olanlara dokunmayalım if ($u.CurrentStart -eq "OKUNAMADI" -or $u.CurrentEnd -eq "OKUNAMADI") { Write-Host "ATLANDI (okunamadı): $($u.DisplayName)" -ForegroundColor Yellow continue } try { Set-MailboxCalendarConfiguration ` -Identity $u.Identity ` -WorkingHoursStartTime $targetStart ` -WorkingHoursEndTime $targetEnd ` -ErrorAction Stop Write-Host "DÜZELTİLDİ: $($u.DisplayName)" -ForegroundColor Green } catch { Write-Host "HATA: $($u.DisplayName) -> $($_.Exception.Message)" -ForegroundColor Red } } Write-Host "" Write-Host "===== ✅ DÜZELTME BİTTİ. İstersen tekrar tarat. =====" -ForegroundColor Green } catch { Write-Host "Script hata ile durdu: $($_.Exception.Message)" -ForegroundColor Red }
Translate »