Replikation der öffentlichen Ordner erfolgreich? 13. August 2012

Jeder Administrator der eine Exchange Organisation zu einer aktuelleren Version migriert hat oder einen bestehenden Exchange Server durch einen anderen ersetzen möchte, kennt das Drama um die öffentlichen Ordner. Bei der Replikation der öffentlichen Ordner kann man sich nie wirklich sicher sein, ob alle Inhalte komplett repliziert wurden. Wenn man das prüfen möchte, dann muss man manuell oder mit dem cmdlet “get-publicfolderstatistics” die Anzahl der einzelnen Elemente eines öffentlichen Ordners zwischen den beiden Server vergleichen. Bei einer kleineren Anzahl von öffentlichen Ordner mag das noch gehen. Wenn die öffentlichen Ordner aber in großer Anzahl vorliegen, kann das manuelle Vergleichen sehr zeitaufwändig werden. Da ich aktuell in einem Migrationsprojekt mit einer öffentlichen Ordner Struktur mit mehr als 3300 öffentlichen Ordnern konfrontiert bin, muss eine andere Lösung her.

Nichts liegt da näher, als die ganze Sache zu automatisieren. Ein Microsoftmitarbeiter hat sich um diese Aufgabe schon einmal gekümmert und ein Powershellskript veröffentlicht, was genau diese Aufgabe erfüllt:

Link zu Code Gallery

Allerdings hat das Skript ein paar Einschränkungen:

  • Bei jedem Durchlauf ermittelt das Skript die einzelnen Ordnerreplikate
  • Für jeden Durchlauf werden die Exchange Server Versionen ermittelt
  • Das Skript gibt als Ergebnis alle öffentlichen Ordner aus mit der Anzahl der Elemente bei jedem einzelnen Replikat
  • Ein paar kleinere Bugs :-)

Bei meinem aktuellen Projekt hat das Skript eine Laufzeit von ca. 4,5 Stunden. Außerdem wird die Ausgabe des Skriptes recht unübersichtlich, wenn es sich um viele öffentliche Ordner handelt. Deshalb musste ein neues Skript her, was die Ordnerreplikate zwischen zwei Servern prüft und mir nur die Ordner ausgibt, bei denen Unterschiede bestehen.

# -------------------------------------------------------------
# Script     : compare-publicfolderitems.ps1
# Author     : Frank Röder info@iteach-online.de
# Date       : 08/07/2012
# Copyright  : ITeach-Online Frank Röder
# -------------------------------------------------------------
.\compare-publicfolderitems.ps1 -Path "\Test\Dokumente" -Recurse -sourceserver SRV-ALT -destinationserver SRV-NEU
    In diesem Beispiel wird der öffentliche Ordner "\Test\Dokumente" inklusive aller Unterordner durchsucht. Es werden alle öffentlichen
	Ordner inklusive der Elementanzahl angezeigt.
.EXAMPLE
	C:\Scripts>.\compare-publicfolderitems.ps1 -Path "\Test\Dokumente" -Recurse -sourceserver SRV-ALT -destinationserver SRV-NEU -onlydifferences
	In diesem Beispiel wird der öffentliche Ordner "\Test\Dokumente" inklusive aller Unterordner durchsucht. Es werden alle öffentlichen Ordner angezeigt,
	bei denen in der Elementanzahl Unterschiede bestehen zwischen dem Quellserver und dem Zielserver.
.PARAMETER Path
    Dieser Parameter gibt den Pfad des öffentlichen Ordners an.
.PARAMETER Recurse
    Wenn der Parameter Recurse angegeben ist, werden auch alle Unterordner des angegebenen Pfades verglichen.
.PARAMETER Sourceserver
	Gibt den Quellserver an, der als Referenz dienen soll
.PARAMETER Destinationserver
	Gibt den Zielserver an, dessen Inhalte mit dem Sourceserver verglichen werden sollen
.PARAMETER Differencesonly
	Gibt an, dass nur die Ordner aufgezählt werden sollen, bei denen Unterschiede bestehen
#>
param(
    #Voller Pfad zu dem Rootordner
    [Parameter(Mandatory=$true)]
    [ValidateNOtNullOrEmpty()]
    [string] $Path,
    #Quellserver
    [Parameter(Mandatory=$true)]
    [ValidateNOtNullOrEmpty()]
    [string] $Sourceserver,
    #Zielserver
    [Parameter(Mandatory=$true)]
    [ValidateNOtNullOrEmpty()]
    [string] $Destinationserver,
    #Rekursiv
    [switch] $Recurse,
    #Nur Unterschiede
    [switch] $OnlyDifferences
    )
#Prüfen ob beide Server erreichbar sind
if(!((test-connection $Sourceserver -Count 1 -Quiet) -and (Test-Connection $Destinationserver -count 1 -quiet)))
	{
	Write-Error "Fehler: Quellserver oder Zielserver nicht erreichbar!"
	exit
	}
if($recurse) #Wenn Recurse angegeben wurde, dann werden alle Ordner vom Quellserver in ein Array geschrieben
    {
    $pfCollection = Get-PublicFolder $Path -ErrorAction silentlycontinue -recurse -resultsize unlimited -server $sourceserver | Select identity,replicas,@{Name="LegPFDN"; Expression = {$_.identity.legacyDistinguishedName}}
    }
else #Kein Recurse also nur der einzelne Ordner
    {
    $pfCollection = Get-PublicFolder $Path -ErrorAction silentlycontinue -server $sourceserver | Select identity,replicas,@{Name="LegPFDN"; Expression = {$_.identity.legacyDistinguishedName}}
    }
if(!$pfCollection) #Kein Ordner gefunden, dann mit Fehlermeldung ausgeben und Skript abbrechen
    {
    Write-Host "FEHLER: Kein Ordner mit dem Pfad $path gefunden"
    Write-Host "Bitte geben Sie einen gültigen Pfadnamen ein"
    exit
    }
#Ermitteln der Serverversion von Sourceserver und Destinationserver
$VersionSource = (get-exchangeserver $Sourceserver).admindisplayversion.major
$VersionDestination = (get-exchangeserver $Destinationserver).admindisplayversion.major
$results = @()
#Jetzt Loop durch alle ermittelten Ordner
foreach ($pf in $pfCollection)
{
	if($VersionSource -lt 8)
		{
		$sourceitemcount = (Get-WmiObject -ComputerName $sourceserver -Namespace "root\MicrosoftExchangeV2" -Class "Exchange_PublicFolder" -Filter "targetaddress = ""$($pf.legPFDN)""").messagecount
		}
	else
		{
		$sourceitemcount = (Get-PublicFolderStatistics $pf.legPFDN -Server $sourceserver -resultsize unlimited).itemcount
		}
	if($VersionDestination -lt 8)
		{
		$destinationitemcount = (Get-WmiObject -ComputerName $destinationserver -Namespace "root\MicrosoftExchangeV2" -Class "Exchange_PublicFolder" -Filter "targetaddress = ""$($pf.legPFDN)""").messagecount
		}
	else
		{
		$destinationitemcount = (Get-PublicFolderStatistics $pf.legPFDN -Server $destinationserver -resultsize unlimited).itemcount
		}
	if($OnlyDifferences)
	{
		if($sourceitemcount -ne $destinationitemcount)
		{
			$tmpFolderObj = New-Object system.object
			Add-Member -InputObject $tmpFolderObj -MemberType NoteProperty "Ordnerpfad" $pf.Identity
			add-member -inputObject $tmpFolderObj -membertype NoteProperty $sourceserver $sourceitemcount
			Add-Member -InputObject $tmpFolderObj -MemberType NoteProperty $destinationserver $destinationitemcount
			$results += $tmpFolderObj
		}
	}
	else
	{
			$tmpFolderObj = New-Object system.object
			Add-Member -InputObject $tmpFolderObj -MemberType NoteProperty "Ordnerpfad" $pf.Identity
			add-member -inputObject $tmpFolderObj -membertype NoteProperty $sourceserver $sourceitemcount
			Add-Member -InputObject $tmpFolderObj -MemberType NoteProperty $destinationserver $destinationitemcount
			$results += $tmpFolderObj
	}
}
$results

Das Skript hat bei den 3300 öffentlichen Ordnern eine Laufzeit von ca. 2,5 Stunden. Das Skript kann hier heruntergeladen werden: compare-publicfolderitems.ps1 (1313)

 

2 Comments
Heiko Juli 12th, 2013

Hi,

leider scheitert das Script schon beim finden des des Ordners. Ein “get-publicfolder \ordner\unterordner” zeigt mir das richtige Ergebnis. Das Script kommt direkt mit “FEHLER: Kein Ordner mit dem Pfad \Ordner\Unterordner gefunden”.

Hast du noch einen Tipp?

Gruß

Frank Röder Juli 12th, 2013

Hi,

schreibe mal den kompletten Aufruf des Skripts. Das muss funktionieren. Zumindest kann ich mir aktuell keinen Reim darauf machen, warum er den Ordner nicht finden sollte. Source und Destination verwechselt?

Bye,

Frank

Leave a Reply

*