我写了一个函数来检查主机是在线还是离线,然后返回$true
或$false
。这个功能很完美,我希望通过观察来改善它
如果可以删除脚本范围的变量,例如$Script:arrayCanPingResult
和$script:tmpPingCheckServers
。
为什么我要这个?
当我在foreach
循环内调用该函数时,我通常使用开关-Remember
,因此它不会检查同一主机两次。为了能够正确使用它,我必须通过声明两个变量为空($Script:arrayCanPingResult=$script:tmpPingCheckServers=@{}
)来开始我使用此函数的所有脚本。我可以想象人们忘记将第一行放在他们的脚本中,并且在PowerShell ISE编辑器中多次测试时,如果在ISE中已经检查过一次主机,它将不会在第二次运行时再次进行测试(F5)
在这种情况下,有没有办法避免使用脚本范围的变量?所以我们不需要在新脚本的开头将它们声明为空?如果这是可能的,那就太棒了,因为我们可以在自定义模块中包含这个功能。
一如既往,感谢您的建议或帮助。我和你们在这里真的学到了很多。
# Function to check if $Server is online
Function Can-Ping ($Server,[switch]$Remember) {
$PingResult = {
# Return $true or $false based on the result from script block $PingCheck
foreach ($_ in $Script:arrayCanPingResult) {
# Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: $_ " -ForegroundColor Green
if ($Server -eq $($_.Split(",")[0])) {
#Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: We will return $($_.Split(",")[1])" -ForegroundColor Green
return $($_.Split(",")[1])
}
}
}
$PingCheck = {
$Error.Clear()
if (Test-Connection -ComputerName $Server -BufferSize 16 -Count 1 -ErrorAction 0 -quiet) { # ErrorAction 0 doesn't display error information when a ping is unsuccessful
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: Ping test ok" -ForegroundColor Gray; $Script:arrayCanPingResult+=@("$Server,$true"); return
}
else {
$Error.Clear()
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: Ping test FAILED" -ForegroundColor Gray
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: Flushing DNS" -ForegroundColor Gray
ipconfig /flushdns | Out-Null
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: Registering DNS" -ForegroundColor Gray
ipconfig /registerdns | Out-Null
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: NSLookup" -ForegroundColor Gray
nslookup $Server | Out-Null # Suppressing error here is not possible unless using '2> $null', but if we do this, we don't get $true or $false for the function so '| Out-Null' is an obligation
if (!$?) {
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: NSlookup can't find the host '$Server', DNS issues or hostname incorrect?" -ForegroundColor Yellow
# Write-Host $Error -ForegroundColor Red
if ($SendMail) {
Send-Mail $MailTo "FAILED Ping test" "$(Get-TimeStamp) NSlookup can't find the host '$Server', hostname incorrect or DNS issues?" "<font color=`"red`">$error</font>"
}
$script:arrayCanPingError += "ERROR | $(Get-TimeStamp) Ping test failed: NSlookup can't find the host '$Server', hostname incorrect or DNS issues?$error"
$script:HTMLarrayCanPingError += "ERROR | $(Get-TimeStamp) Ping test failed:<br>NSlookup can't find the host '$Server', hostname incorrect or DNS issues?<br><font color=`"red`">$error</font>"
$Script:arrayCanPingResult+=@("$Server,$false")
return
}
else {
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: Re-pinging '$Server'" -ForegroundColor Gray
if (Test-Connection -ComputerName $Server -BufferSize 16 -Count 1 -ErrorAction 0 -Quiet) {
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: Ping test ok, problem resolved" -ForegroundColor Gray
$Script:arrayCanPingResult+=@("$Server,$true")
return
}
else {
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: DNS Resolving is ok but can't connect, server offline?" -ForegroundColor Yellow
if ($SendMail) {
Send-Mail $MailTo "FAILED Ping test" "$error" "DNS Resolving is ok but can't connect to $Server, server offline?"
}
$script:arrayCanPingError += "ERROR Ping test failed: DNS Resolving is ok but can't connect to $Server, server offline?$error"
$script:HTMLarrayCanPingError += "ERROR Ping test failed: DNS Resolving is ok but can't connect to $Server, server offline?<br><font color=`"red`">$error</font>"
$Script:arrayCanPingResult+=@("$Server,$false")
return
}
}
}
}
# Call the script block $PingAction every time, unless the switch $Remember is provided, than we only check each server once
if ($Remember) {
Write-Host "$(Get-TimeStamp) $Server > Function Can-Ping: Switch '-Remember' detected" -ForegroundColor Gray
While ($tmpPingCheckServers -notcontains $Server) {
&$PingCheck
$script:tmpPingCheckServers = @($tmpPingCheckServers+$Server) #Script wide variable, otherwise it stays empty when we leave the function / @ is used to store it as an Array (table) instead of a string
}
&$PingResult
}
else {
&$PingCheck
&$PingResult
}
}
答案 0 :(得分:1)
这是我将如何做到的:
function Get-PingStatus {
param(
# Server object.
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
$Server,
[Parameter(Mandatory=$false)]
[Bool]$UseLastPingResult = $false
)
if ( ($UseLastPingResult) `
-and (! [String]::IsNullOrEmpty($Server.LastPingResult)) ) {
# Return unmodified object if LastPingResult property is not empty.
return $Server
}
try {
$oPingResult = Test-Connection -ComputerName $Server.Name `
-BufferSize 16 -Count 1 -ErrorAction Stop
$Server.LastPingResult = "success"
# And just in case.
$Server.IPV4Address = $oPingResult.IPV4Address
}
catch {
$Server.LastPingResult = "failure"
}
return $Server
}
对象输入,对象输出。通常,这是编写PowerShell函数的最佳方法,因为:1)它与库存cmdlet的作用一致; 2)它可以帮助您保持代码简单易读。
使用ErrorAction -Stop和try ... catch ...最后也比ErrorAction -SilentlyContinue更好,然后检查一些变量。
现在让我们假设$ cServerNames是服务器名称的集合或任何可以解析为IP地址的东西。示例:@("server1", "server2", "1.2.3.4", "webserver.example.com")
。
# Converting strings to objects.
$cServers = @()
foreach ($sServerName in $cServerNames) {
$oServer = New-Object PSObject -Property @{
"Name" = $sServerName;
"IPV4Address" = $null;
"LastPingResult" = $null;
}
$cServers += $oServer
}
# Now we can iterate objects and update their properties as necessary.
foreach ($oServer in $cServers) {
$oServer = Get-PingStatus -Server $oServer -UseLastPingResult
if ($oServer.LastPingResult -eq "success") {
# Do something.
} else {
# Do something else like an error message.
}
}
您可以添加所需的任何诊断输出,但我建议您使用写入输出和/或写入错误而不是写入主机。
最后,请注意,在大多数情况下,ping在生产代码中几乎无用。它是多余的,无论主持人是否回复都无法证明。例如,ping可能没问题,但由于某种原因,您在后续的Get-WmiObject查询中获得异常。如果您出于性能原因(为了节省时间)执行ping操作,则应考虑通过background jobs或workflows并行运行脚本块。