我正在编写一个脚本,该脚本检查服务器是否 ping,然后检查所有 SQL Server 服务状态并将其存储在表中。它还适用于 SQL 实例。但是,我必须检查 70 台服务器,并且运行需要一分钟多的时间。我查看了 AsJob 参数,当我将其添加到所有“Get_WMIObject xxService”命令时,它开始为每个服务返回错误信息。即它开始为所有人返回“运行”状态,所以我怀疑它只是重复先前的数据捕获。尽管它确实只运行了 20 秒。有人可以看看下面并建议我哪里出错了或者我可以做些什么来使服务器服务信息的检索异步?
我认为将所有服务器的服务状态存储在哈希表中并一次性更新 SQL 数据表可能会更好,但事实证明它相当复杂。我觉得我的代码需要完全重新考虑才能异步运行,但我试图避免这种情况!
提前致谢
<#
Tests all Servers for Ping and SQL Server Service Status
#>
# Return the Ping Status
Function GetStatusCode
{
Param([int] $StatusCode)
switch($StatusCode)
{
0 {"Success"}
11001 {"Buffer Too Small"}
11002 {"Destination Net Unreachable"}
11003 {"Destination Host Unreachable"}
11004 {"Destination Protocol Unreachable"}
11005 {"Destination Port Unreachable"}
11006 {"No Resources"}
11007 {"Bad Option"}
11008 {"Hardware Error"}
11009 {"Packet Too Big"}
11010 {"Request Timed Out"}
11011 {"Bad Request"}
11012 {"Bad Route"}
11013 {"TimeToLive Expired Transit"}
11014 {"TimeToLive Expired Reassembly"}
11015 {"Parameter Problem"}
11016 {"Source Quench"}
11017 {"Option Too Big"}
11018 {"Bad Destination"}
11032 {"Negotiating IPSEC"}
11050 {"General Failure"}
default {"Failed"}
}
}
# Format the Server Up-time
Function GetUpTime
{
param([string] $LastBootTime)
$Uptime = (Get-Date) - [System.Management.ManagementDateTimeconverter]::ToDateTime($LastBootTime)
"Days: $($Uptime.Days); Hours: $($Uptime.Hours); Minutes: $($Uptime.Minutes); Seconds: $($Uptime.Seconds)"
}
#Main Body
# Populate Table MyDB.dbo.tbl_ServerPingTest
$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source=MyServer; Initial Catalog=MyDB; Integrated Security=SSPI")
$conn.Open()
$cmd = $conn.CreateCommand()
$cmd.CommandText ="DELETE FROM MyDB.dbo.tbl_ServerPingTest
INSERT INTO MyDB.dbo.tbl_ServerPingTest (ServerName, InstanceName)
SELECT ServerName, InstanceName FROM MyDB.dbo.tbl_servers
WHERE ServerCategory <> 'DECOMMED'"
$cmd.ExecuteNonQuery()
$cmd2 = $conn.CreateCommand()
$cmd2.CommandText = "SELECT * FROM MyDB.dbo.tbl_ServerPingTest"
$da = New-Object System.Data.SqlClient.SqlDataAdapter #($cmd2)
$da.SelectCommand = $cmd2
$dt = New-Object System.Data.DataTable
$da.Fill($dt) | Out-Null
# Cycle through Server and Instances and retrieve information
Foreach($row in $dt.rows)
{
$ServerName = $row.ServerName
$InstanceName = $row.InstanceName
$pingStatus = Get-WmiObject -Query "Select * from win32_PingStatus where Address='$ServerName'"
$Uptime = $null
$SQLServerStatus = $null
$SQLAgentStatus = $null
# Enter the Loop if a Server is Pingable
if($pingStatus.StatusCode -eq 0)
{
# Trap needed for server where Access is Denied causes the SQL Job to fail
trap {continue}
$OperatingSystem = Get-WmiObject Win32_OperatingSystem -ComputerName $ServerName -ErrorAction SilentlyContinue -ErrorVariable wmiResults
$Uptime = GetUptime( $OperatingSystem.LastBootUpTime )
if ($wmiResults -ne $null)
{
$tmperr = "Uptime Info Could Not be Obtained"
$Uptime = $null
}
else
{
$tmperr = ""
filter SvcFilter {
if ($_.StartMode -eq "Disabled") {$_.StartMode }
else {$_.State}
}
$props="Name","StartMode","State"
if ($InstanceName -eq 'DEFAULT')
{
$SQLServerStatus = Get-WMIObject win32_service -property $props -filter "name='MSSQLSERVER'" -computer $ServerName | SvcFilter
$SQLAgentStatus = Get-WMIObject win32_service -property $props -filter "name='SQLSERVERAGENT'" -computer $ServerName | SvcFilter
$RSAgentStatus = Get-WMIObject win32_service -property $props -filter "name='ReportServer'" -computer $ServerName | SvcFilter
}
else
{
$NamedInstanceSQLService = "MSSQL$" + $InstanceName
$NamedInstanceAgentService = "SQLAgent$" + $InstanceName
$NamedInstanceRSService = "ReportServer$" + $InstanceName
$SQLServerStatus = Get-WMIObject win32_service -property $props -computer $ServerName | where {$_.name -eq $NamedInstanceSQLService} | SvcFilter
$SQLAgentStatus = Get-WMIObject win32_service -property $props -computer $ServerName | where {$_.name -eq $NamedInstanceAgentService} | SvcFilter
$RSAgentStatus = Get-WMIObject win32_service -property $props -computer $ServerName | where {$_.name -eq $NamedInstanceRSService} | SvcFilter
}
$ASAgentStatus = Get-WMIObject win32_service -property $props -filter "name='MSSQLServerOLAPService'" -computer $ServerName | SvcFilter
}
}
$IPAddress = $pingStatus.IPV4Address
$PingTest = GetStatusCode( $pingStatus.StatusCode )
$ErrMSG = $tmperr
# Update Table MyDB.dbo.tbl_ServerPingTest with all retreived information
$updateRow = $dt.Select("ServerName = '$ServerName' AND InstanceName = '$InstanceName'")
$updateRow[0].IPAddress = $IPAddress
$updateRow[0].PingTest = $PingTest
$updateRow[0].ErrMSG = $ErrMSG
$updateRow[0].Uptime = $Uptime
$updateRow[0].SQLServerStatus = $SQLServerStatus
$updateRow[0].SQLAgentStatus = $SQLAgentStatus
$updateRow[0].RSAgentStatus = $RSAgentStatus
$updateRow[0].ASAgentStatus = $ASAgentStatus
$cmdUpd = $conn.CreateCommand()
$cmdUpd.CommandText = "UPDATE MyDB.dbo.tbl_ServerPingTest
SET IPAddress = @IPAddress, PingTest = @PingTest, ErrMSG = @ErrMSG, Uptime = @Uptime, SQLServerStatus = @SQLServerStatus, SQLAgentStatus = @SQLAgentStatus, RSAgentStatus = @RSAgentStatus, ASAgentStatus = @ASAgentStatus
WHERE ServerName = @ServerName AND InstanceName = @InstanceName"
# Add parameters to pass values to the UPDATE statement
$cmdUpd.Parameters.Add("@ServerName", "nvarchar", 50, "ServerName") | Out-Null
$cmdUpd.Parameters["@ServerName"].SourceVersion = "Original"
$cmdUpd.Parameters.Add("@InstanceName", "nvarchar", 50, "InstanceName") | Out-Null
$cmdUpd.Parameters["@InstanceName"].SourceVersion = "Original"
$cmdUpd.Parameters.Add("@IPAddress", "nvarchar", 50, "IPAddress") | Out-Null
$cmdUpd.Parameters["@IPAddress"].SourceVersion = "Current"
$cmdUpd.Parameters.Add("@PingTest", "nvarchar", 50, "PingTest") | Out-Null
$cmdUpd.Parameters["@PingTest"].SourceVersion = "Current"
$cmdUpd.Parameters.Add("@ErrMSG", "nvarchar", 50, "ErrMSG") | Out-Null
$cmdUpd.Parameters["@ErrMSG"].SourceVersion = "Current"
$cmdUpd.Parameters.Add("@Uptime", "nvarchar", 50, "Uptime") | Out-Null
$cmdUpd.Parameters["@Uptime"].SourceVersion = "Current"
$cmdUpd.Parameters.Add("@SQLServerStatus", "nvarchar", 50, "SQLServerStatus") | Out-Null
$cmdUpd.Parameters["@SQLServerStatus"].SourceVersion = "Current"
$cmdUpd.Parameters.Add("@SQLAgentStatus", "nvarchar", 50, "SQLAgentStatus") | Out-Null
$cmdUpd.Parameters["@SQLAgentStatus"].SourceVersion = "Current"
$cmdUpd.Parameters.Add("@RSAgentStatus", "nvarchar", 50, "RSAgentStatus") | Out-Null
$cmdUpd.Parameters["@RSAgentStatus"].SourceVersion = "Current"
$cmdUpd.Parameters.Add("@ASAgentStatus", "nvarchar", 50, "ASAgentStatus") | Out-Null
$cmdUpd.Parameters["@ASAgentStatus"].SourceVersion = "Current"
# Set the UpdateCommand property
$da.UpdateCommand = $cmdUpd
# Update the database
$RowsUpdated = $da.Update($dt)
}
$conn.Close()
我尝试将 -AsJob 参数添加到每个 Get-WMIObject 行
IE
$SQLServerStatus = Get-WMIObject win32_service -property $props -computer $ServerName | where {$_.name -eq $NamedInstanceSQLService} -AsJob | SvcFilter
但我没有在代码中的任何地方使用 Receive-Job。我注意到每个变量都会返回“运行”状态,即使它是“停止”或“禁用”。所以我猜测作业的结果没有被正确捕获,实际上它正在返回以前的 Get-WMIObject 调用的输出(其中大部分将处于“运行”状态)。