首先,我为这篇冗长冗长的帖子道歉。这是一个有趣的问题,我想尽可能详细。我已尝试浏览该站点上的任何相关 PowerShell 帖子,但找不到任何可以帮助我解决此问题的内容。
我一直在与一个团队一起研究一个 PowerShell 脚本,该团队可以将局域网唤醒数据包发送到一组计算机。它通过读取在两列中包含主机名和 MAC 的 .csv 文件来工作,然后为每台计算机创建 WOL 数据包并将它们广播到网络上。发送 WOL 数据包后,它会等待一分钟,然后 ping 计算机以验证它们是否在线,如果任何计算机没有响应,它将显示一个窗口,显示哪些机器没有响应 ping。直到最后的 If/Else 语句都可以正常工作,所以我不会对脚本的那部分进行太多详细说明(当然,如果您想要/需要更多详细信息,请随时询问)。
我遇到的问题是最后的 If/Else 语句。脚本应该工作的方式是在脚本中间的 ForEach 循环中,变量 $PingResult 的值是真还是假,这取决于计算机是否响应 ping。如果 ping 失败,则 $PingResult 为 $false,然后它将主机名添加到 $PingResult2 变量中。
理论上,如果所有机器都响应,If 语句就会触发,消息框会显示它成功,然后脚本会停止。如果任何机器没有响应,Else 语句就会运行,它将 $PingResult2 变量中的所有项目连接在一起,并在窗口中显示列表。实际发生的情况是,即使所有机器都响应 ping,If 语句完全被跳过,而运行 Else 语句。但是,此时 $PingResult2 变量为空白,因此它不显示任何未能响应的计算机的计算机名称。在我的测试中,我从未见过脚本无法唤醒计算机的情况(假设它已插入等),但 Else 语句仍然运行。在 Else 语句运行的情况下,
为了给问题增加另一个问题,我想回到 $PingResult2 变量。我必须将变量创建为通用列表,以便它支持 Add 方法以允许变量根据需要增长。作为测试,我们修改了脚本以通过使用 += 运算符而不是使 $PingResult2 成为列表来将结果连接在一起,虽然如果机器出现故障,这并没有在最终显示窗口中提供非常可读的视觉结果,但确实如此实际上偶尔可以正常工作。如果所有计算机都成功响应,则 If 语句将按预期运行并显示成功消息。就像我说的那样,它有时会起作用,有时会不起作用,没有其他改变会对结果产生影响。
知道什么可能导致这个问题吗?我和我的团队在这一点上完全没有想法,我们很想弄清楚是什么导致了这个问题。我们已经在 Windows 7、8.1 和 Windows 10 的最新预览版上进行了尝试,但没有成功。提前感谢您的任何帮助。
PS 如果您能解释第 29 行上的正则表达式被称为什么以及它是如何工作的,那么您可以加分。我在一个网络帖子上发现了它,该帖子解决了在每两个字符之间添加一个冒号的问题,但该帖子没有解释它的名称。(原文链接http://powershell.org/wp/forums/topic/add-colon-between-every-2-characters/)
我们构建其余脚本的原始 WOL 脚本由 John Savill 编写(链接http://windowsitpro.com/networking/q-how-can-i-easily-send-magic-packet-wake-machine-my-subnet )
脚本
Add-Type -AssemblyName Microsoft.VisualBasic,System.Windows.Forms
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.ShowDialog() | Out-Null
$FileVerify = Get-Content -Path $OpenFileDialog.FileName -TotalCount 1
$FileVerify = ($FileVerify -split ',')
If($FileVerify[0] -ne "Machine Name" -or $FileVerify[1] -ne "MAC")
{
$MsgBox = [System.Windows.Forms.MessageBox]::Show("The CSV File's headers must be Machine Name and MAC.",'Invalid CSV File headers!',0,48)
Break
}
$ComputerList = Import-Csv -Path $OpenFileDialog.FileName |
Out-GridView -PassThru -Title "Select Computers to Wake up"
ForEach($Computer in $ComputerList)
{
If($Computer.'MAC' -notmatch '([:]|[-])')
{
$Computer.'MAC' = $Computer.'MAC' -replace '(..(?!$))','$1:'
}
$MACAddr = $Computer.'MAC'.split('([:]|[-])') | %{ [byte]('0x' + $_) }
$UDPclient = new-Object System.Net.Sockets.UdpClient
$UDPclient.Connect(([System.Net.IPAddress]::Broadcast),4000)
$packet = [byte[]](,0xFF * 6)
$packet += $MACAddr * 16
[void] $UDPclient.Send($packet, $packet.Length)
write "Wake-On-Lan magic packet sent to $($Computer.'Machine Name'.ToUpper())"
}
Write-Host "Pausing for sixty seconds before verifying connectivity."
Start-Sleep -Seconds 60
$PingResult2 = New-Object System.Collections.Generic.List[System.String]
ForEach($Computer in $ComputerList)
{
Write-Host "Pinging $($Computer.'Machine Name')"
$PingResult = Test-Connection -ComputerName $Computer.'Machine Name' -Quiet
If ($PingResult -eq $false)
{
$PingResult2.Add($Computer.'Machine Name')
}
}
If($PingResult2 -eq "")
{
[System.Windows.Forms.MessageBox]::Show("All machines selected are online.",'Success',0,48)
Break
}
Else
{
$PingResult2 = ($PingResult2 -join ', ')
[System.Windows.Forms.MessageBox]::Show("The following machines did not respond to a ping: $PingResult2",'Unreachable Machines',0,48)
}