PowerShell: Outlook Client-Versionen im Exchange RPC-Log analysieren

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 😉 )


Sie benötigten persönliche Unterstützung oder haben nicht die richtige Lösung für Ihr Problem gefunden?

Dieser Blog wird von mir, Jan Kappen, in seiner Freizeit betrieben, hier beschreibe ich Lösungen für Probleme aller Art oder technische Anleitungen mit Lösungsansätzen.

Die berufliche Unabhängigkeit

Ich bin seit Januar 2020 vollständig selbstständig und habe meine eigene Firma gegründet, die Building Networks mit Sitz in Winterberg im schönen Sauerland. Hier stehe ich als Dienstleister gerne für Anfragen, Support oder Projekte zur Verfügung.

Die Firma Building Networks bietet Ihnen:

  • Hilfe und Support per Telefon, Fernwartung oder persönlich vor Ort
  • Projekt-Unterstützung
  • Ausgezeichnete Kompetenz zu den Themen
    • Microsoft Hyper-V
    • Microsoft Failover Clustering & HA
    • Storage Spaces Direct (S2D) & Azure Stack HCI
    • Veeam Backup & Recovery
    • Microsoft Exchange
    • Microsoft Exchange Hybrid Infrastruktur
    • Microsoft Active Directory
    • Microsoft Office 365
    • Ubiquiti
    • 3CX VoIP PBX
    • Fortinet Network Security
    • Baramundi Software
    • ...

Ich freue mich über Ihren Kontakt, weitere Informationen finden Sie auf der Webseite meiner Firma unter Building-Networks.de

Jan

Jan Kappen arbeitet seit 2005 in der IT. Er hat seine Ausbildung 2008 abgeschlossen und war bis 2018 als IT-Consultant im Bereich Hyper-V, Failover Clustering und Software Defined Storage unterwegs. Seit 2015 wurde er jährlich von Microsoft als Most Valuable Professional (MVP) im Bereich "Cloud & Datacenter Management" ausgezeichnet für seine Kenntnisse und die Weitergabe seines Wissens. Jan ist häufig auf Konferenzen als Sprecher zu finden, weiterhin bloggt er viel. Von September 2018 bis Dezember 2019 war Jan als Senior Network- und Systemadministrator bei einem großen mittelständischen Unternehmen im schönen Sauerland angestellt. Im Januar 2020 hat er den Sprung in die Selbstständigkeit gewagt und ist seitdem Geschäftsführer der Firma Building Networks in Winterberg. In seiner Freizeit kümmert er sich um das Freifunk-Netzwerk in Winterberg und Umgebung.

2 Kommentare:

  1. Pingback:Windows Server 2016 Patchstände aus WSUS auslesen und HTML-Report erzeugen - Jans Blog

  2. Wallner Boris

    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?

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert