When doing this for a large amount of mailboxes it can be useful to use a script to automate this...
As I am lazy, I searched the internet for such a script, and found one from Steve Goodman which was close to what I wanted.. But as needy as I am, I needed more.
I modified, and added to the script which you find below. And is is as good as I am going to make it. It works like a charm (as I do say so myself)
Also made it so that if you are going to export a lot of mailboxes the target share and the source servers won't die on you you can set the maximum concurrent to a number your environment will survive.
The script will start the first batch, wait until completion, and than start the second batch.
When finished it will write some info to the report folder, and the logs for the completed and the failed requests...
Thanks go to Jeff Wouters which reviewed the script for me. And to his blog for the Add-Module function, which gave me a good idea for an add-SnapIN function which does basically the same but than for SnapIns.. so if you run the script multiple times you won't get an error :-)
# Exchange 2010 SP1 Mailbox Export Script # Original script from : Steve Goodman (http://www.stevieg.org/2010/07/using-the-exchange-2010-sp1-mailbox-export-features-for-mass-exports-to-pst/) # input from Jeff Wouters ( www.jeffwouters.nl) # deviations from original script: # - option to export all in the organisation # - option to export all in a list # - option to include archive mailboxes # - option to exclude dumpster # - option to set a maximum concurrent exports # - no need to run from Exchange PowerShell. Needed library is loaded at runtime $starttime = get-date -displayhint time ############### # Settings # ############### # Pick ONE of the two below. If you choose both, it will use $Server. $Server $Database $list = "\\server\share\users1.csv" # Share to export mailboxes to. Needs R/W by Exchange Trusted Subsystem # Must be a UNC path as this is run by the CAS MRS service. $ExportShare = "\\server\share\pst\" if (!(test-path -path $ExportShare -pathtype container)) { mkdir $ExportShare } # After each run a report of the exports can be dropped into the directory specified below. (The user that runs this script needs access to this share) # Must be a UNC path or the full path of a local directory. $ReportShare = "\\server\share\log\" if (!(test-path -path $ReportShare -pathtype container)) { mkdir $ReportShare } # Shall we remove the PST file, if it exists beforehand? (The user that runs this script needs access to the $ExportShare share) # Valid values: $true or $false $RemovePSTBeforeExport = $true # Do we want to include Archive Mailboxes $IncludeArchive = $true # Do we want to exclude dumpster # currently not working as intended. workarround in place $ExcludeDumpster = $false # How many concurrent exports do we want? # This must be an even number (2, 4, 6, 50, 100, 200, 1000 etc) $maxConcurrentExports = 200 ############### # Code # ############### # function created by Jeff Wouters (www.jeffwouters.nl) function Check-LoadedModule { Param( [parameter(Mandatory = $true)][alias("Module")][string]$ModuleName) $LoadedModules = Get-Module | Select Name if (!$LoadedModules -like "*$ModuleName*") {Import-Module -Name $ModuleName} } # Deviation from Jeff Wouters function but for PSAddins function Check-LoadedSnapIN { Param( [parameter(Mandatory = $true)][alias("SnapIN")][string]$SnapINName) if ( (Get-PSSnapin -Name $SnapINName -ErrorAction SilentlyContinue) -eq $null ) { Add-PsSnapin $SnapINName } } # If Archives are included we get 2 exports at a time. so we need to divide the maximum by 2 if ($includeArchive){ $maxConcurrentExports = $maxConcurrentExports / 2 } # load the Exchange powershell snapin if not loaded Check-LoadedSnapIN Microsoft.Exchange.Management.PowerShell.E2010 # this function will create the MailboxExportRequests. function exportMailbox ([String]$CurrentUser) { if ($RemovePSTBeforeExport -eq $true -and (Get-Item "$($ExportShare)\$($CurrentUser).PST" -ErrorAction SilentlyContinue)) { Remove-Item "$($ExportShare)\$CurrentUser.PST" -Confirm:$false -ErrorAction SilentlyContinue Remove-Item "$($ExportShare)\$CurrentUser-Archive.PST" -Confirm:$false -ErrorAction SilentlyContinue } if ($ExcludeDumpster){ # workarround if else. Would rather place this inline in the vode. New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)\$CurrentUser.pst" -ExcludeDumpster if ($IncludeArchive){ New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)\$CurrentUser-Archive.pst" -IsArchive -ExcludeDumpster } } else { New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)\$CurrentUser.pst" if ($IncludeArchive){ New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)\$CurrentUser-Archive.pst" -IsArchive } } } # This function makes the script wait for completion of all exports. function waitForCompletion { while ((Get-MailboxExportRequest -BatchName $BatchName | Where {$_.Status -eq "Queued" -or $_.Status -eq "InProgress"})) { clear Write-Output "Waiting for the exports to complete" Get-MailboxExportRequest -BatchName $BatchName | Get-MailboxExportRequestStatistics | Where {$_.Status -eq "Queued" -or $_.Status -eq "InProgress"} | Out-Default | Format-Table sleep 60 } } # Make batch name $date=Get-Date $BatchName = "Export_$($date.Year)-$($date.Month)-$($date.Day)_$($date.Hour)-$($date.Minute)-$($date.Second)" if ($ExcludeDumpster){ $additionalParm = "-ExcludeDumpster $true" } else { $additionalParm = "" } # the collection of what to be export if ($Server) { write-output "Using Server" if (!(Get-ExchangeServer $Server -ErrorAction SilentlyContinue)) { throw "Exchange Server $Server not found"; } if (!(Get-MailboxDatabase -Server $Server -ErrorAction SilentlyContinue)) { throw "Exchange Server $Server does not have mailbox databases"; } $Mailboxes = Get-Mailbox -Server $Server -ResultSize Unlimited } elseif ($Database) { write-output "Using database" if (!(Get-MailboxDatabase $Database -ErrorAction SilentlyContinue)) { throw "Mailbox database $Database not found" } $Mailboxes = Get-Mailbox -Database $Database -ResultSize Unlimited } elseif ($list) { write-output "Using list: $list" $userlist = Import-CSV $list } else { write-output "None of the above, so exporting all mailboxes.." $mailboxes = Get-Mailbox -ResultSize Unlimited } # The Export if ($list){ Write-Output "Queuing $($userlist.Count) mailboxes as batch '$($BatchName)'" $teller = 0 # Queue all mailbox export requests foreach ($user in $userlist) { $teller = $teller + 1 $curuser = $user.SamAccountName exportMailbox $curuser if ($teller -gt $maxConcurrentExports){ Write-Output "Waiting for batch to complete" # Wait for mailbox export requests to complete waitForCompletion $teller = 0 } } # Wait for mailbox export requests to complete waitForCompletion }elseif ((!$Mailboxes) -and (!$Mailboxes.Count)) { throw "No mailboxes found on $Server or single Mailbox." } else { Write-Output "Queuing $($Mailboxes.Count) mailboxes as batch '$($BatchName)'" # Queue all mailbox export requests $teller = 0 foreach ($Mailbox in $Mailboxes) { $teller = $teller + 1 exportMailBox $Mailbox.alias if ($teller -gt $maxConcurrentExports){ Write-Output "Waiting for batch to complete" # Wait for mailbox export requests to complete waitForCompletion $teller = 0 } } # Wait for mailbox export requests to complete waitForCompletion } # Write reports if required if ($ReportShare) { Write-Output "Writing reports to $($ReportShare)" $Completed = Get-MailboxExportRequest -BatchName $BatchName | Where {$_.Status -eq "Completed"} | Get-MailboxExportRequestStatistics | Format-List if ($Completed) { $Completed | Out-File -FilePath "$($ReportShare)\$($BatchName)_Completed.txt" } $Incomplete = Get-MailboxExportRequest -BatchName $BatchName | Where {$_.Status -ne "Completed"} | Get-MailboxExportRequestStatistics if ($Incomplete) { $Incomplete | Format-List | Out-File -FilePath "$($ReportShare)\$($BatchName)_Incomplete_Report.txt" if (!$list){ $list = "$($ReportShare)\$($BatchName)_failedpst.csv" } set-content -Value "Failed-PST" -Path $list".new" foreach ($woops in $Incomplete) { add-content -Value $woops.FilePath -Path $list".new" } } } $endtime = get-date -displayhint time $runtimefile = "$($ReportShare)\$($BatchName)_runtime.txt" $runtimeentry0 = $starttime.tostring() + ' - ' + $endtime.tostring() $runtimeentry1 = "Completed exports: " + $completed.count $runtimeentry2 = "Failedexports: " + $Incomplete.count $runtimeentry3 = "Errored users:" $runtimeentry4 = ( get-content -Path $list".new" | out-string) Set-Content -Value $runtimeentry0 -Path $runtimefile add-content -Value $runtimeentry1 -Path $runtimefile add-content -Value $runtimeentry2 -Path $runtimefile add-content -Value $runtimeentry3 -Path $runtimefile add-content -Value $runtimeentry4 -Path $runtimefile # Remove Requests Write-Output "Removing requests created as part of batch '$($BatchName)'" Get-MailboxExportRequest -BatchName $BatchName | Remove-MailboxExportRequest -Confirm:$false
This is really great and the improvements are exactly what I was looking for.
ReplyDeleteI need help with the scrip. I get this error. Please help
ReplyDeletePS C:\Users\administrator.CORP> cd C:\pst
PS C:\pst> .\MassExportnew.ps1
Using list: \\fs01\Shared\users1.csv
Queuing 3 mailboxes as batch 'Export_2015-1-23_9-33-7'
New-MailboxExportRequest : Cannot bind parameter 'Mailbox'. Cannot convert value "" to type "Microsoft.Exchange.Configu
ration.Tasks.MailboxOrMailUserIdParameter". Error: "Parameter values of type Microsoft.Exchange.Configuration.Tasks.Mai
lboxOrMailUserIdParameter can't be empty. Specify a value, and try again.
Parameter name: identity"
At C:\pst\MassExportnew.ps1:95 char:62
+ New-MailboxExportRequest -BatchName $BatchName -Mailbox <<<< $CurrentUser -FilePath "$($ExportShare)\$CurrentU
ser.pst"
+ CategoryInfo : InvalidArgument: (:) [New-MailboxExportRequest], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.Exchange.Management.RecipientTasks.NewMailboxEx
portRequest
New-MailboxExportRequest : Cannot bind parameter 'Mailbox'. Cannot convert value "" to type "Microsoft.Exchange.Configu
ration.Tasks.MailboxOrMailUserIdParameter". Error: "Parameter values of type Microsoft.Exchange.Configuration.Tasks.Mai
lboxOrMailUserIdParameter can't be empty. Specify a value, and try again.
Parameter name: identity"
At C:\pst\MassExportnew.ps1:97 char:63
+ New-MailboxExportRequest -BatchName $BatchName -Mailbox <<<< $CurrentUser -FilePath "$($ExportShare)\$Current
User-Archive.pst" -IsArchive
+ CategoryInfo : InvalidArgument: (:) [New-MailboxExportRequest], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.Exchange.Management.RecipientTasks.NewMailboxEx
portRequest
New-MailboxExportRequest : Cannot bind parameter 'Mailbox'. Cannot convert value "" to type "Microsoft.Exchange.Configu
ration.Tasks.MailboxOrMailUserIdParameter". Error: "Parameter values of type Microsoft.Exchange.Configuration.Tasks.Mai
lboxOrMailUserIdParameter can't be empty. Specify a value, and try again.
Parameter name: identity"
At C:\pst\MassExportnew.ps1:95 char:62
+ New-MailboxExportRequest -BatchName $BatchName -Mailbox <<<< $CurrentUser -FilePath "$($ExportShare)\$CurrentU
ser.pst"
+ CategoryInfo : InvalidArgument: (:) [New-MailboxExportRequest], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.Exchange.Management.RecipientTasks.NewMailboxEx
portRequest
New-MailboxExportRequest : Cannot bind parameter 'Mailbox'. Cannot convert value "" to type "Microsoft.Exchange.Configu
ration.Tasks.MailboxOrMailUserIdParameter". Error: "Parameter values of type Microsoft.Exchange.Configuration.Tasks.Mai
lboxOrMailUserIdParameter can't be empty. Specify a value, and try again.
Parameter name: identity"
At C:\pst\MassExportnew.ps1:97 char:63
+ New-MailboxExportRequest -BatchName $BatchName -Mailbox <<<< $CurrentUser -FilePath "$($ExportShare)\$Current
User-Archive.pst" -IsArchive
+ CategoryInfo : InvalidArgument: (:) [New-MailboxExportRequest], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.Exchange.Management.RecipientTasks.NewMailboxEx
portRequest
Could you post the contents of your CSV file?
ReplyDeleteThe first line of the csv should have: SamAccountName
Bas, Thanks for quit reply. Here it is
ReplyDeleteSamAccountName
kklepacki
rklepacki
mklepacki
nklepacki
Bas, Script is working correctly. there was an issue in my test lab setup. Thanks again.
ReplyDelete