首页 > 代码库 > Cmdlet开发与学习(七)

Cmdlet开发与学习(七)

      到目前的例子为止,我们使用的都是不带参数的CreateRunspace()方法创建的运行空间实例,这就意味着,我们使用的都是默认的命令集合,提供程序,初始化脚本和格式信息。

      但是,这些默认的配置信息都是可以控制的,这要通过RunspaceConfiguration类实现。RunspaceConfiguration类是CreateRunspace函数的参数。创建运行空间实例后,其中的会话状态变量可以通过运行空间实例的SessionStateProxy来设置和获取。

      注意:如果运行空间处于BeforeOpen状态,可以直接修改其配置。但是在runspace.open之后,不是任何配置修改都管用。具体上说,在open之后,AddPSSnapin()函数和RemovePSSnapin()函数好使,但是直接修改Assemblies,cmdlet,Formats,Scripts和Types集合的操作却是不允许的。

      

 1         static void Main(string[] args)
 2         {
 3             RunspaceConfiguration configuration = RunspaceConfiguration.Create();
 4             PSSnapInException warning = null;
 5             //Add PSSnapIn,系统自动调用update
 6             configuration.AddPSSnapIn("MySnapin", out warning);
 7 
 8             Runspace runspace = RunspaceFactory.CreateRunspace(configuration);
 9             //通过SessionStateProxy修改会话状态变量
10             runspace.SessionStateProxy.SetVariable("factorOne", 7);
11             runspace.SessionStateProxy.SetVariable("factorTwo", 11);
12 
13             //下面是关于配置集合的修改,只有在update时候才起效
14             //添加cmdlet GetWidgetCmdlet是实现cmdlet的.Net类型
15             runspace.RunspaceConfiguration.Cmdlets.Append(new CmdletConfigurationEntry("get-widget", typeof(GetWidgetCmdlet),null));
16             runspace.RunspaceConfiguration.Cmdlets.Update();
17 
18             //添加格式文件
19             runspace.RunspaceConfiguration.Formats.Append(new FormatConfigurationEntry("C:\\myformat.ps1xml"));
20             runspace.RunspaceConfiguration.Formats.Update();
21 
22             //添加函数
23             runspace.RunspaceConfiguration.Scripts.Append(new ScriptConfigurationEntry("add","return $args[0] + $args[1]"));
24             runspace.RunspaceConfiguration.Scripts.Update();
25             runspace.Open();
26             
27             //...
28         }

        AddPSSnapIn()的PSConsoleLoadException类型的out参数在调用失败时,返回PSSnapInException实例。如果找不到snap-in,或者发生其他致命错误,则AddPSSnapIn()抛出异常。

 

        异步执行管道

        异步执行管道,调用InvokeAsync()方法,它的执行前提条件与调用Invoke类似。

        这里需要注意的是,在调用InvokeAsync后,管道得在关闭输入管道后才执行。     

1             Runspace runspace = RunspaceFactory.CreateRunspace();
2             runspace.Open();
3 
4             Pipeline pipeline = runspace.CreatePipeline("Command");
5             pipeline.InvokeAsync();
6             pipeline.Input.Close();

       如果输入管道已关闭,再次调用close不会产生异常,但是可以用PipelineWriter类的IsOpen属性检查管道是否处于关闭状态。

       既然执行了异步,那么重点必然就是读取输出和错误了。主要看PipelineReader提供的可用方法。

       1.Read():读取对象,如果对象不可用,就阻塞执行一直等待

       2.Read(count):读取count个对象,阻塞执行直到所有的对象都可用

       3.ReadToEnd():读取数据直到管道关闭

       4.Peek():检查是否有可用的对象

       5.NonBlockingRead():读一个对象,如果该对象不存在,则直接返回

       6.NonBlockingRead(count):读取count个对象,如果该对象不存在,则直接返回

       PipelineReader还有个有用的属性WaitHandle,可以用来等待输出和DataReady事件,DataReady事件只有当输出可用时才输出。

 

      下面用一个例子来演示:

      

 1   Runspace runspace = RunspaceFactory.CreateRunspace();
 2             runspace.Open();
 3 
 4             Pipeline pipeline = runspace.CreatePipeline("Command");
 5             pipeline.InvokeAsync();
 6             WaitHandle[] handles = new WaitHandle[2];
 7             handles[0] = pipeline.Output.WaitHandle;
 8             handles[1] = pipeline.Error.WaitHandle;
 9             pipeline.Input.Close();
10 
11             while (pipeline.PipelineStateInfo.State == PipelineState.Running)
12             {
13                 switch (WaitHandle.WaitAny(handles))
14                 {
15                     case 0:
16                         while (pipeline.Output.Count > 0)
17                         {
18                             Console.WriteLine("Output: {0}", pipeline.Output.Read());
19                         }
20                         break;
21                     case 1:
22                         while (pipeline.Error.Count > 0)
23                         {
24                             Console.WriteLine("Error: {0}", pipeline.Error.Read());
25                         }
26                         break;
27                 }
28             }

 

       管道状态   

       管道存在几种状态:NotStarted,Running,Stopping,Stopped,Completed,Failed。

       可以监视管道的StateChanged事件,在管道的状态发生改变时,做出相应的处理。

 

       终结性错误

       当异步管道发生终结型错误时,管道状态变为Failed,抛出StateChanged事件,PipelineStateInfo对象的Reason属性包含了ErrorRecord对象,里面记录着终结型错误信息。

 

       停止管道

       如果希望关闭正在执行的异步管道,管道对象的Stop()和StopAsync()函数都可以实现这个效果。

       这里需要明确的是,调用上述的两个停止方法时,管道状态变为Stopping,StateChanged事件触发。如果管道线程正在调用外部代码,比如其他.Net方法,则管道处于无限Stopping状态,等待外部调用返回。如果管道成功停止,则变为Stopped状态。