Kontaktliste in Userpostfach importieren via PS
Hallo zusammen,
ich bin auf der Suche nach einer Lösung für folgendes Problem:
Eine Kontaktliste (Telefon), erstellt mittels Get-AdUser , soll in ein oder mehrere Userpostfächer importiert werden. Als separater Kontaktordner.
Diese Liste wird 1x wöchentlich erstellt.
Das eigentliche Ziel: eine Mitarbeitertelefonliste (auch user ohne Postfach) sollen via ActivSysnc allen Smartphones zur Verfügung stehen und immer aktuell.
Bisher wurde das klassisch per Hand gemacht und war (natürlich) nie wirklich aktuell.
Unter diesem Link: xxx.fixthis.ch/blog/post/power-shell_Kontakte-von-AD-filtern-nach-Exchange/
habe ich ein Script gefunden, das genau meinen Anforderungen entspricht.
Allerdings läuft es bei mir nicht und eventuell ist es auch etwas zu "heavy" für meine Ansprüche.
Meine PS-Kenntnisse reichen hier leider nicht aus.
Zu dem Script:
EWS Management API Bibliothek (2.0 + 2.2) ist installiert aber es meldet dennoch immer "EWS Management API DLL fehlt". Die dll ist aber vorhanden (C:\ProgramFiles\Microsoft\Exchange\WebServices\2.0\Microsoft.Exchange.WebServices.dll)
Ein Login auf "https://mail.companydomain.ch/ews/exchange.asmx" funktioniert einwandfrei.
Eventuell kann mich hier jemand unterstützen, bzw. hätte noch einen anderen Lösungsvorschlag
Danke und Gruss
atk691
Uuups fast vergessen: Exchange 2010 (bald 2016), W2008R2, PS4
ich bin auf der Suche nach einer Lösung für folgendes Problem:
Eine Kontaktliste (Telefon), erstellt mittels Get-AdUser , soll in ein oder mehrere Userpostfächer importiert werden. Als separater Kontaktordner.
Diese Liste wird 1x wöchentlich erstellt.
Das eigentliche Ziel: eine Mitarbeitertelefonliste (auch user ohne Postfach) sollen via ActivSysnc allen Smartphones zur Verfügung stehen und immer aktuell.
Bisher wurde das klassisch per Hand gemacht und war (natürlich) nie wirklich aktuell.
Unter diesem Link: xxx.fixthis.ch/blog/post/power-shell_Kontakte-von-AD-filtern-nach-Exchange/
habe ich ein Script gefunden, das genau meinen Anforderungen entspricht.
Allerdings läuft es bei mir nicht und eventuell ist es auch etwas zu "heavy" für meine Ansprüche.
Meine PS-Kenntnisse reichen hier leider nicht aus.
Zu dem Script:
EWS Management API Bibliothek (2.0 + 2.2) ist installiert aber es meldet dennoch immer "EWS Management API DLL fehlt". Die dll ist aber vorhanden (C:\ProgramFiles\Microsoft\Exchange\WebServices\2.0\Microsoft.Exchange.WebServices.dll)
Ein Login auf "https://mail.companydomain.ch/ews/exchange.asmx" funktioniert einwandfrei.
Eventuell kann mich hier jemand unterstützen, bzw. hätte noch einen anderen Lösungsvorschlag
Danke und Gruss
atk691
Uuups fast vergessen: Exchange 2010 (bald 2016), W2008R2, PS4
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 322972
Url: https://administrator.de/forum/kontaktliste-in-userpostfach-importieren-via-ps-322972.html
Ausgedruckt am: 22.12.2024 um 06:12 Uhr
41 Kommentare
Neuester Kommentar
Servus @atk691,
dazu hatte ich mal vor langer Zeit ein Skript für den EX2010 geschrieben.
In folgendem Skript werden alle aktiven AD-Benutzer ausgelesen und in einen Unterordner des Standard-Kontakte-Ordners namens 'Firmenkontake' jeder aktiven Usermailbox geschrieben. Überprüft wird ob der Ordner schon existiert, wenn nicht wird er angelegt. Dann wird der Inhalt des Ordners einseitig synchronisiert d.h. bereits vorhandene Kontakte werden aktualisiert, neue Angelegt und falls der User in dem Ordner weitere Kontakte anlegt werden diese dort raus gelöscht.
Damit das ganze über die EWS (Exchange Web Services) funktioniert muss man dem User mit dem das Skript ausgeführt wird das Impersonation-Recht erteilen damit dieser Account auf alle Mailboxen zugreifen kann.
Um z.B. dem User 'Administrator' dieses Recht zu erteilen führt man folgenden Befehl in einer EMS aus
Mehr dazu bitte hier nachlesen:
Configuring Exchange Impersonation in Exchange 2010
Benötigt wird für das Script ebenfalls die Microsoft.Exchange.WebServices.dll die Ihr euch ja bei MS herunterladen könnt. Für das folgende Script ist diese DLL in das Verzeichnis des Scripts zu kopieren, außer man passt den Pfad im Skript an.
Hatte das ganze damals mit Exchange 2010 getestet. Sollte eigentlich noch laufen.
In deinem Fall wäre es auch eigentlich ausreichend die Kontakte in eine einzelne Shared-Mailbox zu transferieren, das lässt sich ja leicht anpassen.
Grüße Uwe
Falls der Beitrag gefällt, seid so nett und unterstützt mich durch eine kleine Spende / If you like my contribution please support me and donate
edit (08.12.2016 13:00): Anpassung im Skript für die eindeutige Identifizierung der Kontakte über eine Custom Extended Property anstatt des selten genutzten Attributs Generation.
edit (09.12.2016 11:15): Prüfung der Kontakteigenschaften auf Nullwerte
dazu hatte ich mal vor langer Zeit ein Skript für den EX2010 geschrieben.
In folgendem Skript werden alle aktiven AD-Benutzer ausgelesen und in einen Unterordner des Standard-Kontakte-Ordners namens 'Firmenkontake' jeder aktiven Usermailbox geschrieben. Überprüft wird ob der Ordner schon existiert, wenn nicht wird er angelegt. Dann wird der Inhalt des Ordners einseitig synchronisiert d.h. bereits vorhandene Kontakte werden aktualisiert, neue Angelegt und falls der User in dem Ordner weitere Kontakte anlegt werden diese dort raus gelöscht.
Damit das ganze über die EWS (Exchange Web Services) funktioniert muss man dem User mit dem das Skript ausgeführt wird das Impersonation-Recht erteilen damit dieser Account auf alle Mailboxen zugreifen kann.
Um z.B. dem User 'Administrator' dieses Recht zu erteilen führt man folgenden Befehl in einer EMS aus
New-ManagementRoleAssignment -Name:impersonationAssignmentName -Role:ApplicationImpersonation -User:Administrator
Configuring Exchange Impersonation in Exchange 2010
Benötigt wird für das Script ebenfalls die Microsoft.Exchange.WebServices.dll die Ihr euch ja bei MS herunterladen könnt. Für das folgende Script ist diese DLL in das Verzeichnis des Scripts zu kopieren, außer man passt den Pfad im Skript an.
Hatte das ganze damals mit Exchange 2010 getestet. Sollte eigentlich noch laufen.
In deinem Fall wäre es auch eigentlich ausreichend die Kontakte in eine einzelne Shared-Mailbox zu transferieren, das lässt sich ja leicht anpassen.
<#
Sync AD-Users to Contact-Folder in all Mailboxes EX2010 / (c) @colinardo
Vor dem Start des Skript ist dem User welcher das Skript später ausführt die Impersonation-Berechtigungzu erteilen:
In diesem Beispiel der User 'Administrator' (Bitte einmalig in einer EMS ausführen)
New-ManagementRoleAssignment -Name:impersonationAssignmentName -Role:ApplicationImpersonation -User:Administrator
#>
if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return}
# Active Directory Modul laden
Import-Module ActiveDirectory
# EWS DLL laden
Add-Type -Path "$(Split-Path $MyInvocation.MyCommand.Definition -Parent)\Microsoft.Exchange.WebServices.dll"
# Mit Exchange verbinden
try{
$exchange_server = Get-ADObject -LDAPFilter 'objectClass=msExchExchangeServer' -SearchBase (([ADSI]"LDAP://RootDse").configurationNamingContext.ToString()) -Properties networkaddress | select -Expand networkaddress | ?{$_ -match 'ncacn_ip_tcp'} | %{$_.split(":")[1]} | select -First 1
if (!$exchange_server){Write-Host "Could not determine Exchange-Server FQDN from AD" -ForegroundColor Red; return}
write-host "Creating connection to Exchange-Server '$exchange_server' ..." -ForegroundColor Green
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$exchange_server/powershell" -Authentication Kerberos
Import-PSSession $session -DisableNameChecking -AllowClobber | out-null
}catch{
throw $_
return
}
# Start Variablen -------------------------------------------------------------------------
# Name des Ordners in dem die Kontake angelegt werden
$foldername = "Firmenkontakte"
# Überordner festlegen
$parentFolder = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Contacts
# Ende Variablen -------------------------------------------------------------------------
# Custom Propertyset erstellen um einen Kontakt eindeutig zu identifizieren
$propid = [GUID]'{05591a58-e392-4aa9-8cbd-06627d605c95}'
$propset = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition($propid,'ObjectSID',[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String)
# EWS Objekt erstellen
$ews = new-object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2)
$ews.Url = [string](Get-WebServicesVirtualDirectory).InternalURL
# Benutze die Credentials mit dem das Skript ausgeführt wird
$ews.UseDefaultCredentials = $true
# Eigenschaft der User welche abgerufen werden
$user_properties = @('DisplayName','EmailAddress','Company','facsimileTelephoneNumber','givenName','initials','l','mailNickname','name','pager','postalCode','sn','streetAddress','telephoneNumber','HomePhone','MobilePhone','title','co','State','Department','Office','wwwHomePage','Manager')
# Aktivierte Benutzer abrufen welche als Kontake in den Mailboxen angelegt werden
$users = Get-ADUser -Filter{ObjectCategory -eq "Person" -and objectClass -eq "user" -and Enabled -eq $true} -Properties $user_properties
# Funktion zum Prüfen von Eigenschaften
function Get-PropValue($prop){return @{$true=$prop;$false=$null}[$prop -ne ""]}
# Für alle aktivierten Usermailboxen ausführen
Get-Mailbox -RecipientTypeDetails UserMailbox -Filter "IsMailBoxEnabled -eq 'True'" | %{
write-host "Updating Mailbox '$($_.Name)'." -ForegroundColor Blue -BackgroundColor White
$ews.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, [string]$_.PrimarySmtpAddress)
# Nach dem Ordner "Firmenkontakte" im Default Kontakte-Ordner suchen
$view = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)
$view.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly,[Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName)
$view.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Shallow
$filter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$foldername)
$result = $ews.FindFolders($parentFolder,$filter,$view)
if ($result.TotalCount){
# Ordner wurde gefunden
$targetFolder = $result.Folders
}else{
# Ordner existiert noch nicht, lege ihn an
write-host "Creating the contact folder '$foldername' in Mailbox." -ForegroundColor Green
$targetFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($ews)
$targetFolder.DisplayName = $foldername
$targetFolder.Save($parentFolder)
}
# Items im Ordner auflisten
$view = New-Object Microsoft.Exchange.WebServices.Data.ItemView(10000)
$view.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly,[Microsoft.Exchange.WebServices.Data.ContactSchema]::DisplayName,$propset)
$result = $ews.FindItems($targetFolder.Id,$view)
$targetSIDs = $result | %{$_.ExtendedProperties | ?{$_.PropertyDefinition.PropertySetId -eq $propid} | select -Expand Value}
# überschüssige Kontakte die vom User dort angelegt wurden im Ordner löschen
$result | ?{$_.ExtendedProperties.Value -notin $users.SID -or $_.ExtendedProperties.Count -eq 0 } | %{
write-host "Removing abandoned contact '$($_.DisplayName)' in '$foldername.'" -ForegroundColor Yellow
$_.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
# Vorhandene Kontakte aktualisieren und neue erstellen
foreach ($user in $users){
if ($user.SID -in $targetSIDs){
$isupdate = $true
$contact = $result | ?{($_.ExtendedProperties | ?{$_.PropertyDefinition.PropertySetId -eq $propid}).Value -eq $user.SID}
write-host "Updating contact '$($user.Name)'." -ForegroundColor Green
}else{
$isupdate = $false
$contact = new-object Microsoft.Exchange.WebServices.Data.Contact($ews)
write-host "Creating new contact '$($user.Name)'." -ForegroundColor Green
}
$contact.GivenName = Get-PropValue $user.GivenName
$contact.Surname = Get-PropValue $user.sn
$contact.Initials = Get-PropValue $user.Initials
$contact.DisplayName = Get-PropValue $user.DisplayName
$contact.CompanyName = Get-PropValue $user.Company
$contact.OfficeLocation = Get-PropValue $user.Office
$contact.Department = Get-PropValue $user.Department
$contact.JobTitle = Get-PropValue $user.Title
$contact.BusinessHomePage = Get-PropValue $user.wwwHomePage
$contact.Manager = Get-PropValue $user.Manager
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::HomePhone] = Get-PropValue $user.HomePhone
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessPhone] = Get-PropValue $user.telephoneNumber
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::MobilePhone] = Get-PropValue $user.MobilePhone
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::Pager] = Get-PropValue $user.Pager
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessFax] = Get-PropValue $user.facsimileTelephoneNumber
$privateAddress = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
$privateAddress.Street = Get-PropValue $user.streetAddress
$privateAddress.City = Get-PropValue $user.l
$privateAddress.PostalCode = Get-PropValue $user.postalCode
$privateAddress.State = Get-PropValue $user.State
$privateAddress.CountryOrRegion = Get-PropValue $user.co
$contact.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::Home] = $privateAddress
$contact.PostalAddressIndex = [Microsoft.Exchange.WebServices.Data.PhysicalAddressIndex]::Home
$contact.EmailAddresses['EMailAddress1'] = Get-PropValue $user.EMailAddress
$contact.FileAsMapping = [Microsoft.Exchange.WebServices.Data.FileAsMapping]::SurnameCommaGivenName
if ($isupdate){
$contact.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite)
}else{
# Schreibe die SID des Users in die custom extended property des Kontakts (Dient zur eindeutigen Identifikation des Kontakts)
$contact.SetExtendedProperty($propset,[string]$user.SID)
$contact.Save($targetFolder.id)
}
}
}
# Exchange Session beenden
Remove-PSSession $session
Falls der Beitrag gefällt, seid so nett und unterstützt mich durch eine kleine Spende / If you like my contribution please support me and donate
edit (08.12.2016 13:00): Anpassung im Skript für die eindeutige Identifizierung der Kontakte über eine Custom Extended Property anstatt des selten genutzten Attributs Generation.
edit (09.12.2016 11:15): Prüfung der Kontakteigenschaften auf Nullwerte
@colinardo Cool, das ist mal was richtig nützliches
Habs gerade mal auf meinem Test-Exchange ausprobiert, läuft echt gut.
Habe sowas ähnliches für einen Kunden zu realisieren, da kommt gleich mal eine Spende zu Dir
HERZLICHES DANKE von meiner Seite!
Gruß mikrotik
Habs gerade mal auf meinem Test-Exchange ausprobiert, läuft echt gut.
Habe sowas ähnliches für einen Kunden zu realisieren, da kommt gleich mal eine Spende zu Dir
HERZLICHES DANKE von meiner Seite!
Gruß mikrotik
Wofür gibt's VMs ?!
Es reicht Zeile 57 auf folgendes zu ändern.
Ein Blick in die Doku zu Get-Mailbox hätte dazu eigentlich auch gereicht.
Allerdings nur bis Zeile 45. Hat Fehlerfrei funktioniert
Bis dahin passiert ja auch nichts weltbewegendes Das es auf alle Mailboxen zugreift, finde ich inzwischen recht gut.
Allerdings möchte ich schon zu testzwecken erst mal nur in eine Usermailbox schreiben. Das wird wohl in Zeile 47/48 gemacht. Nur wie genau ?
Einfach eine beliebigen Filter mit WHERE-Objekt dazwischen schalten oder die Mailbox direkt angebenAllerdings möchte ich schon zu testzwecken erst mal nur in eine Usermailbox schreiben. Das wird wohl in Zeile 47/48 gemacht. Nur wie genau ?
Es reicht Zeile 57 auf folgendes zu ändern.
Get-Mailbox 'maxmuster' | %{
Zitat von @atk691:
Auf die Gefahr hin, dass man mich für blöd erklärt:
Ich kriege weitere Filter nicht gebacken.
Zeile 44 möchte ich mit filter telephonenumber und mobile erweitern.
So das nur user mit Festanschluss oder Handy berücksichtigt werden.
Dann kann ich das Thema abschliessen
Dank und Gruss
atk691
Sorry - aber das ist in meinen Augen schon dreist. Für so etwas bezahlt man üblicherweise Leute...Auf die Gefahr hin, dass man mich für blöd erklärt:
Ich kriege weitere Filter nicht gebacken.
Zeile 44 möchte ich mit filter telephonenumber und mobile erweitern.
So das nur user mit Festanschluss oder Handy berücksichtigt werden.
Dann kann ich das Thema abschliessen
Dank und Gruss
atk691
Zitat von @atk691:
Du hast dich 2x in diesem Thread gemeldet. Beide mal nicht sonderlich produktiv.
Aber irgenwie wirst Du ja Level 2 erreicht haben.
Nix für ungut
das sagt der richtige. Ist ja viel einfacher sich blöd zu stellen und andere machen zu lassen - naja streng genommen dies zu versuchen. Wie man sieht war es nämlich auch für dich ein leichtes, das Skript anzupassen.Du hast dich 2x in diesem Thread gemeldet. Beide mal nicht sonderlich produktiv.
Aber irgenwie wirst Du ja Level 2 erreicht haben.
Nix für ungut
Und wenn du dann mal irgendwann zu einer Lösung beigetragen hast, dann denke ich evtl. auch mal darüber nach, ob ich mich von dir kritisieren lasse...
Nix für ungut
Zitat von @atk691:
letzter Kommentar:
-and telephoneNumber -Like"*" -or MobilePhone -Like "*" in Zeile 44 eingefügt und das gewünschte Ergebnis ist da
Richtiger wäre eher:letzter Kommentar:
-and telephoneNumber -Like"*" -or MobilePhone -Like "*" in Zeile 44 eingefügt und das gewünschte Ergebnis ist da
$users = Get-ADUser -Filter{ObjectCategory -eq "Person" -and objectClass -eq "user" -and Enabled -eq $true} -Properties $user_properties | ?{$_.telephoneNumber -ne $null -or $_.MobilePhone -ne $null}
$users = Get-AdUser -LDAPFilter "(&(ObjectCategory=Person)(ObjectClass=User)(!userAccountControl:1.2.840.113556.1.4.803:=2)(|(mobile=*)(telephoneNumber=*)))" -Properties $user_properties
Und vielen Dank dir ebenfalls für deine Spende. Sie ist soeben einer Krebsstiftung hier vor Ort zu Gute gekommen
Schöne Restwoche
Grüße Uwe
@colinardo
Wenn ich Benutzer nur aus einer bestimmten OU in die Liste eintragen möchte, wie stelle ich das an? Wird der Filter OU mit in Zeile 83 angehangen?
Gruß xbast1x
Wenn ich Benutzer nur aus einer bestimmten OU in die Liste eintragen möchte, wie stelle ich das an? Wird der Filter OU mit in Zeile 83 angehangen?
Gruß xbast1x
Zitat von @xbast1x:
@colinardo
Wenn ich Benutzer nur aus einer bestimmten OU in die Liste eintragen möchte, wie stelle ich das an? Wird der Filter OU mit in Zeile 83 angehangen?
In Zeile 50 legst du fest welche Kontakte angelegt werden. Geb dort einfach zusätzlich den Parameter -SearchBase 'OU=Marketing,DC=domain,DC=de' mit dem DN deiner OU an, fertig.@colinardo
Wenn ich Benutzer nur aus einer bestimmten OU in die Liste eintragen möchte, wie stelle ich das an? Wird der Filter OU mit in Zeile 83 angehangen?
Grüße Uwe
ACHTUNG an alle die das Script bereits verwenden, es wurde an einigen Stellen auf den aktuellen Stand gebracht.
Anfragen für persönliche Anpassungen nehme ich gegen eine entsprechende Aufwandsentschädigung gerne per PN entgegen.
Danke für euer Verständnis.
Grüße Uwe
Anfragen für persönliche Anpassungen nehme ich gegen eine entsprechende Aufwandsentschädigung gerne per PN entgegen.
Danke für euer Verständnis.
Grüße Uwe
Hier nur noch als Ergänzung eine aktuelle Variante des Scripts welches auch auf Exchange 2013 und 2016 lauffähig ist.
Wünsche euch allen schon einmal ein frohes Weihnachtsfest.
Grüße Uwe
<#
Sync AD-Users to Contact-Folder in all Mailboxes / (c) @colinardo
Vor dem Start des Skript ist dem User welcher das Skript später ausführt die Impersonation-Berechtigungzu erteilen:
In diesem Beispiel der User 'Administrator' (Bitte einmalig in einer EMS ausführen)
New-ManagementRoleAssignment -Name:impersonationAssignmentName -Role:ApplicationImpersonation -User:Administrator
#>
if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return}
# Active Directory Modul laden
Import-Module ActiveDirectory
# EWS DLL laden
Add-Type -Path "$(Split-Path $MyInvocation.MyCommand.Definition -Parent)\Microsoft.Exchange.WebServices.dll"
# Mit Exchange verbinden
try{
$exchange_server = Get-ADObject -LDAPFilter 'objectClass=msExchExchangeServer' -SearchBase (([ADSI]"LDAP://RootDse").configurationNamingContext.ToString()) -Properties networkaddress | select -Expand networkaddress | ?{$_ -match 'ncacn_ip_tcp'} | %{$_.split(":")[1]} | select -First 1
if (!$exchange_server){Write-Host "Could not determine Exchange-Server FQDN from AD" -ForegroundColor Red; return}
write-host "Creating connection to Exchange-Server '$exchange_server' ..." -ForegroundColor Green
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$exchange_server/powershell" -Authentication Kerberos
Import-PSSession $session -DisableNameChecking -AllowClobber | out-null
}catch{
throw $_
return
}
# Start Variablen -------------------------------------------------------------------------
# Name des Ordners in dem die Kontake angelegt werden
$foldername = "Firmenkontakte"
# Überordner festlegen
$parentFolder = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Contacts
# Ende Variablen -------------------------------------------------------------------------
# Allen Zertifikaten vertrauen
Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
# Trust all certs policy dem ServicePointManager zuweisen
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
# Custom Propertyset erstellen um einen Kontakt eindeutig zu identifizieren
$propid = [GUID]'{05591a58-e392-4aa9-8cbd-06627d605c95}'
$propset = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition($propid,'ObjectSID',[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String)
# EWS Objekt erstellen
$ews = new-object Microsoft.Exchange.WebServices.Data.ExchangeService
$ews.Url = [string](Get-WebServicesVirtualDirectory).InternalURL
# Benutze die Credentials mit dem das Skript ausgeführt wird
$ews.UseDefaultCredentials = $true
# Eigenschaft der User welche abgerufen werden
$user_properties = @('DisplayName','EmailAddress','Company','facsimileTelephoneNumber','givenName','initials','l','mailNickname','name','pager','postalCode','sn','streetAddress','telephoneNumber','HomePhone','MobilePhone','title','co','State','Department','Office','wwwHomePage','Manager')
# Aktivierte Benutzer abrufen welche als Kontake in den Mailboxen angelegt werden
$users = Get-ADUser -Filter{ObjectCategory -eq "Person" -and objectClass -eq "user" -and Enabled -eq $true} -Properties $user_properties
# Funktion zum Prüfen von Eigenschaften
function Get-PropValue($prop){return (@{$true=$prop;$false=$null}[![string]::IsNullOrEmpty($prop)])}
# Für alle aktivierten Usermailboxen ausführen
Get-Mailbox -RecipientTypeDetails UserMailbox -Filter "IsMailBoxEnabled -eq 'True'" | %{
write-host "Updating Mailbox '$($_.Name)'." -ForegroundColor Blue -BackgroundColor White
$ews.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, [string]$_.PrimarySmtpAddress)
# Nach dem Ordner "Firmenkontakte" im Default Kontakte-Ordner suchen
$view = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)
$view.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly,[Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName)
$view.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Shallow
$filter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$foldername)
$result = $ews.FindFolders($parentFolder,$filter,$view)
if ($result.TotalCount){
# Ordner wurde gefunden
$targetFolder = $result.Folders
}else{
# Ordner existiert noch nicht, lege ihn an
write-host "Creating the contact folder '$foldername' in Mailbox." -ForegroundColor Green
try{
$targetFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($ews)
$targetFolder.DisplayName = $foldername
$targetFolder.Save($parentFolder)
}catch{
Write-Host $_ -F Red
return
}
}
# Items im Ordner auflisten
$view = New-Object Microsoft.Exchange.WebServices.Data.ItemView(10000)
$view.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly,[Microsoft.Exchange.WebServices.Data.ContactSchema]::DisplayName,$propset)
$result = $ews.FindItems($targetFolder.Id,$view)
$targetSIDs = $result | %{$_.ExtendedProperties | ?{$_.PropertyDefinition.PropertySetId -eq $propid} | select -Expand Value}
# überschüssige Kontakte die vom User dort angelegt wurden im Ordner löschen
$result | ?{$_.ExtendedProperties.Value -notin $users.SID -or $_.ExtendedProperties.Count -eq 0 } | %{
write-host "Removing abandoned contact '$($_.DisplayName)' in '$foldername.'" -ForegroundColor Yellow
$_.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
# Vorhandene Kontakte aktualisieren und neue erstellen
foreach ($user in $users){
try{
if ($user.SID -in $targetSIDs){
$isupdate = $true
$contact = $result | ?{($_.ExtendedProperties | ?{$_.PropertyDefinition.PropertySetId -eq $propid}).Value -eq $user.SID}
$contact.Load()
write-host "Updating contact '$($user.Name)'." -ForegroundColor Green
}else{
$isupdate = $false
$contact = new-object Microsoft.Exchange.WebServices.Data.Contact($ews)
write-host "Creating new contact '$($user.Name)'." -ForegroundColor Green
}
$contact.GivenName = Get-PropValue $user.GivenName
$contact.Surname = Get-PropValue $user.sn
$contact.Initials = Get-PropValue $user.Initials
$contact.DisplayName = Get-PropValue $user.DisplayName
$contact.CompanyName = Get-PropValue $user.Company
$contact.OfficeLocation = Get-PropValue $user.Office
$contact.Department = Get-PropValue $user.Department
$contact.JobTitle = Get-PropValue $user.Title
$contact.BusinessHomePage = Get-PropValue $user.wwwHomePage
$contact.Manager = Get-PropValue $user.Manager
$number = ""
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::HomePhone,[ref]$number)
$prop = Get-PropValue $user.HomePhone
if (($numberFound -and $number -ne $user.HomePhone) -or (!$numberFound -and $prop -ne $null)){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::HomePhone] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessPhone,[ref]$number)
$prop = Get-PropValue $user.telephoneNumber
if (($numberFound -and $number -ne $user.telephoneNumber) -or (!$numberFound -and $prop -ne $null)){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessPhone] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::MobilePhone,[ref]$number)
$prop = Get-PropValue $user.MobilePhone
if (($numberFound -and $number -ne $user.MobilePhone) -or (!$numberFound -and $prop -ne $null)){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::MobilePhone] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::Pager,[ref]$number)
$prop = Get-PropValue $user.Pager
if (($numberFound -and $number -ne $user.Pager) -or (!$numberFound -and $prop -ne $null) ){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::Pager] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessFax,[ref]$number)
$prop = Get-PropValue $user.facsimileTelephoneNumber
if (($numberFound -and $number -ne $user.facsimileTelephoneNumber) -or (!$numberFound -and $prop -ne $null)){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessFax] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$privateAddress = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
$privateAddress.Street = Get-PropValue $user.streetAddress
$privateAddress.City = Get-PropValue $user.l
$privateAddress.PostalCode = Get-PropValue $user.postalCode
$privateAddress.State = Get-PropValue $user.State
$privateAddress.CountryOrRegion = Get-PropValue $user.co
$contact.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::Home] = $privateAddress
$contact.PostalAddressIndex = [Microsoft.Exchange.WebServices.Data.PhysicalAddressIndex]::Home
$contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = Get-PropValue $user.EMailAddress
$contact.FileAsMapping = [Microsoft.Exchange.WebServices.Data.FileAsMapping]::SurnameCommaGivenName
if ($isupdate){
$contact.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite)
}else{
# Schreibe die SID des Users in die custom extended property des Kontakts (Dient zur eindeutigen Identifikation des Kontakts)
$contact.SetExtendedProperty($propset,[string]$user.SID)
$contact.Save($targetFolder.id)
}
}catch{
Write-host $_ -F Red
return
}
}
}
# Exchange Session beenden
Remove-PSSession $session
Wünsche euch allen schon einmal ein frohes Weihnachtsfest.
Grüße Uwe
Super Skript Uwe,ich habe das Skript gerade schnell mal durchgelesen.
Doch eine Frage habe ich diesbezüglich
Erstellst du hier erst einen Öffentlichen Kontakte Ordner aus den User Eigenschaften und schreibst ihn dann in den Kontakte Ordner der User?
Die Frage kommt daher, da ich schon einen Öffentlichen Kontakte Ordner habe, welcher über unserer Datenbank abgeglichen wird
Und ich dies dann mit den Userproperties auslesen lassen könnte.
Gruß
Patrick
Doch eine Frage habe ich diesbezüglich
Erstellst du hier erst einen Öffentlichen Kontakte Ordner aus den User Eigenschaften und schreibst ihn dann in den Kontakte Ordner der User?
Die Frage kommt daher, da ich schon einen Öffentlichen Kontakte Ordner habe, welcher über unserer Datenbank abgeglichen wird
Und ich dies dann mit den Userproperties auslesen lassen könnte.
Gruß
Patrick
Hallo Patrick,
Grüße Uwe
Erstellst du hier erst einen Öffentlichen Kontakte Ordner aus den User Eigenschaften und schreibst ihn dann in den Kontakte Ordner der User?
Nein, bei diesem Skript wird in jeder Mailbox der User unterhalb deren Default Kontakte Ordners ein weiterer Ordner erstellt in dem die Kontakte dann landen und bei weiteren Durchläufen dann nur noch aktualisiert/ergänzt/gelöscht.Grüße Uwe
Hey Uwe,
Vielen Dank für deine Info, habe es mir nun, da ich mehr Zeit habe, mal genauer durchgelesen und verstehe eigentlich alles was du machst.
Da ich aber nicht aus der AD auslesen will, sondern von einer Datenbank abfragen will. Ist mir ein Element noch nicht ganz klar, was er da genau macht und daher die Frage kannst du mir den Scriptschnipsel erläutern?
$True und $False sind ja eigentlich Konstanten und es sieht hier so aus als ob du diese neu definierst.
[char]129 ist das Telefonsymbol in AscII
Grüße
Vielen Dank für deine Info, habe es mir nun, da ich mehr Zeit habe, mal genauer durchgelesen und verstehe eigentlich alles was du machst.
Da ich aber nicht aus der AD auslesen will, sondern von einer Datenbank abfragen will. Ist mir ein Element noch nicht ganz klar, was er da genau macht und daher die Frage kannst du mir den Scriptschnipsel erläutern?
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::Pager,[ref]$number)
$prop = Get-PropValue $user.Pager
if (($numberFound -and $number -ne $user.Pager) -or (!$numberFound -and $prop -ne $null) ){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::Pager] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
$True und $False sind ja eigentlich Konstanten und es sieht hier so aus als ob du diese neu definierst.
[char]129 ist das Telefonsymbol in AscII
Grüße
Servus.
Ohne Anpassung, nein, dazu sind diverse Änderungen nötig. zumal ja erstens der Exchange aus dem AD ermittelt wird, die User aus dem lokalen AD kommen etc. pp.
Grüße Uwe
Ohne Anpassung, nein, dazu sind diverse Änderungen nötig. zumal ja erstens der Exchange aus dem AD ermittelt wird, die User aus dem lokalen AD kommen etc. pp.
Grüße Uwe
Moin,
ich habe das soweit bei mir laufen lassen und nur für einen Testaccount in Zeile 71 eingetragen "Get-Mailbox 'Timo Test' | %{".
Leider bekomme ich nach kurzer Laufzeit folgenden Fehler:
Creating connection to Exchange-Server 'Server.Domain.intern' ...
Updating Mailbox 'Timo Test'.
% : Exception calling "FindFolders" with "3" argument(s): "The request failed. The remote server returned an error: (400) Bad Request."
At C:\_Tools\Scripte\Kontakte-in-Useradressbuch.ps1:71 char:27
Get-Mailbox 'timo test' | %{
CategoryInfo : NotSpecified: ( [ForEach-Object], MethodInvocationException
FullyQualifiedErrorId : ServiceRequestException,Microsoft.PowerShell.Commands.ForEachObjectCommand
Wir nutzen Exchange 2016 mit CU 12 (Version 15.1 (Build 1713.5)), insgesamt 4 Systeme mit 2 DAG Clustern (2 Server pro Standort in einem DAG)
Danke für einen Gedankenanschubser...
Grüße
Der Willi
ich habe das soweit bei mir laufen lassen und nur für einen Testaccount in Zeile 71 eingetragen "Get-Mailbox 'Timo Test' | %{".
Leider bekomme ich nach kurzer Laufzeit folgenden Fehler:
Creating connection to Exchange-Server 'Server.Domain.intern' ...
Updating Mailbox 'Timo Test'.
% : Exception calling "FindFolders" with "3" argument(s): "The request failed. The remote server returned an error: (400) Bad Request."
At C:\_Tools\Scripte\Kontakte-in-Useradressbuch.ps1:71 char:27
Get-Mailbox 'timo test' | %{
CategoryInfo : NotSpecified: ( [ForEach-Object], MethodInvocationException
FullyQualifiedErrorId : ServiceRequestException,Microsoft.PowerShell.Commands.ForEachObjectCommand
Wir nutzen Exchange 2016 mit CU 12 (Version 15.1 (Build 1713.5)), insgesamt 4 Systeme mit 2 DAG Clustern (2 Server pro Standort in einem DAG)
Danke für einen Gedankenanschubser...
Grüße
Der Willi
@atk691
Danke für den Ratschlag, das habe ich bereits überprüft.
Die Exchange-Shell ist unter dem Domänen-Administrator über Rechtsklick, als Administrator ausführen gestartet. Soweit sollte es passen. Die erforderlichen Rechte hat der Domänen-Admin auch um im Exchange "arbeiten" zu dürfen.
Wir haben wie gesagt 2 DAG in 2 Standorten. Jeder Standort hat seine eigene DAG.
DAG Standort A:
Exchangeserver1-A
Exchangeserver2-A
DAG Standort B:
Exchangeserver1-B
Exchangeserver2-B
Die Mailbox von "Timo Test" liegt im Standort A. Wenn ich das Skript im Standort B ausführe, kommt der bereits geschriebene Fehler.
In Standort A läuft das Skript zwar etwas weiter, dann kommt aber diese Meldung:
Creating connection to Exchange-Server 'exchangeserver1-a.domäne.intern' ...
Updating Mailbox 'Timo Test'.
Creating the contact folder 'Firmenkontakte' in Mailbox.
Exception calling "Save" with "1" argument(s): "The request failed. The remote server returned an error: (400) Bad Request."
Hier mal das eingesetzte Skript: (es wurden noch Änderungen vorgenommen und entsprechend kommentiert.)
Es scheint als stehe ich auf dem Schlauch..
Grüße
Der Willi
Danke für den Ratschlag, das habe ich bereits überprüft.
Die Exchange-Shell ist unter dem Domänen-Administrator über Rechtsklick, als Administrator ausführen gestartet. Soweit sollte es passen. Die erforderlichen Rechte hat der Domänen-Admin auch um im Exchange "arbeiten" zu dürfen.
Wir haben wie gesagt 2 DAG in 2 Standorten. Jeder Standort hat seine eigene DAG.
DAG Standort A:
Exchangeserver1-A
Exchangeserver2-A
DAG Standort B:
Exchangeserver1-B
Exchangeserver2-B
Die Mailbox von "Timo Test" liegt im Standort A. Wenn ich das Skript im Standort B ausführe, kommt der bereits geschriebene Fehler.
In Standort A läuft das Skript zwar etwas weiter, dann kommt aber diese Meldung:
Creating connection to Exchange-Server 'exchangeserver1-a.domäne.intern' ...
Updating Mailbox 'Timo Test'.
Creating the contact folder 'Firmenkontakte' in Mailbox.
Exception calling "Save" with "1" argument(s): "The request failed. The remote server returned an error: (400) Bad Request."
Hier mal das eingesetzte Skript: (es wurden noch Änderungen vorgenommen und entsprechend kommentiert.)
<#
Sync AD-Users to Contact-Folder in all Mailboxes / (c) @colinardo
Vor dem Start des Skript ist dem User welcher das Skript später ausführt die Impersonation-Berechtigungzu erteilen:
In diesem Beispiel der User 'Administrator' (Bitte einmalig in einer EMS ausführen)
New-ManagementRoleAssignment -Name:impersonationAssignmentName -Role:ApplicationImpersonation -User:Administrator
#>
if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return}
# Active Directory Modul laden
Import-Module ActiveDirectory
# EWS DLL laden
#Original auskommentiert, da das Sktipt in einem anderen Pfad liegt.
#Add-Type -Path "$(Split-Path $MyInvocation.MyCommand.Definition -Parent)\Microsoft.Exchange.WebServices.dll"
Add-Type -Path "D:\Exchange\V15\Bin\Microsoft.Exchange.WebServices.dll"
# Mit Exchange verbinden
try{
#$exchange_server = Get-ADObject -LDAPFilter 'objectClass=msExchExchangeServer' -SearchBase (([ADSI]"LDAP://RootDse").configurationNamingContext.ToString()) -Properties networkaddress | select -Expand networkaddress | ?{$_ -match 'ncacn_ip_tcp'} | %{$_.split(":")[1]} | select -First 1
#Server Manuell angegeben
$exchange_server = "exchangeserver1-b.domäne.intern"
if (!$exchange_server){Write-Host "Could not determine Exchange-Server FQDN from AD" -ForegroundColor Red; return}
write-host "Creating connection to Exchange-Server '$exchange_server' ..." -ForegroundColor Green
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$exchange_server/powershell" -Authentication Kerberos
Import-PSSession $session -DisableNameChecking -AllowClobber | out-null
}catch{
throw $_
return
}
# Start Variablen -------------------------------------------------------------------------
# Name des Ordners in dem die Kontake angelegt werden
$foldername = "Firmenkontakte"
# Überordner festlegen
$parentFolder = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Contacts
# Ende Variablen -------------------------------------------------------------------------
# Allen Zertifikaten vertrauen
Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
# Trust all certs policy dem ServicePointManager zuweisen
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
# Custom Propertyset erstellen um einen Kontakt eindeutig zu identifizieren
$propid = [GUID]'{05591a58-e392-4aa9-8cbd-06627d605c95}'
$propset = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition($propid,'ObjectSID',[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String)
# EWS Objekt erstellen
$ews = new-object Microsoft.Exchange.WebServices.Data.ExchangeService
$ews.Url = [string](Get-WebServicesVirtualDirectory).InternalURL
# Benutze die Credentials mit dem das Skript ausgeführt wird
$ews.UseDefaultCredentials = $true
# Eigenschaft der User welche abgerufen werden
$user_properties = @('DisplayName','EmailAddress','Company','facsimileTelephoneNumber','givenName','initials','l','mailNickname','name','pager','postalCode','sn','streetAddress','telephoneNumber','HomePhone','MobilePhone','title','co','State','Department','Office','wwwHomePage','Manager')
# Aktivierte Benutzer abrufen welche als Kontake in den Mailboxen angelegt werden
$users = Get-ADUser -Filter{ObjectCategory -eq "Person" -and objectClass -eq "user" -and Enabled -eq $true} -Properties $user_properties
# Funktion zum Prüfen von Eigenschaften
function Get-PropValue($prop){return (@{$true=$prop;$false=$null}[![string]::IsNullOrEmpty($prop)])}
# Für alle aktivierten Usermailboxen ausführen
#Für Testzwecke abgeändert
#Get-Mailbox -RecipientTypeDetails UserMailbox -Filter "IsMailBoxEnabled -eq 'True'" | %{
Get-Mailbox 'timo test' | %{
write-host "Updating Mailbox '$($_.Name)'." -ForegroundColor Blue -BackgroundColor White
$ews.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, [string]$_.PrimarySmtpAddress)
# Nach dem Ordner "Firmenkontakte" im Default Kontakte-Ordner suchen
$view = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)
$view.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly,[Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName)
$view.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Shallow
$filter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$foldername)
#$result = $ews.FindFolders($parentFolder,$filter,$view)
if ($result.TotalCount){
# Ordner wurde gefunden
$targetFolder = $result.Folders
}else{
# Ordner existiert noch nicht, lege ihn an
write-host "Creating the contact folder '$foldername' in Mailbox." -ForegroundColor Green
try{
$targetFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($ews)
$targetFolder.DisplayName = $foldername
$targetFolder.Save($parentFolder)
}catch{
Write-Host $_ -F Red
return
}
}
# Items im Ordner auflisten
$view = New-Object Microsoft.Exchange.WebServices.Data.ItemView(10000)
$view.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly,[Microsoft.Exchange.WebServices.Data.ContactSchema]::DisplayName,$propset)
$result = $ews.FindItems($targetFolder.Id,$view)
$targetSIDs = $result | %{$_.ExtendedProperties | ?{$_.PropertyDefinition.PropertySetId -eq $propid} | select -Expand Value}
# überschüssige Kontakte die vom User dort angelegt wurden im Ordner löschen
$result | ?{$_.ExtendedProperties.Value -notin $users.SID -or $_.ExtendedProperties.Count -eq 0 } | %{
write-host "Removing abandoned contact '$($_.DisplayName)' in '$foldername.'" -ForegroundColor Yellow
$_.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
# Vorhandene Kontakte aktualisieren und neue erstellen
foreach ($user in $users){
try{
if ($user.SID -in $targetSIDs){
$isupdate = $true
$contact = $result | ?{($_.ExtendedProperties | ?{$_.PropertyDefinition.PropertySetId -eq $propid}).Value -eq $user.SID}
$contact.Load()
write-host "Updating contact '$($user.Name)'." -ForegroundColor Green
}else{
$isupdate = $false
$contact = new-object Microsoft.Exchange.WebServices.Data.Contact($ews)
write-host "Creating new contact '$($user.Name)'." -ForegroundColor Green
}
$contact.GivenName = Get-PropValue $user.GivenName
$contact.Surname = Get-PropValue $user.sn
$contact.Initials = Get-PropValue $user.Initials
$contact.DisplayName = Get-PropValue $user.DisplayName
$contact.CompanyName = Get-PropValue $user.Company
$contact.OfficeLocation = Get-PropValue $user.Office
$contact.Department = Get-PropValue $user.Department
$contact.JobTitle = Get-PropValue $user.Title
$contact.BusinessHomePage = Get-PropValue $user.wwwHomePage
$contact.Manager = Get-PropValue $user.Manager
$number = ""
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::HomePhone,[ref]$number)
$prop = Get-PropValue $user.HomePhone
if (($numberFound -and $number -ne $user.HomePhone) -or (!$numberFound -and $prop -ne $null)){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::HomePhone] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessPhone,[ref]$number)
$prop = Get-PropValue $user.telephoneNumber
if (($numberFound -and $number -ne $user.telephoneNumber) -or (!$numberFound -and $prop -ne $null)){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessPhone] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::MobilePhone,[ref]$number)
$prop = Get-PropValue $user.MobilePhone
if (($numberFound -and $number -ne $user.MobilePhone) -or (!$numberFound -and $prop -ne $null)){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::MobilePhone] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::Pager,[ref]$number)
$prop = Get-PropValue $user.Pager
if (($numberFound -and $number -ne $user.Pager) -or (!$numberFound -and $prop -ne $null) ){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::Pager] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$numberFound = $contact.PhoneNumbers.TryGetValue([Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessFax,[ref]$number)
$prop = Get-PropValue $user.facsimileTelephoneNumber
if (($numberFound -and $number -ne $user.facsimileTelephoneNumber) -or (!$numberFound -and $prop -ne $null)){
$contact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::BusinessFax] = @{$true=$prop;$false=[char]129}[$prop -ne $null]
}
$privateAddress = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
$privateAddress.Street = Get-PropValue $user.streetAddress
$privateAddress.City = Get-PropValue $user.l
$privateAddress.PostalCode = Get-PropValue $user.postalCode
$privateAddress.State = Get-PropValue $user.State
$privateAddress.CountryOrRegion = Get-PropValue $user.co
$contact.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::Home] = $privateAddress
$contact.PostalAddressIndex = [Microsoft.Exchange.WebServices.Data.PhysicalAddressIndex]::Home
$contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = Get-PropValue $user.EMailAddress
$contact.FileAsMapping = [Microsoft.Exchange.WebServices.Data.FileAsMapping]::SurnameCommaGivenName
if ($isupdate){
$contact.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite)
}else{
# Schreibe die SID des Users in die custom extended property des Kontakts (Dient zur eindeutigen Identifikation des Kontakts)
$contact.SetExtendedProperty($propset,[string]$user.SID)
$contact.Save($targetFolder.id)
}
}catch{
Write-host $_ -F Red
return
}
}
}
# Exchange Session beenden
Remove-PSSession $session
Es scheint als stehe ich auf dem Schlauch..
Grüße
Der Willi
Servus,
auch wenn der Thread schon einige Zeit auf dem Buckel hat, nur noch als Ergänzung für die die hier vorbei schlendern und vielleicht etwas leicht abweichendes suchen.
Ein Powershell-Skript aus meiner Feder das einen öffentlichen Ordner in die User-Mailboxen One-Way synchronisiert:
Also Öffentlicher Ordner => Kontakt-Ordner der User-Mailbox (bestehende Kontakte bleiben natürlich erhalten)
Exchange öffentliche Ordner auf Smartphones übertragen
Grüße Uwe
auch wenn der Thread schon einige Zeit auf dem Buckel hat, nur noch als Ergänzung für die die hier vorbei schlendern und vielleicht etwas leicht abweichendes suchen.
Ein Powershell-Skript aus meiner Feder das einen öffentlichen Ordner in die User-Mailboxen One-Way synchronisiert:
Also Öffentlicher Ordner => Kontakt-Ordner der User-Mailbox (bestehende Kontakte bleiben natürlich erhalten)
Exchange öffentliche Ordner auf Smartphones übertragen
Grüße Uwe
Hallo,
hat schon ma jemand das Script:"Sync AD-Users to Contact-Folder in all Mailboxes"
erfolgreich mit dem Exchange 2019 getestet?
Unter 2013 lief bisher alles perfekt und nun gibt es diverse Fehlermeldungen.
zB.:
% : Ausnahme beim Aufrufen von "FindFolders" mit 3 Argument(en): "The request failed. Die zugrunde liegende Verbindung wurde geschlossen: Unerwarteter Fehler beim Senden.."
hat schon ma jemand das Script:"Sync AD-Users to Contact-Folder in all Mailboxes"
erfolgreich mit dem Exchange 2019 getestet?
Unter 2013 lief bisher alles perfekt und nun gibt es diverse Fehlermeldungen.
zB.:
% : Ausnahme beim Aufrufen von "FindFolders" mit 3 Argument(en): "The request failed. Die zugrunde liegende Verbindung wurde geschlossen: Unerwarteter Fehler beim Senden.."
... entTypeDetails UserMailbox -Filter "IsMailBoxEnabled -eq 'True'" | %{
Guten Tag,
bei mir seit einigen Tagen das gleiche Problem auf einem Exchange 2016. Bisher lief es problemlos. Folgende Ausgabe:
Bisher konnte ich das Problem nicht lösen.
Beste Grüße
JPR
bei mir seit einigen Tagen das gleiche Problem auf einem Exchange 2016. Bisher lief es problemlos. Folgende Ausgabe:
% : Ausnahme beim Aufrufen von "FindFolders" mit 3 Argument(en): "The request failed. Der Remoteserver hat einen Fehler zurückgegeben: (403) Unzulässig."
In C:\PS-Skripte\MLKontakte.ps1:79 Zeichen:23
+ Get-Mailbox 'FooBar' | %{
+ ~~
+ CategoryInfo : NotSpecified: (:) [ForEach-Object], MethodInvocationException
+ FullyQualifiedErrorId : ServiceRequestException,Microsoft.PowerShell.Commands.ForEachObjectCommand
Bisher konnte ich das Problem nicht lösen.
Beste Grüße
JPR
Servus @prinzjulius und @desmu74, willkommen auf Administrator.de!
Habe zur Zeit leider kein lokales Exchange-System für Test mehr im Zugriff. Der letzten Fehlermeldung zu Folge könnte es aber sein das die minimale EWS-Schemaversion in den letzten Wochen auf den Servern per Update angehoben wurde. Wenn das der Fall ist hilft eventuell im Konstruktor des EWS-Objects die minimale Schema-Version zu erhöhen:
Wie gesagt, ich kann zur Zeit leider bezüglich "OnPremise Exchange" keinen weiteren Support leisten da die Umstände es leider nicht zulassen.
Grüße Uwe
Habe zur Zeit leider kein lokales Exchange-System für Test mehr im Zugriff. Der letzten Fehlermeldung zu Folge könnte es aber sein das die minimale EWS-Schemaversion in den letzten Wochen auf den Servern per Update angehoben wurde. Wenn das der Fall ist hilft eventuell im Konstruktor des EWS-Objects die minimale Schema-Version zu erhöhen:
$ews = new-object Microsoft.Exchange.WebServices.Data.ExchangeService ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2016)
Grüße Uwe
@colinardo Vielen Dank für die schnelle Hilfe.
Das hat zwar noch nicht geholfen, aber ist vielleicht ein Ansatz.
Grüße
JPR
Das hat zwar noch nicht geholfen, aber ist vielleicht ein Ansatz.
Grüße
JPR
Hallo,
nachdem nun einige Updates auf dem Testsystem gelaufen sind, gab es wieder Fehler beim ausführen des Scripts.
Abhilfe schaffte ein Reg Eintrag vom Typ REG_MULTI_SZ unter:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
BackConnectionHostNames
hier wurden alle FQDN`s vom Server hinterlegt
Wie hier beschrieben
Ich hoffe es hilft euch.
Grüße
nachdem nun einige Updates auf dem Testsystem gelaufen sind, gab es wieder Fehler beim ausführen des Scripts.
Abhilfe schaffte ein Reg Eintrag vom Typ REG_MULTI_SZ unter:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
BackConnectionHostNames
hier wurden alle FQDN`s vom Server hinterlegt
Wie hier beschrieben
Ich hoffe es hilft euch.
Grüße
@colinardo
Möchte mich recht herzlich für das Script bedanken! Damit konnte ich, im Gegensatz zu vielen anderen Beispielen im Netz, tatsächlich ein Ergebnis erzielen!
Nur noch die User besser filtern und die Automatisierung herstellen, scharf schalten und es dürfte laufen...
Getestet auf Exchange 2019 on-premise mit aktuellstem CU.
Das mit dem Loopback war auch hier ein Thema.
Wenn ich Paypal grad aktiv nutzen würde, wäre sicher eine Spende da...
Möchte mich recht herzlich für das Script bedanken! Damit konnte ich, im Gegensatz zu vielen anderen Beispielen im Netz, tatsächlich ein Ergebnis erzielen!
Nur noch die User besser filtern und die Automatisierung herstellen, scharf schalten und es dürfte laufen...
Getestet auf Exchange 2019 on-premise mit aktuellstem CU.
Das mit dem Loopback war auch hier ein Thema.
Wenn ich Paypal grad aktiv nutzen würde, wäre sicher eine Spende da...