PowerShell runspace 的创建,使用和查错

今天拜读了The Scripting Guy关于runspace的几篇大作,温故而知新,一些忽略的地方更为清楚。

https://blogs.technet.microsoft.com/heyscriptingguy/2015/11/26/beginning-use-of-powershell-runspaces-part-1/

runspace这两年在PowerShell使用的频率越来越高,由于他的高效率,基本上很多时候已经取代了传统的Job后台操作。不管是多线程实现,或者是后台操作,亦或是入侵脚本,runspace 的性能可以是job的几十倍以上。

现在由浅入深的看几个例子,到底是怎么实现的。

例1 同步操作一个PowerShell实例

创建一个PowerShell的实例,然后添加一段代码,然后invoke执行。

$PowerShell = [powershell]::Create()
[void]$PowerShell.AddScript({
    Get-Date
    Start-Sleep -Seconds 10
})
$PowerShell.Invoke()

注意几点:

  • PowerShell不仅仅是一个脚本语言,我们可以通过这个类System.Management.Automation.PowerShell所提供的方法来创建实例,添加脚本和参数。

    Powershell 作为平台的使用方法参考https://blogs.msdn.microsoft.com/powershell/2013/10/01/paap-windows-powershell-as-a-platform-part-1/

  • 我使用了[void]的目的是避免输出太多乱起八糟的信息(比如当前runspace的信息等等)来污染我的输出结果
  • 我在这个脚本里面添加了一条等待10秒的命令,当我们执行invoke命令的时候,会看见屏幕上卡了10秒以后,才返回当前的时间。 这种同步的操作在执行多线程和后台操作的时候应该避免,后面我们会说如何实现异步操作。

可以看见执行invoke之后直接返回了一个结果,事实上,这个和我直接在控制台输入Get-Date的效果一样,这样的脚本并不适合在后台操作。

例2,异步操作Runspace和PowerShell实例。

$Runspace = [runspacefactory]::CreateRunspace()
$PowerShell =[powershell]::Create()
$PowerShell.runspace = $Runspace
$Runspace.Open()
[void]$PowerShell.AddScript({
    Get-Date
    Start-Sleep -Seconds 10
})
$AsyncObject = $PowerShell.BeginInvoke()

这一次,我们创建一个runspace的对象,然后把它绑定到一个PowerShell的实例中,运行这个runspace,然后和上面一样,给这个PowerShell的实例添加脚本。请注意,一个很重要的改进是这里使用了BeginInvoke()方法,这个会返回一个异步的对象。异步和同步的区别在于,同步会死等在某个环节,直到输出结果,而异步会自动切换出来,定期的检查结果,等操作结束之后,再切换回去获取结果。

一个简单有趣的C#例子老王洗澡很生动了对比了同步和异步操作

http://www.cnblogs.com/lxblog/archive/2012/12/11/2813893.html

回到之前的脚本,我们来看看BeginInvoke返回的异步对象是什么样。因为我设置了要等10秒钟,所以可以看见他的IsComleted属性是False

10秒钟以后再查看,就已经变成True,这表示操作已经结束。

现在我们调用EndInvoke这个异步对象切换回去获取结果

$Data = $PowerShell.EndInvoke($AsyncObject)
$Data

成功获取结果

最后别忘记关掉这个实例。

$PowerShell.Dispose()

例3 给PowerShell的平台传递参数

$name = ‘James‘
$title = ‘Manager‘
$PowerShell =[powershell]::Create()
[void]$PowerShell.AddScript({
    Param ($Param1, $Param2)
    [pscustomobject]@{
        Param1 = $Param1
        Param2 = $Param2
    }
}).AddArgument($name).AddArgument($title)
#Invoke the command
$PowerShell.Invoke()
$PowerShell.Dispose()

比如我定义了2个变量,我可以通过AddArgument来传递到脚本块里,当然脚本块里面也得定义对应的参数,然后按顺序传入变量。

例4  如果参数过多,我可以通过定义hash表和 addParameters来传递参数,这样显得更为简洁。

$ParamList = @{
    param1 = ‘Kevin‘
    Param2 = ‘receptionist‘
}
$PowerShell = [powershell]::Create()
[void]$PowerShell.AddScript({
    Param ($Param1, $Param2)
    [pscustomobject]@{
        name = $Param1
        title = $Param2
    }
}).AddParameters($ParamList)
#Invoke the command
$PowerShell.Invoke()
$PowerShell.Dispose()

例5  整合上面的知识点,来个完整的例子,例如使用 runspace pool来实现多线程的Ping

这个是我之前写过的一个例子。http://beanxyz.blog.51cto.com/5570417/1760880

$Throttle = 20 #threads
 
#脚本块,对指定的计算机发送一个ICMP包测试,结果保存在一个对象里面,接收一个计算机名字的参数
  
$ScriptBlock = {
   Param (
      [string]$Computer
   )
   $a=test-connection -ComputerName $Computer -Count 1 
    
   $RunResult = New-Object PSObject -Property @{
      IPv4Adress=$a.ipv4address.IPAddressToString
      ComputerName=$Computer
       
   }
   Return $RunResult
}
 
 
#创建一个资源池,指定多少个runspace可以同时执行,这里表示最低1个,最多20个
 
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, $Throttle)
$RunspacePool.Open()
$Jobs = @()
  
 
#获取Windows 2012服务器的信息,对每一个服务器单独创建一个Powershell实例,每一个实例都异步的执行PING的操作,并把异步对象保存在Result里面
#最后把所有的结果都保存在一个Jobs的对象中。
#注意这里绑定的是RunspacePool,而不是单个的Runspace
  
(get-adcomputer -filter {operatingsystem -like "*2012*"}).name | % {
    
   #Start-Sleep -Seconds 1
   $Job = [powershell]::Create().AddScript($ScriptBlock).AddArgument($_)
   $Job.RunspacePool = $RunspacePool
   $Jobs += New-Object PSObject -Property @{
      Server = $_
      Pipe = $Job
      Result = $Job.BeginInvoke()
   }
}
  
 
 #循环输出等待的信息.... 直到所有的job都完成 
  
Write-Host "Waiting.." -NoNewline
Do {
   Write-Host "." -NoNewline
   Start-Sleep -Seconds 1
} While ( $Jobs.Result.IsCompleted -contains $false)
Write-Host "All jobs completed!"
 
 
#解锁,输出异步操作的结果 
$Results = @()
ForEach ($Job in $Jobs)
{   $Results += $Job.Pipe.EndInvoke($Job.Result)
}
  
$Results

例6, 最后看看来怎么debug runspace。 PowerShell 5 以后提供了一个命令 Debug-Runspace可以像普通的debug一样来跟踪当前执行的命令或者脚本。

先直接创建一个runspace,可以看见他的状态是available

$rs=[runspacefactory]::CreateRunspace()
$rs.name="MyRunSpace"
$rs.open()
get-runspace

把这个runspace绑定到一个powershell的实例,绑定某个脚本,异步执行

$ps=[powershell]::create()
$ps.runspace=$rs
$ps.addscript(‘C:\users\yli\documents\github\Powershell\Restart-WSUSComputers.ps1‘) > $null
$async=$ps.BeginInvoke()
get-runspace

可以看见他的状态变成了busy

这个时候我们来debug一下

Debug-Runspace Myrunspace

他自动就切换到我的脚本页面了,按F10就会一行行的自动跟踪执行下去了

如果需要终止debug,在控制台输入 detach 就可以了

参考资料

1. https://blogs.msdn.microsoft.com/powershell/2015/09/08/powershell-runspace-debugging-part-1/

2. https://blogs.msdn.microsoft.com/powershell/2013/10/01/paap-windows-powershell-as-a-platform-part-1/

3. http://www.cnblogs.com/lxblog/archive/2012/12/11/2813893.html

4. https://blogs.technet.microsoft.com/heyscriptingguy/2015/11/26/beginning-use-of-powershell-runspaces-part-1/

时间: 2024-10-10 10:03:08

PowerShell runspace 的创建,使用和查错的相关文章

Android应用测试工具ThreadingTest查错实例分析

1      ThreadingTest产品简介 ZOA公司研发的ThreadingTest智能型测试工具系列一期,是基于程序源代码的白盒测试工具.采取前端分析器和后端结果分析分离的技术路线,实现对多种语言的编译器级分析和多维度测试. ThreadingTest的核心思想来源于非线性复杂软件工程体系.通过ThreadingTest基于测试用例集与动态代码覆盖的双向追溯的专利技术,使得对于大型应用系统的维护和修改变得不再盲目和极易出错,使得对大型软件的系统测试期和维护期的测试过程从无量化依据到有明

使用DBUnit框架数据库插入特殊字符失败的查错经历

本文记录的是使用DBUnit测试框架进行数据库数据插入时,插入特殊字符失败的查错经历.希望能对向我这样的小白同学们在遇到类似问题时,能够有一些启发.背景:在写跟数据库交互模块的单元测试,数据库表中的ext字段,需要先写入数据,然后再读取出来,进行处理.ext字段格式是key1CTRL^Dvalue1CTRL^CKey2CTRL^Dvalue2.使用DBUnit框架来做单元测试,DBUnit是一个基于junit扩展的数据库测试框架.此次项目里插入数据库的数据是以xml形式的文件来组织的.xml文件

创建maven项目报错

我在自己的电脑上装了一个MyEclipse6.5 和spring tools suit 3.5.1  因为sts自带了maven插件,所以只要在 preference里面配置下maven的本地路径和settings文件的本地路径就可以了, 配置完了之后 我在MyEclipse和sts里面都导入了maven项目 都可以运行,我就觉得maven配置好了,但是我在sts里面创建maven项目的时候报错 Could not calculate build plan: Plugin org.apache.

opennebula kvm 创建VM oned报错日志

Thu Jul 17 10:45:36 2014 [ReM][D]: Req:4720 UID:0 VirtualMachineDeploy result SUCCESS, 12 Thu Jul 17 10:45:40 2014 [TM][D]: Message received: LOG I 12 Command execution fail: /app/opennebula/var/remotes/tm/shared/clone localhost.localdomain:/app/open

使用Eclipse自带的Maven插件创建Web项目时报错:

问题描述: 使用Eclipse自带的Maven插件创建Web项目时报错: Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webapp:RELEASE from any of the configured repositories. Could not resolve artifact org.apache.maven.archetypes:maven-archetype-webapp:pom:REL

Java笔试题之《Java代码查错》

Java代码查错 1.abstract class Name {   private String name;   public abstract boolean isStupidName(String name) {}}     大侠们,这有何错误?     答案: 错.abstract method必须以分号结尾,且不带花括号.2.public class Something {   void doSomething () {       private String s = ""

appium 查错

很高兴最近论坛用appium的人多了不少,但也有不少由于不了解appium导致出现错误后不知道从何下手.这里根据我的个人经验给出一个简单的查错指南,不保证能解决所有错误,但至少让你知道你应该朝哪个方向去解决. 1. 阅读Appium文档 这是很多人忽略但却是最重要的方法.Appium的文档说明了 如何正确使用appium 和 有哪些事情appium做不了或者要通过特殊方法做.大部分刚入门的同学的问题在这里面都能找到答案. 中文文档(由testerhome开源团队翻译,目前已和官方文档一致):ht

诡异的SpriteKit 游戏查错

在Endless Runner 游戏中,做了一些atlas后,发现有个问题,当player跳跃起来的时候,发现他没有动画了,被默认的X图片代替.原来的图像是这样的. 在增加了一些动画后,我的效果就成这样了. 这个不知道为何?当时碰到这个问题,我去查看了我的player.h,而且去看了的一些提供action的一些方法,结果还是不对,最后发现这个动画是在初始化的时候遍历我们的atlas来提供的,所以去查了一下,终于找到了答案.原因:在我们的player sprite相关的类,player.m中,在我

Django:创建用户模型报错: (admin.E108) The value of 'list_display[4]'解决方案

参考资料:虫师-<web接口开发与自动化测试:基于python语言> 日常学习Django框架中,创建了用户模型,但是页面功能验证时候,提示不能进行列表字段操作,debug好久,才找到问题原因,心累... 下面是大概过程和解决方案... models.py文件代码: 1 from django.db import models 2 3 # Create your models here. 4 # 发布会表 5 class Event(models.Model): 6 name = models