在 Windows 服务器上的 Internet Explorer 中使用 PowerShell 运行 Javascript
Using PowerShell to run Javascript in Internet Explorer on Windows Server
我有一段 PowerShell 脚本:
$IE = New-Object -com InternetExplorer.Application
$IE.Navigate($URL)
While ($IE.ReadyState -Ne 4) {Start-Sleep -Milliseconds 100}
$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()
在 Windows 10 上它工作正常但在 Windows Server 2016 上第 4、5 和 6 行我收到错误:
You cannot call a method on a null-valued expression.
我很确定它与 Windows 服务器中的额外安全性有关,阻止 IE 运行ning Javascript。必须有某种方法可以降低安全性,使其与 Windows 10 更加一致,这样该脚本才能正确地 运行,但我不知道如何实现。我关闭了 IE 增强安全配置并确保启用了活动脚本。除此之外我不知道还能做什么。
这可能与 Internet Explorer 有关 'protected mode'。
如果 IE 确实处于保护模式,$IE
对象在 .Navigate()
命令之后丢失,之后的任何操作都会导致错误 You cannot call a method on a null-valued expression.
为了解决这个问题,这里有一个尝试重新连接 $IE 对象的函数。
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' -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"
}
希望对您有所帮助
一位同事帮我解决了这个问题。它与 IE 安全没有任何关系,至少与尚未涵盖的任何内容无关。问题是 GAC 中缺少 'Microsoft.mshtml.dll'。它不会出现在 Windows 服务器的全新安装中,但安装 Office 或 Visual Studio 之类的东西会添加它。但是,我敢打赌,大多数人 运行 一个 Windows 服务器不会仅仅为了让它正常工作而这样做。我所做的是将以下 folder/file 结构从我的 Windows 10 PC 复制到我的服务器,关闭 PowerShell 和 ISE 的所有实例,当我再次打开 PowerShell 时 运行 脚本一切正常.
C:\Windows\assembly\GAC\Microsoft.mshtml
C:\Windows\assembly\GAC\Microsoft.mshtml.0.3300.0__b03f5f7f11d50a3a
C:\Windows\assembly\GAC\Microsoft.mshtml.0.3300.0__b03f5f7f11d50a3a\Microsoft.mshtml.dll
C:\Windows\assembly\GAC\Microsoft.mshtml.0.3300.0__b03f5f7f11d50a3a__AssemblyInfo__.ini
我有一段 PowerShell 脚本:
$IE = New-Object -com InternetExplorer.Application
$IE.Navigate($URL)
While ($IE.ReadyState -Ne 4) {Start-Sleep -Milliseconds 100}
$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()
在 Windows 10 上它工作正常但在 Windows Server 2016 上第 4、5 和 6 行我收到错误:
You cannot call a method on a null-valued expression.
我很确定它与 Windows 服务器中的额外安全性有关,阻止 IE 运行ning Javascript。必须有某种方法可以降低安全性,使其与 Windows 10 更加一致,这样该脚本才能正确地 运行,但我不知道如何实现。我关闭了 IE 增强安全配置并确保启用了活动脚本。除此之外我不知道还能做什么。
这可能与 Internet Explorer 有关 'protected mode'。
如果 IE 确实处于保护模式,$IE
对象在 .Navigate()
命令之后丢失,之后的任何操作都会导致错误 You cannot call a method on a null-valued expression.
为了解决这个问题,这里有一个尝试重新连接 $IE 对象的函数。
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' -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"
}
希望对您有所帮助
一位同事帮我解决了这个问题。它与 IE 安全没有任何关系,至少与尚未涵盖的任何内容无关。问题是 GAC 中缺少 'Microsoft.mshtml.dll'。它不会出现在 Windows 服务器的全新安装中,但安装 Office 或 Visual Studio 之类的东西会添加它。但是,我敢打赌,大多数人 运行 一个 Windows 服务器不会仅仅为了让它正常工作而这样做。我所做的是将以下 folder/file 结构从我的 Windows 10 PC 复制到我的服务器,关闭 PowerShell 和 ISE 的所有实例,当我再次打开 PowerShell 时 运行 脚本一切正常.
C:\Windows\assembly\GAC\Microsoft.mshtml C:\Windows\assembly\GAC\Microsoft.mshtml.0.3300.0__b03f5f7f11d50a3a C:\Windows\assembly\GAC\Microsoft.mshtml.0.3300.0__b03f5f7f11d50a3a\Microsoft.mshtml.dll C:\Windows\assembly\GAC\Microsoft.mshtml.0.3300.0__b03f5f7f11d50a3a__AssemblyInfo__.ini