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.