无法删除变量,因为它已经过优化且无法移除 - 释放COM对象

时间:2017-09-17 21:30:39

标签: powershell com

在我的脚本结束时,我使用'ie' | ForEach-Object {Remove-Variable $_ -Force}。它在PS 2(Windows 7)中运行良好,但PS 5(Windows 10)引发错误:

  

无法删除变量,即因为变量已经过优化而且   是不可拆卸的。尝试使用Remove-Variable cmdlet(不带任何内容)   别名),或者点源你用来删除的命令   变量

如何让它与PS 5一起玩得很好;或者我应该使用Remove-Variable 'ie' -Force

2 个答案:

答案 0 :(得分:5)

删除COM对象的推荐方法是调用ReleaseComObject方法,将对象引用($ ie)传递给COM对象的实例。

以下是Windows PowerShell Tip of the Week中更详细的说明和示例代码,演示了如何摆脱COM对象:

  

每当从公共语言运行库调用COM对象时(   恰好是你从中调用COM对象时所做的事情   Windows PowerShell),该COM对象包装在“运行时可调用   包装器,“并且引用计数递增;那个引用计数   帮助CLR(公共语言运行库)跟踪哪个COM   对象正在运行,以及正在运行的COM对象数。什么时候   从Windows PowerShell中启动Excel,Excel打包   在运行时可调用包装器中,引用计数递增   到1。

     

这很好,除了一件事:当你调用Quit方法时   终止Excel,CLR的引用计数不会减少   (也就是说,它不会重置为0)。而且因为参考   count不为0,CLR保持对COM对象的保持:其中   其他的东西,这意味着我们的对象引用($ x)仍然有效   并且Excel.exe进程继续运行。这绝对是   不是一件好事;毕竟,如果我们希望Excel继续运行我们   可能不会首先调用Quit方法。 ......

     

...调用ReleaseComObject方法[with]我们的   Excel的实例...减少对象的引用计数   题。在这种情况下,这意味着它将改变参考   从1到0计算我们的Excel实例。这是一件好事:   一旦引用计数达到0,CLR就会释放它   对象和进程终止。 (而这一次确实如此   终止。)

$x = New-Object -com Excel.Application
$x.Visible = $True
Start-Sleep 5
$x.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($x)
Remove-Variable x

消息“无法删除变量,即因为变量已经过优化且无法移除。”你得到的,很可能意味着你已经尝试访问(检查,观察或以其他方式访问)已被优化器删除的变量。

答案 1 :(得分:2)

wp78de's helpful answer解释了您需要做什么才能有效地发布使用New-Object -ComObject在PowerShell代码中实例化的COM对象。

释放底层COM对象(这意味着终止COM自动化服务器(如Internet Explorer)的进程)是最重要的,但值得指出:

  • 即使没有先调用[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ie),也没有理由要求Remove-Variable调用失败(即使成功,它本身也不会释放COM对象)。

    • 我没有解释您所看到的错误(我无法重新创建它,但它可能与this bug有关。)
  • 通常没有充分理由将ForEach-ObjectRemove-Variable一起使用,因为您不仅可以直接传递一个变量名,还可以传递数组(隐含)-Name参数的名称 - 请参阅Remove-Variable -?;
    Remove-Variable ie -Force应该有用。

  • 一般情况下,请注意只需要移除只读变量-Force;如果你想(也)防止指定名称的变量不存在的情况,(也)使用
    -ErrorAction Ignore