Import-PSSession causes memory leak in Provisioning System
Problem
When using the Import-PSSession PowerShell command in a provider function, a memory leak occurs.
The provisioning system service consumes an increasing amount of memory and may eventually experience out-of-memory errors.
Solution
Running the provider function as a background job will ensure that the memory consumed by the Import-PSSession command is released when the background job completes.
The following is an example of a very simple provider function that outputs the alias of a specific mailbox identity, and will cause a memory leak.
Function causing memory leak
function Get-Office365MailboxAlias { param( [parameter(Mandatory = $true)] [string]$Identity, [parameter(Mandatory = $true)] [string]$OutputVariableName ) $cred = Get-PFCredential -Name O365 $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell" -Credential $cred -Authentication Basic -AllowRedirection -ErrorAction Stop -WarningAction SilentlyContinue $import = Import-PSSession $session -ErrorAction Stop -WarningAction SilentlyContinue -DisableNameChecking $mailbox = Get-Mailbox -Identity $Identity Get-PSSession | Remove-PSSession @{$OutputVariableName=$mailbox.Alias} }
Below is the same function, now using a background job to work around the issue.
Function using Start-Job (no memory leak)
function Get-Office365MailboxAlias { param( [parameter(Mandatory = $true)] [string]$Identity, [parameter(Mandatory = $true)] [string]$OutputVariableName ) $job = Start-Job -ArgumentList $Identity,$OutputVariableName -ScriptBlock { $Identity = $args[0] $OutputVariableName = $args[1] $cred = Get-PFCredential -Name O365 $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell" -Credential $cred -Authentication Basic -AllowRedirection -ErrorAction Stop -WarningAction SilentlyContinue $import = Import-PSSession $session -ErrorAction Stop -WarningAction SilentlyContinue -DisableNameChecking $mailbox = Get-Mailbox -Identity $Identity Get-PSSession | Remove-PSSession @{$OutputVariableName=$mailbox.Alias} } Wait-Job $job | out-null Receive-Job $job }
Note how the input parameters are passed in the -ArgumentList parameter to the background job. The job then retrieves them from the $args array.
Also note the use of the Wait-Job command to wait for the job to complete, and Receive-Job to replicate the output from the job to the pipeline.