Hi,
I hope my English is sufficient.
In my setup, PSU runs as a Windows service on a server where the Exchange Management Tools are installed. The PSU service runs under a service account that has the required Exchange permissions.
When Exchange cmdlets need to be executed directly from a dashboard, I load a dedicated PSU environment that runs a standard Windows PowerShell 5.1 session. As the startup script for this environment, I execute the following code:
. "E:\Program Files\Microsoft\Exchange Server\V15\bin\RemoteExchange.ps1" # adjust path as needed
Connect-ExchangeServer -ServerFqdn EXCHANGESERVERNAME # adjust server name as needed
This approach has worked best for me. When using PSSession directly, I ran into similar issues as you described.
I solved message tracking differently. Since a large number of servers (>50) need to be queried, the workload is parallelized using jobs. The frontend is similar to what was described earlier; when the form is submitted, the script is triggered:
-OnSubmit {
# build htParameter hashtable
...
...
$job = Invoke-PSUScript -Script 'Get-CCMSMessageTracking.ps1' -htParameter $htParameter
$page:JobID = $job.Id
Sync-UDElement -Id 'dynJobsRunning'
Sync-UDElement -Id 'dynResultTable'
}
Get-CCMSMessageTracking.ps1:
param([hashtable]$htParameter)
Import-Module CCMS-ScriptModule
foreach ($server in $alleExchangeServer.Name) {
$null = Invoke-Command -ComputerName $server -AsJob -ScriptBlock {
$s = New-PSSession `
-Name "Session_$($using:server)" `
-ConfigurationName Microsoft.Exchange `
-ConnectionUri http://$($using:server)/PowerShell/ `
-Authentication Kerberos `
-Credential $using:credCCMS
$null = Import-PSSession $s -CommandName Get-MessageTrackingLog
Get-MessageTrackingLog -Server $using:server @using:htParameter
Remove-PSSession -Name "Session_$($using:server)"
} -JobName "Job_MessagingTracking_$server" -Authentication Kerberos
}
$results = Get-Job -Name "Job_MessagingTracking_*" |
Wait-Job |
Receive-Job |
Select-Object TimeStamp, Sender, Recipients, MessageSubject, EventID,
ServerHostname, MessageID, Source, SourceContext
Get-Job -Name "Job_MessagingTracking_*" | Remove-Job
$results
Within the script module, the Exchange server names are stored as a global variable ($alleExchangeServer.Name), and the service account credentials are stored as a credential object ($credCCMS). Each mailbox server returns its own message tracking results.
Once the PSU job has completed, the results can be retrieved and displayed as a table in the dashboard.
Since other Exchange scripts are also executed as PSU jobs, I implemented a dedicated job overview page for our admins. This page allows previous jobs to be reviewed, displayed, or re-run. For long-running scripts, users can leave the page and later return via the job page once execution has completed. A job badge in the menu bar indicates whether jobs are still running in the context of the current admin user.
I hope this helps.