Receive-Job error

Ask your Windows PowerShell-related questions, including questions on cmdlet development!
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
Locked
User avatar
SakJaTeda
Posts: 11
Joined: Thu Dec 14, 2017 3:57 pm

Receive-Job error

Post by SakJaTeda » Wed Feb 20, 2019 9:25 pm

Hi Guys,

We are receiving notifications of stale AD computer accounts, but those reports seem to be faulty and I got asked to create an application that would basically re-check the results. I am using jobs to check every computer, so that the process does not freeze the form. What I have is basically a Start button and a timer, as follows:

Code: Select all

$buttonStart_Click={
    if ($datagridview1.DataSource)
    {
        $global:Computers = $datagridview1.DataSource
        $timerJobs.Start()
        $buttonOpenExcel.Enabled = $false
        $buttonOpenExcelAndAppend.Enabled = $false
        $buttonClearTable.Enabled = $false
        $buttonStart.Text = 'Working ...'
        $buttonStart.Enabled = $false
        $datagridview1.Cursor = 'WaitCursor'
        foreach ($Computer in $global:Computers)
        {
            $checkJob = Start-Job { Get-ADComputer $Computer."Computer Name" -Properties PasswordLastSet, LastLogonDate }
            $Computer | Add-Member -NotePropertyName "CheckJob" -NotePropertyValue $checkJob -Force
        }
    }
}

$timerJobs_Tick={
    foreach ($Computer in $global:Computers)
    {
        if (($Computer.CheckJob.State -eq 'Completed') -and $Computer.CheckJob.HasMoreData)
        {
            $results = Receive-Job $Computer.CheckJob
            $Computer."Checked PW Last Set" = ((Get-Date) - $results.PasswordLastSet).Days
            $Computer."Checked Last Logon" = ((Get-Date) - $results.LastLogonDate).Days
            Remove-Job $Computer.CheckJob
        }
    }
    Update-DataGridView -DataGridView $datagridview1 -Item $global:Computers
    if ('N/A' -notin $global:Computers."Checked PW Last Set")
    {
        Get-Job | Remove-Job -Force
        $buttonOpenExcel.Enabled = $true
        $buttonOpenExcelAndAppend.Enabled = $true
        $buttonClearTable.Enabled = $true
        $buttonStart.Text = 'Start!'
        $buttonStart.Enabled = $true
        $datagridview1.Cursor = 'Default'
        $timerJobs.Stop()
    }
}
The data is imported from Excel and loaded into a DataTable, like so:

Code: Select all

$PCList = New-Object System.Data.DataTable
$PCList.Columns.Add("Computer Name")
$PCList.Columns.Add("OU Location")
$PCList.Columns.Add("Password Last Set")
$PCList.Columns.Add("Last Logon TimeStamp")
$PCList.Columns.Add("Checked PW Last Set")
$PCList.Columns.Add("Checked Last Logon")
foreach ($row in $ExcelFile)
{
	$PCList.Rows.Add($row."Computer Name", $row."OU Location", $row."Password Last Set", $row."Last Logon TimeStamp", 'N/A', 'N/A')
}
When debugging, it all seems to be working fine until the point where it is about to retrieve the job - it throws an error about Identity in Get-ADComputer being null:

Code: Select all

ERROR: Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again.
ERROR:     + CategoryInfo          : InvalidData: (:) [Get-ADComputer], ParameterBindingValidationException
ERROR:     + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.GetADComputer
ERROR:     + PSComputerName        : localhost
Anyone have any advise on how to fix this, please?

Thanks!

User avatar
jvierra
Posts: 13792
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Receive-Job error

Post by jvierra » Wed Feb 20, 2019 10:09 pm

Your CSV has an empty row or a row has an empty "computer name'" field.
Why would you use separate jobs for such a simple query? Just run the query or query all computers in one job and retrieve the data on each timer tick. There is no need for separate jobs here since AD will return data as it is available and is usually very fast.

User avatar
SakJaTeda
Posts: 11
Joined: Thu Dec 14, 2017 3:57 pm

Re: Receive-Job error

Post by SakJaTeda » Wed Feb 20, 2019 10:27 pm

Thanks for you reply.

There are definitely no empty rows - I tested on a a file that only has 3 rows and all 3 definitely have all the required fields.

The reason for having separate jobs is that we routinely receive ~10 Excel files, all of which may or may not contain several computer accounts and I intended to have it check the accounts simultaneously to save time. Even though AD is fairly fast for single queries, 10s of them will take some time.

User avatar
jvierra
Posts: 13792
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Receive-Job error

Post by jvierra » Wed Feb 20, 2019 10:30 pm

Jobs for each computer will not be faster. It will be slower. The results of each call for the computer response is available whenever you do a receive-job. Just receive the cob and use the data until the job is complete.

Also, variables in PowerShell do not exist in a job. They must be passed.

help Start-Job -online

User avatar
jvierra
Posts: 13792
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Receive-Job error

Post by jvierra » Thu Feb 21, 2019 12:22 am

If you want to get high performance with PowerShell use a workflow. It runs multi-threaded and can create much better performance than a 100 jobs.

Code: Select all

Workflow GetComputerInfo {
    Param($ComputerList)
    foreach -Parallel -throttlelimit 16 ($computer in $ComputerList){
        Get-ADComputer $computer -Properties PasswordLastSet, LastLogonDate
    }
}
$job = GetComputerInfo -ComputerList $global:computers -AsJob
This will run 16 tasks in parallel and create new tasks as needed. The workflow runs as a job and output from each task is available immediately so "Receive-Job" will get the results on each timer tick. You can do 100 computers in less than about 5 seconds. Jobs will slow down after about 20 are defined. Jobs require a whole PowerShell process to be created. Workflow tasks do not.

User avatar
jvierra
Posts: 13792
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Receive-Job error

Post by jvierra » Thu Feb 21, 2019 12:40 am

The attached example shows how to return data from job and update a DGV at high speed. Run it to see how repsponsive it is. It produces a continuous stream of updates to the DGV with no glitches and without freezing the form.
Attachments
Demo-SimpleDGVJobTracker.psf
(22.73 KiB) Downloaded 24 times

User avatar
jvierra
Posts: 13792
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Receive-Job error

Post by jvierra » Thu Feb 21, 2019 1:05 am

SakJaTeda wrote:
Wed Feb 20, 2019 10:27 pm

The reason for having separate jobs is that we routinely receive ~10 Excel files, all of which may or may not contain several computer accounts and I intended to have it check the accounts simultaneously to save time. Even though AD is fairly fast for single queries, 10s of them will take some time.
I can query 50 computers in AD in about 3 seconds. You will also find that AD throttles you number of requests. It will allow about three and new requests will be delayed until earlier connections are closed. Stacking requests will not improve performance by any measurable amount. You could send requests to different DCs which might give a little improvement.

You can also build a filter that can query for many computers in one call. That would produce the fastest results.

-Filter "Name -eq '$comp1' -or Name -eq '$comp2' -or Name -eq '$comp3'"

This filter can be generated programmatically.

Locked