Powershell学习笔记——了解Powershell

2018-06-09 09:55 更新

引子

  公司在Windows环境下进行开发,所以在写自动构建的时候,自然而然地想到了CMD SHELL。本来考虑过使用Windows Script Host脚本(WSF、JS或VBS)来写,但要在WSH脚本里调用VS的批处理来设置环境很困难。随着项目结构变得复杂,CMD SHELL写的构建脚本也开始变得复杂,这个时候就感到CMD SHELL有点吃力了,于是想到了Powershell。

  在这之前对Powershell其实有过一些了解,知道它是一个比CMD SHELL更适合写脚本程序的东西,跟.NET有着莫大的关系。不过之前的了解也仅此而已,所以还是需要先学习一下。通过Google找到了Tobias Weltner博士写的《Master Powershell》(http://powershell.com/cs/blogs/ebook/),花了半天拣想了解的部分通看了一遍,于是有了写下《Powershell学习笔记》的想法。

  感谢Tobias Weltner博士,以及他那本免费的《Master Powershell》!

 

从CMD SHELL到Powershell

  看了《Master Powershell》一遍之后,我觉得学习Powershell是正确的。

  CMD SHELL(以下简称CMD)来源于DOS时代的批处理脚本,它最初的设计就是为着顺序批处理来的。在Windows 2000和Windows XP时代,DOS批处理正式升级为CMD SHELL,在语法和功能上做了一些扩展;脚本文件开始支持.CMD扩展名,并兼容之前的.BAT扩展名;其名称也由“DOS窗口”改为“命令提示符”。CMD SHELL虽然可以完成很多比较复杂的任务,但却非常考验脚本开发者大脑的堆栈大小。

  CMD的确适合写一些简单的SHELL程序,而Powershell却包含了写一个复杂的脚本程序所需要的各种支持,包括语法和函数库——巨大的.NET函数库。

1. 参数处理,Powershell方便不只一点点

  CMD中处理参数,通常是按顺序处理%1-%9,参数比较多还需要通过SHIFT命令来对参数进行移位。如果想处理位置不定的switch参数,或者处理命名参数,那就分析参数这部分脚本都能把人搞搅晕。而Powershell原生就支持参数数组、命名参数和switch参数。比如

  1. # test.ps1 
  2. # 在脚本中定义命名参数和switch参数 
  3. param($name, [switch] $isMale) 
  4. # 如果 .\test.ps1 -name "James Fancy" -ismale 
  5. #  $name的值为James Fancy 
  6. #  $isMale的值为True 
  7. # 如果缺省-ismale参数,$isMale的值为False 
  8. # 如果 .\test.ps1 -name -ismale 
  9. #  会直接报告错误,因为-name需要附加的参数 

  可见Powershell已经将参数处理部分进行了很好的封闭。如果要用CMD来写,那就需要GOTO、SHIFT若干条件分支以及若干临时的环境变量。

2. Powershell,Powered Variable

  CMD中的变量,其实都是环境变量,而且其值一定是字符串。而Powershell中有真正意义的变量,并且这些变量可以是字符串类型、数值类型、日期类型……甚至任意对象类型,只要是.NET库中支持的对象。不错,Powershell是一个面向对象的脚本。很酷,是么?

  CMD中如果需要列表怎么办——用分号分隔的字符串值;那如果需要哈希表呢——用分号分隔的带等号的字符串值……是的,CMD可以做到,只是处理起来麻烦一点而已。当然,在Powershell中不需要这么麻烦,Powershell支持数组类型的变量和哈希表类型的变量,就像——嗯,像什么呢?有点像PHP,也有点像Javascript。

  1. # 定义一个数组 
  2. $a = 1,2,3 
  3. # 也可以这样定义 
  4. $a = @(1,2,3) 
  5. # 或者定义一个空数组 
  6. $a = @() 
  7. # 再定义两个哈希表 
  8. $m1 = ${ key1="value1";key2=1234 } 
  9. $emptymap = ${} 

3. 丰富的表达式

  在CMD中如果想计算四则运算,需要用到SET /A命令,可以进行常见的各种算术运算。Powershell当然不输于CMD。Powershell中可以进行各种各样的运算,而且完全不需要通过命令来进行。

  当然Powershell能做的不仅是这样。比如获取日期,CMD下需要获取日期当然是用DATE命令,如果要干净一点的日期,用DATE /T,不过输出的日期格式嘛……当然就看在Windows里怎么设置的啦。而在Powershell里,日期是一个对象,格式嘛,当然可以想什么样就什么样……

  1. # 按两种格式输出日期 
  2. (get-date).toString("yyyy-MM-dd HH:mm:ss") 
  3. # 输出 2011-10-04 09:54:47 
  4. (get-date).toString("yyyy年M月d日") 
  5. # 输出 2011年10月4日 

  对了,还有条件表达式,Powershell是通过-eq、-ne、-lt、-gt等运算符来进行比较,还可以通过-and、-or等运算符来表达组合条件……差点忘了-not,当然它还可以简写成“!”。

  1. # 下面表达式返回True 
  2. (1 -lt 2) -and (3 -eq 03) 

4. 字符串处理的天堂

  CMD中想要处理字符串,那简直就是恶梦!虽然SET和FOR命令外加GOTO或者CALL命令可以对字符串进行一些简单的处理,但是处理起来那是真的太太太复杂了。现在来到Powershell,天堂啊!字符串可以非常方便地重复、拼接、拆分、各种比较,甚至匹配正则表达式,因为这些都是.NET中的String对象所具有的能力。

  1. # 输出20个减号 
  2. "-" * 20 
  3. # 拼接为Powershell 
  4. "Powerh" + "shell" 
  5. # 匹配,以下均返回True 
  6. "powershell" -eq "POWERSHELL" 
  7. "powershell" -like "power*" 
  8. "powershell" -match "shell" 
  9. "powershell".startsWith("p") 
  10. # 区分大小写的比较和匹配,以下均返回False 
  11. "powershell" -ceq "POWERSHELL" 
  12. "powershell" -clike "P*" 
  13. "powershell".startsWith("P") 

  差点忘了伟大的String.Format,格式化字符串,直接看疗效:

  1. # 输出00EA 
  2. "{0:X4}" -f 234 
  3. # 上述语句等效于 
  4. [string]::format("{0:X4}", 234) 

5. 流程控制,伟大的飞跃

  CMD当然提供了控制流程控制,因为它提供了IF命令和FOR命令。IF命令很简单,它的方便性完全取决于条件表达式是否方便,从这一点一说,CMD的IF语句很好很强大。虽然没有SWITCH语句是个遗憾,但至少很多个IF语句是完全撑得起场面的。但话说回来,要FOR语句撑起循环的一片天,还真有点吃力,所以才经常会有通过GOTO语句来模拟循环的情况发生。

  来到Powershell中,说起流程控制,那简直就是一个飞跃。

  从条件分支控制来说,if和switch当然一个都不能少,而switch,更是非常的强大。switch精确匹配数值,这是常规功能;它还能匹配条件表达式,这似乎有点让人惊喜了;它还可以按区分大小写和不区分大小写两种方式匹配字符串;不止这些,它还可以按通配符进行匹配;都到这一步了,那按正则表达式匹配也少不掉啦!

  说起Powershell的循环,那就更是多样了,光Foreach都有两种,一种是Foreach关键字,用于数组地遍历;另一种是Foreach-Object命令,用于遍历管道输出的多个对象。很巧……也许是Microsoft故意的,Foreach-Object有个别名,就叫Foreach。另外,For语句当然不会少,还有常见的Do...While和While {}两种循环。这些都很觉,最神奇的,是Switch语句也可以用于循环处理数组,并且根据数组中各项的匹配情况来进行不同的处理——就相当于是把内嵌Switch的For/Foreach结构简化了一样!来个例子

  1. $array = 1..5 
  2. switch ($array) { 
  3. {$_ % 2} { "$_ is odd" } 
  4. default { "$_ is even" } 
  5. # 输出如下 
  6. # 1 is odd 
  7. # 2 is even 
  8. # 3 is odd 
  9. # 4 is even 
  10. # 5 is odd 

6. 函数和函数库

  CMD有函数吗?没有。CMD只是通过CALL模拟了函数调用。在脚本内部,“CALL:标签”和GOTO:EOF可以模拟函数调用及返回。而在脚本外部,则通过“CALL 脚本.CMD”来实现。所以CMD的函数库,是一堆.CMD或者.BAT文件。

  Powershell当然是支持定义函数的——通过function关键字。而且如果把若干函数放在一个.ps1脚本文本中,再通过点号(.)来调用的话,这些函数立即对当前环境可用——也就是说,这个.ps1脚本文件就是函数库。将相关的函数组织在一个脚本文件中当然会比组织在N个脚本文件中方便得多,也更利于发布。

  当然,关键问题在于Powershell支持函数。Powershell的函数也可以像脚本文件一样定义参数列表、命名参数和switch参数,并提供极其方便的解析功能。除此之外,Powershell的函数可以有返回值。不仅有,而且很强大,它可以以数组的的方式返回多个值。就像这样

  1. # 定义函数 
  2. function test([string] $a, [string] $b) { 
  3.     $a.toUpper(); 
  4.     $b.toLower(); 
  5. # 调用 
  6. $x, $y = test("James", "Fancy") 
  7. "`$x = $x, `$y = $y" 
  8. # 输出 $x = JAMES, $y = fancy 

7. 其它

  Powershell的好处远不止上面所说的那些,难怪Microsoft这么强烈的推荐使用Powershell代替CMD。甚至有人认为Powershell将成为Windows脚本的霸主。它的确比CMD强大了不止一点点,就是相对于WSH来说,它的便捷性和强大的.NET支持也是WSH所不能比拟的——压根就不是一个数量级的东西。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号