4

I have a PowerShell script that navigates to a (presumably) classic ASP page on our intranet to stop a Windows Service running on our server as part of the deployment process for that service (and restarts it after deploying the new files). It ran fine until we recently upgraded to IE9. Here's the script.

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

Now when I run the script, it successfully launches IE, but throws the following error:

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

When I investigate in PowerShell, I find that if I create the IE ComObject, it at first has valid properties, but as soon as I navigate to the the service control page, all the properties are null (almost as if the ComObject gone away?). For example, before the HWND property had a valid value, but now it's null ($ie.hwnd -eq $null returns true). No error is displayed in PowerShell when I navigate to the page.

I looked at some similar questions, but the first one doesn't match my circumstance (the Document property is null in my case) and as for the latter one, IE9 defaults to compatibility mode for intranet sites. I saved the ASP page and ran it through the w3c validator and it threw some errors (although none related to the elements I'm trying to deal with). Unfortunately I can't fix those. Other sites don't seem to have this problem. Any suspicions on what the problem may be and recommendations on work-arounds?

Community
  • 1
  • 1
Jeff B
  • 8,572
  • 17
  • 61
  • 140

2 Answers2

11

I just worked through this.. sort of. I was seeing the same behavior until I turned off protected mode in IE. This seems to have something to do with submitting from one security zone to the next. So.. assuming that your original page is in the internet zone, with protected mode on, you submit to a page in a trusted zone or intranet or whatever, it seems like the COM context is lost. Probably intentional. I'm going to try fixing the zones, and keeping protected mode on.

Hope this helps.

EDIT: This is also a non-issue if you run your powershell in elevated mode (run as admin)

Nick
  • 126
  • 2
  • 4
  • Wow, that's exactly it! Turning of protected mode for the Internet zone under the Security tab in setting did the trick. However, since I'll have this script in a repository for other people I might have to go with the admin trick. Thanks! – Jeff B Feb 22 '13 at 15:43
  • @JeffBridgman, you might also be able to put the desired site in a different, trusted zone. – Wayne Werner Feb 22 '13 at 15:50
  • But only for me, not for others, eh? The site is in my intranet zone which already has Protected Mode turned off. It looks like IE starts off in the Internet Zone with Protected Mode turned on. I tried setting my homepage to something in the Intranet zone, but oddly enough the script still failed. – Jeff B Feb 22 '13 at 15:55
  • Wow, you saved my life! I thought I had an error in my code, but it was excactly this solution which helped! Thank you sir :) – Manuel Allenspach Dec 16 '13 at 09:08
9

In addition: http://msdn.microsoft.com/en-us/library/bb625962.aspx

This problem is caused by integrity levels since Internet Explorer 8. That is also the reason, why the application runs well as administrator.

Since IE-8 runs in "low integrity" mode, it is not possible to automate IE from within a script. This is because the script runs as an user which belongs to "medium integrity" mode. The security design is such that it can send instructions from medium to low integrity, but can not receive data from low to medium integrity.

Update: Here is a working example how to do it without changing any settings. It gets back the lost com-Object.

 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
  • 269
  • 6
  • 16
  • I have updated my answer with my workaround for this problem. – bnu Jun 26 '15 at 06:14
  • Tried this but it doesn't find the process. Also, the new process has a different HWND so I don't see how this can find the correct process. – Mrchief Jun 30 '15 at 16:08
  • Hmm, for me this works well. Which IE-Version do you have? I have retested it with the code above. when I print out `$objIE` after the Script I get the right Object. – bnu Jul 01 '15 at 09:14