已添加通过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.