Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multithreading Help w/Powershell

Tags:

sql

powershell

So I have a script that will go through and ping all the servers from a list that is stored in SQL Server. The script works fine but it does it all sequentially (lame).

Can someone help me out as to how I would change this to use multithreading instead of a foreach loop?

    $Server = "ServerName"
$Database = "DatabaseName"

$con = "server=$Server;database=$Database;Integrated Security=sspi"
$cmd = "SELECT ServerName FROM dbo.vwServerListActive"

  $da = new-object System.Data.SqlClient.SqlDataAdapter ($cmd, $con)

  $dt = new-object System.Data.DataTable

  $da.fill($dt) | out-null


  foreach ($srv in $dt)
    {

    $ping = new-object System.Net.NetworkInformation.Ping
    $Reply = $ping.send($srv.ServerName)

    $ServerName = $srv.ServerName 

    $ServerName
    $Reply.status

    if ($Reply.status –eq “Success”)
    {
        $sql = "UPDATE dbo.ServerList SET GoodPing = 1 WHERE GoodPing <> 1 AND ServerName = '$ServerName'"

    }
    else
    {
        $sql = "UPDATE dbo.ServerList SET GoodPing = 0 WHERE GoodPing <> 0 AND ServerName = '$ServerName'"
    }

    $Reply = ""

    invoke-sqlcmd -serverinstance $Server -database $Database -query $sql


    }
like image 470
ColinStasiuk Avatar asked Jul 13 '10 17:07

ColinStasiuk


People also ask

Can I run 2 PowerShell scripts in parallel?

Parallel foreach (PowerShell 7.0)You can run all scripts in parallel for each piped input object. If your script is crunching a lot of data over a significant period of time and if the machine you are running on has multiple cores that can host the script block threads.

Is PowerShell asynchronous?

PowerShell does not provide an async or await keyword. The PowerShell engine itself has a tendency to very single-threaded unless you take steps to use Start-Job or Start-ThreadJob . Because of this, you'll need to take care when calling async methods in .

What is $using in PowerShell?

The using statement allows you to specify which namespaces are used in the session. Adding namespaces simplifies usage of . NET classes and member and allows you to import classes from script modules and assemblies. The using statements must come before any other statements in a script or module.

What is PowerShell Runspace?

This container holds all variables, drives, commands, and the like that are used during the execution of a [PowerShell] object invocation. A runspace is always required when you want to execute PowerShell code, regardless of the mechanism used to execute that code, either API or script.


1 Answers

(Edited as per Chad Miller's Suggestion + Throttling Requirement + Wait-Job fix + STA fix)

Support.ps1

powershell -File "Main.ps1" -Sta

Main.ps1

$Server = "ServerName"   
$Database = "DatabaseName"   

$con = "server=$Server;database=$Database;Integrated Security=sspi"   
$cmd = "SELECT ServerName FROM dbo.vwServerListActive"   

$da = New-Object System.Data.SqlClient.SqlDataAdapter -ArgumentList $cmd, $con  

$dt = New-Object System.Data.DataTable   

$da.Fill($dt) | Out-Null  

$ThrottleLimit = 10 
$activeJobs = New-Object 'System.Collections.Generic.List[Int32]' 

$JobStateChanged = { 
    param ( 
        [System.Object]$Sender, 
        [System.Management.Automation.JobStateEventArgs]$EventArgs 
    ) 

    switch ($EventArgs.JobStateInfo.State) 
    { 
        Blocked { return } 
        Completed { $activeJobs.Remove($Sender.Id); break } 
        Failed { $activeJobs.Remove($Sender.Id); break } 
        NotStarted { return } 
        Running { return } 
        Stopped { $activeJobs.Remove($Sender.Id); break } 
    }

    Unregister-Event -SourceIdentifier ("{0}.StateChanged" -f $Sender.Name)
} 

foreach ($srv in $dt)   
{ 
    while ($true) 
    { 
        if ($activeJobs.Count -lt $ThrottleLimit) 
        { 
            $job = Start-Job -InitializationScript {   
                Add-PSSnapin -Name SqlServerCmdletSnapin100   
            } -ScriptBlock {  
                param (  
                    [String]$Server,  
                    [String]$Database,  
                    [String]$ServerName  
                )  

                if (Test-Connection -ComputerName $ServerName -Quiet)   
                {   
                    $sql = "UPDATE dbo.ServerList SET GoodPing = 1 WHERE GoodPing <> 1 AND ServerName = '$ServerName'"  
                }   
                else   
                {   
                    $sql = "UPDATE dbo.ServerList SET GoodPing = 0 WHERE GoodPing <> 0 AND ServerName = '$ServerName'"  
                }  

                Invoke-SqlCmd -ServerInstance $Server -Database $Database -Query $sql  
            } -ArgumentList $Server, $Database, $srv.ServerName  

            $activeJobs.Add($job.Id) 

            Register-ObjectEvent -InputObject $job -EventName StateChanged -SourceIdentifier ("{0}.StateChanged" -f $job.Name) -Action $JobStateChanged 

            break 
        } 
    } 
} 

Get-Job | Where-Object { $_.State -eq "Running" } | Wait-Job
Get-Job | Remove-Job
like image 65
George Howarth Avatar answered Oct 14 '22 18:10

George Howarth