【问题标题】:Dispose of COM Objects in Powershell Script在 Powershell 脚本中处理 COM 对象
【发布时间】:2020-09-30 07:17:58
【问题描述】:

我有一个运行 Powershell 脚本的计划任务。此 Powershell 脚本发送 HTTP 请求并搜索返回的 HTML。由于这个脚本,我留下了一堆没有关闭的 dllhost 进程。如果我理解正确,这是 COM 对象的结果。

与 COM 对象相关的唯一变量是:

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

当我运行$specifiedDiv.GetType() 时,结果如下:

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

我的问题是如何关闭此对象或阻止脚本创建 dllhost 进程?

编辑:

    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)
        }

我尝试了上述方法,但仍然得到 dllhost 进程。

【问题讨论】:

    标签: powershell com httprequest dllhost


    【解决方案1】:

    嗯,比这更复杂。有

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

    这可能行得通……但是,.NET 处理 COM 对象的方式,您可能会在各处创建大量中间 COM 对象。如$request、$request.ParsedHtml、$request.ParsedHtml.Body。然后可能会在调用 $_.getAttributeNode('class') 时创建一大堆其他 COM 对象。

    $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)
    

    【讨论】:

    • 那么我是否必须遍历变量的所有属性并释放 com 对象?
    • 好吧,当我遇到 COM/.NET 引用计数问题时,我在 C# 代码中做什么...我创建了中间对象。像 $parsedHtml = $request.ParsedHtml、$body = $parsedHtml.Body 等。然后,完成后,对所有单个对象调用 ReleaseComObject。你可以设置 $request = $null,然后调用垃圾回收函数。
    • 我创建了中间对象,但我仍然不断获得 dllhost 进程。查看编辑
    • 您还在 where {} 子句中创建临时对象。将需要编写为更具体的 foreach 循环。因此,foreach ($div in $divs) { } 在循环内的每个 $div 上调用 ReleaseComObject,当然,当您找到 $specifiedDiv 时除外。您在 getAttributeNode 上还有一个临时对象,因此您需要一个临时 $classAttribute。如果您可以封装并在完成后调用 [System.GC]::Collect(),那么这也可能解决您的问题。
    • 类似$classAttribute = $divs | Where-Object{$_.getAttributeNode('class')}
    猜你喜欢
    • 2016-09-05
    • 2014-03-18
    • 2019-06-16
    • 2011-07-25
    • 2011-08-13
    • 2023-03-18
    • 2013-07-30
    • 1970-01-01
    • 2016-06-19
    相关资源
    最近更新 更多