Why is it so messy to export mailbox in PST format from Exchange Online?
Anyway… simple powershell script to automate mailbox download with Compliance Search cmdlets and unifiedexporttool executable from Microsoft
😎😚
write-host "INIZIO PROCEDURA"
$password = "password"
$user_management = "username"
$Mailbox = "mailbox@domain.com"
$ExportLocation = "c:\export"
$datetime = get-date -format yyyyMMddHHmmss
$SearchName = "$($Mailbox)_$($datetime)_PST"
$pass_management = $password | convertto-securestring -asplaintext -force
$UserCredential = new-object -typename System.Management.Automation.PSCredential -argumentlist $user_management, $pass_management
write-host "Connessione a Exchange Online..."
connect-ExchangeOnline -Credential $UserCredential -ShowBanner:$false
Connect-IPPSSession -Credential $UserCredential
write-host "Creo ricerca compliance $SearchName..."
New-ComplianceSearch -Name $SearchName -ExchangeLocation $Mailbox -AllowNotFoundExchangeLocationsEnabled $true
write-host "Avvio ricerca..."
Start-ComplianceSearch -Identity $SearchName
while ((Get-ComplianceSearch $SearchName | Select-Object -ExpandProperty Status) -ne "Completed") {
Start-Sleep -s 2
Write-Host -NoNewline "."
}
write-host "Ricerca $SearchName completata!"
write-host "Creo ricerca export $SearchName..."
New-ComplianceSearchAction -SearchName $SearchName -Export -Format FxStream -ExchangeArchiveFormat PerUserPst -Scope BothIndexedAndUnindexedItems -EnableDedupe $true -SharePointArchiveFormat IndividualMessage -IncludeSharePointDocumentVersions $true
Start-Sleep -s 5
While (-Not ((Get-ChildItem -Path $($env:LOCALAPPDATA + "\Apps\2.0\") -Filter microsoft.office.client.discovery.unifiedexporttool.exe -Recurse).FullName | Where-Object{ $_ -notmatch "_none_" } | Select-Object -First 1)){
write-host "Scarico Unified Export Tool da Azure."
$Manifest = "https://complianceclientsdf.blob.core.windows.net/v16/Microsoft.Office.Client.Discovery.UnifiedExportTool.application"
$ElevatePermissions = $true
Try {
Add-Type -AssemblyName System.Deployment
write-host " Inizializzo installazione ClickOnce $Manifest"
$RemoteURI = [URI]::New( $Manifest , [UriKind]::Absolute)
if (-not $Manifest){
throw "Url di connessione non valido '$ConnectionUri'"
}
$HostingManager = New-Object System.Deployment.Application.InPlaceHostingManager -ArgumentList $RemoteURI , $False
Register-ObjectEvent -InputObject $HostingManager -EventName GetManifestCompleted -Action {
new-event -SourceIdentifier "ManifestDownloadComplete"
} | Out-Null
Register-ObjectEvent -InputObject $HostingManager -EventName DownloadApplicationCompleted -Action {
new-event -SourceIdentifier "DownloadApplicationCompleted"
} | Out-Null
$HostingManager.GetManifestAsync()
$event = Wait-Event -SourceIdentifier "ManifestDownloadComplete" -Timeout 15
if ($event ) {
$event | Remove-Event
write-host "Manifest Clickonce scaricato"
$HostingManager.AssertApplicationRequirements($ElevatePermissions)
$HostingManager.DownloadApplicationAsync()
$event = Wait-Event -SourceIdentifier "DownloadApplicationCompleted" -Timeout 60
if ($event ) {
$event | Remove-Event
write-host "ClickOnce scaricato"
}
else {
write-host "ClickOnce non scaricato entro 60s" -level "ERROR"
}
}
else {
Write-error "ClickOnce Manifest non scararicato in 15s" -level "ERROR"
}
}
finally {
Get-EventSubscriber|? {$_.SourceObject.ToString() -eq 'System.Deployment.Application.InPlaceHostingManager'} | Unregister-Event
}
}
$ExportExe = ((Get-ChildItem -Path $($env:LOCALAPPDATA + "\Apps\2.0\") -Filter microsoft.office.client.discovery.unifiedexporttool.exe -Recurse).FullName | Where-Object{ $_ -notmatch "_none_" } | Select-Object -First 1)
$ExportName = $SearchName + "_Export"
$ExportDetails = Get-ComplianceSearchAction -Identity $ExportName -IncludeCredential -Details | Select-Object *
write-host "Inizio Export $ExportName"
while ( (Get-ComplianceSearchAction -Identity $ExportName -IncludeCredential -Details).status -ne "Completed" ) {
Start-Sleep -s 2
Write-Host -NoNewline "."
}
$ExportDetails = Get-ComplianceSearchAction -Identity $ExportName -IncludeCredential -Details | Select-Object *
$ExportDetails = $ExportDetails.Results.split(";")
$ExportContainerUrl = $ExportDetails[0].trimStart("Container url: ")
$ExportSasToken = $ExportDetails[1].trimStart(" SAS token: ")
$ExportEstSize = [double]($ExportDetails[18].TrimStart(" Total estimated bytes: ")).replace(".","")
$ExportTransferred = [double]($ExportDetails[20].TrimStart(" Total transferred bytes: ")).replace(".","")
$ExportProgress = $ExportDetails[22].TrimStart(" Progress: ").TrimEnd("%")
$ExportStatus = $ExportDetails[25].TrimStart(" Export status: ")
write-host "Scarico Export su: $ExportLocation\$SearchName"
$Arguments = "-name ""$SearchName""","-source ""$ExportContainerUrl""","-key ""$ExportSasToken""","-dest ""$ExportLocation""","-trace true"
Start-Process -FilePath "$ExportExe" -ArgumentList $Arguments
while(Get-Process microsoft.office.client.discovery.unifiedexporttool -ErrorAction SilentlyContinue){
$Downloaded = Get-ChildItem $ExportLocation\$SearchName -Recurse | Measure-Object -Property Length -Sum | Select-Object -ExpandProperty Sum
Write-Progress -Id 1 -Activity "Esportazione in corso...." -Status "Completato..." -PercentComplete $ExportProgress -ErrorAction Continue
if ( ($Downloaded/$ExportEstSize*100) -gt "100" ) {
$percent = "100"
} else {
$percent = ($Downloaded/$ExportEstSize*100)
}
if ("Completed" -notlike $ExportStatus){
Write-Progress -Id 2 -Activity "Download in corso" -Status "Completato..." -PercentComplete $percent -CurrentOperation "$Downloaded/$ExportEstSize bytes scaricati." -ErrorAction Continue
} else {
Write-Progress -Id 2 -Activity "Download in corso" -Status "Completato..." -PercentComplete $percent -CurrentOperation "$Downloaded/$ExportTransferred bytes scaricati." -ErrorAction Continue
}
Start-Sleep 10
$ExportDetails = Get-ComplianceSearchAction -Identity $ExportName -IncludeCredential -Details
$ExportDetails = $ExportDetails.Results.split(";")
$ExportEstSize = [double]($ExportDetails[18].TrimStart(" Total estimated bytes: ").replace(".",""))
$ExportTransferred = [double]($ExportDetails[20].TrimStart(" Total transferred bytes: ").replace(".",""))
$ExportProgress = ($ExportDetails[22].TrimStart(" Progress: ").TrimEnd("%")).substring(0,($ExportDetails[22].TrimStart(" Progress: ").TrimEnd("%")).IndexOf(","))
$ExportStatus = $ExportDetails[25].TrimStart(" Export status: ")
Write-Host -NoNewline "."
}
write-host "Download PST Completato su $ExportLocation\$SearchName"
write-host "Cancello ricerca $SearchName"
Get-ComplianceSearch -Identity $SearchName | remove-compliancesearch -confirm:$false
Disconnect-ExchangeOnline -Confirm:$false