今天拜读了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-DateStart-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-DateStart-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 = $Param1Param2 = $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 = $Param1title = $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.IPAddressToStringComputerName=$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 = $JobResult = $Job.BeginInvoke()}
}#循环输出等待的信息.... 直到所有的job都完成 Write-Host "Waiting.." -NoNewline
Do {Write-Host "." -NoNewlineStart-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/

PowerShell runspace 的创建,使用和查错相关推荐

  1. SAP MM MB21创建预留单据报错- Error during conversion to alternative units of measure -

    SAP MM MB21创建预留单据报错- Error during conversion to alternative units of measure - 某日下午收到业务部门报错,说是创建预留单保 ...

  2. SAP WM自动创建TO后台作业报错 - Processing Type没有维护 - 之对策

    SAP WM自动创建TO后台作业报错 - Processing Type没有维护 - 之对策 笔者所在的D项目上,需要设置自动创建TO的后台作业.笔者为程序RLAUTA10定义了变式,然后设置了后台作 ...

  3. Windows PowerShell 2.0创建调用脚本文件

    在PowerShell中不存在文件和目录的概念,涉及文件和目录的操作总是转换为项(item)处理,即Get-Item.Get-ChildItem和Get-ItemProperty.在PowerShel ...

  4. java实现简易计算器,实现加减乘除,括号,算式查错,

    java实现简易计算器 问题分析 一.计算机界面显示 二. 计算器计算数据处理 三. 部分源代码(该源码未加入算式查错,文件资源正在上传) 三.完整源码,加减乘除,括号,delete,算式查错 问题分 ...

  5. IDEA创建maven项目报错解决:Failed to create a Maven project: 'C:/Users/../IdeaProjects/../pom.xml' already e

    此文首发于我的个人博客:IDEA创建maven项目报错解决 Failed to create a Maven project 'C:/Users/-/IdeaProjects/-/pom.xml' a ...

  6. SAP WM 执行VL06P为交货单创建组,报错-TO for multiple deliveries only with delayed delivery update-

    SAP WM 执行VL06P为交货单创建组,报错-TO for multiple deliveries only with delayed delivery update- 1, 如下销售订单728, ...

  7. SAP WM LT42创建TO,报错-No entry in Table 329S (NM1 B)-

    SAP WM LT42创建TO,报错-No entry in Table 329S (NM1 B)- 在2-step拣配流程里,执行事务代码LT42为Allocation创建TO单据的时候, 系统提醒 ...

  8. eclipse 向HDFS中创建文件夹报错 permission denied

    环境:win7  eclipse    hadoop 1.1.2 当执行创建文件的的时候, 即: String Path = "hdfs://host2:9000"; FileSy ...

  9. (五)stm32工程代码HardFault异常查错调试方法

    (五)stm32工程代码HardFault异常查错调试方法 参考文章: (1)(五)stm32工程代码HardFault异常查错调试方法 (2)https://www.cnblogs.com/zhan ...

最新文章

  1. 如何改变android5.1音量进度条,HTML5音频audio属性
  2. 梳理MVC 架构 MVVM架构
  3. SVN Access Manager 0.5.5.14 发布 - SVN 管理工具
  4. 惊呆!学习MySQL真的这一篇就够了!太全了
  5. Android Binder Driver缺陷导致定屏问题分析
  6. 历史最牛 多页切换TabHost,给大家参考。
  7. java list 移除_java 中List删除实例详解
  8. 使用ASP.NET AJAX异步调用Web Service和页面中的类方法(2):处理异步调用中的异常...
  9. 【LOJ】#2887. 「APIO2015」雅加达的摩天楼 Jakarta Skyscrapers
  10. 苹果cmsv10整合七牛云播放器插件
  11. quarts集群 运维_Quartz.Net分布式运用
  12. 官网CentOs7镜像下载详细步骤
  13. maven日记(一):Maven使用入门
  14. winform 鼠标拖动移动图片位置
  15. 宿舍管理程序c语言,学生宿舍管理软件C语言源代码完整版
  16. Mars XLog日志模块集成
  17. 如何用Java读取单元格的数据_Java读取Excel中的单元格数据
  18. 21个小故事,21个启示
  19. NMOS管与PMOS管的区别与总结
  20. 王者荣耀 让好友看到的括号中不显示默认备注

热门文章

  1. !!!光线对视频识别技术的影响
  2. 【哈利波特】Sherbert Lemon对HP的解读之六
  3. 设计模式之美:Type Object(类型对象)
  4. JavaScript 编码小技巧
  5. 浅谈inode和block与磁盘性能的初级优化
  6. SQL中truncate table和delete的区别
  7. 7 款从 HTML 文档提取文本的工具
  8. Git中的AutoCRLF与SafeCRLF换行符问题
  9. css案例学习之div与span的区别
  10. (转)pipe row的用法, Oracle split 函数写法.