PowerShell - If/Else 语句无法正常工作
PowerShell - If/Else Statement Doesn't Work Properly
首先,对于冗长冗长的 post,我深表歉意。这是一个有趣的问题,我想尽可能详细。我已经尝试浏览网站上所有相关的 PowerShell post,但找不到任何可以帮助我解决此问题的信息。
我一直在与一个团队一起开发 PowerShell 脚本,该脚本可以将 Wake-On-Lan 数据包发送到一组计算机。它通过读取一个 .csv 文件来工作,该文件在两列中包含主机名和 MAC,然后它为每台计算机创建 WOL 数据包并将它们广播到网络上。发送 WOL 数据包后,它会等待一分钟,然后 ping 计算机以验证它们是否在线,如果没有响应,它将显示 window 表示哪些计算机没有响应 ping。直到最后的 If/Else 语句工作正常,所以我不会对脚本的那部分进行过多的详细介绍(当然,如果您 want/need 更多详细信息,请随时询问)。
我遇到的问题是最后的 If/Else 语句。脚本的工作方式是,在脚本中间的 ForEach 循环中,变量 $PingResult 的值是真还是假,这取决于计算机是否响应 ping。如果 ping 失败,$PingResult 为 $false,然后它将主机名添加到 $PingResult2 变量。
理论上,如果所有机器都响应,则 If 语句会触发,消息框会显示它已成功,然后脚本停止。如果任何机器未能响应,则 Else 语句 运行s 并将 $PingResult2 变量中的所有项目连接在一起,并在 window 中显示列表。
实际发生的情况是,即使所有机器都响应 ping,If 语句也被完全跳过,而 Else 语句 运行s 代替。但是,此时 $PingResult2 变量为空,因此它不会显示未能响应的计算机的任何计算机名称。在我的测试中,我从未见过脚本无法唤醒计算机的情况(假设它已插入等),但无论如何 Else 语句仍然 运行s。在 Else 语句 运行s 的情况下,我检查了 $PingResult2 变量的值并确认它为空,然后键入 $PingResult2 –eq “” returns $true.
为了给问题添加另一个皱纹,我想 return 到 $PingResult2 变量。我必须将变量创建为通用列表,以便它支持 Add 方法以允许变量根据需要增长。作为测试,我们修改了脚本,通过使用 += 运算符而不是使 $PingResult2 成为列表来将结果连接在一起,虽然这在最终显示 window if machines 中没有给出非常可读的视觉结果失败了,它确实偶尔能正常工作。如果所有计算机都成功响应,则 If 语句将按预期 运行 并显示成功消息。就像我说的,它有时有效,有时无效,没有其他变化对结果产生影响。我们尝试的另一件事是删除对 Visual Basic 程序集和其他 GUI 元素的所有引用(除了 Out-GridView window),但这也没有用。
知道是什么导致了这个问题吗?在这一点上,我和我的团队完全没有想法,我们很想找出导致问题的原因。我们已经在 Windows 7、8.1 和 Windows 10 的最新预览版上尝试过,但没有成功。在此先感谢您的帮助。
P.S 如果您能解释第 29 行的正则表达式的名称及其具体工作原理,可额外加分。我是在网上找到的 posting 解决了每两个字符之间加一个冒号的问题,但是 posting 并没有解释它叫什么。 (原文linkhttp://powershell.org/wp/forums/topic/add-colon-between-every-2-characters/)
我们围绕脚本的其余部分构建的原始 WOL 脚本由 John Savill (link 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 '(..(?!$))',':'
}
$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)
}
您的 If
语句中的比较不正确,因为您将 $PingResult2
、List<string>
与字符串进行比较。相反,尝试
If ($PingResult2.Count -eq 0)
{
# Show the message box
}
Else
{
# Show the other message box
}
或此主题的无数其他变体之一。
有问题的正则表达式使用反向引用将两个字符完全替换为相同的两个字符加上一个冒号字符。不过,我不确定你到底想做什么 "define,"。
您正在检查列表是否具有空字符串值,而不是检查列表中的项目数。
如果将 if 语句更改为以下内容,它应该可以正常工作:
If($PingResult2.count -eq 0)
我猜正则表达式试图在字符串的每两个字符之间插入一个冒号,以将 0123456789ab
表示为 01:23:45:67:89:ab
.
代码的意思是,如果MAC中没有连字符或冒号,则在每个字符中放入一个冒号,然后使用冒号作为分隔符拆分地址,然后将每个字符表示为一个字节:
If($Computer.'MAC' -notmatch '([:]|[-])')
{
$Computer.'MAC' = $Computer.'MAC' -replace '(..(?!$))',':'
}
$MACAddr = $Computer.'MAC'.split('([:]|[-])') | %{ [byte]('0x' + $_) }
另一个答案很好地解释了为什么你的代码不起作用。我不会去那里。相反,我会给出一些我认为可以改进您的脚本的建议,并解释我为什么这么认为。让我们从功能开始。你做的一些事情是我手边的功能,因为,嗯,它们工作得很好,而且经常使用,所以我喜欢把它们放在手边。
首先,您的对话框获取 CSV 文件路径。它有效,请不要误会我的意思,但它可能会更好......因为它是你弹出一个没有参数的打开文件对话框。此函数允许您根据需要使用一些不同的参数,或者 none 用于非常通用的“打开文件”对话框,但我认为这里略有改进:
Function Get-FilePath{
[CmdletBinding()]
Param(
[String]$Filter = "|*.*",
[String]$InitialDirectory = "C:\")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $InitialDirectory
$OpenFileDialog.filter = $Filter
[void]$OpenFileDialog.ShowDialog()
$OpenFileDialog.filename
}
那么就这样称呼它:
$CSVFile = Get-FilePath -Filter "Comma Separated Value (.CSV)|*.CSV" -InitialDirectory "$env:USERPROFILE\Desktop"
这会打开仅针对 CSV 文件的对话框过滤,并让他们开始查看他们的桌面(我发现很多人将东西保存到他们的桌面)。这只会获取路径,因此您将 运行 像以前一样进行验证。其实,不像你。你似乎真的把那一点复杂化了。位我会在一瞬间,首先,另一个功能!您相当频繁地调用消息框,然后键入一堆选项,然后每次都调用类型和所有内容。如果你打算不止一次这样做,让自己轻松一点,做一个功能。在这里,检查一下:
Function Show-MsgBox ($Text,$Title="",[Windows.Forms.MessageBoxButtons]$Button = "OK",[Windows.Forms.MessageBoxIcon]$Icon="Information"){
[Windows.Forms.MessageBox]::Show("$Text", "$Title", [Windows.Forms.MessageBoxButtons]::$Button, $Icon) | ?{(!($_ -eq "OK"))}
}
然后您可以根据需要指定多少。另外它使用 Type'd 参数,所以选项卡完成工作,或者在 ISE 中(如果那是你编写脚本的地方,就像我一样)它会弹出有效选项,你只需从列表中选择按钮或图标以显示。另外,如果它是一个简单的 'OK' 响应,它不会 return 任何东西,以保持事情干净,但会 return Yes/No/Cancel 或您为按钮选择的任何其他选项。
好的,这就是函数,让我们进入脚本的核心部分。您的文件验证...好的,您拉出文件的第一行,所以它应该只是一个字符串,我不确定您为什么要拆分它并单独验证每个 header。只需匹配整个字符串即可。我建议不区分大小写,因为我们在这里并不真正关心大小写。此外,根据 CSV 文件的生成方式,header 周围可能有引号,您可能需要考虑到这一点。使用 -Match
将执行更宽容的 RegEx 匹配。
If((Get-Content $CSVFile -TotalCount 1) -match '^"?machine name"?,"?mac"?$'){
Show-MsgBox "The CSV File's headers must be Machine Name and MAC." 'Invalid CSV File headers!' -Icon Warning
break
}
所以现在我们有两个函数和 5 行代码。是的,这些函数占用的空间比您以前拥有的多 space,但它们使用起来更友好,并且 IMO 功能更强大。你的MAC地址更正,WOL发送部分在我看来都是王牌。没有理由改变那部分。现在,为了验证计算机是否恢复正常……我们可以在这里进行一些改进。不是创建 [List]
,而是向每个 object 添加一个成员,然后过滤下面的内容。整个脚本会更长一点,但我认为它更好。
Add-Type -AssemblyName Microsoft.VisualBasic,System.Windows.Forms
Function Get-FilePath{
[CmdletBinding()]
Param(
[String]$Filter = "|*.*",
[String]$InitialDirectory = "C:\")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $InitialDirectory
$OpenFileDialog.filter = $Filter
[void]$OpenFileDialog.ShowDialog()
$OpenFileDialog.filename
}
Function Show-MsgBox ($Text,$Title="",[Windows.Forms.MessageBoxButtons]$Button = "OK",[Windows.Forms.MessageBoxIcon]$Icon="Information"){
[Windows.Forms.MessageBox]::Show("$Text", "$Title", [Windows.Forms.MessageBoxButtons]::$Button, $Icon) | ?{(!($_ -eq "OK"))}
}
#Get File Path
$CSVFile = Get-FilePath -Filter "Comma Separated Value (.CSV)|*.CSV" -InitialDirectory "$env:USERPROFILE\Desktop"
#Validate Header
If((Get-Content $CSVFile -TotalCount 1) -match '^"?machine name"?,"?mac"?$'){
Show-MsgBox "The CSV File's headers must be Machine Name and MAC." 'Invalid CSV File headers!' -Icon Warning
break
}
$ComputerList = Import-Csv -Path $CSVFile |
Out-GridView -PassThru -Title "Select Computers to Wake up"
ForEach($Computer in $ComputerList)
{
If($Computer.'MAC' -notmatch '([:]|[-])')
{
$Computer.'MAC' = $Computer.'MAC' -replace '(..(?!$))',':'
}
$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
$ComputerList|ForEach
{
Write-Host "Pinging $($_.'Machine Name')"
Add-Member -InputObject $_ -NotePropertyName "PingResult" -NotePropertyValue (Test-Connection -ComputerName $Computer.'Machine Name' -Quiet)
}
If(($ComputerList|Where{!($_.PingResult)}).Count -gt 0)
{
Show-MsgBox "All machines selected are online." 'Success'
}
Else
{
Show-MsgBox "The following machines did not respond to a ping: $(($ComputerList|?{!($_.PingResult)}) -join ", ")" 'Unreachable Machines' -Icon Asterisk
}
好吧,我要离开我的肥皂盒回家了,我的班次结束了,该喝点冷的了。
首先,对于冗长冗长的 post,我深表歉意。这是一个有趣的问题,我想尽可能详细。我已经尝试浏览网站上所有相关的 PowerShell post,但找不到任何可以帮助我解决此问题的信息。
我一直在与一个团队一起开发 PowerShell 脚本,该脚本可以将 Wake-On-Lan 数据包发送到一组计算机。它通过读取一个 .csv 文件来工作,该文件在两列中包含主机名和 MAC,然后它为每台计算机创建 WOL 数据包并将它们广播到网络上。发送 WOL 数据包后,它会等待一分钟,然后 ping 计算机以验证它们是否在线,如果没有响应,它将显示 window 表示哪些计算机没有响应 ping。直到最后的 If/Else 语句工作正常,所以我不会对脚本的那部分进行过多的详细介绍(当然,如果您 want/need 更多详细信息,请随时询问)。
我遇到的问题是最后的 If/Else 语句。脚本的工作方式是,在脚本中间的 ForEach 循环中,变量 $PingResult 的值是真还是假,这取决于计算机是否响应 ping。如果 ping 失败,$PingResult 为 $false,然后它将主机名添加到 $PingResult2 变量。
理论上,如果所有机器都响应,则 If 语句会触发,消息框会显示它已成功,然后脚本停止。如果任何机器未能响应,则 Else 语句 运行s 并将 $PingResult2 变量中的所有项目连接在一起,并在 window 中显示列表。 实际发生的情况是,即使所有机器都响应 ping,If 语句也被完全跳过,而 Else 语句 运行s 代替。但是,此时 $PingResult2 变量为空,因此它不会显示未能响应的计算机的任何计算机名称。在我的测试中,我从未见过脚本无法唤醒计算机的情况(假设它已插入等),但无论如何 Else 语句仍然 运行s。在 Else 语句 运行s 的情况下,我检查了 $PingResult2 变量的值并确认它为空,然后键入 $PingResult2 –eq “” returns $true.
为了给问题添加另一个皱纹,我想 return 到 $PingResult2 变量。我必须将变量创建为通用列表,以便它支持 Add 方法以允许变量根据需要增长。作为测试,我们修改了脚本,通过使用 += 运算符而不是使 $PingResult2 成为列表来将结果连接在一起,虽然这在最终显示 window if machines 中没有给出非常可读的视觉结果失败了,它确实偶尔能正常工作。如果所有计算机都成功响应,则 If 语句将按预期 运行 并显示成功消息。就像我说的,它有时有效,有时无效,没有其他变化对结果产生影响。我们尝试的另一件事是删除对 Visual Basic 程序集和其他 GUI 元素的所有引用(除了 Out-GridView window),但这也没有用。
知道是什么导致了这个问题吗?在这一点上,我和我的团队完全没有想法,我们很想找出导致问题的原因。我们已经在 Windows 7、8.1 和 Windows 10 的最新预览版上尝试过,但没有成功。在此先感谢您的帮助。
P.S 如果您能解释第 29 行的正则表达式的名称及其具体工作原理,可额外加分。我是在网上找到的 posting 解决了每两个字符之间加一个冒号的问题,但是 posting 并没有解释它叫什么。 (原文linkhttp://powershell.org/wp/forums/topic/add-colon-between-every-2-characters/)
我们围绕脚本的其余部分构建的原始 WOL 脚本由 John Savill (link 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 '(..(?!$))',':'
}
$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)
}
您的 If
语句中的比较不正确,因为您将 $PingResult2
、List<string>
与字符串进行比较。相反,尝试
If ($PingResult2.Count -eq 0)
{
# Show the message box
}
Else
{
# Show the other message box
}
或此主题的无数其他变体之一。
有问题的正则表达式使用反向引用将两个字符完全替换为相同的两个字符加上一个冒号字符。不过,我不确定你到底想做什么 "define,"。
您正在检查列表是否具有空字符串值,而不是检查列表中的项目数。
如果将 if 语句更改为以下内容,它应该可以正常工作:
If($PingResult2.count -eq 0)
我猜正则表达式试图在字符串的每两个字符之间插入一个冒号,以将 0123456789ab
表示为 01:23:45:67:89:ab
.
代码的意思是,如果MAC中没有连字符或冒号,则在每个字符中放入一个冒号,然后使用冒号作为分隔符拆分地址,然后将每个字符表示为一个字节:
If($Computer.'MAC' -notmatch '([:]|[-])')
{
$Computer.'MAC' = $Computer.'MAC' -replace '(..(?!$))',':'
}
$MACAddr = $Computer.'MAC'.split('([:]|[-])') | %{ [byte]('0x' + $_) }
另一个答案很好地解释了为什么你的代码不起作用。我不会去那里。相反,我会给出一些我认为可以改进您的脚本的建议,并解释我为什么这么认为。让我们从功能开始。你做的一些事情是我手边的功能,因为,嗯,它们工作得很好,而且经常使用,所以我喜欢把它们放在手边。
首先,您的对话框获取 CSV 文件路径。它有效,请不要误会我的意思,但它可能会更好......因为它是你弹出一个没有参数的打开文件对话框。此函数允许您根据需要使用一些不同的参数,或者 none 用于非常通用的“打开文件”对话框,但我认为这里略有改进:
Function Get-FilePath{
[CmdletBinding()]
Param(
[String]$Filter = "|*.*",
[String]$InitialDirectory = "C:\")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $InitialDirectory
$OpenFileDialog.filter = $Filter
[void]$OpenFileDialog.ShowDialog()
$OpenFileDialog.filename
}
那么就这样称呼它:
$CSVFile = Get-FilePath -Filter "Comma Separated Value (.CSV)|*.CSV" -InitialDirectory "$env:USERPROFILE\Desktop"
这会打开仅针对 CSV 文件的对话框过滤,并让他们开始查看他们的桌面(我发现很多人将东西保存到他们的桌面)。这只会获取路径,因此您将 运行 像以前一样进行验证。其实,不像你。你似乎真的把那一点复杂化了。位我会在一瞬间,首先,另一个功能!您相当频繁地调用消息框,然后键入一堆选项,然后每次都调用类型和所有内容。如果你打算不止一次这样做,让自己轻松一点,做一个功能。在这里,检查一下:
Function Show-MsgBox ($Text,$Title="",[Windows.Forms.MessageBoxButtons]$Button = "OK",[Windows.Forms.MessageBoxIcon]$Icon="Information"){
[Windows.Forms.MessageBox]::Show("$Text", "$Title", [Windows.Forms.MessageBoxButtons]::$Button, $Icon) | ?{(!($_ -eq "OK"))}
}
然后您可以根据需要指定多少。另外它使用 Type'd 参数,所以选项卡完成工作,或者在 ISE 中(如果那是你编写脚本的地方,就像我一样)它会弹出有效选项,你只需从列表中选择按钮或图标以显示。另外,如果它是一个简单的 'OK' 响应,它不会 return 任何东西,以保持事情干净,但会 return Yes/No/Cancel 或您为按钮选择的任何其他选项。
好的,这就是函数,让我们进入脚本的核心部分。您的文件验证...好的,您拉出文件的第一行,所以它应该只是一个字符串,我不确定您为什么要拆分它并单独验证每个 header。只需匹配整个字符串即可。我建议不区分大小写,因为我们在这里并不真正关心大小写。此外,根据 CSV 文件的生成方式,header 周围可能有引号,您可能需要考虑到这一点。使用 -Match
将执行更宽容的 RegEx 匹配。
If((Get-Content $CSVFile -TotalCount 1) -match '^"?machine name"?,"?mac"?$'){
Show-MsgBox "The CSV File's headers must be Machine Name and MAC." 'Invalid CSV File headers!' -Icon Warning
break
}
所以现在我们有两个函数和 5 行代码。是的,这些函数占用的空间比您以前拥有的多 space,但它们使用起来更友好,并且 IMO 功能更强大。你的MAC地址更正,WOL发送部分在我看来都是王牌。没有理由改变那部分。现在,为了验证计算机是否恢复正常……我们可以在这里进行一些改进。不是创建 [List]
,而是向每个 object 添加一个成员,然后过滤下面的内容。整个脚本会更长一点,但我认为它更好。
Add-Type -AssemblyName Microsoft.VisualBasic,System.Windows.Forms
Function Get-FilePath{
[CmdletBinding()]
Param(
[String]$Filter = "|*.*",
[String]$InitialDirectory = "C:\")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $InitialDirectory
$OpenFileDialog.filter = $Filter
[void]$OpenFileDialog.ShowDialog()
$OpenFileDialog.filename
}
Function Show-MsgBox ($Text,$Title="",[Windows.Forms.MessageBoxButtons]$Button = "OK",[Windows.Forms.MessageBoxIcon]$Icon="Information"){
[Windows.Forms.MessageBox]::Show("$Text", "$Title", [Windows.Forms.MessageBoxButtons]::$Button, $Icon) | ?{(!($_ -eq "OK"))}
}
#Get File Path
$CSVFile = Get-FilePath -Filter "Comma Separated Value (.CSV)|*.CSV" -InitialDirectory "$env:USERPROFILE\Desktop"
#Validate Header
If((Get-Content $CSVFile -TotalCount 1) -match '^"?machine name"?,"?mac"?$'){
Show-MsgBox "The CSV File's headers must be Machine Name and MAC." 'Invalid CSV File headers!' -Icon Warning
break
}
$ComputerList = Import-Csv -Path $CSVFile |
Out-GridView -PassThru -Title "Select Computers to Wake up"
ForEach($Computer in $ComputerList)
{
If($Computer.'MAC' -notmatch '([:]|[-])')
{
$Computer.'MAC' = $Computer.'MAC' -replace '(..(?!$))',':'
}
$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
$ComputerList|ForEach
{
Write-Host "Pinging $($_.'Machine Name')"
Add-Member -InputObject $_ -NotePropertyName "PingResult" -NotePropertyValue (Test-Connection -ComputerName $Computer.'Machine Name' -Quiet)
}
If(($ComputerList|Where{!($_.PingResult)}).Count -gt 0)
{
Show-MsgBox "All machines selected are online." 'Success'
}
Else
{
Show-MsgBox "The following machines did not respond to a ping: $(($ComputerList|?{!($_.PingResult)}) -join ", ")" 'Unreachable Machines' -Icon Asterisk
}
好吧,我要离开我的肥皂盒回家了,我的班次结束了,该喝点冷的了。