已添加通过C#-异步运行空间池-密钥的PowerShell

已添加通过C#-异步运行空间池-密钥的PowerShell,c#,powershell,asynchronous,runspace,C#,Powershell,Asynchronous,Runspace,长期潜伏者(特别是在这个问题上)。我一直在研究这个网站上与我的问题直接相关的异步帖子,但我没有找到解决方案。我还尝试了以下代码的许多不同变体,但都没有成功 正在发生的事情是,我异步执行ps.BeginInvoke(),在将命令加载到它之后,使用某种方法异步启动调用,它确实始终异步运行!但问题是(例如),执行的命令只会返回结果,有时是10次中的2次,有时是10次中的8次。以下是我正在执行的当前代码的示例: internal class aSyncPowershellCommand { //

长期潜伏者(特别是在这个问题上)。我一直在研究这个网站上与我的问题直接相关的异步帖子,但我没有找到解决方案。我还尝试了以下代码的许多不同变体,但都没有成功

正在发生的事情是,我异步执行
ps.BeginInvoke()
,在将命令加载到它之后,使用某种方法异步启动调用,它确实始终异步运行!但问题是(例如),执行的命令只会返回结果,有时是10次中的2次,有时是10次中的8次。以下是我正在执行的当前代码的示例:

internal class aSyncPowershellCommand
{
    //private static Collection<Collection<PSObject>> GlobalResults = new Collection<Collection<PSObject>>();

    // This exists simply
    public bool Finished { get; set; }

    private object instanceLock = new object();
    private PowerShell ps;
   // private Guid uniqueGuid = Guid.NewGuid();

    private PSDataCollection<PSObject> psresult;

    public async Task<bool> PowershellLaunchPool(Dictionary<ARS_GroupObject, string> 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<Guid, IAsyncResult> powershellCommandResults = new ConcurrentDictionary<Guid, IAsyncResult>();
        ConcurrentDictionary<Guid, PowerShell> powershellSessions = new ConcurrentDictionary<Guid, PowerShell>();

        // 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<PSObject>();

            // 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<DataAddedEventArgs>(tmpInstance_DataAdded);
            this.ps.InvocationStateChanged += new EventHandler<PSInvocationStateChangedEventArgs>(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<PSObject, PSObject>(null, this.psresult));
        }

        while (Finished != true)
        {
            Thread.Sleep(3000);
        }
        return true;
    }

    private void tmpInstance_DataAdded(object sender, DataAddedEventArgs e)
    {
        PSDataCollection<PSObject> tmpReturn = (PSDataCollection<PSObject>)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());
        }

    }
}
否则,它会很快返回结果

我认为问题在于PowerShell会话正在尝试写入同一个内部输出对象,尽管它正在以相同的方式执行

1.)它自己的新PowerShell实例
2.)在运行空间池管理的不同运行空间中

每次运行脚本时,此错误至少发生一次。有时,它实际上会吐出10个组中的8个结果,有时它只对1个有效


我怎样才能阻止碰撞的发生?我怀疑是PowerShell内部发生了什么事情导致了这种情况。

我实际上刚刚尝试了MSDN运行空间池示例代码的一个非常基本的版本,并将默认命令替换为get qadgroup命令,我得到了完全相同的错误消息。所有Powershell实例是否可能同时尝试写入同一共享PSCollection?我想知道是否有一个设置可以用来将会话输出到不同的默认对象。或者我可以在只发生一个特定错误的情况下继续尝试?我不知道我是在兜圈子还是不在这里。。。。但现在当我看到这个问题时,似乎问题在于发送到PowerShell对象的命令需要更加独特。。。我注意到该命令以
get qaduser
开头,它表示“已经添加了密钥”,尽管每个命令中的标识参数都不同。首先尝试将命令包装到一个唯一命名的PowerShell函数中有意义吗?
System.Management.Automation.CmdletInvocationException: An item with the same key has already been added. 
---> System.ArgumentException: An item with the same key has already been added.