title: How to implement Runspaces into a powershell script
body: <p>I was very recently introduced to the concepts of Runspaces. After several YouTube videos and forum posts I get the idea as to how they work, but I struggle when trying to include it in a script of my own.</p>
  
  <p>if i have the code to implement one:</p>
  
  <p>(thanks to <a href="https://blog.netnerds.net/2016/12/runspaces-simplified/" rel="nofollow noreferrer">https://blog.netnerds.net/2016/12/runspaces-simplified/</a>)</p>
  
  <pre><code># BLOCK 1: Create and open runspace pool, setup runspaces array with min and max threads
  $pool = [RunspaceFactory]::CreateRunspacePool(1, [int]$env:NUMBER_OF_PROCESSORS+1)
  $pool.ApartmentState = "MTA"
  $pool.Open()
  $runspaces = $results = @()
  
  # BLOCK 2: Create reusable scriptblock. This is the workhorse of the runspace. Think of it as a function.
  $scriptblock = {
      Param (
      [string]$connectionString,
      [object]$batch,
      [int]$batchsize
      )
  
      $bulkcopy = New-Object Data.SqlClient.SqlBulkCopy($connectionstring,"TableLock")
      $bulkcopy.DestinationTableName = "mytable"
      $bulkcopy.BatchSize = $batchsize
      $bulkcopy.WriteToServer($batch)
      $bulkcopy.Close()
      $dtbatch.Clear()
      $bulkcopy.Dispose()
      $dtbatch.Dispose()
  
      # return whatever you want, or don't.
      return $error[0]
  }
  
  # BLOCK 3: Create runspace and add to runspace pool
  if ($datatable.rows.count -eq 50000) {
  
      $runspace = [PowerShell]::Create()
      $null = $runspace.AddScript($scriptblock)
      $null = $runspace.AddArgument($connstring)
      $null = $runspace.AddArgument($datatable)
      $null = $runspace.AddArgument($batchsize)
      $runspace.RunspacePool = $pool
  
  # BLOCK 4: Add runspace to runspaces collection and "start" it
      # Asynchronously runs the commands of the PowerShell object pipeline
      $runspaces += [PSCustomObject]@{ Pipe = $runspace; Status = $runspace.BeginInvoke() }
      $datatable.Clear()
  }
  
  # BLOCK 5: Wait for runspaces to finish
   while ($runspaces.Status.IsCompleted -notcontains $true) {}
  
  # BLOCK 6: Clean up
  foreach ($runspace in $runspaces ) {
      # EndInvoke method retrieves the results of the asynchronous call
      $results += $runspace.Pipe.EndInvoke($runspace.Status)
      $runspace.Pipe.Dispose()
  }
  
  $pool.Close() 
  $pool.Dispose()
  
  # Bonus block 7
  # Look at $results to see any errors or whatever was returned from the runspaces
  </code></pre>
  
  <p>And a script I want to include it in:</p>
  
  <pre><code>$OUs = "OU=Terminated,OU=####,OU=####,DC=####,DC=####"
  
  foreach ($ou in $OUs) 
  {
    $users = Get-ADUser -SearchBase $ou -Filter * 
    foreach ($user in $users)
    {
        $groups = Get-ADPrincipalGroupMembership -Identity $User | ? {$_.distinguishedName -like "*Groups I want removed*" }
        foreach($group in $groups) 
        {
           Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $group -whatif    
        }
    }
  }
  
  $results = foreach ($OU in $OUs) 
  {
      get-aduser -SearchBase $OU -filter * -Properties MemberOf | ? MemberOf -like "*Distribution Lists*"
  }
  $results | Export-Csv .\Remainingusers.csv -NoTypeInformation
  </code></pre>
  
  <p>How would I merge these together? from what I'm reading and seeing I just drop 1 into the beginning of 2 however when I do that the script docent seem to run at all and just looks frozen. I know I'm doing something wrong, but I don't know what.</p>
  
  <p>Splicing My script in between blocks 4 and 5 lets it work, but I don't notice it being any faster.</p>