0

サーバーのpingをチェックし、すべてのSQL Serverサービスのステータスをチェックして、これをテーブルに保存するスクリプトに取り組んでいます。また、SQL インスタンスにも対応しています。ただし、70 台のサーバーをチェックする必要があり、実行に 1 分以上かかります。AsJob パラメータを調べて、これをすべての「Get_WMIObject xxService」コマンドに追加すると、サービスごとに間違った情報が返されるようになりました。つまり、すべてに対して「実行中」ステータスを返し始めたので、以前のデータキャプチャを繰り返していたのではないかと思います。わずか20秒で実行されましたが。誰かが以下を見て、私がどこで間違っているか、またはサーバーサービス情報の取得を非同期にするために何ができるかをアドバイスできますか?

すべてのサーバーのサービス ステータスをハッシュ テーブルに格納し、SQL DataTable を一度に更新する方がよいと考えましたが、非常に複雑であることがわかりました。非同期で実行するには、コードを完全に再考する必要があると感じていますが、これを回避しようとしています!

前もって感謝します

<#
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 行に追加しようとしました

すなわち

$SQLServerStatus = Get-WMIObject win32_service -property $props -computer $ServerName | where {$_.name -eq $NamedInstanceSQLService} -AsJob | SvcFilter

しかし、コードのどこにも Receive-Job を使用しませんでした。「停止」または「無効」であっても、すべての変数が「実行中」ステータスを返すことに気付きました。したがって、ジョブの結果が適切にキャプチャされておらず、実際には以前の Get-WMIObject 呼び出しの出力が返されていると推測しています (そのほとんどは「実行中」ステータスになります)。

4

3 に答える 3

0

get-wmiobject-asjobパラメータがありますが、where-objectありません。

また、-asjob を使用すると、戻り値は、get-wmiobject 呼び出しなどによって返されるオブジェクトではなく、"ジョブ オブジェクト" になります。

コマンドレットを使用しreceive-jobて、リモート サーバーでジョブが完了したら、各ジョブから実際のオブジェクトを取得します (また、 と を使用wait-jobして、いつジョブが完了したget-jobかを知ることができます)。

get-help about_Remote_Jobsコードを構築する方法についての背景を理解するために、 を実行することをお勧めします。

于 2013-04-24T14:53:31.857 に答える
0

Start-Job を使用して書き直したところ、80 秒から 20 秒に短縮されました。それをさらに効率的にする方法に関して、誰かがさらに提案をしてくれれば幸いです。すべての WMIObjects を 1 つずつではなく一度に取得することを考えていますか? 誰でも方法を提案できますか?

#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

# Create list
$serverlist = @()

$sb = {
    param ([string] $ServerName, [string] $InstanceName)

    # 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)"  
    } 

    try {

        # Fetch IP
        $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') 
                    {
                        #Write-Host $ServerName + '\' + $InstanceName 
                        $SQLServerStatus = Get-WMIObject win32_service -property $props -filter "name='MSSQLSERVER'" -computer $ServerName | SvcFilter
                        #Write-Host $SQLServerStatus
                        $SQLAgentStatus = Get-WMIObject win32_service -property $props -filter "name='SQLSERVERAGENT'" -computer $ServerName | SvcFilter
                        #Write-Host $SQLAgentStatus
                        $RSAgentStatus = Get-WMIObject win32_service -property $props -filter "name='ReportServer'" -computer $ServerName | SvcFilter
                        #Write-Host $RSAgentStatus
                    }
                    else
                    {
                        #Write-Host $ServerName + '\' + $InstanceName 
                        $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

        # Save info about server
        $serverInfo = New-Object -TypeName PSObject -Property @{
        ServerName = $ServerName
        InstanceName = $InstanceName
        IPAddress = $IPAddress
        PingTest = $PingTest
        ErrMSG = $ErrMSG
        Uptime = $Uptime
        SQLServerStatus = $SQLServerStatus
        SQLAgentStatus = $SQLAgentStatus   
        RSAgentStatus = $RSAgentStatus 
        ASAgentStatus = $ASAgentStatus 

        }
        return $serverInfo
    } catch {
        throw 'Failed to process server named {0}. The error was "{1}".' -f $ServerName, $_
    }
}

# Loop servers
$max = 5
$jobs = @()
foreach($row in $dt.rows) {
    #$InstanceName = "DEFAULT"
    $server = $row.ServerName
    $InstanceName = $row.InstanceName
    $jobs += Start-Job -ScriptBlock $sb -ArgumentList @($server, $InstanceName) 
    $running = @($jobs | ? {$_.State -eq 'Running'})

    # Throttle jobs.
    while ($running.Count -ge $max) {
        $finished = Wait-Job -Job $jobs -Any
        $running = @($jobs | ? {$_.State -eq 'Running'})
    }
}

# Wait for remaining.
Wait-Job -Job $jobs > $null

# Check for failed jobs.
$failed = @($jobs | ? {$_.State -eq 'Failed'})
if ($failed.Count -gt 0) {
    $failed | % {
        $_.ChildJobs[0].JobStateInfo.Reason.Message
    }
}

# Collect job data.
$jobs | % {
    $serverlist += $_ | Receive-Job | Select-Object ServerName,InstanceName,IPAddress,PingTest,ErrMSG,Uptime,SQLServerStatus,SQLAgentStatus,RSAgentStatus,ASAgentStatus
}

#$serverlist

Foreach($row in $serverlist) 
{ 
    $ServerName = $row.ServerName
    $InstanceName = $row.InstanceName

    #$dt.Select("ServerName = '$ServerName' AND InstanceName = '$InstanceName'")

    $IPAddress = $row.IPAddress
    $PingTest = $row.PingTest
    $ErrMSG = $row.ErrMSG
    $Uptime = $row.Uptime
    $SQLServerStatus = $row.SQLServerStatus
    $SQLAgentStatus = $row.SQLAgentStatus   
    $RSAgentStatus = $row.RSAgentStatus 
    $ASAgentStatus = $row.ASAgentStatus 


   # Write-Host $ServerName
   # Write-Host $InstanceName

    $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()
于 2013-04-25T13:54:54.663 に答える