无法删除变量,因为它已被优化且不可删除 - 释放 COM 对象
Cannot remove variable because it has been optimized and is not removable - releasing a COM object
在我的脚本末尾,我使用 'ie' | ForEach-Object {Remove-Variable $_ -Force}
。它在 PS 2 (Windows 7) 中工作正常,但 PS 5 (Windows 10) 会引发错误:
Cannot remove variable ie because the variable has been optimized and
is not removable. Try using the Remove-Variable cmdlet (without any
aliases), or dot-sourcing the command that you are using to remove the
variable.
我怎样才能使它与 PS 5 配合得很好?或者我应该只使用 Remove-Variable 'ie' -Force
?
删除 COM 对象的推荐方法是调用 ReleaseComObject 方法,将对象引用 ($ie) 传递给 COM 对象的实例。
下面是来自 Windows PowerShell Tip of the Week 的更详细的解释和示例代码,展示了如何摆脱 COM 对象:
Whenever you call a COM object from the common language runtime (which
happens to be the very thing you do when you call a COM object from
Windows PowerShell), that COM object is wrapped in a “runtime callable
wrapper,” and a reference count is incremented; that reference count
helps the CLR (common language runtime) keep track of which COM
objects are running, as well as how many COM objects are running. When
you start Excel from within Windows PowerShell, Excel gets packaged up
in a runtime callable wrapper, and the reference count is incremented
to 1.
That’s fine, except for one thing: when you call the Quit method and
terminate Excel, the CLR’s reference count does not get decremented
(that is, it doesn’t get reset back to 0). And because the reference
count is not 0, the CLR maintains its hold on the COM object: among
other things, that means that our object reference ($x) is still valid
and that the Excel.exe process continues to run. And that’s definitely
not a good thing; after all, if we wanted Excel to keep running we
probably wouldn’t have called the Quit method in the first place. ...
... calling the ReleaseComObject method [with] our
instance of Excel ... decrements the reference count for the object in
question. In this case, that means it’s going to change the reference
count for our instance of Excel from 1 to 0. And that is a good thing:
once the reference count reaches 0 the CLR releases its hold on the
object and the process terminates. (And this time it really does
terminate.)
$x = New-Object -com Excel.Application
$x.Visible = $True
Start-Sleep 5
$x.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($x)
Remove-Variable x
您收到的消息 "Cannot remove variable ie because the variable has been optimized and is not removable." 很可能意味着您已尝试访问(检查、观察或以其他方式访问)已被优化器删除的变量。
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-Object
与Remove-Variable
一起使用,因为你不仅可以直接传递一个变量名,但即使是(隐含的)-Name
参数的 数组 名称 - 参见 Remove-Variable -?
;
Remove-Variable ie -Force
应该可以。
通常,请注意 -Force
只需要删除 只读 变量;如果您想(也)防止指定名称的变量不存在 存在 的情况,(也)使用
-ErrorAction Ignore
。
在我的脚本末尾,我使用 'ie' | ForEach-Object {Remove-Variable $_ -Force}
。它在 PS 2 (Windows 7) 中工作正常,但 PS 5 (Windows 10) 会引发错误:
Cannot remove variable ie because the variable has been optimized and is not removable. Try using the Remove-Variable cmdlet (without any aliases), or dot-sourcing the command that you are using to remove the variable.
我怎样才能使它与 PS 5 配合得很好?或者我应该只使用 Remove-Variable 'ie' -Force
?
删除 COM 对象的推荐方法是调用 ReleaseComObject 方法,将对象引用 ($ie) 传递给 COM 对象的实例。
下面是来自 Windows PowerShell Tip of the Week 的更详细的解释和示例代码,展示了如何摆脱 COM 对象:
Whenever you call a COM object from the common language runtime (which happens to be the very thing you do when you call a COM object from Windows PowerShell), that COM object is wrapped in a “runtime callable wrapper,” and a reference count is incremented; that reference count helps the CLR (common language runtime) keep track of which COM objects are running, as well as how many COM objects are running. When you start Excel from within Windows PowerShell, Excel gets packaged up in a runtime callable wrapper, and the reference count is incremented to 1.
That’s fine, except for one thing: when you call the Quit method and terminate Excel, the CLR’s reference count does not get decremented (that is, it doesn’t get reset back to 0). And because the reference count is not 0, the CLR maintains its hold on the COM object: among other things, that means that our object reference ($x) is still valid and that the Excel.exe process continues to run. And that’s definitely not a good thing; after all, if we wanted Excel to keep running we probably wouldn’t have called the Quit method in the first place. ...
... calling the ReleaseComObject method [with] our instance of Excel ... decrements the reference count for the object in question. In this case, that means it’s going to change the reference count for our instance of Excel from 1 to 0. And that is a good thing: once the reference count reaches 0 the CLR releases its hold on the object and the process terminates. (And this time it really does terminate.)
$x = New-Object -com Excel.Application $x.Visible = $True Start-Sleep 5 $x.Quit() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($x) Remove-Variable x
您收到的消息 "Cannot remove variable ie because the variable has been optimized and is not removable." 很可能意味着您已尝试访问(检查、观察或以其他方式访问)已被优化器删除的变量。
wp78de's helpful answer 解释了您需要做什么才能有效地 释放使用 New-Object -ComObject
.
释放底层 COM 对象(这意味着终止 COM 自动化服务器(如 Internet Explorer)的进程)是最重要的,但值得指出的是:
即使不先调用
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ie)
,您的Remove-Variable
调用也没有理由失败(尽管如果成功,它本身不会释放 COM 对象).- 我无法解释您看到的错误(我无法重现它,但它可能与 this bug 有关)。
通常没有充分的理由将
ForEach-Object
与Remove-Variable
一起使用,因为你不仅可以直接传递一个变量名,但即使是(隐含的)-Name
参数的 数组 名称 - 参见Remove-Variable -?
;
Remove-Variable ie -Force
应该可以。通常,请注意
-Force
只需要删除 只读 变量;如果您想(也)防止指定名称的变量不存在 存在 的情况,(也)使用
-ErrorAction Ignore
。