上次忘记提SDK的路径了,Windows 7中的PowerShell SDK是存放在%ProgramFiles%\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0下,64位系统则是%ProgramFiles(x86)%\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0。其中的DLL都是Managed的,在用Visual Studio添加引用的时候,要指定路径才可以。
PowerShell.Invoke函数会执行当前存放在PowerShell对象中的命令,并返回一系统PSObject(即Collection<PSObject>),这是PowerShell对象中的最后一条命令的执行结果,当于有可能整个Collection为空,比如Import-Module这种cmdlet就是不返回任何结果的。在上一个例子中:
1 2 3 4 5 6 7 | Collection<PSObject> results = ps.Invoke(); Console.WriteLine("Id\tName\tCPU Time\tHandleCount"); foreach (PSObject result in results) { System.Diagnostics.Process p = result.BaseObject as System.Diagnostics.Process; Console.WriteLine(String.Format("{0}\t{1}\t{2}\t{3}", p.Id, p.ProcessName, p.UserProcessorTime, p.HandleCount)); } |
我们可以看到,PSObject可以被转换成实际的对象,比如Get-Process返回的对象实际上是System.Diagnostics.Process类的实例。转换完成后,操作起来就方便多了。当然,如果你不知道它的实际类型是什么,你也可以通过PSObject.Members属性来获得它的一些成员。
那么,出现了错误该怎么办?有两种方法,一种是通过PowerShell的公共参数ErrorVariable把某一条命令的错误存放到一个PowerShell的变量中,然后再用Write-Host命令把它当成Invoke的结果返回出来。这样做有一个坏处是,在发生错误的时候,你可能就拿不到那条命令的实际结果了。
另一种方法是,用PowerShell类中的Streams属性。Streams中保存中PowerShell脚本执行过程中出现的各种Warning和Error对象。下面看一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class InvocationResult { public InvocationResult() { Errors = new List<ErrorRecord>(); Warnings = new List<WarningRecord>(); Results = new List<PSObject>(); } public List<ErrorRecord> Errors { get; private set; } public List<WarningRecord> Warnings { get; private set; } public List<PSObject> Results { get; private set; } } |
这是一个简单的类,于是保存Invoke之后的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | static InvocationResult Invoke(PowerShell ps) { InvocationResult result = new InvocationResult(); try { Collection<PSObject> tmp = ps.Invoke(); result.Results.AddRange(tmp); } catch (RuntimeException re) { result.Errors.Add(re.ErrorRecord); } result.Errors.AddRange(ps.Streams.Error); result.Warnings.AddRange(ps.Streams.Warning); return result; } |
这样我们就可以把整个PowerShell脚本执行过程中所有的Error、Warning都保存下来了,为之后要详细的检测做准备。