How do I run my PowerShell scripts in parallel without using Jobs?How do I remotely issue a CLI command to thousands of Windows domain computers at once?How to retrieve data from powershell runspace jobHow to run Azure cmdlets in background?How to run PowerShell/PowerCli scripts on esxi 4?Method to integrate Powershell scripts with non-Windows workflow?Remote location management copy and install large software updates to 50 LANExecute Powershell Add-Computer remotely via Invoke-CommandPowershell Workflow ParallelWindows Remote Management Over Untrusted DomainsHow can I run this powershell script in parallel?Powershell DSC File copy - Workgroup machinesWhy does Get-Winevent in parallel workflow wants to use PSRemoting?Remote Powershell for non-admin user in non-domain pc

Trigonometry substitution issue with sign

Endgame puzzle: How to avoid stalemate and win?

What is the closest airport to the center of the city it serves?

Is it normal for gliders not to have attitude indicators?

How to deal with employer who keeps me at work after working hours

Any examples of liquids volatile at room temp but non-flammable?

My first c++ game (snake console game)

Why do these characters still seem to be the same age after the events of Endgame?

How does the reduce() method work in Java 8?

History of the kernel of a homomorphism?

Is any special diet an effective treatment of autism?

Formatting Datetime.now()

Will 700 more planes a day fly because of the Heathrow expansion?

What was Bran's plan to kill the Night King?

Would you use "llamarse" for an animal's name?

Is there an age requirement to play in Adventurers League?

Where to draw the line between quantum mechanics theory and its interpretation(s)?

Is disk brake effectiveness mitigated by tyres losing traction under strong braking?

Why didn't this character get a funeral at the end of Avengers: Endgame?

Why symmetry transformations have to commute with Hamiltonian?

Are sleeping system R-ratings additive?

Can I use a Cat5e cable with an RJ45 and Cat6 port?

Mug and wireframe entirely disappeared

Are there terms in German for different skull shapes?



How do I run my PowerShell scripts in parallel without using Jobs?


How do I remotely issue a CLI command to thousands of Windows domain computers at once?How to retrieve data from powershell runspace jobHow to run Azure cmdlets in background?How to run PowerShell/PowerCli scripts on esxi 4?Method to integrate Powershell scripts with non-Windows workflow?Remote location management copy and install large software updates to 50 LANExecute Powershell Add-Computer remotely via Invoke-CommandPowershell Workflow ParallelWindows Remote Management Over Untrusted DomainsHow can I run this powershell script in parallel?Powershell DSC File copy - Workgroup machinesWhy does Get-Winevent in parallel workflow wants to use PSRemoting?Remote Powershell for non-admin user in non-domain pc






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








28















If I have a script that I need to run against multiple computers, or with multiple different arguments, how can I execute it in parallel, without having to incur the overhead of spawning a new PSJob with Start-Job?



As an example, I want to re-sync the time on all domain members, like so:



$computers = Get-ADComputer -filter * |Select-Object -ExpandProperty dnsHostName
$creds = Get-Credential domainuser
foreach($computer in $computers)

$session = New-PSSession -ComputerName $computer -Credential $creds
Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover



But I don't want to wait for each PSSession to connect and invoke the command. How can this be done in parallel, without Jobs?










share|improve this question






























    28















    If I have a script that I need to run against multiple computers, or with multiple different arguments, how can I execute it in parallel, without having to incur the overhead of spawning a new PSJob with Start-Job?



    As an example, I want to re-sync the time on all domain members, like so:



    $computers = Get-ADComputer -filter * |Select-Object -ExpandProperty dnsHostName
    $creds = Get-Credential domainuser
    foreach($computer in $computers)

    $session = New-PSSession -ComputerName $computer -Credential $creds
    Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover



    But I don't want to wait for each PSSession to connect and invoke the command. How can this be done in parallel, without Jobs?










    share|improve this question


























      28












      28








      28


      15






      If I have a script that I need to run against multiple computers, or with multiple different arguments, how can I execute it in parallel, without having to incur the overhead of spawning a new PSJob with Start-Job?



      As an example, I want to re-sync the time on all domain members, like so:



      $computers = Get-ADComputer -filter * |Select-Object -ExpandProperty dnsHostName
      $creds = Get-Credential domainuser
      foreach($computer in $computers)

      $session = New-PSSession -ComputerName $computer -Credential $creds
      Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover



      But I don't want to wait for each PSSession to connect and invoke the command. How can this be done in parallel, without Jobs?










      share|improve this question
















      If I have a script that I need to run against multiple computers, or with multiple different arguments, how can I execute it in parallel, without having to incur the overhead of spawning a new PSJob with Start-Job?



      As an example, I want to re-sync the time on all domain members, like so:



      $computers = Get-ADComputer -filter * |Select-Object -ExpandProperty dnsHostName
      $creds = Get-Credential domainuser
      foreach($computer in $computers)

      $session = New-PSSession -ComputerName $computer -Credential $creds
      Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover



      But I don't want to wait for each PSSession to connect and invoke the command. How can this be done in parallel, without Jobs?







      performance powershell automation






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Apr 13 '17 at 12:14









      Community

      1




      1










      asked Sep 6 '14 at 13:56









      Mathias R. JessenMathias R. Jessen

      22.8k35189




      22.8k35189




















          4 Answers
          4






          active

          oldest

          votes


















          50














          Update - While this answer explains the process and mechanics of PowerShell runspaces and how they can help you multi-thread non-sequential workloads, fellow PowerShell aficionado Warren 'Cookie Monster' F has gone the extra mile and incorporated these same concepts into a single tool called Invoke-Parallel - it does what I describe below, and he has since expanded it with optional switches for logging and prepared session state including imported modules, really cool stuff - I strongly recommend you check it out before building you own shiny solution!




          With Parallel Runspace execution:



          Reducing inescapable waiting time



          In the original specific case, the executable invoked has a /nowait option which prevents blocking the invoking thread while the job (in this case, time re-synchronization) finishes on its own.



          This greatly reduces the overall execution time from the issuers perspective, but connecting to each machine is still done in sequential order. Connecting to thousands of clients in sequence may take a long time depending on the number of machines that are for one reason or another inaccessible, due to an accumulation of timeout waits.



          To get around having to queue up all subsequent connections in case of a single or a few consecutive timeouts, we can dispatch the job of connecting and invoking commands to separate PowerShell Runspaces, executing in parallel.



          What is a Runspace?



          A Runspace is the virtual container in which your powershell code executes, and represents/holds the Environment from the perspective of a PowerShell statement/command.



          In broad terms, 1 Runspace = 1 thread of execution, so all we need to "multi-thread" our PowerShell script is a collection of Runspaces that can then in turn execute in parallel.



          Like the original problem, the job of invoking commands multiple runspaces can be broken down into:



          1. Creating a RunspacePool

          2. Assigning a PowerShell script or an equivalent piece of executable code to the RunspacePool

          3. Invoke the code asynchronously (ie. not having to wait for the code to return)

          RunspacePool template



          PowerShell has a type accelerator called [RunspaceFactory] that will assist us in the creation of runspace components - let's put it to work



          1. Create a RunspacePool and Open() it:



          $RunspacePool = [runspacefactory]::CreateRunspacePool(1,8)
          $RunspacePool.Open()


          The two arguments passed to CreateRunspacePool(), 1 and 8 is the minimum and maximum number of runspaces allowed to execute at any given time, giving us an effective maximum degree of parallelism of 8.



          2. Create an instance of PowerShell, attach some executable code to it and assign it to our RunspacePool:



          An instance of PowerShell is not the same as the powershell.exe process (which is really a Host application), but an internal runtime object representing the PowerShell code to execute. We can use the [powershell] type accelerator to create a new PowerShell instance within PowerShell:



          $Code = 
          param($Credentials,$ComputerName)
          $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
          Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover

          $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument("computer1.domain.tld")
          $PSinstance.RunspacePool = $RunspacePool


          3. Invoke the PowerShell instance asynchronously using APM:



          Using what is known in .NET development terminology as the Asynchronous Programming Model, we can split the invocation of a command into a Begin method, for giving a "green light" to execute the code, and an End method to collect the results. Since we in this case are not really interested in any feedback (we don't wait for the output from w32tm anyways), we can make due by simply calling the first method



          $PSinstance.BeginInvoke()



          Wrapping it up in a RunspacePool



          Using the above technique, we can wrap the sequential iterations of creating new connections and invoking the remote command in a parallel execution flow:



          $ComputerNames = Get-ADComputer -filter * -Properties dnsHostName |select -Expand dnsHostName

          $Code =
          param($Credentials,$ComputerName)
          $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
          Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover


          $creds = Get-Credential domainuser

          $rsPool = [runspacefactory]::CreateRunspacePool(1,8)
          $rsPool.Open()

          foreach($ComputerName in $ComputerNames)

          $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument($ComputerName)
          $PSinstance.RunspacePool = $rsPool
          $PSinstance.BeginInvoke()



          Assuming that the CPU has the capacity to execute all 8 runspaces at once, we should be able to see that the execution time is greatly reduced, but at the cost of readability of the script due to the rather "advanced" methods used.




          Determining the optimum degree of parallism:



          We could easily create a RunspacePool that allows for the execution of a 100 runspaces at the same time:



          [runspacefactory]::CreateRunspacePool(1,100)


          But at the end of the day, it all comes down to how many units of execution our local CPU can handle. In other words, as long as your code is executing, it does not make sense to allow more runspaces than you have logical processors to dispatch execution of code to.



          Thanks to WMI, this threshold is fairly easy to determine:



          $NumberOfLogicalProcessor = (Get-WmiObject Win32_Processor).NumberOfLogicalProcessors
          [runspacefactory]::CreateRunspacePool(1,$NumberOfLogicalProcessors)


          If, on the other hand, the code you are executing itself incurs a lot of wait time due to external factors like network latency, you can still benefit from running more simultanous runspaces than you have logical processors, so you'd probably want to test of range possible maximum runspaces to find break-even:



          foreach($n in ($NumberOfLogicalProcessors..($NumberOfLogicalProcessors*3)))

          Write-Host "$n: " -NoNewLine
          (Measure-Command
          $Computers = Get-ADComputer -filter * -Properties dnsHostName ).TotalSeconds






          share|improve this answer




















          • 4





            If the jobs are waiting on the network, e.g. you are running PowerShell commands on remote computers, you could easily go far over the number of logical processors before you hit any CPU bottleneck.

            – Michael Hampton
            Sep 6 '14 at 14:00












          • Well, that is true. Changed it a bit and provided an example for testing

            – Mathias R. Jessen
            Sep 6 '14 at 14:09











          • How to make sure all the job is done at the end? (May need to something after all the script blocks finished)

            – sjzls
            Nov 18 '14 at 18:04











          • @NickW Great question. I'll do a follow-up on tracking the jobs and "harvesting" potential output later today, stay tuned

            – Mathias R. Jessen
            Nov 19 '14 at 12:23






          • 1





            @MathiasR.Jessen Very well-written answer! Looking forward to the update.

            – Signal15
            Dec 3 '14 at 16:55


















          5














          Adding to this discussion, what's missing is a collector to store the data that is created from the runspace, and a variable to check the status of the runspace, i.e. is it completed or not.



          #Add an collector object that will store the data
          $Object = New-Object 'System.Management.Automation.PSDataCollection[psobject]'

          #Create a variable to check the status
          $Handle = $PSinstance.BeginInvoke($Object,$Object)

          #So if you want to check the status simply type:
          $Handle

          #If you want to see the data collected, type:
          $Object





          share|improve this answer
































            3














            Check out PoshRSJob. It provides same/similar functions as the native *-Job functions, but uses Runspaces which tend to be much quicker and more responsive than the standard Powershell jobs.






            share|improve this answer






























              1














              @mathias-r-jessen has a great answer though there are details I'd like to add.



              Max Threads



              In theory threads should be limited by the number of system processors. However, while testing AsyncTcpScan I achieved far better performance by choosing a much larger value for MaxThreads. Thus why that module has a -MaxThreads input parameter. Keep in mind that allocating too many threads will hinder performance.



              Returning Data



              Getting data back from the ScriptBlock is tricky. I've updated the OP code and integrated it into what was used for AsyncTcpScan.




              WARNING: I wasn't able to test the following code. I made some changes
              to the OP script based on my experience working with the Active
              Directory cmdlets.




              # Script to run in each thread.
              [System.Management.Automation.ScriptBlock]$ScriptBlock =

              $result = New-Object PSObject -Property @ 'Computer' = $args[0];
              'Success' = $false;

              try
              $session = New-PSSession -ComputerName $args[0] -Credential $args[1]
              Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover
              Disconnect-PSSession -Session $session
              $result.Success = $true
              catch



              return $result

              # End Scriptblock

              function Invoke-AsyncJob

              [CmdletBinding()]
              param(
              [parameter(Mandatory=$true)]
              [System.Management.Automation.PSCredential]
              # Credential object to login to remote systems
              $Credentials
              )

              Import-Module ActiveDirectory

              $Results = @()

              $AllJobs = New-Object System.Collections.ArrayList

              $AllDomainComputers = Get-ADComputer -Filter * -Properties dnsHostName

              $HostRunspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(2,10,$Host)

              $HostRunspacePool.Open()

              foreach($DomainComputer in $AllDomainComputers)
              Out-Null


              $ProcessingJobs = $true

              Do

              $CompletedJobs = $AllJobs While ($ProcessingJobs)

              $HostRunspacePool.Close()
              $HostRunspacePool.Dispose()

              return $Results

              # End function Invoke-AsyncJob





              share|improve this answer

























                Your Answer








                StackExchange.ready(function()
                var channelOptions =
                tags: "".split(" "),
                id: "2"
                ;
                initTagRenderer("".split(" "), "".split(" "), channelOptions);

                StackExchange.using("externalEditor", function()
                // Have to fire editor after snippets, if snippets enabled
                if (StackExchange.settings.snippets.snippetsEnabled)
                StackExchange.using("snippets", function()
                createEditor();
                );

                else
                createEditor();

                );

                function createEditor()
                StackExchange.prepareEditor(
                heartbeatType: 'answer',
                autoActivateHeartbeat: false,
                convertImagesToLinks: true,
                noModals: true,
                showLowRepImageUploadWarning: true,
                reputationToPostImages: 10,
                bindNavPrevention: true,
                postfix: "",
                imageUploader:
                brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                allowUrls: true
                ,
                onDemand: true,
                discardSelector: ".discard-answer"
                ,immediatelyShowMarkdownHelp:true
                );



                );













                draft saved

                draft discarded


















                StackExchange.ready(
                function ()
                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fserverfault.com%2fquestions%2f626711%2fhow-do-i-run-my-powershell-scripts-in-parallel-without-using-jobs%23new-answer', 'question_page');

                );

                Post as a guest















                Required, but never shown

























                4 Answers
                4






                active

                oldest

                votes








                4 Answers
                4






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes









                50














                Update - While this answer explains the process and mechanics of PowerShell runspaces and how they can help you multi-thread non-sequential workloads, fellow PowerShell aficionado Warren 'Cookie Monster' F has gone the extra mile and incorporated these same concepts into a single tool called Invoke-Parallel - it does what I describe below, and he has since expanded it with optional switches for logging and prepared session state including imported modules, really cool stuff - I strongly recommend you check it out before building you own shiny solution!




                With Parallel Runspace execution:



                Reducing inescapable waiting time



                In the original specific case, the executable invoked has a /nowait option which prevents blocking the invoking thread while the job (in this case, time re-synchronization) finishes on its own.



                This greatly reduces the overall execution time from the issuers perspective, but connecting to each machine is still done in sequential order. Connecting to thousands of clients in sequence may take a long time depending on the number of machines that are for one reason or another inaccessible, due to an accumulation of timeout waits.



                To get around having to queue up all subsequent connections in case of a single or a few consecutive timeouts, we can dispatch the job of connecting and invoking commands to separate PowerShell Runspaces, executing in parallel.



                What is a Runspace?



                A Runspace is the virtual container in which your powershell code executes, and represents/holds the Environment from the perspective of a PowerShell statement/command.



                In broad terms, 1 Runspace = 1 thread of execution, so all we need to "multi-thread" our PowerShell script is a collection of Runspaces that can then in turn execute in parallel.



                Like the original problem, the job of invoking commands multiple runspaces can be broken down into:



                1. Creating a RunspacePool

                2. Assigning a PowerShell script or an equivalent piece of executable code to the RunspacePool

                3. Invoke the code asynchronously (ie. not having to wait for the code to return)

                RunspacePool template



                PowerShell has a type accelerator called [RunspaceFactory] that will assist us in the creation of runspace components - let's put it to work



                1. Create a RunspacePool and Open() it:



                $RunspacePool = [runspacefactory]::CreateRunspacePool(1,8)
                $RunspacePool.Open()


                The two arguments passed to CreateRunspacePool(), 1 and 8 is the minimum and maximum number of runspaces allowed to execute at any given time, giving us an effective maximum degree of parallelism of 8.



                2. Create an instance of PowerShell, attach some executable code to it and assign it to our RunspacePool:



                An instance of PowerShell is not the same as the powershell.exe process (which is really a Host application), but an internal runtime object representing the PowerShell code to execute. We can use the [powershell] type accelerator to create a new PowerShell instance within PowerShell:



                $Code = 
                param($Credentials,$ComputerName)
                $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
                Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover

                $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument("computer1.domain.tld")
                $PSinstance.RunspacePool = $RunspacePool


                3. Invoke the PowerShell instance asynchronously using APM:



                Using what is known in .NET development terminology as the Asynchronous Programming Model, we can split the invocation of a command into a Begin method, for giving a "green light" to execute the code, and an End method to collect the results. Since we in this case are not really interested in any feedback (we don't wait for the output from w32tm anyways), we can make due by simply calling the first method



                $PSinstance.BeginInvoke()



                Wrapping it up in a RunspacePool



                Using the above technique, we can wrap the sequential iterations of creating new connections and invoking the remote command in a parallel execution flow:



                $ComputerNames = Get-ADComputer -filter * -Properties dnsHostName |select -Expand dnsHostName

                $Code =
                param($Credentials,$ComputerName)
                $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
                Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover


                $creds = Get-Credential domainuser

                $rsPool = [runspacefactory]::CreateRunspacePool(1,8)
                $rsPool.Open()

                foreach($ComputerName in $ComputerNames)

                $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument($ComputerName)
                $PSinstance.RunspacePool = $rsPool
                $PSinstance.BeginInvoke()



                Assuming that the CPU has the capacity to execute all 8 runspaces at once, we should be able to see that the execution time is greatly reduced, but at the cost of readability of the script due to the rather "advanced" methods used.




                Determining the optimum degree of parallism:



                We could easily create a RunspacePool that allows for the execution of a 100 runspaces at the same time:



                [runspacefactory]::CreateRunspacePool(1,100)


                But at the end of the day, it all comes down to how many units of execution our local CPU can handle. In other words, as long as your code is executing, it does not make sense to allow more runspaces than you have logical processors to dispatch execution of code to.



                Thanks to WMI, this threshold is fairly easy to determine:



                $NumberOfLogicalProcessor = (Get-WmiObject Win32_Processor).NumberOfLogicalProcessors
                [runspacefactory]::CreateRunspacePool(1,$NumberOfLogicalProcessors)


                If, on the other hand, the code you are executing itself incurs a lot of wait time due to external factors like network latency, you can still benefit from running more simultanous runspaces than you have logical processors, so you'd probably want to test of range possible maximum runspaces to find break-even:



                foreach($n in ($NumberOfLogicalProcessors..($NumberOfLogicalProcessors*3)))

                Write-Host "$n: " -NoNewLine
                (Measure-Command
                $Computers = Get-ADComputer -filter * -Properties dnsHostName ).TotalSeconds






                share|improve this answer




















                • 4





                  If the jobs are waiting on the network, e.g. you are running PowerShell commands on remote computers, you could easily go far over the number of logical processors before you hit any CPU bottleneck.

                  – Michael Hampton
                  Sep 6 '14 at 14:00












                • Well, that is true. Changed it a bit and provided an example for testing

                  – Mathias R. Jessen
                  Sep 6 '14 at 14:09











                • How to make sure all the job is done at the end? (May need to something after all the script blocks finished)

                  – sjzls
                  Nov 18 '14 at 18:04











                • @NickW Great question. I'll do a follow-up on tracking the jobs and "harvesting" potential output later today, stay tuned

                  – Mathias R. Jessen
                  Nov 19 '14 at 12:23






                • 1





                  @MathiasR.Jessen Very well-written answer! Looking forward to the update.

                  – Signal15
                  Dec 3 '14 at 16:55















                50














                Update - While this answer explains the process and mechanics of PowerShell runspaces and how they can help you multi-thread non-sequential workloads, fellow PowerShell aficionado Warren 'Cookie Monster' F has gone the extra mile and incorporated these same concepts into a single tool called Invoke-Parallel - it does what I describe below, and he has since expanded it with optional switches for logging and prepared session state including imported modules, really cool stuff - I strongly recommend you check it out before building you own shiny solution!




                With Parallel Runspace execution:



                Reducing inescapable waiting time



                In the original specific case, the executable invoked has a /nowait option which prevents blocking the invoking thread while the job (in this case, time re-synchronization) finishes on its own.



                This greatly reduces the overall execution time from the issuers perspective, but connecting to each machine is still done in sequential order. Connecting to thousands of clients in sequence may take a long time depending on the number of machines that are for one reason or another inaccessible, due to an accumulation of timeout waits.



                To get around having to queue up all subsequent connections in case of a single or a few consecutive timeouts, we can dispatch the job of connecting and invoking commands to separate PowerShell Runspaces, executing in parallel.



                What is a Runspace?



                A Runspace is the virtual container in which your powershell code executes, and represents/holds the Environment from the perspective of a PowerShell statement/command.



                In broad terms, 1 Runspace = 1 thread of execution, so all we need to "multi-thread" our PowerShell script is a collection of Runspaces that can then in turn execute in parallel.



                Like the original problem, the job of invoking commands multiple runspaces can be broken down into:



                1. Creating a RunspacePool

                2. Assigning a PowerShell script or an equivalent piece of executable code to the RunspacePool

                3. Invoke the code asynchronously (ie. not having to wait for the code to return)

                RunspacePool template



                PowerShell has a type accelerator called [RunspaceFactory] that will assist us in the creation of runspace components - let's put it to work



                1. Create a RunspacePool and Open() it:



                $RunspacePool = [runspacefactory]::CreateRunspacePool(1,8)
                $RunspacePool.Open()


                The two arguments passed to CreateRunspacePool(), 1 and 8 is the minimum and maximum number of runspaces allowed to execute at any given time, giving us an effective maximum degree of parallelism of 8.



                2. Create an instance of PowerShell, attach some executable code to it and assign it to our RunspacePool:



                An instance of PowerShell is not the same as the powershell.exe process (which is really a Host application), but an internal runtime object representing the PowerShell code to execute. We can use the [powershell] type accelerator to create a new PowerShell instance within PowerShell:



                $Code = 
                param($Credentials,$ComputerName)
                $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
                Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover

                $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument("computer1.domain.tld")
                $PSinstance.RunspacePool = $RunspacePool


                3. Invoke the PowerShell instance asynchronously using APM:



                Using what is known in .NET development terminology as the Asynchronous Programming Model, we can split the invocation of a command into a Begin method, for giving a "green light" to execute the code, and an End method to collect the results. Since we in this case are not really interested in any feedback (we don't wait for the output from w32tm anyways), we can make due by simply calling the first method



                $PSinstance.BeginInvoke()



                Wrapping it up in a RunspacePool



                Using the above technique, we can wrap the sequential iterations of creating new connections and invoking the remote command in a parallel execution flow:



                $ComputerNames = Get-ADComputer -filter * -Properties dnsHostName |select -Expand dnsHostName

                $Code =
                param($Credentials,$ComputerName)
                $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
                Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover


                $creds = Get-Credential domainuser

                $rsPool = [runspacefactory]::CreateRunspacePool(1,8)
                $rsPool.Open()

                foreach($ComputerName in $ComputerNames)

                $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument($ComputerName)
                $PSinstance.RunspacePool = $rsPool
                $PSinstance.BeginInvoke()



                Assuming that the CPU has the capacity to execute all 8 runspaces at once, we should be able to see that the execution time is greatly reduced, but at the cost of readability of the script due to the rather "advanced" methods used.




                Determining the optimum degree of parallism:



                We could easily create a RunspacePool that allows for the execution of a 100 runspaces at the same time:



                [runspacefactory]::CreateRunspacePool(1,100)


                But at the end of the day, it all comes down to how many units of execution our local CPU can handle. In other words, as long as your code is executing, it does not make sense to allow more runspaces than you have logical processors to dispatch execution of code to.



                Thanks to WMI, this threshold is fairly easy to determine:



                $NumberOfLogicalProcessor = (Get-WmiObject Win32_Processor).NumberOfLogicalProcessors
                [runspacefactory]::CreateRunspacePool(1,$NumberOfLogicalProcessors)


                If, on the other hand, the code you are executing itself incurs a lot of wait time due to external factors like network latency, you can still benefit from running more simultanous runspaces than you have logical processors, so you'd probably want to test of range possible maximum runspaces to find break-even:



                foreach($n in ($NumberOfLogicalProcessors..($NumberOfLogicalProcessors*3)))

                Write-Host "$n: " -NoNewLine
                (Measure-Command
                $Computers = Get-ADComputer -filter * -Properties dnsHostName ).TotalSeconds






                share|improve this answer




















                • 4





                  If the jobs are waiting on the network, e.g. you are running PowerShell commands on remote computers, you could easily go far over the number of logical processors before you hit any CPU bottleneck.

                  – Michael Hampton
                  Sep 6 '14 at 14:00












                • Well, that is true. Changed it a bit and provided an example for testing

                  – Mathias R. Jessen
                  Sep 6 '14 at 14:09











                • How to make sure all the job is done at the end? (May need to something after all the script blocks finished)

                  – sjzls
                  Nov 18 '14 at 18:04











                • @NickW Great question. I'll do a follow-up on tracking the jobs and "harvesting" potential output later today, stay tuned

                  – Mathias R. Jessen
                  Nov 19 '14 at 12:23






                • 1





                  @MathiasR.Jessen Very well-written answer! Looking forward to the update.

                  – Signal15
                  Dec 3 '14 at 16:55













                50












                50








                50







                Update - While this answer explains the process and mechanics of PowerShell runspaces and how they can help you multi-thread non-sequential workloads, fellow PowerShell aficionado Warren 'Cookie Monster' F has gone the extra mile and incorporated these same concepts into a single tool called Invoke-Parallel - it does what I describe below, and he has since expanded it with optional switches for logging and prepared session state including imported modules, really cool stuff - I strongly recommend you check it out before building you own shiny solution!




                With Parallel Runspace execution:



                Reducing inescapable waiting time



                In the original specific case, the executable invoked has a /nowait option which prevents blocking the invoking thread while the job (in this case, time re-synchronization) finishes on its own.



                This greatly reduces the overall execution time from the issuers perspective, but connecting to each machine is still done in sequential order. Connecting to thousands of clients in sequence may take a long time depending on the number of machines that are for one reason or another inaccessible, due to an accumulation of timeout waits.



                To get around having to queue up all subsequent connections in case of a single or a few consecutive timeouts, we can dispatch the job of connecting and invoking commands to separate PowerShell Runspaces, executing in parallel.



                What is a Runspace?



                A Runspace is the virtual container in which your powershell code executes, and represents/holds the Environment from the perspective of a PowerShell statement/command.



                In broad terms, 1 Runspace = 1 thread of execution, so all we need to "multi-thread" our PowerShell script is a collection of Runspaces that can then in turn execute in parallel.



                Like the original problem, the job of invoking commands multiple runspaces can be broken down into:



                1. Creating a RunspacePool

                2. Assigning a PowerShell script or an equivalent piece of executable code to the RunspacePool

                3. Invoke the code asynchronously (ie. not having to wait for the code to return)

                RunspacePool template



                PowerShell has a type accelerator called [RunspaceFactory] that will assist us in the creation of runspace components - let's put it to work



                1. Create a RunspacePool and Open() it:



                $RunspacePool = [runspacefactory]::CreateRunspacePool(1,8)
                $RunspacePool.Open()


                The two arguments passed to CreateRunspacePool(), 1 and 8 is the minimum and maximum number of runspaces allowed to execute at any given time, giving us an effective maximum degree of parallelism of 8.



                2. Create an instance of PowerShell, attach some executable code to it and assign it to our RunspacePool:



                An instance of PowerShell is not the same as the powershell.exe process (which is really a Host application), but an internal runtime object representing the PowerShell code to execute. We can use the [powershell] type accelerator to create a new PowerShell instance within PowerShell:



                $Code = 
                param($Credentials,$ComputerName)
                $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
                Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover

                $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument("computer1.domain.tld")
                $PSinstance.RunspacePool = $RunspacePool


                3. Invoke the PowerShell instance asynchronously using APM:



                Using what is known in .NET development terminology as the Asynchronous Programming Model, we can split the invocation of a command into a Begin method, for giving a "green light" to execute the code, and an End method to collect the results. Since we in this case are not really interested in any feedback (we don't wait for the output from w32tm anyways), we can make due by simply calling the first method



                $PSinstance.BeginInvoke()



                Wrapping it up in a RunspacePool



                Using the above technique, we can wrap the sequential iterations of creating new connections and invoking the remote command in a parallel execution flow:



                $ComputerNames = Get-ADComputer -filter * -Properties dnsHostName |select -Expand dnsHostName

                $Code =
                param($Credentials,$ComputerName)
                $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
                Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover


                $creds = Get-Credential domainuser

                $rsPool = [runspacefactory]::CreateRunspacePool(1,8)
                $rsPool.Open()

                foreach($ComputerName in $ComputerNames)

                $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument($ComputerName)
                $PSinstance.RunspacePool = $rsPool
                $PSinstance.BeginInvoke()



                Assuming that the CPU has the capacity to execute all 8 runspaces at once, we should be able to see that the execution time is greatly reduced, but at the cost of readability of the script due to the rather "advanced" methods used.




                Determining the optimum degree of parallism:



                We could easily create a RunspacePool that allows for the execution of a 100 runspaces at the same time:



                [runspacefactory]::CreateRunspacePool(1,100)


                But at the end of the day, it all comes down to how many units of execution our local CPU can handle. In other words, as long as your code is executing, it does not make sense to allow more runspaces than you have logical processors to dispatch execution of code to.



                Thanks to WMI, this threshold is fairly easy to determine:



                $NumberOfLogicalProcessor = (Get-WmiObject Win32_Processor).NumberOfLogicalProcessors
                [runspacefactory]::CreateRunspacePool(1,$NumberOfLogicalProcessors)


                If, on the other hand, the code you are executing itself incurs a lot of wait time due to external factors like network latency, you can still benefit from running more simultanous runspaces than you have logical processors, so you'd probably want to test of range possible maximum runspaces to find break-even:



                foreach($n in ($NumberOfLogicalProcessors..($NumberOfLogicalProcessors*3)))

                Write-Host "$n: " -NoNewLine
                (Measure-Command
                $Computers = Get-ADComputer -filter * -Properties dnsHostName ).TotalSeconds






                share|improve this answer















                Update - While this answer explains the process and mechanics of PowerShell runspaces and how they can help you multi-thread non-sequential workloads, fellow PowerShell aficionado Warren 'Cookie Monster' F has gone the extra mile and incorporated these same concepts into a single tool called Invoke-Parallel - it does what I describe below, and he has since expanded it with optional switches for logging and prepared session state including imported modules, really cool stuff - I strongly recommend you check it out before building you own shiny solution!




                With Parallel Runspace execution:



                Reducing inescapable waiting time



                In the original specific case, the executable invoked has a /nowait option which prevents blocking the invoking thread while the job (in this case, time re-synchronization) finishes on its own.



                This greatly reduces the overall execution time from the issuers perspective, but connecting to each machine is still done in sequential order. Connecting to thousands of clients in sequence may take a long time depending on the number of machines that are for one reason or another inaccessible, due to an accumulation of timeout waits.



                To get around having to queue up all subsequent connections in case of a single or a few consecutive timeouts, we can dispatch the job of connecting and invoking commands to separate PowerShell Runspaces, executing in parallel.



                What is a Runspace?



                A Runspace is the virtual container in which your powershell code executes, and represents/holds the Environment from the perspective of a PowerShell statement/command.



                In broad terms, 1 Runspace = 1 thread of execution, so all we need to "multi-thread" our PowerShell script is a collection of Runspaces that can then in turn execute in parallel.



                Like the original problem, the job of invoking commands multiple runspaces can be broken down into:



                1. Creating a RunspacePool

                2. Assigning a PowerShell script or an equivalent piece of executable code to the RunspacePool

                3. Invoke the code asynchronously (ie. not having to wait for the code to return)

                RunspacePool template



                PowerShell has a type accelerator called [RunspaceFactory] that will assist us in the creation of runspace components - let's put it to work



                1. Create a RunspacePool and Open() it:



                $RunspacePool = [runspacefactory]::CreateRunspacePool(1,8)
                $RunspacePool.Open()


                The two arguments passed to CreateRunspacePool(), 1 and 8 is the minimum and maximum number of runspaces allowed to execute at any given time, giving us an effective maximum degree of parallelism of 8.



                2. Create an instance of PowerShell, attach some executable code to it and assign it to our RunspacePool:



                An instance of PowerShell is not the same as the powershell.exe process (which is really a Host application), but an internal runtime object representing the PowerShell code to execute. We can use the [powershell] type accelerator to create a new PowerShell instance within PowerShell:



                $Code = 
                param($Credentials,$ComputerName)
                $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
                Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover

                $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument("computer1.domain.tld")
                $PSinstance.RunspacePool = $RunspacePool


                3. Invoke the PowerShell instance asynchronously using APM:



                Using what is known in .NET development terminology as the Asynchronous Programming Model, we can split the invocation of a command into a Begin method, for giving a "green light" to execute the code, and an End method to collect the results. Since we in this case are not really interested in any feedback (we don't wait for the output from w32tm anyways), we can make due by simply calling the first method



                $PSinstance.BeginInvoke()



                Wrapping it up in a RunspacePool



                Using the above technique, we can wrap the sequential iterations of creating new connections and invoking the remote command in a parallel execution flow:



                $ComputerNames = Get-ADComputer -filter * -Properties dnsHostName |select -Expand dnsHostName

                $Code =
                param($Credentials,$ComputerName)
                $session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
                Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover


                $creds = Get-Credential domainuser

                $rsPool = [runspacefactory]::CreateRunspacePool(1,8)
                $rsPool.Open()

                foreach($ComputerName in $ComputerNames)

                $PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument($ComputerName)
                $PSinstance.RunspacePool = $rsPool
                $PSinstance.BeginInvoke()



                Assuming that the CPU has the capacity to execute all 8 runspaces at once, we should be able to see that the execution time is greatly reduced, but at the cost of readability of the script due to the rather "advanced" methods used.




                Determining the optimum degree of parallism:



                We could easily create a RunspacePool that allows for the execution of a 100 runspaces at the same time:



                [runspacefactory]::CreateRunspacePool(1,100)


                But at the end of the day, it all comes down to how many units of execution our local CPU can handle. In other words, as long as your code is executing, it does not make sense to allow more runspaces than you have logical processors to dispatch execution of code to.



                Thanks to WMI, this threshold is fairly easy to determine:



                $NumberOfLogicalProcessor = (Get-WmiObject Win32_Processor).NumberOfLogicalProcessors
                [runspacefactory]::CreateRunspacePool(1,$NumberOfLogicalProcessors)


                If, on the other hand, the code you are executing itself incurs a lot of wait time due to external factors like network latency, you can still benefit from running more simultanous runspaces than you have logical processors, so you'd probably want to test of range possible maximum runspaces to find break-even:



                foreach($n in ($NumberOfLogicalProcessors..($NumberOfLogicalProcessors*3)))

                Write-Host "$n: " -NoNewLine
                (Measure-Command
                $Computers = Get-ADComputer -filter * -Properties dnsHostName ).TotalSeconds







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Feb 8 '18 at 13:29









                mklement

                21516




                21516










                answered Sep 6 '14 at 13:56









                Mathias R. JessenMathias R. Jessen

                22.8k35189




                22.8k35189







                • 4





                  If the jobs are waiting on the network, e.g. you are running PowerShell commands on remote computers, you could easily go far over the number of logical processors before you hit any CPU bottleneck.

                  – Michael Hampton
                  Sep 6 '14 at 14:00












                • Well, that is true. Changed it a bit and provided an example for testing

                  – Mathias R. Jessen
                  Sep 6 '14 at 14:09











                • How to make sure all the job is done at the end? (May need to something after all the script blocks finished)

                  – sjzls
                  Nov 18 '14 at 18:04











                • @NickW Great question. I'll do a follow-up on tracking the jobs and "harvesting" potential output later today, stay tuned

                  – Mathias R. Jessen
                  Nov 19 '14 at 12:23






                • 1





                  @MathiasR.Jessen Very well-written answer! Looking forward to the update.

                  – Signal15
                  Dec 3 '14 at 16:55












                • 4





                  If the jobs are waiting on the network, e.g. you are running PowerShell commands on remote computers, you could easily go far over the number of logical processors before you hit any CPU bottleneck.

                  – Michael Hampton
                  Sep 6 '14 at 14:00












                • Well, that is true. Changed it a bit and provided an example for testing

                  – Mathias R. Jessen
                  Sep 6 '14 at 14:09











                • How to make sure all the job is done at the end? (May need to something after all the script blocks finished)

                  – sjzls
                  Nov 18 '14 at 18:04











                • @NickW Great question. I'll do a follow-up on tracking the jobs and "harvesting" potential output later today, stay tuned

                  – Mathias R. Jessen
                  Nov 19 '14 at 12:23






                • 1





                  @MathiasR.Jessen Very well-written answer! Looking forward to the update.

                  – Signal15
                  Dec 3 '14 at 16:55







                4




                4





                If the jobs are waiting on the network, e.g. you are running PowerShell commands on remote computers, you could easily go far over the number of logical processors before you hit any CPU bottleneck.

                – Michael Hampton
                Sep 6 '14 at 14:00






                If the jobs are waiting on the network, e.g. you are running PowerShell commands on remote computers, you could easily go far over the number of logical processors before you hit any CPU bottleneck.

                – Michael Hampton
                Sep 6 '14 at 14:00














                Well, that is true. Changed it a bit and provided an example for testing

                – Mathias R. Jessen
                Sep 6 '14 at 14:09





                Well, that is true. Changed it a bit and provided an example for testing

                – Mathias R. Jessen
                Sep 6 '14 at 14:09













                How to make sure all the job is done at the end? (May need to something after all the script blocks finished)

                – sjzls
                Nov 18 '14 at 18:04





                How to make sure all the job is done at the end? (May need to something after all the script blocks finished)

                – sjzls
                Nov 18 '14 at 18:04













                @NickW Great question. I'll do a follow-up on tracking the jobs and "harvesting" potential output later today, stay tuned

                – Mathias R. Jessen
                Nov 19 '14 at 12:23





                @NickW Great question. I'll do a follow-up on tracking the jobs and "harvesting" potential output later today, stay tuned

                – Mathias R. Jessen
                Nov 19 '14 at 12:23




                1




                1





                @MathiasR.Jessen Very well-written answer! Looking forward to the update.

                – Signal15
                Dec 3 '14 at 16:55





                @MathiasR.Jessen Very well-written answer! Looking forward to the update.

                – Signal15
                Dec 3 '14 at 16:55













                5














                Adding to this discussion, what's missing is a collector to store the data that is created from the runspace, and a variable to check the status of the runspace, i.e. is it completed or not.



                #Add an collector object that will store the data
                $Object = New-Object 'System.Management.Automation.PSDataCollection[psobject]'

                #Create a variable to check the status
                $Handle = $PSinstance.BeginInvoke($Object,$Object)

                #So if you want to check the status simply type:
                $Handle

                #If you want to see the data collected, type:
                $Object





                share|improve this answer





























                  5














                  Adding to this discussion, what's missing is a collector to store the data that is created from the runspace, and a variable to check the status of the runspace, i.e. is it completed or not.



                  #Add an collector object that will store the data
                  $Object = New-Object 'System.Management.Automation.PSDataCollection[psobject]'

                  #Create a variable to check the status
                  $Handle = $PSinstance.BeginInvoke($Object,$Object)

                  #So if you want to check the status simply type:
                  $Handle

                  #If you want to see the data collected, type:
                  $Object





                  share|improve this answer



























                    5












                    5








                    5







                    Adding to this discussion, what's missing is a collector to store the data that is created from the runspace, and a variable to check the status of the runspace, i.e. is it completed or not.



                    #Add an collector object that will store the data
                    $Object = New-Object 'System.Management.Automation.PSDataCollection[psobject]'

                    #Create a variable to check the status
                    $Handle = $PSinstance.BeginInvoke($Object,$Object)

                    #So if you want to check the status simply type:
                    $Handle

                    #If you want to see the data collected, type:
                    $Object





                    share|improve this answer















                    Adding to this discussion, what's missing is a collector to store the data that is created from the runspace, and a variable to check the status of the runspace, i.e. is it completed or not.



                    #Add an collector object that will store the data
                    $Object = New-Object 'System.Management.Automation.PSDataCollection[psobject]'

                    #Create a variable to check the status
                    $Handle = $PSinstance.BeginInvoke($Object,$Object)

                    #So if you want to check the status simply type:
                    $Handle

                    #If you want to see the data collected, type:
                    $Object






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Feb 9 '17 at 16:25









                    Mathias R. Jessen

                    22.8k35189




                    22.8k35189










                    answered Feb 9 '17 at 16:22









                    Nate StoneNate Stone

                    4912




                    4912





















                        3














                        Check out PoshRSJob. It provides same/similar functions as the native *-Job functions, but uses Runspaces which tend to be much quicker and more responsive than the standard Powershell jobs.






                        share|improve this answer



























                          3














                          Check out PoshRSJob. It provides same/similar functions as the native *-Job functions, but uses Runspaces which tend to be much quicker and more responsive than the standard Powershell jobs.






                          share|improve this answer

























                            3












                            3








                            3







                            Check out PoshRSJob. It provides same/similar functions as the native *-Job functions, but uses Runspaces which tend to be much quicker and more responsive than the standard Powershell jobs.






                            share|improve this answer













                            Check out PoshRSJob. It provides same/similar functions as the native *-Job functions, but uses Runspaces which tend to be much quicker and more responsive than the standard Powershell jobs.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Dec 6 '17 at 23:21









                            RoscoRosco

                            311




                            311





















                                1














                                @mathias-r-jessen has a great answer though there are details I'd like to add.



                                Max Threads



                                In theory threads should be limited by the number of system processors. However, while testing AsyncTcpScan I achieved far better performance by choosing a much larger value for MaxThreads. Thus why that module has a -MaxThreads input parameter. Keep in mind that allocating too many threads will hinder performance.



                                Returning Data



                                Getting data back from the ScriptBlock is tricky. I've updated the OP code and integrated it into what was used for AsyncTcpScan.




                                WARNING: I wasn't able to test the following code. I made some changes
                                to the OP script based on my experience working with the Active
                                Directory cmdlets.




                                # Script to run in each thread.
                                [System.Management.Automation.ScriptBlock]$ScriptBlock =

                                $result = New-Object PSObject -Property @ 'Computer' = $args[0];
                                'Success' = $false;

                                try
                                $session = New-PSSession -ComputerName $args[0] -Credential $args[1]
                                Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover
                                Disconnect-PSSession -Session $session
                                $result.Success = $true
                                catch



                                return $result

                                # End Scriptblock

                                function Invoke-AsyncJob

                                [CmdletBinding()]
                                param(
                                [parameter(Mandatory=$true)]
                                [System.Management.Automation.PSCredential]
                                # Credential object to login to remote systems
                                $Credentials
                                )

                                Import-Module ActiveDirectory

                                $Results = @()

                                $AllJobs = New-Object System.Collections.ArrayList

                                $AllDomainComputers = Get-ADComputer -Filter * -Properties dnsHostName

                                $HostRunspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(2,10,$Host)

                                $HostRunspacePool.Open()

                                foreach($DomainComputer in $AllDomainComputers)
                                Out-Null


                                $ProcessingJobs = $true

                                Do

                                $CompletedJobs = $AllJobs While ($ProcessingJobs)

                                $HostRunspacePool.Close()
                                $HostRunspacePool.Dispose()

                                return $Results

                                # End function Invoke-AsyncJob





                                share|improve this answer





























                                  1














                                  @mathias-r-jessen has a great answer though there are details I'd like to add.



                                  Max Threads



                                  In theory threads should be limited by the number of system processors. However, while testing AsyncTcpScan I achieved far better performance by choosing a much larger value for MaxThreads. Thus why that module has a -MaxThreads input parameter. Keep in mind that allocating too many threads will hinder performance.



                                  Returning Data



                                  Getting data back from the ScriptBlock is tricky. I've updated the OP code and integrated it into what was used for AsyncTcpScan.




                                  WARNING: I wasn't able to test the following code. I made some changes
                                  to the OP script based on my experience working with the Active
                                  Directory cmdlets.




                                  # Script to run in each thread.
                                  [System.Management.Automation.ScriptBlock]$ScriptBlock =

                                  $result = New-Object PSObject -Property @ 'Computer' = $args[0];
                                  'Success' = $false;

                                  try
                                  $session = New-PSSession -ComputerName $args[0] -Credential $args[1]
                                  Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover
                                  Disconnect-PSSession -Session $session
                                  $result.Success = $true
                                  catch



                                  return $result

                                  # End Scriptblock

                                  function Invoke-AsyncJob

                                  [CmdletBinding()]
                                  param(
                                  [parameter(Mandatory=$true)]
                                  [System.Management.Automation.PSCredential]
                                  # Credential object to login to remote systems
                                  $Credentials
                                  )

                                  Import-Module ActiveDirectory

                                  $Results = @()

                                  $AllJobs = New-Object System.Collections.ArrayList

                                  $AllDomainComputers = Get-ADComputer -Filter * -Properties dnsHostName

                                  $HostRunspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(2,10,$Host)

                                  $HostRunspacePool.Open()

                                  foreach($DomainComputer in $AllDomainComputers)
                                  Out-Null


                                  $ProcessingJobs = $true

                                  Do

                                  $CompletedJobs = $AllJobs While ($ProcessingJobs)

                                  $HostRunspacePool.Close()
                                  $HostRunspacePool.Dispose()

                                  return $Results

                                  # End function Invoke-AsyncJob





                                  share|improve this answer



























                                    1












                                    1








                                    1







                                    @mathias-r-jessen has a great answer though there are details I'd like to add.



                                    Max Threads



                                    In theory threads should be limited by the number of system processors. However, while testing AsyncTcpScan I achieved far better performance by choosing a much larger value for MaxThreads. Thus why that module has a -MaxThreads input parameter. Keep in mind that allocating too many threads will hinder performance.



                                    Returning Data



                                    Getting data back from the ScriptBlock is tricky. I've updated the OP code and integrated it into what was used for AsyncTcpScan.




                                    WARNING: I wasn't able to test the following code. I made some changes
                                    to the OP script based on my experience working with the Active
                                    Directory cmdlets.




                                    # Script to run in each thread.
                                    [System.Management.Automation.ScriptBlock]$ScriptBlock =

                                    $result = New-Object PSObject -Property @ 'Computer' = $args[0];
                                    'Success' = $false;

                                    try
                                    $session = New-PSSession -ComputerName $args[0] -Credential $args[1]
                                    Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover
                                    Disconnect-PSSession -Session $session
                                    $result.Success = $true
                                    catch



                                    return $result

                                    # End Scriptblock

                                    function Invoke-AsyncJob

                                    [CmdletBinding()]
                                    param(
                                    [parameter(Mandatory=$true)]
                                    [System.Management.Automation.PSCredential]
                                    # Credential object to login to remote systems
                                    $Credentials
                                    )

                                    Import-Module ActiveDirectory

                                    $Results = @()

                                    $AllJobs = New-Object System.Collections.ArrayList

                                    $AllDomainComputers = Get-ADComputer -Filter * -Properties dnsHostName

                                    $HostRunspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(2,10,$Host)

                                    $HostRunspacePool.Open()

                                    foreach($DomainComputer in $AllDomainComputers)
                                    Out-Null


                                    $ProcessingJobs = $true

                                    Do

                                    $CompletedJobs = $AllJobs While ($ProcessingJobs)

                                    $HostRunspacePool.Close()
                                    $HostRunspacePool.Dispose()

                                    return $Results

                                    # End function Invoke-AsyncJob





                                    share|improve this answer















                                    @mathias-r-jessen has a great answer though there are details I'd like to add.



                                    Max Threads



                                    In theory threads should be limited by the number of system processors. However, while testing AsyncTcpScan I achieved far better performance by choosing a much larger value for MaxThreads. Thus why that module has a -MaxThreads input parameter. Keep in mind that allocating too many threads will hinder performance.



                                    Returning Data



                                    Getting data back from the ScriptBlock is tricky. I've updated the OP code and integrated it into what was used for AsyncTcpScan.




                                    WARNING: I wasn't able to test the following code. I made some changes
                                    to the OP script based on my experience working with the Active
                                    Directory cmdlets.




                                    # Script to run in each thread.
                                    [System.Management.Automation.ScriptBlock]$ScriptBlock =

                                    $result = New-Object PSObject -Property @ 'Computer' = $args[0];
                                    'Success' = $false;

                                    try
                                    $session = New-PSSession -ComputerName $args[0] -Credential $args[1]
                                    Invoke-Command -Session $session -ScriptBlock w32tm /resync /nowait /rediscover
                                    Disconnect-PSSession -Session $session
                                    $result.Success = $true
                                    catch



                                    return $result

                                    # End Scriptblock

                                    function Invoke-AsyncJob

                                    [CmdletBinding()]
                                    param(
                                    [parameter(Mandatory=$true)]
                                    [System.Management.Automation.PSCredential]
                                    # Credential object to login to remote systems
                                    $Credentials
                                    )

                                    Import-Module ActiveDirectory

                                    $Results = @()

                                    $AllJobs = New-Object System.Collections.ArrayList

                                    $AllDomainComputers = Get-ADComputer -Filter * -Properties dnsHostName

                                    $HostRunspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(2,10,$Host)

                                    $HostRunspacePool.Open()

                                    foreach($DomainComputer in $AllDomainComputers)
                                    Out-Null


                                    $ProcessingJobs = $true

                                    Do

                                    $CompletedJobs = $AllJobs While ($ProcessingJobs)

                                    $HostRunspacePool.Close()
                                    $HostRunspacePool.Dispose()

                                    return $Results

                                    # End function Invoke-AsyncJob






                                    share|improve this answer














                                    share|improve this answer



                                    share|improve this answer








                                    edited Apr 26 at 13:19

























                                    answered Apr 25 at 23:57









                                    phbitsphbits

                                    314




                                    314



























                                        draft saved

                                        draft discarded
















































                                        Thanks for contributing an answer to Server Fault!


                                        • Please be sure to answer the question. Provide details and share your research!

                                        But avoid


                                        • Asking for help, clarification, or responding to other answers.

                                        • Making statements based on opinion; back them up with references or personal experience.

                                        To learn more, see our tips on writing great answers.




                                        draft saved


                                        draft discarded














                                        StackExchange.ready(
                                        function ()
                                        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fserverfault.com%2fquestions%2f626711%2fhow-do-i-run-my-powershell-scripts-in-parallel-without-using-jobs%23new-answer', 'question_page');

                                        );

                                        Post as a guest















                                        Required, but never shown





















































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown

































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown







                                        Popular posts from this blog

                                        Wikipedia:Vital articles Мазмуну Biography - Өмүр баян Philosophy and psychology - Философия жана психология Religion - Дин Social sciences - Коомдук илимдер Language and literature - Тил жана адабият Science - Илим Technology - Технология Arts and recreation - Искусство жана эс алуу History and geography - Тарых жана география Навигация менюсу

                                        Bruxelas-Capital Índice Historia | Composición | Situación lingüística | Clima | Cidades irmandadas | Notas | Véxase tamén | Menú de navegacióneO uso das linguas en Bruxelas e a situación do neerlandés"Rexión de Bruxelas Capital"o orixinalSitio da rexiónPáxina de Bruselas no sitio da Oficina de Promoción Turística de Valonia e BruxelasMapa Interactivo da Rexión de Bruxelas-CapitaleeWorldCat332144929079854441105155190212ID28008674080552-90000 0001 0666 3698n94104302ID540940339365017018237

                                        What should I write in an apology letter, since I have decided not to join a company after accepting an offer letterShould I keep looking after accepting a job offer?What should I do when I've been verbally told I would get an offer letter, but still haven't gotten one after 4 weeks?Do I accept an offer from a company that I am not likely to join?New job hasn't confirmed starting date and I want to give current employer as much notice as possibleHow should I address my manager in my resignation letter?HR delayed background verification, now jobless as resignedNo email communication after accepting a formal written offer. How should I phrase the call?What should I do if after receiving a verbal offer letter I am informed that my written job offer is put on hold due to some internal issues?Should I inform the current employer that I am about to resign within 1-2 weeks since I have signed the offer letter and waiting for visa?What company will do, if I send their offer letter to another company