3

这一部分着重于介绍Powershell的程序知识,让我们能够编写功能强大的Powershell脚本,执行比较复杂的任务。

变量

变量使用$变量名创建和引用。举个例子,Get-Location命令用于获取当前工作目录位置,它的别名是pwd。那么我们可以使用下面的命令来创建一个变量,存储当前目录位置。

C:\Users\asddf> $current=pwd

然后我们访问$current,就可以获取实际值了。

C:\Users\asddf> $current

Path          
----          
C:\Users\asddf

如果知道这个命令返回的实际是.NET对象的话,我们还可以更进一步,比方说直接访问这个对象的Path属性,获取值。

C:\Users\asddf> $current.Path
C:\Users\asddf

还有一个命令Get-Member,别名是gm,用于获取对象的属性。比方说,我们将Get-Location命令的结果通过管道传递给Get-Member命令,就会显示下面的输出。如果不了解.NET的话,可能感觉比较陌生。但是如果你懂得.NET和C#的话,就会像我一样大喊一声:“卧槽,还能这样玩?!”

C:\Users\asddf> Get-Location|Get-Member


   TypeName:System.Management.Automation.PathInfo

Name         MemberType Definition                                               
----         ---------- ----------                                               
Equals       Method     bool Equals(System.Object obj)                           
GetHashCode  Method     int GetHashCode()                                        
GetType      Method     type GetType()                                           
ToString     Method     string ToString()                                        
Drive        Property   System.Management.Automation.PSDriveInfo Drive {get;}    
Path         Property   string Path {get;}                                       
Provider     Property   System.Management.Automation.ProviderInfo Provider {get;}
ProviderPath Property   string ProviderPath {get;}

如果我们要获取对象的所有属性,使用MemberType参数。

C:\Users\asddf> pwd|gm -MemberType Property

我们还可以在变量上调用方法, 比如说将路径转换为全小写。


C:\Users\asddf> $current.Path.ToLower()
c:\users\asddf

最后,如果不再需要一个变量,可以使用Remove-Variable删除变量,它的别名是rv

C:\Users\asddf> Remove-Variable current

操作符

来看看Powershell中支持的操作符。

数学运算符

首先,基本的数学运算符都是支持的。

PS D:\Desktop> $i=5
PS D:\Desktop> $sum=3+4*($i-3)/2
PS D:\Desktop> $sum
7

前置后置自增自减运算符也是支持的。

PS D:\Desktop> $i=0
PS D:\Desktop> $i--
PS D:\Desktop> $i++
PS D:\Desktop> ++$i
PS D:\Desktop> --$i

比较运算符

然后是比较运算符,这些和Linux Shell中很相似,有大于(-gt),大于等于(-ge),小于(-lt),小于等于(-le),等于(-eq),不等于(-ne)几个。

字符串匹配运算符

-like-notlike用于?*这样的通配符。

PS D:\Desktop> 'hello' -like '?ello'
True
PS D:\Desktop> 'hello' -notlike '?ello'
False
PS D:\Desktop> 'hello' -like '*o'
True

-match-notmatch用于正则表达式。

PS D:\Desktop> 'aabcc' -match 'a*b?c+'
True
PS D:\Desktop> 'aab' -match 'a*b?c+'
False

包含和替换运算符

-contains查找序列中是否包含某个元素。

PS D:\Desktop> 'hello','zhang3' -contains 'zhang3'
True

-replace用于替换字符串中某个部分,当然正则表达式也是支持的。

PS D:\Desktop> 'hello zhang3' -replace 'zhang3','yitian'
hello yitian

分隔和连接运算符

-split-join用于将一个字符串分为几个子部分,或者将几个子部分组合为一个字符串。

PS D:\Desktop> 'A B C DE' -split ' '
A
B
C
DE
PS D:\Desktop> 'A','B','C' -join ','
A,B,C

上面这些运算符都是大小写不敏感的,如果需要大小写敏感的功能,可以在运算符前面添加c前缀。

PS D:\Desktop> 'yitian' -match 'Yitian'
True
PS D:\Desktop> 'yitian' -cmatch 'Yitian'
False

逻辑运算符

逻辑运算符有与(-and)、或(-or)、非(-not!)以及异或(xor)几个,并且支持短路计算。

如果需要使用真值和假值字面量,可以使用$true$false

类型运算符

Powershell 和.NET平台绑定,所以它是一门强类型的脚本。因此我们可以在脚本中判断数据的类型,只要使用-is-isnot运算符即可,类型需要写到方括号中。这里的类型可以是所有合适的.NET类型。

PS D:\Desktop> 3.14 -is [Double]
True
PS D:\Desktop> 3.14 -isnot [Float]
True

重定向运算符

这个稍微比较麻烦一点。

首先是>>>运算符,用于将标准输出流重定向到文件,前者会覆盖已有文件,后者则是追加到已有文件末尾。

然后我们来说说日志级别,如果有使用过某些语言的日志框架的话,就很好理解了。在这里,2代表错误、3代表警告、4代表信息、5代表调试信息。n>n>>运算符就是用于将对应级别的输出重定向到文件的,这两者的区别和前面相同。n>&1将对应级别的输出和标准输出一起重定向到文件。

最后就是*>*>>了,这两者将所有输出信息重定向到文件。

需要注意,Powershell使用Unicode编码来输出信息。如果你需要使用其他类型的编码,就不能使用重定向运算符了,而应该使用Out-File命令。

特殊运算符

&运算符将它后面的命令设置为后台运行,当运行的命令需要阻塞当前终端的时候很有用。

.\\运算符用于执行一个脚本或命令。如果执行的是Powershell脚本,那么脚本会在自己的作用域中执行,也就是说在当前环境下无法访问被执行的脚本中的变量。

[]运算符用于转换变量的类型,比如说下面的代码,就将pi变量转换为了Float类型。

[Float]$pi = 3.14
$pi -is [Float]

.运算符用于调用.NET对象的成员,它也可以用于执行脚本。当它用于执行脚本的时候,脚本会在当前作用域中执行。所以脚本结束之后,我们可以访问脚本中的元素。

::运算符用于调用类中的静态成员,例如下面就会调用.NET平台中DateTime类的Now属性。

PS D:\Desktop> [DateTime]::Now

2017年5月18日 22:45:42

..运算符用于创建一个范围闭区间,例如下面这样。

PS D:\Desktop> 1..3
1
2
3
PS D:\Desktop> 3..1
3
2
1

-f运算符用于格式化数据,例如下面这样。格式化方法和C#中的完全相同,所以如果不熟悉的话直接看在C#中如何格式化数据就行了。

PS D:\Desktop> 'My name is {0}, I am {1} years old' -f 'yitian',24
My name is yitian, I am 24 years old

$运算符可以将字符串内部的变量转换为实际的值,例如下面这样。需要注意使用内插操作符的时候,外部字符串需要使用双引号,否则Powershell会直接输出字符串内容。

PS D:\Desktop> $name='yitian'
PS D:\Desktop> $age=24
PS D:\Desktop> "My name is $name, I am $age years old."
My name is yitian, I am 24 years old.

@()运算符用于将一系列值转换为一个数组。假如在脚本中有一个函数可能返回0、1或多个值,就可以使用这个操作符,将一系列值合并为一个数组,方便后续处理。

,逗号运算符如果放置在单个值前面,就会创建一个包含这个值的单元素数组。

条件判断

if判断

Powershell中的条件判断和一般的编程语言以及Shell编程都很类似,直接看代码就能理解。

$condition = $true

if ($condition -eq $true) {
    Write-Output "condition is $true"
}
elseif ($condition -ne $true ) {
    Write-Output "condition is $false"
}
else {
    Write-Output "other ocndition"
}

switch判断

如果需要多重判断,可以考虑使用switch语句。一个典型的switch如下所示。

$n = 4
switch ($n) {
    1 {"n is 1"}
    2 {"n is 2"}
    3 {"n is 3"}
    default {"n is others"}
}

其实细说起来,这个switch的坑还是不少的。例如,switch语句可以接受多个值来测试,在switch语句中还可以编写多个case相同的语句。这里我就不细说了,想具体了解的话直接看官方文档 about_Switch吧。

循环语句

提醒一下,不管是哪种循环语句,在循环体内都可以使用breakcontinue中断/继续循环。

do循环

首先来看看do-while循环,先执行循环体,然后判断是否满足条件,如果满足条件则继续执行。

$i = 0
do {
    $i++
    Write-Output $i
}while ($i -ne 3)

然后是do-until循环,和do-while类似,不过当条件不满足的时候才会继续循环,如果满足条件则退出循环。

$i = 0
do {
    $i++
    Write-Output $i
}until ($i -eq 3)

while循环

while循环是先判断循环条件,满足条件时执行循环。

$i = 0
while ($i -lt 3) {
    Write-Output $i
    $i++
}

for循环

for循环可以看做是while循环的另一种形式,常用于固定次数的循环。

for ($i = 0; $i -ne 3; $i++) {
    Write-Output $i
}

for-each循环

for-each循环用于遍历一个集合中的所有元素。

$array = @(1, 2, 3, 4)
foreach ($i in $array) {
    Write-Output $i
}

值得一提的是,for-each语句用在管道上时,还有以下一种用法。

<command> | foreach {<beginning command_block>}{<middle command_block>}{<ending command_block>}

使用这种方法时,for-each后面可以跟三个语句块,第一个语句块是开始语句块,在循环前执行一次,常用来初始化一些数据;第三个是结束语句块,在循环结束之后执行一次,常用于统计一些循环数据;第二个就是正常的循环语句块,会循环多次。

函数

定义函数

定义函数使用function关键字。

function hello {
    Write-Output 'Hello Powershell'
}

定义好函数之后,就可以使用函数名来调用函数了。

hello

函数的参数

函数当然也可以带参数了,参数列表有两种写法:第一种是C风格的,参数列表写在函数名后面,使用小括号分隔开;第二种方式是在方法体中,使用param关键字声明参数。这两种方法是完全等价的,当然我习惯上还是喜欢使用第一种方式。

Powershell是一种强类型的脚本语言,所以可以在参数列表上添加参数类型,参数类型是可选的,不过我还是推荐写的时候带上类型,方便阅读和类型检查。

function Say-Hello ([string] $name) {
    Write-Output "Hello, $name"
}

function Say-Hello2 {
    param([string] $name)
    Write-Output "Hello, $name"
}

调用带参数的函数时,需要向调用命令那样,使用-参数名来传递参数,例如下面这样。

Say-Hello -name 'yitian'

默认参数

Powershell支持默认参数,直接用赋值号=在参数列表上指定参数默认值即可。


function Say-Hello3 {
    param([string] $name = 'zhang3')
    Write-Output "Hello, $name"
}

位置参数

Powershell也支持位置参数,它会把所有参数包装到$args数组中,所以我们可以通过这个变量访问所有位置的参数。例如下面,将所有参数合并一个字符串,然后打印出来。

function Say-Hellos {
    $names = $args -join ','
    Write-Output "Hello, $names"
}

这个函数调用时候需要指定多个参数,注意不要在多个参数之间添加括号,否则会变成一个数组参数,而不是多个参数。

Say-Hellos 'yitian' 'zhang3' 'li4'

开关参数

开关参数没有类型,作用仅仅是标志是或者否。如果在使用函数的时候带上开关参数,那么它就是的状态,否则就是的状态。开关参数需要指定参数类型为switch

function Answer-Hello ([switch] $yes) {
    if ($yes) {
        Write-Output "Hi"
    }
}

然后在调用时就可以看出区别了。

Answer-Hello -yes
Answer-Hello 

函数返回值

最后来说说函数返回值。这个其实也很简单,只要使用return语句就可以了。

function Add ([double]$a, [double]$b) {
    $c = $a + $b
    return $c
}

然后我们调用函数,就可以看到结果了。

Add -a 3 -b 5

关于Powershell编程的知识就介绍到这里,其实如果看看官方文档的话,就知道这里介绍的也仅仅是一部分而已。不过这一部分对于我们日常使用和学习基本上也够用了。

如果要查看详细帮助的话,可以运行一下下面的命令,这样会显示所有和Powershell相关的帮助文档。

Get-Help about*

然后,就可以阅读自己感兴趣的部分了。比方说,如果我们想了解用Powershell编写类,就可以使用下面的命令。如果想在浏览器中浏览器在线版本,加上-online参数即可。

Get-Help about_Classes

参考资料

https://msdn.microsoft.com/en...

http://windowsitpro.com/power...


techstay
988 声望55 粉丝