Bei der Migration von einem Exchange Server auf eine neuere Version ist es wichtig zu wissen, mit welchen Clients das aktuelle System noch kommuniziert. Hierzu gibt es mehrere Möglichkeiten, diese kann unter anderem mit einer evtl. vorhandenen Software zur Inventarisierung gemacht werden, mit einer temporären Indizierung von Software oder mit der folgenden Variante gemacht werden: Eine automatische Auswertung der Exchange RPC-Log-Dateien.
Die genutzten Dateien
Auf jeden Exchange-Server, der mit Clients kommuniziert, werden standardmäßig im Exchange-Installationsverzeichnis Logdateien angelegt, in die die Verbindungen mitprotokolliert werden. Da es sich im meinem aktuellen Fall um eine Exchange Server 2010-Farm handelt, die abgelöst werden soll, liegen die Logfiles unter
C:\Program Files\Microsoft\Exchange Server\V14\Logging\RPC Client Access
Diese Dateien werden durchforstet und ausgewertet. Für die Auswertung nutze ich nur die Windows PowerShell, für die spätere Ausgabe als HTML-Datei greife ich wieder auf das Modul ReportHTML zurück, welches ich bereits hier beschrieben habe.
Der Ablauf
Alles beginnt damit, dass ich testweise die Log-Dateien vom Exchange-Server aus dem weiter vorne aufgeführten Pfad C:\Program Files\Microsoft\Exchange Server\V14\Logging\RPC Client Access in einen temporären Ordner auf meinem Client kopiere. Dies mache ich nur, um das Skript anzupassen und um die Menge an Logfiles klein zu halten, damit Test-Durchläufe nicht ewig lang dauern (und natürlich, um nicht Logdateien auf dem Live-System löschen zu müssen) 🙂
Mit diesen drei Dateien kann ich erstmal testen und die Ausgabe so anpassen, wie ich sie benötige. Was alles zu beachten ist:
- Welche Informationen möchte ich sehen?
- Wie viele (Cas-) Server habe ich im Einsatz?
- Wie soll der fertige Report aussehen?
Mein Report
Damit das alles ein bisschen greifbarer wird, hier ein Beispiel von meinem Report. Ich habe insgesamt zwei Server, die Verbindungen zu Clients aufbauen. Diese beiden Server möchte ich gerne nebeneinander im Report anzeigen, damit ich nicht erst komplett über den ersten Server scrollen muss, damit ich die Verbindungen vom zweiten System sehe.
Weiterhin möchte ich sehen, welcher Benutzer sich verbindet, welche Outlook-Version sich dahinter versteckt, welche Build-Nummer das Outlook hat und welche IP-Adresse der Client hat.
Das ganze sieht dann final wie folgt aus:
Wird die HTML-Datei aufgerufen, sieht das erstmal so aus wie im Screenshot. Man kann nun die einzelnen Reiter anklicken, um eine Sortierung zu bekommen: entweder nach Benutzer, Version, Build-Nummer oder IP-Adresse. Awesome 🙂
Der PowerShell-Code
Bevor wir zu den Erklärungen kommen, hier der eigentliche PowerShell-Code:
<# .SYNOPSIS Auflistung aller Outlook-Client-Verbindungen zum Exchange Server als HTML Report .DESCRIPTION PowerShell Skript zur automatischen Auswertung der RPC-Log-Dateien auf einem oder mehreren Exchange Servern inkl. Erstellung von einem übersichtlichen HTML Report .EXAMPLE C:\Scripts\Outlook_Version.ps1 .NOTES Date: 12.12.2018 Author: Jan Kappen Website: https://www.zueschen.eu Twitter: @JanKappen Thanks to Mike F Robbins for his cool function, for more informations have a look at his description #> #Requires -Version 3.0 function Get-MrRCAProtocolLog { <# .SYNOPSIS Identifies and reports which Outlook client versions are being used to access Exchange. .DESCRIPTION Get-MrRCAProtocolLog is an advanced PowerShell function that parses Exchange Server RPC logs to determine what Outlook client versions are being used to access the Exchange Server. .PARAMETER LogFile The path to the Exchange RPC log files. .EXAMPLE Get-MrRCAProtocolLog -LogFile 'C:\Program Files\Microsoft\Exchange Server\V15\Logging\RPC Client Access\RCA_20140831-1.LOG' .EXAMPLE Get-ChildItem -Path '\\servername\c$\Program Files\Microsoft\Exchange Server\V15\Logging\RPC Client Access\*.log' | Get-MrRCAProtocolLog | Out-GridView -Title 'Outlook Client Versions' .INPUTS String .OUTPUTS PSCustomObject .NOTES Author: Mike F Robbins Website: http://mikefrobbins.com Twitter: @mikefrobbins #> [CmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipeline)] [ValidateScript({ Test-Path -Path $_ -PathType Leaf -Include '*.log' })] [string[]]$LogFile ) PROCESS { foreach ($file in $LogFile) { $Headers = (Get-Content -Path $file -TotalCount 5 | Where-Object {$_ -like '#Fields*'}) -replace '#Fields: ' -split ',' Import-Csv -Header $Headers -Path $file | Where-Object {$_.operation -eq 'Connect' -and $_.'client-software' -eq 'outlook.exe'} | Select-Object -Unique -Property @{label='User';expression={$_.'client-name' -replace '^.*cn='}}, @{label='Version';expression={Get-MrOutlookVersion -OutlookBuild $_.'client-software-version'}}, client-software-version, client-ip } } } function Get-MrOutlookVersion { param ( [string]$OutlookBuild ) switch ($OutlookBuild) { # Outlook 2016 / Outlook 365 / Outlook 2019 {$_ -ge '16.0.11001.20097'} {'Outlook 2016 / 365 / 2019'; break} {$_ -ge '16.0.4229.1003'} {'Outlook 2016 / 365 / 2019'; break} # Outlook 2013 {$_ -ge '15.0.4569.1506'} {'Outlook 2013 SP1'; break} {$_ -ge '15.0.4420.1017'} {'Outlook 2013 RTM'; break} # Outlook 2010 {$_ -ge '14.0.7015.1000'} {'Outlook 2010 SP2'; break} {$_ -ge '14.0.6025.1000'} {'Outlook 2010 SP1'; break} {$_ -ge '14.0.4734.1000'} {'Outlook 2010 RTM'; break} # Outlook 2007 {$_ -ge '12.0.6606.1000'} {'Outlook 2007 SP3'; break} {$_ -ge '12.0.6423.1000'} {'Outlook 2007 SP2'; break} {$_ -ge '12.0.6212.1000'} {'Outlook 2007 SP1'; break} {$_ -ge '12.0.4518.1014'} {'Outlook 2007 RTM'; break} # Outlook 2003 {$_ -ge '11.0.8303.0'} {'Outlook 2003 SP3'; break} {$_ -ge '11.0.8000.0'} {'Outlook 2003 SP2'; break} {$_ -ge '11.0.6352.0'} {'Outlook 2003 SP1'; break} {$_ -ge '11.0.5604.0'} {'Outlook 2003'; break} # Noch älter Default {'Älter als Outlook 2003...'} } } # Prüfung auf benötigtes Modul if (-not (Get-Module -ListAvailable -Name ReportHTML)) { Write-Host -ForegroundColor Red 'Benötigtes Modul "ReportHTML" nicht vorhanden, Abbruch!'`n Write-Host -ForegroundColor Green 'Installation muss mir "Install-Module -Name ReportHTML" durchgeführt werden' Write-Host -ForegroundColor Green 'Weitere Infos unter "https://www.powershellgallery.com/packages/ReportHTML/"' # Hilfe und Anleitung: https://azurefieldnotesblog.blob.core.windows.net/wp-content/2017/06/Help-ReportHTML2.html exit } $cas1 = Get-ChildItem -Path 'C:\Temp\RPC Client Access\cas1\*.log' | Get-MrRCAProtocolLog | Sort-Object -Property User -Unique $cas2 = Get-ChildItem -Path 'C:\Temp\RPC Client Access\cas2\*.log' | Get-MrRCAProtocolLog | Sort-Object -Property User -Unique # Bau den Report, Bob! $rpt = @() $rpt += Get-HTMLOpenPage -TitleText "Exchange 2010 - Client Verbindungen" -HideLogos # cas1 $rpt += Get-HtmlContentOpen -BackgroundShade 3 -HeaderText "Client Verbindungen Exchange 2010" $rpt+= get-HtmlColumn1of2 $rpt+= Get-HtmlContentOpen -BackgroundShade 2 -HeaderText 'CAS1' $rpt+= Get-HtmlContentTable $cas1 $rpt += Get-HTMLContentClose $rpt+= get-htmlColumnClose # cas2 $rpt+= get-HtmlColumn2of2 $rpt+= Get-HtmlContentOpen -BackgroundShade 2 -HeaderText 'CAS2' $rpt+= Get-HtmlContentTable $cas2 $rpt += Get-HTMLContentClose $rpt+= get-htmlColumnClose $rpt += Get-HTMLClosePage $rpt | set-content -path "c:\temp\exchange_connections.html" # Set-Content -Value $rpt -path "c:\temp\exchange_connections.html"
Download als TXT-Datei:
Einige Erklärungen zum Code
Ich habe ein bisschen gebraucht, bis ich den Code so hatte, wie ich ihn letztendlich haben wollte. Diese Informationen gebe ich hier mal an euch weiter, Hilfe und Beschreibungen können ja nicht schaden 🙂
Die Auswertung der .log-Dateien
Die eigentliche Auswertung der Dateien erfolgt mit dem Befehl
$cas1 = Get-ChildItem -Path 'C:\Temp\RPC Client Access\cas1\*.log' | Get-MrRCAProtocolLog | Sort-Object -Property User -Unique
Alle Dateien mit der Endung .log werden mit Get-ChildItem geholt und an die Funktion Get-MrRCAProtocolLog übergeben. Diese Funktion macht einen großen Teil des Skripts aus und wurde von Mike F Robbins geschrieben, thank you for this! 🙂
Die Funktion durchforstet alle Log-Dateien und ich nutze die drei Werte client-name, client-software-version und client-ip. Um nicht ausschließlich die Build-Version zu nutzen, wird die Nummer nochmal in einen Namen umgeschrieben. Dies wird mit der zweiten Funktion Get-MrOutlookVersion realisiert. Der relevante Code-Teil ist
Select-Object -Unique -Property @{label='User';expression={$_.'client-name' -replace '^.*cn='}},
@{label='Version';expression={Get-MrOutlookVersion -OutlookBuild $_.'client-software-version'}},
client-software-version,
client-ip
An dieser Stelle könnten auch noch weitere Attribute abgefragt und aufgelistet werden. Welche Attribute dies sind, lässt sich aus einer .log-Datei auslesen:
Der Parameter -unique sorgt dafür, dass ein Benutzer nur einmal aufgeführt wird. Wird dies nicht genutzt, so wäre jede Log-Zeile auch in der Auswertung enthalten. Meldet sich ein Client an einem Tag 7x an über einen Zeitraum von einem Monat, wären dies über 200 Einträge für einen einzigen Benutzer. Ein kleines Manko habe ich allerdings mit dieser Filterung: Benutzt ein Anwender mehrere Geräte, so wird hier nur der erste Eintrag aufgegriffen. Hier könnte alternativ nach einer einmaligen IP-Adresse gefiltert werden, dies macht allerdings auf einem Terminal Server keinen Sinn, da hier mehrere Benutzer von der gleichen IP-Adresse kommen.
Besonders gut gefallen (weil ich wieder was neues gelernt habe) hat mir die folgende Zeile:
@{label='Version';expression={Get-MrOutlookVersion -OutlookBuild $_.'client-software-version'}},
Diese kleine Zeile ersetzt die Build-Nummer durch einen sprechenden Namen. Realisiert wird dies durch die Funktion Get-MrOutlookVersion.
Innerhalb dieser Funktion wird die Build-Nummer abgefragt, dies sieht dann wie folgt aus:
Ich habe die ursprüngliche Liste ein wenig erweitert und um weitere Versionen ergänzt. Was wichtig ist, ist die Abfrage nach der Outlook-Version mit einer fünfstelligen Nummer an Stelle drei (16.0.11001.xxxxx). Wird diese nicht explizit angegeben, kommt die Abfrage hier durcheinander und sortiert das Office 2019 bzw. Office 365 unter Office 2013 ein.
Kleiner Tipp von mir an dieser Stelle: Schauen Sie sich die Build-Nummern einmal an, manchmal kann man hier „Zwischenversionen“ erkennen, z.B. durch die Installation von Hotfixes oder ähnliches. Nicht immer sind die Build-Nummern genau so, wie man sie erwartet. Dies ist auch der Grund, warum ich neben einem sprechenden Namen zusätzlich noch die eigentliche Build-Nummer mit ausgebe, obwohl diese ja schon durch die kleine Funktion „korrekt“ ersetzt hätte werden müssen (könnte, sollte und so 😉 )
Pingback:Windows Server 2016 Patchstände aus WSUS auslesen und HTML-Report erzeugen - Jans Blog
Hallo Jan,
toller Artikel, hat uns bei unseren Umstellungen der großen DAG-Umgebungen sehr geholfen!
Uns ist aber nun aufgefallen, dass die Attribute unter Exchange 2016 und auch 2019 nicht mehr ausgelesen werden können bzw. in den RPC Client Access Logs nur noch Zugriffe von den HealthMailboxes via „Microsoft.Exchange.RpcClientAccess.Monitoring.dll“ protokolliert werden.
ist dir eine andere Möglichkeit bekannt die Outlook Client-Versionen direkt am Exchange auszulesen?