This may have something to do with Internet Explorer 'protected mode'.
If IE indeed is in protected mode, the $IE object gets lost after the .Navigate() command and any action after that will result in the error You cannot call a method on a null-valued expression.
To handle this, here's a function that tries to reconnect the $IE object.
function Connect-InternetExplorer {
# creates a new 'InternetExplorer.Application' object and navigates to the given url.
# If IE is in 'protected mode', the function tries to reconnect using the window handle
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, Position = 0)]
$Url,
[switch]$Visible
)
# test if Internet Explorer is in 'Protected Mode'
# see https://www.lifewire.com/how-to-disable-protected-mode-in-internet-explorer-2624507
$ieProtectedMode = ((Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3' -Name '2500').2500 -ne 3)
$ie = New-Object -ComObject 'InternetExplorer.Application' -ErrorAction SilentlyContinue
$ie.Visible = [bool]$Visible
$ie.Silent = $true
$hwnd = $ie.Hwnd
$ie.Navigate($Url)
if ($ieProtectedMode) {
$oldErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
$objShell = New-Object -ComObject 'Shell.Application'
Start-Sleep -Milliseconds 100
try {
$ie = $objShell.Windows() | Where-Object {$_.HWND -eq $Hwnd}
$ie.Visible = [bool]$Visible
}
catch {
# sometimes the Shell.Application does not find the window quickly enough,
Start-Sleep -Milliseconds 500
try {
$ie = $objShell.Windows() | Where-Object {$_.HWND -eq $Hwnd}
$ie.Visible = [bool]$Visible
}
catch {
Write-Warning "Could not connect to the InternetExplorer ComObject."
}
}
finally {
$ErrorActionPreference = $oldErrorActionPreference
# clean up the Com object
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($objShell) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
}
if (!$ie) { return $null }
while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 50 }
return $ie
}
# this replaces the first three lines of your original code
$IE = Connect-InternetExplorer -Url $URL
if ($IE) {
$IE.Document.ParentWindow.ExecScript("var JSIEVariable = new XMLSerializer().serializeToString(document);", "javascript")
$Obj = $IE.Document.ParentWindow.GetType().InvokeMember("JSIEVariable", 4096, $Null, $IE.Document.parentWindow, $Null)
$HTML = $Obj.ToString()
$IE.Quit()
# clean up the $IE Com object
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($IE) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
else {
Write-Warning "Could not connect Internet Explorer"
}
Hope that helps