Solved

Multithreaded Powershell Script

Posted on 2013-01-24
24
887 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
  • 11
  • 8
  • 4
  • +1
24 Comments
 
LVL 14

Expert Comment

by:athomsfere
Comment Utility
What error do you get?
0
 
LVL 13

Author Comment

by:IT_Crowd
Comment Utility
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
Comment Utility
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
 
LVL 13

Author Comment

by:IT_Crowd
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Change Get-ADComputer DellE6430U to Get-ADComputer DellE6430U | `
0
 
LVL 13

Author Comment

by:IT_Crowd
Comment Utility
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
Comment Utility
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
Comment Utility
Yes, though there is a ` after the pipe.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 40

Expert Comment

by:Subsun
Comment Utility
Ahh.. replace $_.Name with $args[0] inside the ScriptBlock ..
0
 
LVL 68

Expert Comment

by:Qlemo
Comment Utility
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
Comment Utility
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 68

Expert Comment

by:Qlemo
Comment Utility
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
Comment Utility
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 68

Expert Comment

by:Qlemo
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
No problem - I was just verifying.  

Thanks!
0
 
LVL 68

Expert Comment

by:Qlemo
Comment Utility
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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

In this article, we will see the basic design consideration while designing a Multi-tenant web application in a simple manner. Though, many frameworks are available in the market to develop a multi - tenant application, but do they provide data, cod…
This article will help you understand what HashTables are and how to use them in PowerShell.
Learn the basics of strings in Python: declaration, operations, indices, and slicing. Strings are declared with quotations; for example: s = "string": Strings are immutable.: Strings may be concatenated or multiplied using the addition and multiplic…
The viewer will learn how to count occurrences of each item in an array.

762 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

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now