Jak dodać dużą ilość kontaktów do Microsoft 365 (hurtowo z CSV + PowerShell)
Dodawanie setek lub tysięcy kontaktów zewnętrznych do Microsoft 365 ręcznie to droga przez mękę. Poniżej pokazuję sprawdzony sposób na hurtowe wgrywanie kontaktów (Mail Contacts) z pliku CSV z pełną walidacją oraz bez duplikatów — wszystko jednym skryptem PowerShell.
Co zyskasz?
- Oszczędność czasu – import całych list w minutach.
- Idempotencja – skrypt nie doda duplikatów (sprawdza DisplayName i ExternalEmailAddress).
- Czytelne komunikaty – wiesz, co się udało, co już istniało i co poszło nie tak.
Wymagania wstępne
- Uprawnienia z rolą wystarczającą do tworzenia Mail Contacts (np. Exchange Admin).
- PowerShell 5.1+ (Windows) lub 7.x (Core).
- Moduł:
ExchangeOnlineManagement
.
Instalacja modułu i logowanie:
Install-Module ExchangeOnlineManagement -Scope CurrentUser -Force
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline
Przygotowanie CSV
Plik CSV musi mieć nagłówki dokładnie w tej postaci (bez polskich znaków i spacji, jak niżej):
FirstName,LastName,DisplayName,Alias,ExternalEmailAddress
Jan,Kowalski,Jan Kowalski,j.kowalski,[email protected]
Anna,Nowak,Anna Nowak,a.nowak,[email protected]
Wskazówki:
- Kodowanie pliku: UTF-8 (z BOM), separator: przecinek (,).
Alias
powinien być unikalny (bez spacji i znaków specjalnych).ExternalEmailAddress
– pełny, poprawny e-mail (np.[email protected]
).
Skrypt PowerShell (wklej i uruchom)
Poniżej skrypt, który:
- importuje CSV,
- dla każdego wiersza sprawdza, czy kontakt już istnieje (po
DisplayName
lubExternalEmailAddress
), - tworzy kontakt tylko gdy go nie ma,
- wypisuje przejrzyste komunikaty.
Kod powershell do wczytania wielu kontaktów
$csvFilePath = "export-csc.csv"
try {
$Contacts = Import-Csv $csvFilePath
foreach ($Contact in $Contacts) {
try {
if (Get-MailContact -Filter "DisplayName -eq '$($Contact.DisplayName)' -or ExternalEmailAddress -eq '$($Contact.ExternalEmailAddress)'" -ErrorAction SilentlyContinue) {
Write-Host "Contact $($Contact.ExternalEmailAddress) already exists" -ForegroundColor Yellow
}
else {
$contactParams = @{
Name = $Contact.DisplayName
FirstName = $Contact.FirstName
LastName = $Contact.LastName
DisplayName = $Contact.DisplayName
Alias = $Contact.Alias
ExternalEmailAddress = $Contact.ExternalEmailAddress
# WhatIf = $true # <- odkomentuj do testów (dry-run)
}
$null = New-MailContact @contactParams
Write-Host "Contact $($Contact.ExternalEmailAddress) added successfully" -ForegroundColor Green
}
}
catch {
Write-Host "Failed to add contact $($Contact.ExternalEmailAddress). Error: $_" -ForegroundColor Red
}
}
}
catch {
Write-Host "Failed to import CSV file. Error: $_" -ForegroundColor Red
}
One-liner (wskażesz tylko plik)
Po zalogowaniu Connect-ExchangeOnline
możesz użyć wersji jednowierszowej (przeklej w jedną linię, zmień ścieżkę):
$csv="C:\ścieżka\export-csc.csv"; Import-Csv $csv | % { if(Get-MailContact -Filter "DisplayName -eq '$($_.DisplayName)' -or ExternalEmailAddress -eq '$($_.ExternalEmailAddress)'" -ErrorAction SilentlyContinue){Write-Host "Contact $($_.ExternalEmailAddress) already exists" -ForegroundColor Yellow} else { try { New-MailContact -Name $_.DisplayName -FirstName $_.FirstName -LastName $_.LastName -DisplayName $_.DisplayName -Alias $_.Alias -ExternalEmailAddress $_.ExternalEmailAddress | Out-Null; Write-Host "Contact $($_.ExternalEmailAddress) added successfully" -ForegroundColor Green } catch { Write-Host "Failed to add contact $($_.ExternalEmailAddress). Error: $_" -ForegroundColor Red } } }
Test bez zmian (tryb „WhatIf”)
Chcesz sprawdzić import bez tworzenia kontaktów?
W skrypcie głównym odkomentuj linię WhatIf = $true
. Dzięki temu zobaczysz, co zostałoby utworzone.
Weryfikacja po imporcie
- Centrum administracyjne Microsoft 365 → Exchange admin center → Recipients → Contacts.
- Tu zobaczysz nowo dodane pozycje, możesz też je edytować (telefon, firma, uwagi).
Najczęstsze problemy i rozwiązania
- „Failed to import CSV” – sprawdź kodowanie (UTF-8), separator (
,
), brak pustych kolumn. - Duplikaty – skrypt ich nie tworzy; jeżeli kontakt istnieje (po
DisplayName
lubExternalEmailAddress
), dostaniesz żółty komunikat. - Brak uprawnień – upewnij się, że konto ma rolę Exchange Admin / odpowiednie RBAC.
- Throttling / limity – przy bardzo dużych paczkach rozważ batchowanie (np. po 500 rekordów) lub przerwę
Start-Sleep -Seconds 1
w pętli.