長年の潜伏者(特にこの問題について)。私の問題に直接関連するこの Web サイトの非同期投稿を調べていますが、解決策が見つかりません。また、以下のコードのさまざまなバリエーションを試してみましたが、役に立ちませんでした。
何が起こっているのか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());
}
}
}
さまざまな組み合わせを試しIASyncResult result = ps.BeginInvoke()
て、そのコマンドを何度も待っていますが、上記のコードと同じ結果になります。また、それをスタイルブロックに投げ込みvar task = Task.Factory.FromAsync(ps.beginInvoke(), p => ps.EndInvoke(p));
、タスクのリストに追加してから、もう一度すべての実行を待ってみ.ConfigureAwait(false);
ました...同じ結果です!
果たして結果はいかに?コマンドはすべて実行されますが、試行に失敗すると、次の例外がスローされます。
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.
それ以外の場合は、非常に迅速に結果を返します。
問題は、PowerShell セッションが次のように実行されているにもかかわらず、同じ内部出力オブジェクトに書き込もうとしていることにあると思います。
1.) それは独自の新しい PowerShell インスタンスです
。 2.) RunSpace プールによって管理される別の実行空間にあります。
このエラーは、スクリプトを実行するたびに少なくとも 1 回発生します。10 個のグループ結果のうち 8 個が実際に吐き出されることもあれば、1 つしか機能しないこともあります。
この衝突が起こらないようにするにはどうすればよいですか? これが発生する原因となっている PowerShell 内で内部的に何かが起こっているのではないかと疑っています。