Использование PowerShell для запуска Javascript в Internet Explorer на Windows Server - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть этот фрагмент скрипта 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 я получаю сообщение об ошибке:

Вы не можете вызывать метод для выражения с нулевым значением.

Я почти уверен, что это как-то связано с дополнительной безопасностью в Windows Server, не позволяющей IE запускать Javascript.Должен быть какой-то способ вернуть эту защиту на уровень Windows 10, чтобы этот сценарий мог работать правильно, но я не могу понять, как это сделать.Я отключил IE Enhanced Security Configuration и убедился, что Active Scripting включен.Кроме того, я не знаю, что еще делать.

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Коллега помог мне понять это.Это не имеет ничего общего с безопасностью IE, по крайней мере, не настолько, как то, что еще не было рассмотрено.Проблема в том, что в GAC отсутствует Microsoft.mshtml.dll.Он не будет присутствовать при чистой установке Windows Server, но установка чего-то вроде Office или Visual Studio добавит его.Тем не менее, я бы поспорил, что большинство людей, работающих под управлением Windows Server, не захотят делать это только ради того, чтобы это работало.Я скопировал следующую структуру папок / файлов со своего компьютера с Windows 10 на свой сервер, закрыл все экземпляры PowerShell и ISE, а когда я снова открыл PowerShell и запустил скрипт, все заработало.

C: \Windows \ Assembly \ GAC \ Microsoft.mshtml C: \ Windows \ Assembly \ GAC \ Microsoft.mshtml \ 7.0.3300.0__b03f5f7f11d50a3a C: \ Windows \ Assembly \ GAC \ Microsoft.mshtml \ 7.0.3300.0__b03f5f7f11d50a3a \ Microsoft.mshtml.dll C: \ Windows \ Assembly \ GAC \ Microsoft.mshtml \ 7.0.3300.0__b03f5f7f11d50a3a__AssemblyInfo __ INI

.
0 голосов
/ 28 ноября 2018

Это может быть как-то связано с «защищенным режимом» Internet Explorer.Если 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\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"
}

Надеюсь, это поможет

...