6

在过去的 6 个月里,我一直在运行密码过期脚本,没有任何问题。该脚本将读取静态 html 文件并更改内存中的一些内容,然后将 html 电子邮件发送给所有密码到期的用户。

剧本似乎在过去一周左右就坏了。经过进一步调查,我已将错误范围缩小到 Powershell 应该创建新 ComObject 并将该 HTML 文件写入 ComObject 的部分。

我现在得到错误:

No coercion operator is defined between types 'System.Array' and 'System.String'
At line:1 char:1
+ $html.write($source);
+ ~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], InvalidOperationException
    + FullyQualifiedErrorId : System.InvalidOperationException

当我运行以下代码行时会发生上述错误:

$html = New-Object -ComObject "HTMLFile"
$src = Get-Content -path "./passwordreminder.html" -Raw
$html.write($src)

当我调用该write()方法时,我得到了错误。

自从过去 6 个月一直运行良好以来,我能想到的唯一改变的是我的 powershell 版本。我相信当我开始运行这个脚本时,我使用的是 Powershell v4.0,但在 Windows 更新之后,我猜 Powershell 现在是 v5.0。见下文 :

Name                           Value
----                           -----
PSVersion                      5.0.10105.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.34209
BuildVersion                   10.0.10105.0
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3

该脚本在 Windows Server 2012 R2 操作系统上运行。

有人有想法么?

我在其他问题中看到了一些建议,要求IHTMLDocument2_write()在 ComObject 上使用该方法,但是当我尝试调用它时该方法不存在。

更新 :

我能够确认这在我的 Powershell 版本中确实被破坏了。

我只能在具有相同操作系统但低于 Powershell 版本的不同服务器上测试相同的代码:

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.34014
BuildVersion                   6.3.9600.17090
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2

并且代码按预期工作。

有人知道这个新版本的 Powershell 可以使用什么吗?

4

4 回答 4

5

如果您提供 UCS-2 字节数组而不是字符串,这似乎可以正常工作:

$html = New-Object -ComObject "HTMLFile"
$src = Get-Content -path "./passwordreminder.html" -Raw
$src = [System.Text.Encoding]::Unicode.GetBytes($src)
try
{
    # This works in PowerShell 4
    $html.IHTMLDocument2_write($src)
}
catch
{
    # This works in PowerShell 5
    $html.write($src)
}
于 2016-05-22T22:39:51.997 回答
2

您可以尝试使用 Internet Explorer COM 对象:

$ie = New-Object -COM 'InternetExplorer.Application'

$ie.Navigate("file://$($PWD.Path)/passwordreminder.html")
do {
  Start-Sleep -Milliseconds 100
} until ($ie.ReadyState -eq 4)

# do stuff

不过,我没有 PowerShell v5,所以无法测试。如果 HTMLFile 被破坏,这可能也是如此。

如果需要重复运行,可以在外部循环中调用该Navigate()方法(以及等待它完成页面加载的循环)。

$ie = New-Object -COM 'InternetExplorer.Application'

foreach (...) {
  $ie.Navigate("file://$($PWD.Path)/passwordreminder.html")
  do {
    Start-Sleep -Milliseconds 100
  } until ($ie.ReadyState -eq 4)

  # do stuff
}
于 2015-06-20T21:17:24.190 回答
2

此代码片段通过Add-Type -AssemblyName cmdlet 添加 .NET Framework 的mshtml.HTMLDocumentClass类型来工作。

Add-Type -AssemblyName "Microsoft.mshtml"
$html = New-Object -ComObject "HTMLFile"
$svc = Get-Service | Select-Object Name, Status | ConvertTo-Html
$svc | Out-File -FilePath .\report.html -Force
$htmlFile = Get-Content -Path .\report.html -Raw
$html.IHTMLDocument2_write($htmlFile)

$html 变量包含“HTMLFile”对象引用及其所有方法和属性。

于 2018-08-03T21:01:33.060 回答
0

通过添加路径引用并指定对象类型来解决

Add-Type -Path "C:\Program Files (x86)\Microsoft.NET\Primary Interop Assemblies\Microsoft.mshtml.dll"

$webpage = New-Object mshtml.HTMLDocumentClass

这是完整的代码

$url = 'http://website'
$outFile = 'C:\content.txt'
$showCount = 10;

[net.httpwebrequest]$httpwebrequest = [net.webrequest]::create($url)
[net.httpWebResponse]$httpwebresponse = $httpwebrequest.getResponse()
$reader = new-object IO.StreamReader($httpwebresponse.getResponseStream())
$html = $reader.ReadToEnd()
$reader.Close()

Add-Type -Path "C:\Program Files (x86)\Microsoft.NET\Primary Interop Assemblies\Microsoft.mshtml.dll"


$webpage = New-Object mshtml.HTMLDocumentClass
$webpage.IHTMLDocument2_write($html)

$topicElements = $webpage.documentElement.getElementsByClassName('topic')

$time = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
$content = '[www.hkgalden.com] [' + $time + '] '

$i = 0;
foreach ($topicElement in $topicElements) {
    $titleElement = $topicElement.getElementsByClassName('title')[0].getElementsByTagName('a')[0]
    $title = $titleElement.innerText

    $usernameElement = $topicElement.getElementsByClassName('username')[0]
    $username = $usernameElement.innerText

    $content += $username + ': ' + $title + ' // '
    $i++
    if ($i -gt $showCount) {
        break
    }
}
#$content
$content | Out-File -Encoding utf8 $outFile
于 2016-04-24T05:23:31.030 回答