Dank der globalen Adressliste können wir im Handy problemlos nach den Kontaktdaten von anderen AD-Usern suchen. Das bringt uns aber nichts, wenn wir von einem dieser User angerufen werden, denn das Handy schaut nicht in der GAL, sondern nur in den Kontakten die auf das Handy synchronisiert wurden. Somit weiß man nicht wer einen anruft, außer man hat die Nummer selbst ins Outlook oder ins Handy eingetragen.
Die Lösung: Alle AD-User zu Outlook Kontakte machen. Und bei der Gelegenheit nehmen wir etwaige AD-Bilder gleich mit.
Dieses Skript kann man dann einfach jede Nacht laufen lassen:
- Es leert den Kontakte Ordner im Outlook den es beim letzten mal angelegt hat
- Exportiert die Bilder aus dem AD
- Erzeugt die Kontakte für jeden User neu
Hierdurch ist sichergestellt, dass keine alten User in den Kontakten rum dümpeln.
# Hier kommen alles User rein, die ihr Outlook nicht upgedatet haben wollen. # Es ist der SAMAccountName einzutragen, das heißt der Login-Name. # Z.B. mmustermann für Max Mustermann oder ssorglos für Susi Sorglos, etc... # Es ist für jeden User eine neue Zeile unter der letzten $wollen_nicht +=... Zeile zu erstellen. # Die Syntax ist: $wollen_nicht += "SAMACCOUNTNAME" # Also z.B.: $wollen_nicht += "mmustermann" $wollen_nicht = @() # $wollen_nicht += "SAMAccountName" --> Als Beispiel, bei kopieren das # nicht mit kopieren, sonst greift es nicht. # So soll der Ordner der Kontakte im Outlook heißen $OutlookFoldername = "Contoso-Mitarbeiter" #export the thmbnailphotos from AD to local storage $thumbnailPhotoPath = "C:\Scripts\thumbnailPhoto" $thumbnailPhotoPathResized = "C:\scripts\thumbnailPhoto_resized" Function Set-ImageSize{ [CmdletBinding( SupportsShouldProcess=$True, ConfirmImpact="Low" )] Param( [parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [Alias("Image")] [String[]]$FullName, [String]$Destination = $(Get-Location), [Switch]$Overwrite, [Int]$WidthPx, [Int]$HeightPx, [Int]$DPIWidth, [Int]$DPIHeight, [Switch]$FixedSize, [Switch]$RemoveSource ) Begin{ [void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms") #[void][reflection.assembly]::loadfile( "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll") } Process{ Foreach($ImageFile in $FullName){ If(Test-Path $ImageFile){ $OldImage = new-object System.Drawing.Bitmap $ImageFile $OldWidth = $OldImage.Width $OldHeight = $OldImage.Height if($WidthPx -eq $Null){ $WidthPx = $OldWidth } if($HeightPx -eq $Null){ $HeightPx = $OldHeight } if($FixedSize){ $NewWidth = $WidthPx $NewHeight = $HeightPx }else{ if($OldWidth -lt $OldHeight){ $NewWidth = $WidthPx [int]$NewHeight = [Math]::Round(($NewWidth*$OldHeight)/$OldWidth) if($NewHeight -gt $HeightPx){ $NewHeight = $HeightPx [int]$NewWidth = [Math]::Round(($NewHeight*$OldWidth)/$OldHeight) } }else{ $NewHeight = $HeightPx [int]$NewWidth = [Math]::Round(($NewHeight*$OldWidth)/$OldHeight) if($NewWidth -gt $WidthPx){ $NewWidth = $WidthPx [int]$NewHeight = [Math]::Round(($NewWidth*$OldHeight)/$OldWidth) } } } $ImageProperty = Get-ItemProperty $ImageFile $SaveLocation = Join-Path -Path $Destination -ChildPath ($ImageProperty.Name) If(!$Overwrite){ If(Test-Path $SaveLocation){ $Title = "A file already exists: $SaveLocation" $ChoiceOverwrite = New-Object System.Management.Automation.Host.ChoiceDescription "&Overwrite" $ChoiceCancel = New-Object System.Management.Automation.Host.ChoiceDescription "&Cancel" $Options = [System.Management.Automation.Host.ChoiceDescription[]]($ChoiceCancel, $ChoiceOverwrite) If(($host.ui.PromptForChoice($Title, $null, $Options, 1)) -eq 0){ Write-Verbose "Image '$ImageFile' exist in destination location - skiped" Continue } #End If ($host.ui.PromptForChoice($Title, $null, $Options, 1)) -eq 0 } #End If Test-Path $SaveLocation } #End If !$Overwrite $NewImage = new-object System.Drawing.Bitmap $NewWidth,$NewHeight $Graphics = [System.Drawing.Graphics]::FromImage($NewImage) $Graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic $Graphics.DrawImage($OldImage, 0, 0, $NewWidth, $NewHeight) $ImageFormat = $OldImage.RawFormat $OldImage.Dispose() if($DPIWidth -and $DPIHeight){ $NewImage.SetResolution($DPIWidth,$DPIHeight) } #End If $DPIWidth -and $DPIHeight $NewImage.Save($SaveLocation,$ImageFormat) $NewImage.Dispose() Write-Verbose "Image '$ImageFile' was resize from $($OldWidth)x$($OldHeight) to $($NewWidth)x$($NewHeight) and save in '$SaveLocation'" If($RemoveSource){ Remove-Item $Image -Force Write-Verbose "Image source '$ImageFile' was removed" } #End If $RemoveSource } } } #End Process End{} } Function Copy-OrgContactsToUserMailboxContacts{ param( $Mailbox, $FolderName, $Users, $thumbnailPhotoPath ) $EwsUrl = ([array](Get-WebServicesVirtualDirectory))[0].InternalURL.AbsoluteURI $ContactMapping=@{ "FirstName" = "GivenName"; "LastName" = "Surname"; "Company" = "CompanyName"; "WindowsEmailAddress" = "Email:EmailAddress1"; "Phone" = "Phone:BusinessPhone"; "Fax" = "Phone:BusinessFax"; "MobilePhone" = "Phone:MobilePhone"; "Manager" = "Manager"; "Title" = "JobTitle"; "WebPage" = "BusinessHomePage"; "AssistantName" = "AssistantName"; "Office" = "OfficeLocation"; "Department" = "Department"; } $UserMailbox = Get-Mailbox $Mailbox if (!$UserMailbox){ throw "Mailbox $($Mailbox) not found"; exit; } $EmailAddress = $UserMailbox.PrimarySMTPAddress # Load EWS Managed API [void][Reflection.Assembly]::LoadFile("E:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"); $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1) $service.UseDefaultCredentials = $true; $service.URL = New-Object Uri($EwsUrl); # Search for an existing copy of the Folder to store Org contacts $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress); $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot) $RootFolder.Load() $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress); $FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000) $ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where {$_.DisplayName -eq $FolderName} if ($ContactsFolderSearch){ # Empty if found $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress); $ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id); $ContactsFolder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true) }else{ # Create new contacts folder $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress); $ContactsFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($service); $ContactsFolder.DisplayName = $FolderName $ContactsFolder.Save([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot) # Search for the new folder instance $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot) $RootFolder.Load() $FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000) $ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where {$_.DisplayName -eq $FolderName} $ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id); } # Add contacts foreach ($ContactItem in $Users){ $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress); $ExchangeContact = New-Object Microsoft.Exchange.WebServices.Data.Contact($service); if ($ContactItem.FirstName -and $ContactItem.LastName){ $ExchangeContact.NickName = $ContactItem.LastName + ", " + $ContactItem.FirstName; }elseif ($ContactItem.FirstName -and !$ContactItem.LastName){ $ExchangeContact.NickName = $ContactItem.FirstName; }elseif (!$ContactItem.FirstName -and $ContactItem.LastName){ $ExchangeContact.NickName = $ContactItem.LastName; }elseif (!$ContactItem.FirstName -and !$ContactItem.LastName){ $ExchangeContact.NickName = $ContactItem.DisplayName; $ContactItem.FirstName = $ContactItem.DisplayName; } #Set profile picture from exported thumbnailphoto, if empty then skip $ContactPictureFile = $thumbnailPhotoPath + "\" + $ContactItem.SamAccountName + ".jpg" if ((Test-Path -Path $ContactPictureFile) -eq $true){ $ExchangeContact.SetContactPicture($ContactPictureFile); } $ExchangeContact.DisplayName = $ExchangeContact.NickName; $ExchangeContact.FileAs = $ExchangeContact.NickName; # This uses the Contact Mapping above to save coding each and every field, one by one. Instead we look for a mapping and perform an action on # what maps across. As some methods need more "code" a fake multi-dimensional array (seperated by :'s) is used where needed. foreach ($Key in $ContactMapping.Keys){ # Only do something if the key exists if ($ContactItem.$Key){ # Will this call a more complicated mapping? if ($ContactMapping[$Key] -like "*:*"){ # Make an array using the : to split items. $MappingArray = $ContactMapping[$Key].Split(":") # Do action switch ($MappingArray[0]){ "Email"{ $ExchangeContact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::($MappingArray[1])] = $ContactItem.$Key.ToString(); }"Phone"{ $ExchangeContact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::($MappingArray[1])] = $ContactItem.$Key; } } }elseif($ContactMapping[$Key] -like "Manager"){ $ExchangeContact.($ContactMapping[$Key]) = $ContactItem.$Key.Name }elseif($ContactMapping[$Key] -like "JobTitle"){ $Title = $ContactItem.$Key if($Title -like ".*"){ $Title = $Title.SubString(1, ($Title.Length - 1)) } $ExchangeContact.($ContactMapping[$Key]) = $Title }else{ $ExchangeContact.($ContactMapping[$Key]) = $ContactItem.$Key; } } } # Save the contact $ExchangeContact.Save($ContactsFolder.Id); # Provide output that can be used on the pipeline $Output_Object = New-Object Object; $Output_Object | Add-Member NoteProperty FileAs $ExchangeContact.FileAs; $Output_Object | Add-Member NoteProperty GivenName $ExchangeContact.GivenName; $Output_Object | Add-Member NoteProperty Surname $ExchangeContact.Surname; $Output_Object | Add-Member NoteProperty EmailAddress1 $ExchangeContact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] $Output_Object; } } # Module laden Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 Import-Module ActiveDirectory # Ggf. Ordner erstellen if ((Test-Path -Path $thumbnailPhotoPath) -eq $true){ Remove-Item -Path $thumbnailPhotoPath -Force -Recurse New-Item -Path $thumbnailPhotoPath -ItemType directory -Force }else{ New-Item -Path $thumbnailPhotoPath -ItemType directory -Force } # Kurz warten sleep(5) # Alle User einlesen die ein Bild im AD haben # Dann für jeden User das Bild exportieren $bilderuser = Get-ADUser -Filter * -Properties thumbnailphoto | where {$_.thumbnailphoto} for ($i = 0; $i -lt $bilderuser.Count; $i++){ $newpath = $thumbnailPhotoPath + "\" + $bilderuser[$i].SamAccountName + ".jpg" $bilderuser[$i].thumbnailphoto | Set-Content -Path $newpath -Encoding Byte } # Die Bilder auf eine neue Größe anpassen, weil Outlook diese sonst nicht anzeigen kann $45kb = 40960 # 40KB in Byte # Hilfs-Counter, weil es auf Grund von mathematischen Rundungen passieren kann, dass er nicht genau die richtige Größe trifft... $count = 0 while(1){ if($count -ge 10){ echo "Abbruch" break; } echo "Los geht's" $bilder = gci "$thumbnailPhotoPath\*.jpg" $zugrossebilder = @() foreach ($bild in $bilder){ $size = $bild.Length if($size -gt $45kb){ $zugrossebilder += $bild } } if($zugrossebilder.Count -ge 1){ if (!(Test-Path $thumbnailPhotoPathResized)){ New-Item -Path $thumbnailPhotoPathResized -ItemType directory -Force } foreach($zugrossesbild in $zugrossebilder){ $size = $zugrossesbild.Length $sizeratio = $size / $45kb $dateiname = $zugrossesbild.Versioninfo.Filename $image = New-Object -ComObject Wia.ImageFile $image.LoadFile($dateiname) $oldHeight = $image.Height $oldWidth = $image.Width $oldPixel = $oldHeight * $oldWidth $newPixel = $oldPixel / $sizeratio $faktor = [math]::Sqrt($newPixel / ($oldHeight * $oldWidth)) $newWidth = $OldWidth * $faktor $newWidth = [math]::Round($newWidth, 0) $newHeight = $OldHeight * $faktor $newHeight = [math]::Round($newHeight, 0) Set-ImageSize -Fullname $dateiname -WidthPx $newWidth -HeightPx $newHeight -Destination $thumbnailPhotoPathResized echo $dateiname [System.Runtime.Interopservices.Marshal]::ReleaseComObject($image) Remove-Variable image } sleep(1) Move-Item -Path "$thumbnailPhotoPathResized\*.*" -Destination $thumbnailPhotoPath -Force Remove-Item $thumbnailPhotoPathResized -Force -Recurse sleep(1) $count++ }else{ break; } } # Alle User die eine E-Mail Adresse und Rufnummer haben werden eingelesen $users = @() $Users += get-user -Filter {WindowsEmailAddress -ne $null -and (MobilePhone -ne $null -or Phone -ne $null)} | select SamAccountName $newUsers = @() foreach($newUser in $Users){ $newUsers += get-ADuser $newUser.SAMAccountName } # Da wir ein Array mit dem Attribut SAMAccountName haben, soll das weg und nur ein Text-Array erstellt werden $umschrieb = @() foreach ($user in $newUsers){ $umschrieb += $user.SAMAccountName } $user = $null # Jetzt werden alle o.g. User aus der Liste gelöscht foreach ($user in $wollen_nicht){ $umschrieb = $umschrieb -ne $user } # Leere Einträge rausnehmen $umschrieb = $umschrieb | ? {$_} $Users = @() $newUsers = $newUsers | ? {$_.SamAccountName} $User = $null foreach($User in $newUsers){ $Users += get-user $User.SamAccountName | select * } # Für alle User die übrig bleiben wird das Script ausgeführt foreach ($Mailbox in $umschrieb){ echo "Jetz kommt: $Mailbox" Copy-OrgContactsToUserMailboxContacts -Mailbox $Mailbox -Foldername $OutlookFoldername -Users $Users -thumbnailPhotoPath $thumbnailPhotoPath echo "" echo "$Mailbox ist fertig!" echo "---------------------------------------------" echo "---------------------------------------------" } if ((Test-Path -Path $thumbnailPhotoPath) -eq $true){ Remove-Item -Path $thumbnailPhotoPath -Force -Recurse } exit