2013-07-17 136 views
1

我正在编写与PowerShell接口的代码。我原本有以下几种:为什么Runspace.OpenAsync()会忽略InitialSessionState?

using (var runspace = RunspaceFactory.CreateRunspace(initialSessionState)) 
{ 
    runspace.Open(); 

此代码工作得很好。然而,由于该代码实际上已经是一个异步方法,我写了下面只是实验:

public static Task OpenTaskAsync(this Runspace runspace) 
{ 
    if (runspace.RunspaceStateInfo.State == RunspaceState.Opened) 
     return Task.FromResult<object>(null); 

    var tcs = new TaskCompletionSource<object>(); 
    EventHandler<RunspaceStateEventArgs> stateHandler = null; 
    stateHandler = (o, e) => 
    { 
     if (e.RunspaceStateInfo.Reason != null) 
     { 
      runspace.StateChanged -= stateHandler; 
      tcs.TrySetException(e.RunspaceStateInfo.Reason); 
     } 
     else if (e.RunspaceStateInfo.State == RunspaceState.Opened) 
     { 
      runspace.StateChanged -= stateHandler; 
      tcs.TrySetResult(null); 
     } 
    }; 
    runspace.StateChanged += stateHandler; 
    runspace.OpenAsync(); 

    return tcs.Task; 
} 

然而,改变我的代码之后:

using (var runspace = RunspaceFactory.CreateRunspace(initialSessionState)) 
{ 
    await runspace.OpenTaskAsync(); 

我的测试,现在失败。造成这种情况的原因是,PowerShell无法再从导入InitialSessionState的模块中找到命令(在运行空间创建之前)。我无法确定这是为什么。我已经调试过,并且在此任务完成后,运行空间已打开并可用,并且在它执行之前,我不会继续调用任何命令。有任何想法吗?

回答

1

我查看了反射器中的runspace开放代码并查看了一件可能解释它的事情。在LocalRunspace.DoOpenHelper()StateChanged事件(当状态变为“打开”时)发生之前模块被导入。看起来您可以在默认驱动器上进行轮询(在InitialSessionState.SetSessionStateDrive()中)作为解决方法。

+0

有趣的是,我也看了反编译的代码(通过ReSharper/dotPeek)。我一定错过了那个细节。我再次检查,你是正确的。这是不幸的,因为似乎没有一个干净的替代解决方案(即你提到的投票)。好吧。我想知道他们为什么会提供异步方法而无法等待它们(即使是IAsyncResult)。 –

+1

我只能推测,但从某种意义上说,在这个点上运行空间是“打开”的。这是“为商业做好准备”。不幸的是,尚未准备好需要导入模块的业务。你可以改变初始会话状态来执行一些PowerShell代码(也许是一个小模块)来表明它已被加载。 (现在你可以玩“挑选最少的攻击手段”) –