Forum Discussion
Export to PST via Powershell
- Aug 10, 2017
No way to do it without going to the SCC and initializing the download via the click-one app, sorry. Perhaps you can automate it via AzCopy or some other tool that takes container/token as input - you can get those via the Result property of Get-ComplianceSearchAction.
As for the cmdlet, make sure you also use the -Format parameter!
The Format parameter specifies the format of the search results when you use the Export switch. Valid values are:
FxStream Export to PST files. This is the only option that's available when you export search results from the Security & Compliance Center.
Mime Export to .eml messsage files. This the default value when you use cmdlets to export the search results.It's most likely what causes the issue in your case.
It looks like the export tool can't load one of it's dependency files. Did you copy the exe out of your profile folder without all the rest of the files? And, are you using Tom Aguero's code? If so, try replacing:
$exportexe = "\UnifiedExportTool\microsoft.office.client.discovery.unifiedexporttool.exe"
with:
$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)
and see if that helps?
This should find the exe within your profile, without having to copy the file or use any static paths, which should help if you have multiple people that may run the script.
Also, thanks for the Reddit link, I like their way of pulling the URL and token much better! I'll have to try it out on the next run of the script.
Additionally, If anyone wants to automate downloading the unified export tool:
# Check if the export tool is installed for the user, and download if not.
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 "Downloading Unified Export Tool ."
Write-Host "This is installed per-user by the Click-Once installer."
# Credit to Jos Verlinde for his code in Load-ExchangeMFA in the Powershell Gallery! All I've done is update the manifest url and remove all the comments
# Ripped from https://www.powershellgallery.com/packages/Load-ExchangeMFA/1.2
# In case anyone else has any ClickOnce applications they'd like to automate the install for:
# If you're looking for where to find a manifest URL, once you have run the ClickOnce application at least once on your computer, the url for the application manifest can be found in the Windows Registry at "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall" (yes, CTR apps are installed per-user).
# Look through the keys with names that are 16 characters long hex strings. They'll have a string value (REG_SZ) named either "ShortcutAppId" or "UrlUpdateInfo" that contains the URL as the first part of the string.
$Manifest = "https://complianceclientsdf.blob.core.windows.net/v16/Microsoft.Office.Client.Discovery.UnifiedExportTool.application"
$ElevatePermissions = $true
Try {
Add-Type -AssemblyName System.Deployment
Write-Host "Starting installation of ClickOnce Application $Manifest "
$RemoteURI = [URI]::New( $Manifest , [UriKind]::Absolute)
if (-not $Manifest){
throw "Invalid ConnectionUri parameter '$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 "ClickOnce Manifest Download Completed"
$HostingManager.AssertApplicationRequirements($ElevatePermissions)
$HostingManager.DownloadApplicationAsync()
$event = Wait-Event -SourceIdentifier "DownloadApplicationCompleted" -Timeout 60
if ($event ) {
$event | Remove-Event
Write-Host "ClickOnce Application Download Completed"
}
else {
Write-error "ClickOnce Application Download did not complete in time (60s)"
}
}
else {
Write-error "ClickOnce Manifest Download did not complete in time (15s)"
}
}
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)
If the application has already been installed, you'll get a misleading InvalidOperationException from AssertApplicationRequirements. This doc "suggests" to check GetManifestCompletedEventArgs before calling AssertApplicationRequirements.
Register-ObjectEvent -InputObject $HostingManager -EventName GetManifestCompleted -Action {
New-Event -SourceIdentifier "GetManifestCompleted" -EventArguments @($EventArgs.Error)
} | Out-Null
$HostingManagerEvent = Wait-Event -SourceIdentifier "GetManifestCompleted" -Timeout 15
if($HostingManager){
if ($HostingManagerEvent.SourceArgs[0]) {
if($HostingManagerEvent.SourceArgs[0].Message.Contains("already installed")){
Write-Output "ClickOnce Application has already been downloaded"
}else{
Write-Error -Message $HostingManagerEvent.SourceArgs[0].Message
}
}
}
Additionally, VSCode warned me $event is an automatic variable. Unless it was intentionally named that way, I renamed mine to something else.