2

I have a scheduled task that runs a Powershell script. This Powershell script sends a HTTP request and searches through the returned HTML. As a result of this script, I am left with a bunch of dllhost processes that don't close. If I understand right, this is a result of COM objects.

The only variable related to COM objects is this:

$specifiedDiv = $request.ParsedHtml.Body.getElementsByTagName('div') |
    Where-Object{$_.getAttributeNode('class').Value -eq 'results'}

When I run $specifiedDiv.GetType(), I get this as the result:

IsPublic IsSerial Name                                     BaseType                                                                                                                                                              
-------- -------- ----                                     --------                                                                                                                                                              
True     False    __ComObject                              System.MarshalByRefObject 

My question is how can I close this object or prevent the script from creating the dllhost processes?

Edit:

    Function garbageCollect ([object]$ref){

            ([System.Runtime.Interopservices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0)
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()
        }
$parsedHtml = $request.ParsedHtml
$body = $parsedHtml.Body
$divs = $body.getElementsByTagName('div')


$classAttribute = $divs | Where-Object{$_.getAttributeNode('class').Value -eq 'results-found'}

        Remove-Variable -Name classAttribute
        Remove-Variable -Name parsedHtml
        Remove-Variable -Name body
        Remove-Variable -Name divs

        garbageCollect($parsedHtml)
        garbageCollect($body)

        foreach($div in $divs)
        {
            garbageCollect($div)
        }
        foreach($thing in $classAttribute)
        {
            garbageCollect($div)
        }

I tried the above but I still get the dllhost process.

1 Answer 1

2

Well, it's more complicated than that. There is

[System.Runtime.InteropServices.Marshal]::ReleaseComobject($specifiedDiv)

That might work... however, the way .NET works with COM objects, you might have a bunch of intermediate COM objects getting created all over the place. Such as $request, $request.ParsedHtml, $request.ParsedHtml.Body. Then there might be a whole bunch of other COM objects created in calls to $_.getAttributeNode('class').

$parsedHtml = $request.ParsedHtml
$body = $parsedHtml.Body
$divs = $body.getElementsByTagName('div')

foreach ($div in $divs)
{
   $attrNode = $div.getAttributeNode('class')
   
   if ($attrNode.Value -eq 'results')
   {
      $specificDiv = $attrNode
      break
   }
   else
   {
      [System.Runtime.Interopservices.Marshal]::ReleaseComObject($div)
   }
}

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($divs)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($body)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($parsedHtml)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($request)
### what is this ??? [System.Runtime.Interopservices.Marshal]::ReleaseComObject($requestHome)


#### Do something with $specificDiv if you want...however, you might create more COM objects...


[System.Runtime.Interopservices.Marshal]::ReleaseComObject($specifiedDiv)
Sign up to request clarification or add additional context in comments.

6 Comments

So would I have to iterate through all the properties of the variable and release the com objects?
Well, what I do in C# code when I have COM/.NET reference counting issues... I create intermediate objects. Like $parsedHtml = $request.ParsedHtml, $body = $parsedHtml.Body, etc. Then, when done, call ReleaseComObject on all the individual objects. You might get away with setting $request = $null, and then calling the garbage collection functions.
I created the intermediate objects and I still keep getting the dllhost process. See the edit
You're also creating temporary objects in the where {} clause. Will need to write as a more specific foreach loop. So, foreach ($div in $divs) { } Call ReleaseComObject on every $div inside the loop except of course when you find your $specifiedDiv. You are also having a temporary object on the getAttributeNode, so you will need a temporary $classAttribute. If you can encapsulate and instead call [System.GC]::Collect() when you're done, then that might solve your problems as well.
Something like $classAttribute = $divs | Where-Object{$_.getAttributeNode('class')}
|

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.