14

I have a small utility function in one PowerShell script:

function Unzip-File{
    param(
        [Parameter(Mandatory=$true)]
        [string]$ZipFile,
        [Parameter(Mandatory=$true)]
        [string]$Path
    )

    $shell=New-Object -ComObject shell.application

    $zip = $shell.namespace($ZipFile)
    $target = $shell.NameSpace($Path)
    $target.CopyHere($zip.Items())
}

Am I supposed to clean-up the COM objects within the script? Or is PowerShell smart enough to automatically garbage COM Objects?

I've read Getting Rid of a COM Object (Once and For All) and blindly applied:

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($zip)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($target)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell)

But I'm not sure if this was needed.

What the correct pattern of using COM objects in local functions?

1
  • 1
    I think the article you found is probably right. Read a bit further to the notes on Remove-Variable to release any other references to the variables and then GC will probably take care of the rest. If your objects have a Dispose() method you may want to call that as well (before releasing). Commented Sep 26, 2013 at 13:40

2 Answers 2

12

Usually I use this function:

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 )

(see here) return the new value of the reference count of the RCW associated with object. This value is typically zero since the RCW keeps just one reference to the wrapped COM object regardless of the number of managed clients calling it. I've noted that for shell.application you need to call it until this value becomes 0.

To test if all references are released you can try, when value is 0, to read the value of $shell: it returns an error..

Sign up to request clarification or add additional context in comments.

10 Comments

Is there a way to "monitor" if my objects are properly cleared?
Usually I work with office automation and I just look to the relative process (ie excel.exe) if is no longer present but with shell.application I've some doubt it works...
I believe the ReleaseComObject is the key. I also believe the two other lines are not mandatory. With C#, I've always read it's better to let the GC work when it decides. I'll keep this advise in PS.
@SteveB I've added some new info.
I've seen the 0 value, and it was always 0. I guess it's because I create the object locally in my function, and thus, control the short life of the object.
|
0

The GC works on .NET objects and not .NET wrapped COM objects. You need to explicitly clean-up the underlaying COM object.

1 Comment

Incorrect. The GC also works on .NET wrapped COM objects. When the GC detects that a .NET COM object is no longer referenced by anything else, then it cleans up the object. Part of that cleanup is to call Release on the underlying interface. So, if a .NET object is no longer referencing a COM object, it will be cleaned up. However, IMHO, .NET and COM do not play well together. It generally is easier to manually call ReleaseComObject than it is to wait for the GC to do its business.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.