title: PowerShell through C# - Asynchronous RunspacePool - Key has already been added
body: <p>Long time lurker (especially on this problem).  I have been studying asynchronous posts on this website directly related to my problem, but I have not found a solution.  I have also tried many different variations of the below code to no avail.</p>
  
  <p>What is happening is I asynchronously execute <code>ps.BeginInvoke()</code> after loading commands into it, use some sort of method to launch the invocation asynchronously, and it has indeed always run asynchronously!  The problem though is that (for example), the commands executed will only return results sometimes 2 out of 10 times, sometimes 8 out of 10 times.  Here is an example of the current code I am executing:</p>
  
  <pre><code>internal class aSyncPowershellCommand
  {
      //private static Collection&lt;Collection&lt;PSObject&gt;&gt; GlobalResults = new Collection&lt;Collection&lt;PSObject&gt;&gt;();
  
      // This exists simply
      public bool Finished { get; set; }
  
      private object instanceLock = new object();
      private PowerShell ps;
     // private Guid uniqueGuid = Guid.NewGuid();
  
      private PSDataCollection&lt;PSObject&gt; psresult;
  
      public async Task&lt;bool&gt; PowershellLaunchPool(Dictionary&lt;ARS_GroupObject, string&gt; itemListing)
      // itemListing contains a custom class that specified details about an ARS group object
      // and the String "Value" contains the action (in this case, "get-QADGroup".
  
      {
          // Create a common RunspacePool --- it should be noted that for testing purposes, I am sending exactly 8 groups as 
          // part of the query, for testing purposes.
          RunspacePool pool = RunspaceFactory.CreateRunspacePool(1, 8);
  
          pool.CleanupInterval = new TimeSpan(0, 5, 0);
          pool.Open();
  
          // Create a spot to track the results in a unique way (I have experimented with lists, dictionaries, etc.... the results are
          // always the same though, this just happens to be my latest method to attempt to avoid the "Key already added" error"
  
          ConcurrentDictionary&lt;Guid, IAsyncResult&gt; powershellCommandResults = new ConcurrentDictionary&lt;Guid, IAsyncResult&gt;();
          ConcurrentDictionary&lt;Guid, PowerShell&gt; powershellSessions = new ConcurrentDictionary&lt;Guid, PowerShell&gt;();
  
          // Locking the instance, again, not sure if this actually does anything as far as my code is concerned, but it's
          // still keeping in line with the same results as before.... semi-success and a lot of "key already added" errors.
          lock (instanceLock)
          {
          foreach (var grpPair in itemListing)
          {
              // Create a unique GUID for the dictionary, just in case this is what was triggering the "key already added" error
              Guid uniqueGuid = Guid.NewGuid();
  
              //  This passes text output to a textbox, not important
              StatusUpdater.PassPowershellStatus(uniqueGuid.ToString() + " - 1\n");
  
              // Create a fresh PowerShell instance
              this.ps = PowerShell.Create();
              //StatusUpdater.PassPowershellStatus(this.ps.InstanceId.ToString());
  
              // Add this fresh PowerShell instance to the common RunspacePool
              this.ps.RunspacePool = pool;
  
              // Create a fresh instance of psresult to keep track of changes.  This is honestly one piece of code I am suspicious
              // of as far as throwing the "key already added" error, but I haven't been able to isolate.
              this.psresult = new PSDataCollection&lt;PSObject&gt;();
  
              // grpPair.value is "get-QADGroup"
              this.ps.Commands.AddCommand(grpPair.Value);
              //grpPair.Key.Groupname ---- name of the group
              this.ps.Commands.AddParameter("identity", grpPair.Key.GroupName);
  
              // loading up the collection of PowerShell sessions to keep track of, trying as hard as possible to keep this
              // all as unique as I possibly can.
              powershellSessions.TryAdd(uniqueGuid, this.ps);
  
              // Reference event handlers for when something happens with the variable psResult
              this.psresult.DataAdded += new EventHandler&lt;DataAddedEventArgs&gt;(tmpInstance_DataAdded);
              this.ps.InvocationStateChanged += new EventHandler&lt;PSInvocationStateChangedEventArgs&gt;(ps_InvocationStateChanged);
          }       
  
          }
  
          foreach (var execute in powershellSessions)
          {
              // Looping through all of the PowerSHell sessions queue up and invoking, relying on their same instance of psresult 
              // to return the results and trigger the tmpInstance_DataAdded and ps_InvocationStateChanged events.
              powershellCommandResults.TryAdd(execute.Key, execute.Value.BeginInvoke&lt;PSObject, PSObject&gt;(null, this.psresult));
          }
  
          while (Finished != true)
          {
              Thread.Sleep(3000);
          }
          return true;
      }
  
      private void tmpInstance_DataAdded(object sender, DataAddedEventArgs e)
      {
          PSDataCollection&lt;PSObject&gt; tmpReturn = (PSDataCollection&lt;PSObject&gt;)sender;
          foreach (var item in tmpReturn)
          {
              StatusUpdater.PassPowershellStatus(item.BaseObject.ToString() + "\n");
          }
      }
  
      private void ps_InvocationStateChanged(object sender, PSInvocationStateChangedEventArgs e)
      {
          var psInfo = (PowerShell)sender;
  
          if (e.InvocationStateInfo.State == PSInvocationState.Completed)
          {
              StatusUpdater.PassPowershellStatus("RESULT --- " + e.InvocationStateInfo.Reason.ToString() + "\n");
              psInfo.Stop();
              psInfo.Dispose();
              psInfo = null;
  
          }
          if (e.InvocationStateInfo.State == PSInvocationState.Failed)
          {
              StatusUpdater.PassPowershellStatus("*** ERROR - \n" + e.InvocationStateInfo.Reason.ToString() + " ***\n");
              psInfo.Stop();
              psInfo.Dispose();
              psInfo = null;
            //  StatusUpdater.PassPowershellStatus(e.InvocationStateInfo.Reason.ToString());
          }
  
      }
  }
  </code></pre>
  
  <p>I have tried different combinations of <code>IASyncResult result = ps.BeginInvoke()</code> and awaiting that command many times, but it has the same results as the code above.  Also tried throwing it into a <code>var task = Task.Factory.FromAsync(ps.beginInvoke(), p =&gt; ps.EndInvoke(p));</code> style block and adding to a list of tasks and then awaiting all of their executions with <code>.ConfigureAwait(false);</code>, again... the same results!</p>
  
  <p>So what are the results anyhow?  The commands all execute, but on <strong>unsuccessful</strong> attempts, thee following exception is thrown:</p>
  
  <pre><code>System.Management.Automation.CmdletInvocationException: An item with the same key has already been added. 
  ---&gt; System.ArgumentException: An item with the same key has already been added.
  </code></pre>
  
  <p>Otherwise, it returns results, and very quickly.</p>
  
  <p>I believe that the problem is the PowerShell session is trying to write to the same internal output object, despite the fact that it is executing as </p>
  
  <p>1.)  It's own new PowerShell instance<br>
  2.)  In a different runspace as managedby the RunSpace pool.</p>
  
  <p>This error occurs at least once every single time I run the script.  Sometimes it actually spits out 8 out of 10 group results, and sometimes it only works on 1.</p>
  
  <p>How can I stop this collision from happening?  I am suspecting that there is something internally happening within PowerShell that is causing this to happen.</p>