Multithreaded Powershell Script

Experts

I'm trying to make the following script multithreaded but I dont think the search for A/D computers is working correctly. After all of the jobs start, they all error out right away. The code inside "ScriptBlock" should work, by itself, but I cant seem to get it to work with the extra multithreading code.

Objective: Create a script that searches A/D for computer descriptions that start with a hyphen. If found, it will shutdown a PC.

Here is what I have so far...
import-module ActiveDirectory
Get-ADComputer -Filter * |`
%{ 
    $ScriptBlock = 
    {
        $time = Get-Date
        $dsc = (Get-WmiObject -Class Win32_OperatingSystem -computerName $_.Name -errorAction silentlyContinue);
        if(-not $dsc)
        { 
            write-host $time.Hour$time.Minute The RPC server is unavailable on this computer!
         
        }
        elseif(-not $dsc.description) 
        {
            write-host $time.Hour$time.Minute This computer has no description!
        }
        else
        {
            $chkName = $dsc.description.StartsWith("-");
            if($chkName)
            {
                write-host $time.Hour$time.Minute Initiating FAKE Shutdown of Remote Host $_.Name -ForegroundColor DarkYellow
            }
        }
    }
    # Execute the jobs in parallel
    Start-Job $ScriptBlock         
}

Get-Job

# Wait for it all to complete
While (Get-Job -State "Running")
{
    Start-Sleep 10
}

# Getting the information back from the jobs
Get-Job | Receive-Job

Open in new window

LVL 13
IT_CrowdAsked:
Who is Participating?
 
SubsunCommented:
I know icm have ThrottleLimit of 32 but not sure about Start-Job. I have added a While loop to Throttle jobs, Check and see if it works for you...
import-module ActiveDirectory
Get-ADComputer -Filter * | `
%{
    $ScriptBlock = 
    {
        $time = Get-Date
        $dsc = (Get-WmiObject -Class Win32_OperatingSystem -computerName $args[0] -errorAction silentlyContinue);
        if(-not $dsc)
        { 
            write-host $time.Hour$time.Minute The RPC server is unavailable on this computer!
         
        }
        elseif(-not $dsc.description) 
        {
            write-host $time.Hour$time.Minute This computer has no description!
        }
        else
        {
            $chkName = $dsc.description.StartsWith("-");
            if($chkName)
            {
                write-host $time.Hour$time.Minute Initiating FAKE Shutdown of Remote Host $args[0] -ForegroundColor RED
            }
        }
    }
#    Execute the jobs in parallel

while ( (Get-Job -State Running).Count -gt 32) {
   Start-Sleep -Milliseconds 10  
    }  

Start-Job $ScriptBlock -Args $_.Name

Get-Job | Receive-Job
Get-Job -State Completed | ? {! $_.HasMoreData } | Remove-Job
}
Get-job | Wait-Job
Get-Job | Receive-Job
Get-Job -State Completed | Remove-Job

Write-Host "*** Following jobs did not complete ***"
Get-Job

Open in new window

0
 
athomsfereCommented:
What error do you get?
0
 
IT_CrowdAuthor Commented:
Sorry - that would have been helpful!   :P

.....

14 51 The RPC server is unavailable on this computer!
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
14 51 The RPC server is unavailable on this computer!
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
14 51 The RPC server is unavailable on this computer!
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
14 51 The RPC server is unavailable on this computer!
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
14 51 The RPC server is unavailable on this computer!
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
14 51 The RPC server is unavailable on this computer!
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
14 51 The RPC server is unavailable on this computer!
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
14 51 The RPC server is unavailable on this computer!
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
14 51 The RPC server is unavailable on this computer!
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
14 51 The RPC server is unavailable on this computer!

.....
0
Making Bulk Changes to Active Directory

Watch this video to see how easy it is to make mass changes to Active Directory from an external text file without using complicated scripts.

 
SubsunCommented:
Try to pass variable as a argument to ScriptBlock..

import-module ActiveDirectory
Get-ADComputer -Filter * |`
%{ 
    $ScriptBlock = 
    {
        $time = Get-Date
        $dsc = (Get-WmiObject -Class Win32_OperatingSystem -computerName $args[0] -errorAction silentlyContinue);
        if(-not $dsc)
        { 
            write-host $time.Hour$time.Minute The RPC server is unavailable on this computer!
         
        }
        elseif(-not $dsc.description) 
        {
            write-host $time.Hour$time.Minute This computer has no description!
        }
        else
        {
            $chkName = $dsc.description.StartsWith("-");
            if($chkName)
            {
                write-host $time.Hour$time.Minute Initiating FAKE Shutdown of Remote Host $args[0] -ForegroundColor DarkYellow
            }
        }
    }
    # Execute the jobs in parallel
    Start-Job $ScriptBlock -Args $_.Name
}

Get-Job

# Wait for it all to complete
While (Get-Job -State "Running")
{
    Start-Sleep 10
}

# Getting the information back from the jobs
Get-Job | Receive-Job

Open in new window

0
 
IT_CrowdAuthor Commented:
Well, the errors are gone, but it looks like the jobs just stop...

see output file.
output.txt
0
 
SubsunCommented:
Do you have computers with description StartsWith "-"?
I am getting result like this.. (I have changed the ForegroundColor)  Test
0
 
IT_CrowdAuthor Commented:
Nice...well at least you can get it to work. Yeah, we have about 30 machines that have a hyphen in the description  (first character).
0
 
SubsunCommented:
You can test with one computer Get-ADComputer TestServer which has "-" as a first character in description?
0
 
IT_CrowdAuthor Commented:
Hmmm... check this output. It doesn't make sense to me at all.

import-module ActiveDirectory
Get-ADComputer DellE6430U
%{ 
    $ScriptBlock = 
    {
        $time = Get-Date
        $dsc = (Get-WmiObject -Class Win32_OperatingSystem -computerName $_.Name -errorAction silentlyContinue);
        if(-not $dsc)
        { 
            write-host $time.Hour$time.Minute The RPC server is unavailable on this computer!
         
        }
        elseif(-not $dsc.description) 
        {
            write-host $time.Hour$time.Minute This computer has no description!
        }
        else
        {
            $chkName = $dsc.description.StartsWith("+");
            if($chkName)
            {
                write-host $time.Hour$time.Minute Initiating FAKE Shutdown of Remote Host $_.Name -ForegroundColor DarkYellow
            }
        }
    }
    #Execute the jobs in parallel
    Start-Job $ScriptBlock -Args $_.Name   
}

Get-Job

#Wait for it all to complete
While (Get-Job -State "Running")
{
    Start-Sleep 10
}

#Getting the information back from the jobs
Get-Job | Receive-Job

Open in new window

output2.txt
0
 
SubsunCommented:
Change Get-ADComputer DellE6430U to Get-ADComputer DellE6430U | `
0
 
IT_CrowdAuthor Commented:
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    + CategoryInfo          : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 
16 30 The RPC server is unavailable on this computer!
0
 
SubsunCommented:
Is this what you running?
import-module ActiveDirectory
Get-ADComputer DellE6430U | % { 
    $ScriptBlock = 
    {
        $time = Get-Date
        $dsc = (Get-WmiObject -Class Win32_OperatingSystem -computerName $_.Name -errorAction silentlyContinue);
        if(-not $dsc)
        { 
            write-host $time.Hour$time.Minute The RPC server is unavailable on this computer!
         
        }
        elseif(-not $dsc.description) 
        {
            write-host $time.Hour$time.Minute This computer has no description!
        }
        else
        {
            $chkName = $dsc.description.StartsWith("+");
            if($chkName)
            {
                write-host $time.Hour$time.Minute Initiating FAKE Shutdown of Remote Host $_.Name -ForegroundColor Red
            }
        }
    }
    #Execute the jobs in parallel
    Start-Job $ScriptBlock -Args $_.Name   
}

Get-Job

#Wait for it all to complete
While (Get-Job -State "Running")
{
    Start-Sleep 10
}

#Getting the information back from the jobs
Get-Job | Receive-Job

Open in new window

0
 
IT_CrowdAuthor Commented:
Yes, though there is a ` after the pipe.
0
 
SubsunCommented:
Ahh.. replace $_.Name with $args[0] inside the ScriptBlock ..
0
 
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
Remember you have to use $args[0] inside of the script block, not $_.Name.

And you do not need the backtick after the pipe.
In addition it is not necessary to use a wait loop, wait-job can wait for all, any or a specific job to complete.
import-module ActiveDirectory
Get-ADComputer DellE6430U | % { 
    $ScriptBlock = 
    {
        $time = Get-Date
        $dsc = (Get-WmiObject -Class Win32_OperatingSystem -computerName $args[0] -errorAction silentlyContinue);
        if(-not $dsc)
        { 
            write-host $time.Hour$time.Minute The RPC server is unavailable on this computer!
         
        }
        elseif(-not $dsc.description) 
        {
            write-host $time.Hour$time.Minute This computer has no description!
        }
        else
        {
            $chkName = $dsc.description.StartsWith("+");
            if($chkName)
            {
                write-host $time.Hour$time.Minute Initiating FAKE Shutdown of Remote Host $_.Name -ForegroundColor Red
            }
        }
    }
    #Execute the jobs in parallel
    Start-Job $ScriptBlock -Args $_.Name   
}

Get-Job

#Wait for it all to complete
wait-job

#Getting the information back from the jobs
Get-Job | Receive-Job

Open in new window

0
 
IT_CrowdAuthor Commented:
Well i got the single PC to work, and I have replaced the top line with
Get-ADComputer -Filter * |`

Open in new window


...but now it seems like it runs forever, and eventually Windows complains there is no more memory available. Sounds like its stuck in an infinite loop.   Here is a refresh of the current code I am using.

Thanks for the help!

import-module ActiveDirectory
Get-ADComputer -Filter * |`
%{ 
    $ScriptBlock = 
    {
        $time = Get-Date
        $dsc = (Get-WmiObject -Class Win32_OperatingSystem -computerName $args[0] -errorAction silentlyContinue);
        if(-not $dsc)
        { 
            write-host $time.Hour$time.Minute The RPC server is unavailable on this computer!
         
        }
        elseif(-not $dsc.description) 
        {
            write-host $time.Hour$time.Minute This computer has no description!
        }
        else
        {
            $chkName = $dsc.description.StartsWith("-");
            if($chkName)
            {
                write-host $time.Hour$time.Minute Initiating FAKE Shutdown of Remote Host $args[0] -ForegroundColor RED
            }
        }
    }
#    Execute the jobs in parallel
    Start-Job $ScriptBlock -Args $_.Name  
}

Get-Job

#Wait for it all to complete
While (Get-Job -State "Running")
{
    Start-Sleep 10
}

#Getting the information back from the jobs
Get-Job | Receive-Job

Open in new window

0
 
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
Probably you have a lot of machines. The way you perform above action requires PS to store all process info until you are finished with processing. It is better to send all collected output to screen ASAP, and delete jobs if they are finished (and all output read):
import-module ActiveDirectory
Get-ADComputer -Filter * |
%{ 
    $ScriptBlock = 
    {
        $time = Get-Date
        $dsc = (Get-WmiObject -Class Win32_OperatingSystem -computerName $args[0] -errorAction silentlyContinue);
        if(-not $dsc)
        { 
            write-host $time.Hour$time.Minute The RPC server is unavailable on this computer!
         
        }
        elseif(-not $dsc.description) 
        {
            write-host $time.Hour$time.Minute This computer has no description!
        }
        else
        {
            $chkName = $dsc.description.StartsWith("-");
            if($chkName)
            {
                write-host $time.Hour$time.Minute Initiating FAKE Shutdown of Remote Host $args[0] -ForegroundColor RED
            }
        }
    }
#    Execute the jobs in parallel
    Start-Job $ScriptBlock -Args $_.Name  
    Get-Job | Receive-Job
    Get-Job -State Completed | ? {! $_.HasMoreData } | Remove-Job
}

Wait-Job
Get-Job | Receive-Job
Get-Job -State Completed | Remove-Job

Write-Host "*** Following jobs did not complete ***"
Get-Job

Open in new window

0
 
IT_CrowdAuthor Commented:
Thanks  Qlemo, but all 16GB on my machine filled up again with your new code, and I never got any of my output lines. All I got was...(see attachment)

We have about 500 computers.
output3.txt
0
 
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
That is impossible. Start-Job is throttling execution if more than X jobs are running, unless at least one is completed again.
0
 
IT_CrowdAuthor Commented:
Well I hate to break it to you pal, but it IS happening. Check the screenshot - it eats all of my RAM, and then Windows locks up until I end PowerShell.
Low Memory
The output on the screen continues like this until the RAM fills up:

Id              Name            State      HasMoreData     Location             Command                  
--              ----            -----      -----------     --------             -------                  
1               Job1            Running    True            localhost            ...                      
3               Job3            Running    True            localhost            ...                      
5               Job5            Running    True            localhost            ...                      
7               Job7            Running    True            localhost            ...                      

.... it just continues - I think I saw ID 700 before it started to crash...
0
 
IT_CrowdAuthor Commented:
Thanks subsun, yeah it looks like its working ok. The output is pretty jumbled. Is that because of the multithreading?

1033            Job1033         Running    True            localhost            ...                      
1035            Job1035         Running    True            localhost            ...                      
1037            Job1037         Running    True            localhost            ...                      
1039            Job1039         Running    True            localhost            ...                      
 unavailable1041            Job1041         Running    True            localhost            ...                      
1043            Job1043         Running    True            localhost            ...                      
1045            Job1045         Running    True            localhost            ...                      
1047            Job1047         Running    True            localhost            ...                      
15 24 The 15 24 The 15 24 The RPC1515 24 15 24 The 15 24 The RPC 15 24 The RPC15 24 The 15 24 The  on this computer!
15 2415 241049            Job1049         Running    True            localhost            ...                      
RPC server is unavailable on this computer!
RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
 server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
 24 The RPC server is unavailable on this computer!
The RPC server is unavailable on this computer!
RPC server is unavailable on this computer!
server is unavailable on this computer!
 server is unavailable on this computer!
RPC server is unavailable on this computer!
RPC server is unavailable on this computer!
 The RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
 The RPC server is unavailable on this computer!
1051            Job1051         Running    True            localhost            ...                      
1053            Job1053         Running    True            localhost            ...                      
1055            Job1055         Running    True            localhost            ...                      
1057            Job1057         Running    True            localhost            ...                      
15 24 The RPC server is unavailable on this computer!
15 24 The RPC server is unavailable on this computer!
0
 
SubsunCommented:
Yes.. The results show up as soon as the jobs get completed.. If you want you can Write the result to a log file..
0
 
IT_CrowdAuthor Commented:
No problem - I was just verifying.  

Thanks!
0
 
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
Subsun is correct, there is no throttle limit for Start-Job, I've mixed that up with icm.

Nevertheless, I'm convinced that throttling will only work in combination with the "on-the-fly cleanup" part here, as that frees a lot of memory, and hence a point split is appropriate.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.