title: Why does an argument passed into a script block fail to work?
body: <p>Full disclosure: My problem may be based on a incomplete understanding of the Citrix PowerShell module for Xen Desktop.</p>
  
  <p>I have the following script block. It's called in a loop, once for each VM in a list. I'm using <code>PowerShell Jobs</code> because I want to keep the UI thread free to update the UI while the jobs run.</p>
  
  <p><strong>Code "A"</strong></p>
  
  <pre><code>$j = Start-Job -Name $jobName -ScriptBlock {
      param($url, $uuid, $cred, $snapshotName)
      $ErrorActionPreference = "Stop" 
      try
      {
          $error.clear()
          $xSS = $cred | Connect-XenServer -url $url -NoWarnCertificates -SetDefaultSession -PassThru; 
          $vm = (Get-XenVM -SessionOpaqueRef $xss.opaque_ref -uuid $uuid)
          #Create snapshot
          Invoke-XenVM -Async -SessionOpaqueRef $xss.opaque_ref -VM $vm -XenAction Snapshot -NewName $snapshotName
          return "OK"
      }
      catch
      {
          return ("ERROR: "+$error)
      }
  } -ArgumentList $global:configFileVmMetaData.poolUrl, $xenVm.key, $global:cred, $snapshotName
  </code></pre>
  
  <p><strong>Code "A"</strong> works ok, but it takes longer then necessary because I'm executing the <code>Connect-XenServer</code> cmdlet each time I invoke the script block.</p>
  
  <p>So, I tried calling <code>Connect-XenServer</code> once outside the loop and passing in the session variable as shown below in <strong>Code "B"</strong>. The result was the error <code>Could not find open sessions to any XenServers</code> being thrown inside the script block. I'm assuming that the $xss session variable is getting whanged somehow when its passed into the script block.</p>
  
  <p>Any ideas why $xss session variable is getting whanged?</p>
  
  <p><strong>Code "B"</strong></p>
  
  <pre><code>$xSS = $cred | Connect-XenServer -url $global:configFileVmMetaData.poolUrl -NoWarnCertificates -SetDefaultSession -PassThru; 
  
  loop
  {
  
      $j = Start-Job -Name $jobName -ScriptBlock {
          param($xss, $uuid, $snapshotName)
          $ErrorActionPreference = "Stop" 
          try
          {
              $error.clear()
              $vm = (Get-XenVM -SessionOpaqueRef $xss.opaque_ref -uuid $uuid)
              #Create snapshot
              Invoke-XenVM -Async -SessionOpaqueRef $xss.opaque_ref -VM $vm -XenAction Snapshot -NewName $snapshotName
              return "OK"
          }
          catch
          {
              return ("ERROR: "+$error)
          }
      } -ArgumentList $xss, $xenVm.key, $snapshotName
  
  }
  </code></pre>
  
  <blockquote>
    <p>Additional examples inspired by the <code>Robert Cotterman</code> answer</p>
    
    <p>In all cases, I still get the <code>Could not find open sessions to any
    XenServers</code> error</p>
    
    <p>FYI - Using PowerShell 5.1</p>
  </blockquote>
  
  <p><strong>Example using <code>$using</code>. Variable contents are passed in and back out as expected</strong></p>
  
  <pre><code>cls
  
  $aLocal = "AAA"
  $bLocal = "BBB"
  
  $j = Start-Job -Name "TestJob" -ScriptBlock {
      return ($using:aLocal + " *** " + $using:bLocal)
      }
  
  while ($true)
  {
      $g = get-job -name "TestJob"
  
      write-host ("get-job " + $g.Name + " is " + $g.State)
  
      if ($g.State -ne "Running")
      {
          break
      }
  
      start-sleep -Seconds 1
  }
  
  write-host ("receive-Job='" + (receive-Job -Name "TestJob") +"'")
  
  $g = get-Job -Name "TestJob"
  Write-Host ("get-Job "+$g.name + " " + $g.state + " " + $g.HasMoreData + " " + $g.id)
  
  if($g)
  {
      Remove-Job -Name "TestJob"
  }
  </code></pre>
  
  <p><strong>Output</strong></p>
  
  <pre><code>get-job TestJob is Running
  get-job TestJob is Completed
  receive-Job='AAA *** BBB'
  get-Job TestJob Completed False 45
  Remove-Job
  </code></pre>
  
  <p><strong>Example using args. Variable contents are passed in and back out as expected</strong>    </p>
  
  <pre><code>cls
  
  $aLocal = "AAA"
  $bLocal = "BBB"
  
  $j = Start-Job -Name "TestJob" -ScriptBlock {
      return ($args[0] + " *** " + $args[1])
      } -ArgumentList ($aLocal, $bLocal)
  
  while ($true)
  {
      $g = get-job -name "TestJob"
  
      write-host ("get-job " + $g.Name + " is " + $g.State)
  
      if ($g.State -ne "Running")
      {
          break
      }
  
      start-sleep -Seconds 1
  }
  
  write-host ("receive-Job='" + (receive-Job -Name "TestJob") +"'")
  
  $g = get-Job -Name "TestJob"
  Write-Host ("get-Job "+$g.name + " " + $g.state + " " + $g.HasMoreData + " " + $g.id)
  
  if($g)
  {
      Remove-Job -Name "TestJob"
  }
  </code></pre>
  
  <p><strong>Output</strong></p>
  
  <pre><code>get-job TestJob is Running
  get-job TestJob is Completed
  receive-Job='AAA *** BBB'
  get-Job TestJob Completed False 49
  </code></pre>
  
  <p><strong>Example using named args. Variable contents are passed in and back out as expected</strong>  </p>
  
  <pre><code>cls
  
  $aLocal = "AAA"
  $bLocal = "BBB"
  
  $j = Start-Job -Name "TestJob" -ScriptBlock {
      param($a, $b)
      return ($a + " *** " + $b)
      } -ArgumentList ($aLocal, $bLocal)
  
  while ($true)
  {
      $g = get-job -name "TestJob"
  
      write-host ("get-job " + $g.Name + " is " + $g.State)
  
      if ($g.State -ne "Running")
      {
          break
      }
  
      start-sleep -Seconds 1
  }
  
  write-host ("receive-Job='" + (receive-Job -Name "TestJob") +"'")
  
  $g = get-Job -Name "TestJob"
  Write-Host ("get-Job "+$g.name + " " + $g.state + " " + $g.HasMoreData + " " + $g.id)
  
  if($g)
  {
      Remove-Job -Name "TestJob"
  }
  </code></pre>
  
  <p><strong>Output</strong></p>
  
  <pre><code>get-job TestJob is Running
  get-job TestJob is Completed
  receive-Job='AAA *** BBB'
  get-Job TestJob Completed False 55
  </code></pre>