Solved

Multithreaded Powershell Script

Posted on 2013-01-24
24
940 Views
Last Modified: 2013-01-26
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

0
Comment
Question by:IT_Crowd
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 11
  • 8
  • 4
  • +1
24 Comments
 
LVL 14

Expert Comment

by:athomsfere
ID: 38816114
What error do you get?
0
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38816136
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
 
LVL 40

Expert Comment

by:Subsun
ID: 38816154
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
Free eBook: Backup on AWS

Everything you need to know about backup and disaster recovery with AWS, for FREE!

 
LVL 13

Author Comment

by:IT_Crowd
ID: 38816217
Well, the errors are gone, but it looks like the jobs just stop...

see output file.
output.txt
0
 
LVL 40

Expert Comment

by:Subsun
ID: 38816340
Do you have computers with description StartsWith "-"?
I am getting result like this.. (I have changed the ForegroundColor)  Test
0
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38816380
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
 
LVL 40

Expert Comment

by:Subsun
ID: 38816398
You can test with one computer Get-ADComputer TestServer which has "-" as a first character in description?
0
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38816471
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
 
LVL 40

Expert Comment

by:Subsun
ID: 38816482
Change Get-ADComputer DellE6430U to Get-ADComputer DellE6430U | `
0
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38816548
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
 
LVL 40

Expert Comment

by:Subsun
ID: 38816574
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
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38816597
Yes, though there is a ` after the pipe.
0
 
LVL 40

Expert Comment

by:Subsun
ID: 38816615
Ahh.. replace $_.Name with $args[0] inside the ScriptBlock ..
0
 
LVL 70

Expert Comment

by:Qlemo
ID: 38816617
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
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38819511
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
 
LVL 70

Expert Comment

by:Qlemo
ID: 38819588
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
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38819846
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
 
LVL 70

Expert Comment

by:Qlemo
ID: 38820039
That is impossible. Start-Job is throttling execution if more than X jobs are running, unless at least one is completed again.
0
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38820448
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
 
LVL 40

Accepted Solution

by:
Subsun earned 500 total points
ID: 38820457
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
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38820496
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
 
LVL 40

Expert Comment

by:Subsun
ID: 38820514
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
 
LVL 13

Author Comment

by:IT_Crowd
ID: 38820561
No problem - I was just verifying.  

Thanks!
0
 
LVL 70

Expert Comment

by:Qlemo
ID: 38821912
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

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows the method of using the Resultant Set of Policy Tool to locate Group Policy that applies a particular setting.
Auditing domain password hashes is a commonly overlooked but critical requirement to ensuring secure passwords practices are followed. Methods exist to extract hashes directly for a live domain however this article describes a process to extract u…
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.

738 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question