PowerShell IE9 ComObject在导航到网页后所有属性都为null。

4

我有一个PowerShell脚本,它可以导航到我们企业内网上的(可能是)经典ASP页面,以在服务部署过程中停止运行在我们服务器上的Windows服务(并在部署新文件后重新启动它)。在我们最近升级到IE9之前,这个脚本一直很好用。以下是脚本。

# Open service page in IE
$ie = new-object -comobject InternetExplorer.Application
$ie.visible = $true
$ie.navigate($serviceUrl)
while($ie.busy) { start-sleep 1 }

# Stop service
$ie.Document.getElementById("dropDownActionList").value = "Stop"
$ie.Document.getElementById("buttonTakeAction").click()
while($ie.busy) { start-sleep 1 }

现在当我运行脚本时,它成功启动了IE浏览器,但是抛出了以下错误:
You cannot call a method on a null-valued expression.
At C:\Projects\ABC\Scripts\Deploy.ps1:85 char:28
+ $ie.Document.getElementById <<<< ("dropDownActionList").value = "Stop"
    + CategoryInfo          : InvalidOperation: (getElementById:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

当我在PowerShell中进行调查时,我发现如果我创建IE ComObject,则它的属性一开始是有效的,但是一旦我导航到服务控制页面,所有属性都为null(几乎就像ComObject消失了?)。例如,在 HWND 属性具有有效值之前,但现在为null( $ie.hwnd -eq $null 返回true)。在导航到页面时,PowerShell没有显示任何错误。
我查看了一些类似的问题,但第一个与我的情况不符(在我的情况下,文档属性为空),至于后者,IE9默认将内部网站设置为兼容模式。 我保存了ASP页面,并通过W3C验证器运行它,它会抛出一些错误(尽管没有与我正在处理的元素相关的错误)。不幸的是,我无法解决这些问题。其他网站似乎没有这个问题。关于可能的问题和解决方法,有什么疑虑吗?
2个回答

11

我刚刚研究了这个问题...差不多吧。在关闭IE的保护模式之前,我看到了相同的行为。这似乎与从一个安全区域提交到另一个安全区域有关。所以..假设您的原始页面在Internet区域中,在保护模式下,您提交到可信区域、Intranet或其他页面,似乎会丢失COM上下文。可能是有意为之。我将尝试修复区域,并保持保护模式。

希望这可以帮助你。

编辑:如果以提升模式运行powershell(以管理员身份运行),这也不是问题。


哇,就是这样!在设置的安全选项卡下,关闭Internet区域的保护模式就解决了问题。然而,由于我将在存储库中为其他人提供此脚本,我可能需要使用管理员技巧。谢谢! - Jeff B
@JeffBridgman,您也可以将所需的网站放入不同的受信任区域。 - Wayne Werner
但只有对我有效,对其他人无效,是吗?该网站位于我的内部网络区域,已关闭了受保护模式。看起来IE在Internet区域中启动时默认开启了受保护模式。我尝试将我的主页设置为内部网络区域中的某个内容,但奇怪的是脚本仍然失败了。 - Jeff B
哇,你救了我的命!我以为我的代码出错了,但正是这个解决方案帮了我!谢谢您先生 :) - Manuel Allenspach

9
此外: http://msdn.microsoft.com/en-us/library/bb625962.aspx 从Internet Explorer 8开始,此问题由完整性级别引起。这也是为什么应用程序以管理员身份运行良好的原因。
由于IE-8运行在“低完整性”模式下,因此无法从脚本中自动化IE。这是因为脚本作为属于“中等完整性”模式的用户运行。安全设计是这样的,它可以从中等到低完整性发送指令,但无法从低到中等完整性接收数据。
更新:这里有一个可行的例子,无需更改任何设置即可找回失去的Com对象。
 function ConnectIExplorer() {
    param($HWND)

    $objShellApp = New-Object -ComObject Shell.Application 
    try {
      $EA = $ErrorActionPreference; $ErrorActionPreference = 'Stop'
      $objNewIE = $objShellApp.Windows() | ?{$_.HWND -eq $HWND}
      $objNewIE.Visible = $true
    } catch {
      #it may happen, that the Shell.Application does not find the window in a timely-manner, therefore quick-sleep and try again
      Write-Host "Waiting for page to be loaded ..." 
      Start-Sleep -Milliseconds 500
      try {
        $objNewIE = $objShellApp.Windows() | ?{$_.HWND -eq $HWND}
        $objNewIE.Visible = $true
      } catch {
        Write-Host "Could not retreive the -com Object InternetExplorer. Aborting." -ForegroundColor Red
        $objNewIE = $null
      }     
    } finally { 
      $ErrorActionPreference = $EA
      $objShellApp = $null
    }
    return $objNewIE
  } 




$HWND = ($objIE = New-Object -ComObject InternetExplorer.Application).HWND
$objIE.Navigate("https://www.google.com")
$objIE = ConnectIExplorer -HWND $HWND

我已经更新了我的答案,并提供了解决此问题的方法。 - bnu
尝试过这个,但它找不到进程。此外,新进程具有不同的HWND,因此我不知道如何找到正确的进程。 - Mrchief
嗯,对我来说这很有效。你用的是哪个IE版本?我已经用上面的代码重新测试过了。当我在脚本后打印出$objIE时,我得到了正确的对象。 - bnu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接