PowerShell: Start-Job, Receive-Job: no return value

Randall.Cummins picture Randall.Cummins · Jan 30, 2013 · Viewed 7.3k times · Source

Ok, Here is my script

$server=@("SERVER1","SERVER2")
$A=@()

foreach($srv in $server){
    start-job -scriptblock {Get-AppHangs $srv}}

while (Get-Job -State "Running"){}

foreach($JB in Get-Job){$A+=Receive-Job $JB}

Remove-Job *

$A|Out-GridView


function Get-AppHangs($srv){
    $A=@()
    $XX=Get-EventLog -ComputerName $srv -LogName "application" | Where-Object {$_.InstanceID -ge 1000 -and $_.InstanceID -lt 1005} | select -First 5

    foreach($x in $XX){
        $time = $_.Time.ToString()
        $obj=New-Object PSObject
        $obj|Add-Member -MemberType "NoteProperty" -Name Server -Value $srv
        $obj|Add-Member -MemberType "NoteProperty" -Name Index -Value $x.Index
        $obj|Add-Member -MemberType "NoteProperty" -Name Time -Value $x.Time -SecondValue System.string
        $obj|Add-Member -MemberType "NoteProperty" -Name EntryType -Value $x.EntryType
        $obj|Add-Member -MemberType "NoteProperty" -Name Source -Value $x.Source
        $obj|Add-Member -MemberType "NoteProperty" -Name InstanceID -Value $x.InstanceID
        $obj|Add-Member -MemberType "NoteProperty" -Name Message -Value $x.Message
        $A+=$obj
    }
    $obj3=New-Object PSObject
    $A+=$obj3
    return $A
}

My problem is that I am expecting the line $A|Out-GridView to produce something meaningful. but the gridview doesn't even pop up.

So if I look down this script, I don't see anything glaring at me, but I am hoping a fresh set of eyes can review...

The purpose of this script is to be able to find all the Application Hang ID's in the event viewer for a set of servers and show up in a nice gridview...

I am able to see the gridview if I cut out the start-job and receive-job business, but I want to make this run faster and more efficient.

heeeeelp ;) Thanks in advance! Also I couldn't figure out how to get the Time property into my custom object... if you have a tip for that, that would be amazing as well.

UPDATED Script:

    $server=@("SERVER1","SERVER2")
    $A=@()

    foreach($srv in $server)
    {
        start-job -scriptblock {
                                $A=@()
                                $XX=Get-EventLog -ComputerName $srv -LogName "application" | Where-Object {$_.InstanceID -ge 1000 -and $_.InstanceID -lt 1005} | select -First 5

                                foreach($x in $XX){
                                    $obj=New-Object PSObject
                                    $obj|Add-Member -MemberType "NoteProperty" -Name Server -Value $srv
                                    $obj|Add-Member -MemberType "NoteProperty" -Name Index -Value $x.Index
                                    $obj|Add-Member -MemberType "NoteProperty" -Name EntryType -Value $x.EntryType
                                    $obj|Add-Member -MemberType "NoteProperty" -Name Source -Value $x.Source
                                    $obj|Add-Member -MemberType "NoteProperty" -Name InstanceID -Value $x.InstanceID
                                    $obj|Add-Member -MemberType "NoteProperty" -Name Message -Value $x.Message
                                    $A+=$obj}

                                $obj3=New-Object PSObject
                                $A+=$obj3

                                return $A
                                }
    }
    while (Get-Job -State "Running"){}
    foreach($JB in Get-Job){$A+=Receive-Job $JB}
    Remove-Job *
    $A|Out-GridView

Answer

Frode F. picture Frode F. · Jan 30, 2013

You have to pass in the server parameter. The job is run in a seperate process and can't access your $srv string if you don't pass it as an argument. In PS3.0 you could use the "using" scope (ex. $using:srv), but in PS2.0 you need to use param(..)in your scriptblock and -Argumentlist to send the objects. Try this:

$server=@("SERVER1","SERVER2")

foreach($srv in $server)
{
    Start-Job -scriptblock {
        param($serv)
        $out=@()
        $XX=Get-EventLog -ComputerName $serv -LogName "application" | Where-Object {$_.InstanceID -ge 1000 -and $_.InstanceID -lt 1005} | select -First 5

        foreach($x in $XX){
            $obj=New-Object PSObject
            $obj|Add-Member -MemberType "NoteProperty" -Name Server -Value $srv
            $obj|Add-Member -MemberType "NoteProperty" -Name Index -Value $x.Index
            $obj|Add-Member -MemberType "NoteProperty" -Name EntryType -Value $x.EntryType
            $obj|Add-Member -MemberType "NoteProperty" -Name Source -Value $x.Source
            $obj|Add-Member -MemberType "NoteProperty" -Name InstanceID -Value $x.InstanceID
            $obj|Add-Member -MemberType "NoteProperty" -Name Message -Value $x.Message
            $out += $obj
        }
        $out
    } -ArgumentList $srv
}

$A = Get-Job | Wait-Job | Receive-Job
$A | Out-GridView

If you want to exclude the runspaceid(one of the properties that start-job adds to specify where the object was created), try something like this :

$A | Select-Object -Property * -ExcludeProperty RunspaceID | Out-GridView