title: Passing a script from runspacepool
body: <p>I am trying to work on an existing script that I had some assistance from in another thread. With some member assistance I was able to get my script to run using the &quot;ThreadJob&quot; module, however I was hoping I can also make use of runspacepools in conjunction with the ThreadJob to make it run faster.</p>
  <p>In my code I post below, I am printing out a line to notify me that the function get's called. And I can see it is getting called. So it makes me think that line 56 and line 59 are incorrectly being called and I can't figure out how to call them.</p>
  <p>if I run the &quot;$rootPath\UpdateContacts\UpdateContacts.ps1&quot; file manually through powershell ISE, it runs fine (obviously outside of the runspace), but I'd like to try and get it to work within the runspacepool.</p>
  <p>Here is what I'm working with. I think I am pretty close.</p>
  <pre><code>begin
  {
      CLS
  
      [switch]$MultiThread=$true
  
      $rootPath = $(Split-path $MyInvocation.MyCommand.path -Parent)
  
      $userEmail = &quot;user@domain.com&quot;
      
      $SessionState = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
      $RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, 10,$Sessionstate, $Host)
      $RunspacePool.Open()
      $Jobs = @()
      
  }
  
  process 
  {
      function ContactUpdater()
      {
          ##################### Start Comparing Data #####################
  
          #Our Array of values we will be comparing
          [array]$CompareValues = &quot;FirstName&quot;,&quot;MiddleName&quot;,&quot;LastName&quot;,&quot;DisplayName&quot;,&quot;Email&quot;,&quot;Mobile&quot;,&quot;TelephoneNumber&quot;,&quot;Title&quot;,&quot;Dept&quot;,&quot;Company&quot;
  
          for($i=0; $i -lt $CompareValues.Count; $i++)
          {
              #First let's create 2 variables that will hold the info we want
              $A = ($Users).($CompareValues[$i])
              $B = ($Contacts).($CompareValues[$i])
  
              ##################### Update Contacts #####################
  
              #Only Run if there are contacts; otherwise there is nothing for us to compare
              if(($NULL -ne $B))
              {
                  #Displays all differences
                  #$Differences = [string[]]([Linq.Enumerable]::Except([object[]]$a, [object[]]$b) + [Linq.Enumerable]::Except([object[]]$b, [object[]]$a))
  
                  #Displays what accounts we need to import
                  $NeedsToBeAdded = [string[]]([Linq.Enumerable]::Except([object[]]$a, [object[]]$b))
  
                  #Displays what accounts we need to delete because they no longer exist
                  $NeedsToBeDeleted = [string[]]([Linq.Enumerable]::Except([object[]]$b, [object[]]$a))
              }
          }
              ##################### Import All Contacts #####################
  
          if($NULL -eq $Contacts)
          {
              Write-Host &quot;I am in the import&quot;
              
              # Load UpdateContacts function in memory
              . &quot;$rootPath\UpdateContacts\UpdateContacts\UpdateContacts.ps1&quot;
  
              #Write-host &quot;Importing Contacts. This could take several minutes.&quot;
              &amp; &quot;$rootPath\UpdateContacts\UpdateContacts.ps1&quot;
          }
      }
  
      if($MultiThread)
      {
          foreach($userEmail in $EmailAddress)
          {
              try
              {
                  ##################### Create Contact Folder #####################
  
                  if($NULL -eq $folderId)
                  {
                      $start = [datetime]::UtcNow
  
                      Write-Host &quot;Creating Contacts Folder&quot;
  
                      Try
                      {
                          while($NULL = (Invoke-RestMethod -Uri &quot;https://graph.microsoft.com/v1.0/users/$UPN/contactFolders/$folderId&quot; -Headers $headers -Method get))
                          {
                              $NewContactFolder = Invoke-RestMethod -Uri &quot;https://graph.microsoft.com/v1.0/users/$UPN/contactFolders&quot; -Body $ContactsFolderBody -Headers $headers -Method post -ContentType 'application/json'
                              sleep -Milliseconds 1
                              $folderId = $($NewContactFolder.id)
                          }
                      }
                      Catch
                      {
                          Out-Null
                      }
  
                      Add-Content &quot;$rootPath\progress.txt&quot; &quot;`t`tCreated Contacts Folder in: $('{0:N2}' -f ([datetime]::UtcNow - $start).TotalSeconds) seconds&quot;
                      Add-Content &quot;$rootPath\progress.txt&quot; &quot;&quot;
                  }
  
                  ##################### Getting All User Info #####################
  
                  $start = [datetime]::UtcNow
  
                  $Users = &amp; $rootPath\GetUserInfo\GetUserInfo.ps1
  
                  Add-Content &quot;$rootPath\progress.txt&quot; &quot;`t`tFinished Getting all User Info in: $('{0:N2}' -f ([datetime]::UtcNow - $start).TotalSeconds) seconds&quot;
                  Add-Content &quot;$rootPath\progress.txt&quot; &quot;&quot;
  
                  ##################### Getting Contact Info #####################
  
                  if($NULL -ne $folderId)
                  {
                      $start = [datetime]::UtcNow
  
                      $Contacts = &amp; $rootPath\GetContactInfo\GetContactInfo.ps1
  
                      Add-Content &quot;$rootPath\progress.txt&quot; &quot;`t`tFinished Getting all Contact Info in: $('{0:N2}' -f ([datetime]::UtcNow - $start).TotalSeconds) seconds&quot;
                      Add-Content &quot;$rootPath\progress.txt&quot; &quot;&quot;
                  }
  
                  ##################### Import Contacts #####################
  
                  $start = [datetime]::UtcNow
  
                  CLS
  
                  if($NULL -eq $ImportMsg)
                  {
                      Write-host &quot;Importing Contacts. This could take several minutes.&quot;
                      $ImportMsg = &quot;Ran&quot;
                  }
  
                  $ContactImporter = ContactUpdater
  
                  Add-Content &quot;$rootPath\progress.txt&quot; &quot;`t`tFinished Importing Contact Info in: $('{0:N2}' -f ([datetime]::UtcNow - $start).TotalSeconds) seconds&quot;
  
              }
              catch
              {
                  $LogFile = &quot;$rootPath\log.txt&quot;
                  $errcond = $_.Exception.Message
                  $timestamp = (get-date).DateTime
                  &quot;Time of exception: $timestamp&quot; | Out-File $LogFile -Append
                  &quot;User: $userEmail&quot; | out-file $LogFile -Append
                  $errcond | out-file -FilePath $LogFile -append
              }
              
              1..10 | Foreach-Object {
                  $PowershellThread = [powershell]::Create()
                  $PowershellThread.RunspacePool = $RunspacePool
                  $PowershellThread.AddScript($ContactImporter).AddArgument($userEmail)
                  $Jobs += $PowershellThread.BeginInvoke()
              }
          }
      }
  }
  
  end
  {
      if($MultiThread)
      {
          while ($Jobs.IsCompleted -contains $false) 
          {
              Start-Sleep -Milliseconds 100
          }
  
          $RunspacePool.Close() | Out-Null
          $RunspacePool.Dispose() | Out-Null
      }
  }
  </code></pre>
  <p>The part in the &quot;Import all Contacts&quot; section within the ContactUpdater() Function, should call the script:</p>
  <pre><code>&amp; &quot;$rootPath\UpdateContacts\UpdateContacts.ps1&quot;
  </code></pre>
  <p>That script looks like this:</p>
  <pre><code># Save the function in a scriptBlock, we need this
  # so we can pass this function in the scope of the ThreadJobs
  $updateContacts = &quot;function UpdateContacts { $function:updateContacts }&quot;
  
  # Define the Number of Threads we are going to use
  # (Get-CimInstance win32_processor).NumberOfLogicalProcessors
  # Can give you a good perspective as to how many Threads is safe to use.
  $numberOfThreads = 10
  
  # $users is the array we want to process with
  # the UpdateContacts function. 
  # Grouping the users in chunks so each running Job can process
  # a chunk of users. Each chunk will contain around 50 users to process.
  $groupSize = [math]::Ceiling($users.Count / $numberOfThreads)
  $counter = [pscustomobject]@{ Value = 0 }
  $chunks = $users | Group-Object -Property {
      [math]::Floor($counter.Value++ / $groupSize)
  }
  
  foreach($chunk in $chunks)
  {
      # Capture this chunk of users in a variable
      $thisGroup = $chunk.Group
      
      # This is what we are running inside the scope
      # of our threadJob
      $scriptBlock = {
  
          # Pass our variables to this scope
          $UPN = $using:UPN
          $folderID = $using:folderId
          $headers = $using:headers
          $contactsBody = $using:contactsBody
          $ImportMsg = $using:ImportMsg
  
          # First we need to define the function inside this scope
          . ([scriptBlock]::Create($using:updateContacts))
  
          # Loop through each user
          foreach($user in $using:thisGroup)
          {
              UpdateContacts -User $user
          }
      }
  
      # ThrottleLimit is the number of Jobs that can run at the same time.
      # Be aware, a higher number of Jobs running does NOT mean that the
      # task will perform faster. This always depends on your CPU &amp; Memory.
      # And, this case in particular, the number of requests your URI is able to handle
      Start-ThreadJob -ScriptBlock $scriptBlock -ThrottleLimit $numberOfThreads
  }
  
  # Now we should have 10 Jobs running at the same time, each Job
  # is processing a chunk of 50 users aprox. (500 users / 10)
  # the output of all Jobs:
  $result = Get-Job | Receive-Job -Wait
  
  # Free up memory:
  Get-Job | Remove-Job
  </code></pre>
  <p>That code above, starts a threadjob and launches another function in &quot;$rootPath\UpdateContacts\UpdateContacts\UpdateContacts.ps1&quot;</p>
  <p>And that script looks like this:</p>
  <pre><code>Function UpdateContacts($User)
  {
          #FirstName, MiddleName, LastName, DisplayName, SamAccountName, Email, Mobile, TelephoneNumber, Title, Dept, Company, Photo, ExtensionAttribute2
          $ContactsBody = @&quot;
          { 
              &quot;givenName&quot;      : &quot;$($User.FirstName)&quot;,
              &quot;middleName&quot;     : &quot;$($User.MiddleName)&quot;,
              &quot;surname&quot;        : &quot;$($User.LastName)&quot;,
              &quot;fileAs&quot;         : &quot;$($User.LastName)&quot;,
              &quot;displayName&quot;    : &quot;$($User.DisplayName)&quot;,
              &quot;jobTitle&quot;       : &quot;$($User.Title)&quot;,
              &quot;companyName&quot;    : &quot;$($User.Company)&quot;,
              &quot;department&quot;     : &quot;$($User.Dept)&quot;,
              &quot;mobilePhone&quot;    : &quot;$($User.Mobile)&quot;,
              &quot;homePhones&quot;     : [&quot;$($User.TelephoneNumber)&quot;],
              &quot;emailAddresses&quot;: 
              [
                  {
                      &quot;address&quot;: &quot;$($User.Email)&quot;,
                      &quot;name&quot;: &quot;$($User.DisplayName)&quot;
                  }
              ]
          }
  &quot;@
          Try
          {
              Invoke-RestMethod -Uri &quot;https://graph.microsoft.com/v1.0/users/$UPN/contactFolders/$folderId/contacts&quot; -Headers $headers -Body $ContactsBody -Method Post -ContentType 'application/json' | Out-Null
  
              #After each user clear the info
              $User = $NULL
          }
          Catch
          {
              if($error)
              {
                  $User
                  $error
                  pause
              }
  
              $_.Exception.Message
              Write-Host &quot;--------------------------------------------------------------------------------------&quot;
              $_.Exception.ItemName
          }
  }
  </code></pre>