Yes, and no... as this...
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
... is a common and best practice.
Windows will always do a cleanup, but it's always clean up your environment when you are done.
As documented...
Clean Up Your PowerShell Environment by Tracking Variable Use
https://devblogs.microsoft.com/scripting/clean-up-your-powershell-environment-by-tracking-variable-use
And covered by this SO Q&A and accepted answer...
PowerShell release COM object
function Release-Ref ($ref) {
[System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) | out-null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
because I've noted that my comobject always stay alive, I think Powershell 2.0 is not able to remove comobject no more used.
[System.Runtime.InteropServices.Marshal]::ReleaseComObject( $ref )
and that SO is exactly what you are asking, so this question is really a duplicate.
My example, I use a prefix to my variable so they are easy to find and simple globally clean up.
# Assign results to a variable and output to the screen using variable squeezing
($ponMyShell = New-Object -com "Wscript.Shell")
($ponDate = Get-Date)
($ponProcess = Get-Process |
Select -First 3)
<#
# Results
Monday, 2 March, 2020 19:40:47
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
186 14 2648 6800 0.14 15336 0 aesm_service
465 27 24300 34064 0.33 27612 22 ApplicationFrameHost
158 8 1928 4848 0.02 14268 0 AppVShNotify
SpecialFolders CurrentDirectory
-------------- ----------------
System.__ComObject C:\Windows\system32
#>
Get-Variable -Name 'pon*'
<#
# Results
Name Value
---- -----
ponDate 02-Mar-20 19:46:59
ponMyShell System.__ComObject
ponProcess {System.Diagnostics.Process (aesm_service), System.Diagnostics.Process (ApplicationFrameHost), System.Diagnostics.Process (AppVShNotify)}
#>
# Clear resource environment
Get-PSSession |
Remove-PSSession
<#
# Results
#>
[System.Runtime.InteropServices.Marshal]::
ReleaseComObject([System.__ComObject]$ponMyShell) |
Out-Null
<#
# Results
#>
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
<#
# Results
#>
Get-Variable -Name 'pon*' |
ForEach { Get-Variable -Name $_ |
Remove-Variable -Force }
# Validate clean-up
Get-Variable -Name 'pon*'
<#
# Results
#>
Remove-Variableinside a function on a local variable such as$ref, because it will go out of scope automatically when the function is exited; aside from that, you have to pass the name of the variable (ref), not its value ($ref) - ergo:Remove-Variable $ref; also,Remove-Variablenever produces (success) output, so there's no point in piping it toOut-Null.