PowerShell入门指南(三)·一门新的编程语言
作为独立的编程语言
作为一门独立的语言来说,PowerShell 是非常地Powerful,我们先来了解一下它的特点:
特点
破天荒的方便
诸如存储计算中
GB,MB,KB单位等;数组声明中的1..n和下标为-1的处理;还有所见即所得,通俗易懂的动词+名词结构的Cmdlet(PowerShell命令的称呼)。
还有自带的文档支持也很是丰富,只要熟练掌握Get-Help命令,其他命令的用法均可通过Get-Help查到面向对象
良心啊,这个语言竟然是面向对象的
与面向过程相比,面向对象更方便更容易描述现实世界,也算赶上了时髦。依托 .NET
正所谓大树下面好乘凉,
PowerShell绑上.NET这个大款了,借助.NET平台强大的类库,几乎让一切都成为可能。强大的兼容性
完全兼容
Windows平台上其它调用,如可执行文件(exe),批处理bat/cmd和VBscript等, 在Linux和macOS上也能很好地工作。基于平台的可扩展性
微软有个优点,与应用相比,它更喜欢做平台。
PowerShell早已变成一个平台,在PowerShell刚发布的第二年,微软的 System Center Operations Manager 和 SharePoint 就提供了针对该平台的组件,后来的活动目录,Hyper-V,Windows Azure,Office 365就更不用说了。除了微软,亚马逊的云平台管理,Dell的out-of-hand 管理,也都提供了基于PowerShell的管理组件。PowerShell俨然变成了一个标准,变成了一个规范。
使用Get-Help 快速入门
下面用一个简单例子说明如何Get-Help,设想这样一个场景:
你想通过命令行查看所有进程,你第一个反应应该是用一个跟Process相关的命令来达到此目的,所以你可以会尝试执行:
1 | Get-Command *Process |
得知处理进程的命令有这些
然后再用 Get-Help Get-Process -full 就能得到 Get-Process 的详细用法以及使用范例
基本语法
背景
PowerShell 是一个强类型(变量一旦定义,其本身类型不可改变就是强类型,反之就是弱类型)的动态脚本语言,支持面向对象,支持调用系统API和 .NET 库。
受到了 Python, Ksh, Perl, C#, CL, DCL, SQL, Tcl, Tk, Chef, Puppet 等语言的影响,结合了以上语言的部分特性。
PowerShell 代码的外观和操作方式与C#的相似程度最高,不过也有它自己的特色。
关于空白字符
与 Python 等语言不同,**PowerShell 的解释器不会考虑代码中的空格或制表符**(这些字符统称空白字符)。这样一来,格式化代码就有很大的自由度,但是遵循某些规则将有助于提高代码的可读性。
代码块和代码基本结构
PowerShell 代码由一系列语句构成,每条语句可以使用一个分号结束,当然也可以不写。按照习惯是不写分号的,因此要用换行来区分不同的语句,如果必须写到一行中,那就在每一句后加个分号。
和C语系的大多数语言类似,PowerShell 是一种块结构的语言,这些块用 { 和 } 来界定,代码块可以包含任意多条语句,或者不包含任何语句,下面的示例还使用了缩进格式,这样能大大提高可读性,实际上编译器会自带缩进代码。一般情况下,每个代码块都有自己的缩进级别,代码块之间还能嵌套。
1 | { |
当然 PowerShell 的缩进不是强制的。
在 PowerShell 代码中,另一种常见的语句是注释,注释并不是能执行的语句,而是对代码的描述说明性文本。当代码运行时,解释器会忽略这些内容。
代码最好有注释,特别是处理较复杂的工作时,注释可以为正在进行的操作添加提示,例如“这行代码要求用户输入一个字符”、“此段代码是 LNP 编写的”。PowerShell 有两种添加注释方法
- 行注释:
# - 块注释:
<#和#>
1 | #这是一行注释 |
第一个 #> 后面的部分会被认为是 PowerShell 代码,因此出现错误。
还有特别的注意一点,**PowerShell 代码是不区分大小写的**,因此只要拼写正确的命令(或变量),而无需关心大小写即可执行,不过最好还是有一定规范。
PowerShell 脚本的基本结构
PowerShell 像 Python 一样,允许使用控制台直接输入命令进行交互,也可以事先把代码写入一个文件再作为脚本运行。
一个 PowerShell 脚本仅仅是一个包含 PowerShell 代码的文本文件。如果这个文本文件执行, PowerShell 解释器会逐行解释并执行它的的语句。PowerShell 脚本有点像以前 CMD 控制台上的批处理文件。可以通过非常简单的文本编辑工具创建 PowerShell 脚本。
PowerShell脚本文件的扩展名是 .ps1
执行策略限制
PowerShell 一般初始化情况下都会禁止脚本执行。脚本能否执行取决于PowerShell的执行策略。
1 | PS E:> ./MyScript.ps1 |
只有管理员才有权限更改这个策略。非管理员会报错。
查看脚本执行策略,可以通过在 PowerShell 控制台直接输入:Get-ExecutionPolicy
更改脚本执行策略,可以管理员启动PowerShell,在控制台输入:Set-ExecutionPolicy <策略>
策略|解释
-|-
Unrestricted|权限最高,可以不受限制执行任何脚本。
Default|为Powershell默认的策略,即Restricted
Restricted|不允许任何脚本执行
AllSigned|所有脚本都必须经过签名才能在运行
RemoteSigned|本地脚本无限制,但是对来自网络的脚本必须经过签名
如果要使用脚本功能又要兼顾安全性,我们就选择RemoteSigned
即在以管理员身份允许的 PowerShell 输入Set-ExecutionPolicy RemoteSigned
1 |
|
运行 PowerShell 脚本
当您的脚本编写成功后您可能第一次会像下面的方式运行它,也就是只输入脚本的文件名,会报错。
1 | PS E:> MyScript.ps1 |
解决办法很简单,如果脚本在当前工作目录,请在脚本文件明前添加./,或者使用绝对路径。
1 | PS E:> .\MyScript.ps1 |
通过重定向创建脚本
如果想要执行的脚本不是很长,我们甚至可以直接在控制台中要执行的语句重定向给一个脚本文件。
1 | PS E:> '"Hello,World!"' > MyScript.ps1 |
这样有个缺点,就是您的代码必须放在闭合的引号中。这样的书写方式一旦在脚本内部也有引号时,是一件很痛苦的事。甚至您还可能希望在脚本中换行。下面的Here-strings例子不错,也就是将脚本文件通过@' '@闭合起来。
1 | PS E:> @' |
Here-String以 @'开头,以'@结束.任何文本都可以存放在里面,哪怕是一些特殊字符,空号,白空格。但是如果您不小心将单引号写成了双引号,PowerShell 将会把里面的变量进行解析。
通过编辑器创建脚本
其实最方便的还是使用文本编辑器直接编写代码,保存成PS1文件,右键即可执行。
这里推荐使用Visual Studio Code(以下简称VSC),VSC提供了PS1的自动补全(安装插件)、语法高亮、自动缩进、格式化代码、断点调试等功能。
变量
变量可以临时保存数据,因此可以把数据保存在变量中,以便进一步操作。PowerShell 的变量定义非常方便。
我们可以用 $变量名=初值 的方法定义变量,解释器会根据所赋的初值判断变量类型,类似于C#的 var 关键字或C++11中的 auto 关键字PowerShell 不需要显示地去声明,可以自动创建变量,只须记住变量的前缀为$.
创建好了变量后,可以通过变量名输出变量,也可以把变量名存在字符串中。但是有个例外:单引号中的字符串不会识别和处理变量名。
选择变量名
在 PowerShell 中变量名均是以美元符 $ 开始,剩余字符可以是数字、字母、下划线的任意字符,并且PowerShell变量名也对大小写不敏感($a 和 $A 是同一个变量)。
某些特殊的字符(比如$等)在 PowerShell 中有特殊的用途,一般不推荐使用这些字符作为变量名。当然你硬要使用,请把整个变量名后缀用花括号括起来。
1 | PS C:/> ${"I"like $}=5.1 |
不能定义和保留变量名称相同的变量
使用ls variable: 列出当前使用的所有变量,刚启动的 PowerShell 执行此命令能看到 PowerShell 的所有自动化变量(一旦打开 Powershell 就会自动加载的变量,后面将会详细解释这些变量的作用)
1 | Name Value |
查看变量类型
变量可以自动存储任何PowerShell能够识别的类型信息,可以通过 $变量名.GetType() 查看和验证 PowerShell 分配给变量的数据类型
1 | PS C:/> $num=10 |
删除变量
如果不想继续使用自定义的变量,可以使用del variable:变量名的方法删除变量,注意此处无$符号
1 | $a=0 |
PowerShell支持的变量类型和C#大体相同(没有了short、uint、ulong等),大多都继承自System.ValueType类( .NET类),其基本数据类型包括
整型
| 类型 | 名称 | 允许的值 | 所属类 |
|---|---|---|---|
| byte | 无符号整数(1字节) | 0~255之间的整数 | System.Byte |
| sbyte | 有符号整数(1字节) | -128~127之间的整数 | System.SByte |
| int16 | 有符号短整型(2字节) | -32768~32767之间的整数 | System.Int16 |
| uint16 | 无符号短整型(2字节) | 0~65535之间的整数 | System.UInt16 |
| int | 有符号整型 | -2147483648~2147483647之间的整数 | System.Int32 |
| uint32 | 无符号整型 | 0~4294967295之间的整数 | System.UInt32 |
| long | 有符号长整数(8字节) | -9223372036854775808~9223372036854775807之间的整数 | System.Int64 |
| ulong | 无符号长整数(8字节) | 0~18446744073709551615之间的整数 | System.UInt64 |
其实 int 、long 、以及下面的 float 都是 .NET的语法糖,真正的原生类型名是int32、int64、single 之类的类名
浮点型
浮点数标准形式(float和double)
$+/-m×2^e$
其中m为尾数,e为阶码,尾数是一个非负数,阶码是一个整数
PowerShell还支持一个特别的浮点数类型 decimal,其形式为
$+/-m×10^e$
| 类型 | 名称 | 指数 | m范围 | e范围 | 近似最小值 | 近似最大值 | 所属类 |
|---|---|---|---|---|---|---|---|
| float | 单精度浮点数 | 2 | 0~$2^{24}$ | -149~104 | $1.5×10^{-45}$ | $3.4×10^{38}$ | System.Single |
| double | 双精度浮点数 | 2 | 0~$2^{53}$ | -1075~970 | $5.0×10^{-324}$ | $1.7×10^{308}$ | System.Double |
| decimal | 16字节浮点数 | 10 | 0~$2^{96}$ | -28~0 | $1.0×10^{-28}$ | $7.9×10^{28}$ | System.Decimal |
其他简单类型
除了数值类型以外,还有3种基本类型
| 类型 | 名称 | 允许的值 | 所属类 |
|---|---|---|---|
| char | 字符型 | 一个Unicode字符,存储0~65535之间的整数 | System.Char |
| bool | 布尔型 | 布尔值: $true 或 $false(必须加$符号) |
System.Boolean |
| enum | 枚举 | 限定取值一组命名常量的独特的值类型 | System.Enum |
| datetime | 时间型 | 包含日期、时间的类型 | System.DateTime |
| string | 字符串 | 一组字符 | System.String |
注意 C/C++的 char 仅支持ASCII里面的256个字符, PowerShell 和 C# 的 char 是支持Unicode的,
PowerShell和C#的string类型并不是继承自 System.ValuType 类,而是继承自 System.Object 类,因此严格来说 string 类型并非是简单类型。
**PowerShell的转义字符是 ` 而不是 \**,这也是和C#的一个区别
1 | #使用char |
赋值和返回值
赋值操作符为 =,几乎可以把任何数据赋值给一个变量,甚至一条cmdlet命令
,因为 PowerShell 支持面向对象,对象可以包罗万象。
1 | PS D:\powershell\test> $item=ls |
弱类型与强类型
一般对 PowerShell 变量重新赋值时,变量类型会自动改变,这是弱类型语言的特点;
而 PowerShell 依托的 .NET是强类型的,所以 PowerShell 可以使用强类型。
强类型语言在速度上略逊于弱类型语言,但是强类型定义语言带来的严谨性又能避免不必要的错误。
可以在变量前添加类型限定符使该变量变为强类型,可以确保变量的类型不会随着赋值而改变
1 | [int]$num=123 #正确 |
类型转换
PowerShell 能够非常方便地将字符串等基本类型转换成期望的类型。之所以神奇,是因为 PowerShell 本身做了很多辛苦的工作,按照优先级:
- 直接赋值:输入类型和期望类型一致,可以直接交付。
- 基于语言的类型转换:当目标类型为
void,Boolean,String,Array,Hashtable,PSReference(i.e.: [ref]),XmlDocument,Delegate和Enum时,基于语言的类型转换开始工作。 - Parse 转换:如果目标类型包含了
Parse()方法,则采用它。 - Static Create 转换:如果目标类型包含静态的Create,则采用它。
- 构造函数转换:如果目标类型定义了构造函数,采用它。
- Cast 转换:如果目标类型定义了从源类型的显式或者隐式的操作符,则采用它。
- IConvertible 接口转换:如果目标类型实现了支持源类型
IConvertible接口,则采用它。 - IDictionary 转换:如果源类型是词典或者哈希表,会尝试创建一个实例,然后来填充name和value属性。
- PSObject 属性转换:如果源类型是
PSObject,通过目标类型的默认的构造函数创建一个实例,然后使用PSObject中的属性名称和值来填充实例的属性。 - TypeConverter 转换:如果存在注册的
TypeConverter或PSTypeConverter来处理转换,则使用它。
注意对浮点数向整数进行类型转换时,会自动四舍五入!!
如果要C++/C#那种向下取整的方法请使用 [math]::Floor() 函数
看几个转换的例子
1 | PS D:/test> $s=12.56 |
[convert]::ToInt32() 是 .NET System.Convert 类提供的转换函数convert 类中的转换函数格式为:TO+原生类型名(),这里的原生类型名指的是各个类型实际类名
常用:
[convert]::ToInt32()[convert]::ToSingle()[convert]::ToDouble()[convert]::ToBoolean()[convert]::ToString()
convert 类提供了一系列方法来完成不同变量之间的转换,获得函数列表及使用方法请参考微软的 .NET文档Convert类 方法列表
运算符
注意逻辑运算符和比较运算符的写法,不支持 C# 的&& || ! == != < > >= <=这些运算符
1 | #加 减 乘 除 取余 |
条件分支
if else
if 和 else 用法和C#完全一样,除了大括号不允许省略,多分支时还多了个elseif 可用,和Python 的 elif 作用相同
1 | if($true -and $true) { |
switch
PowerShell的switch非常灵活,使用起来较为方便
相对C#或C++,PowerShell的switch不需要写`case:``,但是必须写大括号
1 | $a="Beijing" |
默认比较运算符为-eq,你也可以使用下面的例子自定义比较条件,必须保证表达式返回boolen类型($true和$false)
1 | $v=18 |
循环
接下来介绍循环
for循环
PowerShell 的 for 循环类似于C#,看一个样例:
1 | for($i=0;$i -lt 10;$i++) |
do-while循环
Do 和 While 可能产生死循环,为了防止死循环的发生,因此我们必须确切的指定循环终止的条件。指定了循环终止的条件后,一旦条件不满足就会退出循环。do-while() 会先执行再去判断,能保证循环至少执行一次。
1 | do |
只使用while
1 | $n=5 |
跳出循环
使用 continue 关键字,可以终止当前循环,跳过 continue 后其它语句,重新下一次循环。
跳出循环语句使用 break 关键字
1 | $n=1 |
还有一种循环 foreach ,等到我们讲到数组再说
数组
定义数组
在 PowerShell 中创建数组可以使用逗号
1 | PS C:/Powershell> $nums=2,0,1,2 |
对于连续的数字数组可以使用一个更快捷的方法:
1 | PS C:/Powershell> $nums=1..5 |
对象数组的多态
像变量一样,如果数组中元素的类型为弱类型,默认可以存储不同类型的值。
1 | PS C:/Powershell> $array=1,"2019",([Guid]::NewGuid()),(get-date) |
空数组和单元素数组
对数组元素可以查看它的公有属性,比如长度
只需要输入$数组名.Count即可显示数组长度
空数组
1 | PS C:/Powershell> $a=@() |
单元素数组
1 | PS C:Powershell> $a=,"moss" |
使用数组
遍历
直接法
将数组作为单独一行将会自动遍历这个数组的所有元素
1 | PS C:/> $a=1..10 |
for 循环遍历
1 | PS C:/> $a=1..5 |
foreach 遍历法
还有一种遍历的方法,用到了之前提到的 foreach 语句
意思是使用变量 $n 对 $a 元素进行迭代,这实际上是一种对可迭代对象的访问算法
在 C# 也有这种语法
1 | $a="A","B","C","D","E" |
foreach还有一种遍历的写法
这里我们需要先了解一下管道
管道的符号 |
管道允许将它左侧命令的输出结果发送到右侧做命令的参数
管道并不是什么新事物,以前的Cmd控制台也有重定向的命令,例如Dir | More可以将结果分屏显示。
传统的Cmd管道是基于文本的,但是 PowerShell 是基于对象的
列出当前目录下的目录和文件,然后根据文件名降序排列,再投影(数据库术语)文件名,文件大小,文件的修改时间:
1 | PS D:/test> ls | Sort-Object -Descending Name | Select-Object Name,Length,LastWriteTime |
可迭代对象(比如数组)可以由管道送到一些命令上进一步处理foreach就可以接受管道送来的可迭代对象,并进行遍历
1 | $array="A","B","C","D","E" |
将数组逆序输出
1 | PS C:/Powershell> $books="A1","B2","C3" |
访问某些元素
与C#相同,数组的元素可以使用索引寻址,第一个元素的索引为0,第i个元素的索引为i-1,最后一个元素的索引为Count-1,但是 PowerShell 为了使用方便,直接可以将 -1 作为最后的一个元素的索引(参考了 Python 的语法)
1 | PS C:/Powershell> $books="1A","2B","3C" |
从数组中选择多个元素
1 | PS C:/Powershell> $result=ls |
给数组添加元素
因为PowerShell数组在内存中是顺序存储的,所以数组的大小必须是确定的,这样才方便分配存储空间,所以给数组增加元素其实相当于创建一个新的数组,只不过之后会把原来的副本删除。在当前数组追加元素可以使用 += 操作符。
1 | PS C:/Powershell> $books="A1","B2","C3" |
删除指定位置元素
采用截断重连法删除指定元素
1 | PS C:/Powershell> $num=1..4 |
复制数组
数组属于引用类型,使用默认的的赋值运算符在两个变量之间赋值只是复制了一个引用,两个变量共享同一份数据。这样的模式有一个弊病如果其中一个改变也会株连到另外一个。所以复制数组最好使用 Clone() 方法( System.Array 类的成员函数),除非有特殊需求。
1 | PS C:/Powershell> $chs=@("A","B","C") |
强类型数组
PowerShell 数组一般具有多态性,如果你不指定元素的具体类型,解释器会自动选择合适的类型存储每个元素。如果要统一限制所有元素的类型,可是使用类型名和一对方括号作为数组变量的类型。这样每当赋值时,会自动类型检查。如果目标数据类型不能转换成功,就会抛出一个异常,这样的数组被称为强类型数组
定义方法[类型[]]$数组名=初值
1 | PS C:/Powershell> [int[]] $nums=@() |
命令返回数组
当我们把一个命令的执行结果保存到一个变量中,可能会认为变量存放的是纯文本。
但是,事实上 PowerShell 会把文本按每一行作为元素存为数组。如果一个命令的返回值不止一个结果时, PowerShell 也会自动把结果存储为数组
1 | PS C:/Powershell> $IPcfg=ipconfig |
使用数组存储结果
判断一个变量是否为数组
1 | PS C:/Powershell> $ip=ipconfig |
使用真实的对象操作
为什么不愿把IPconfig返回的结果称为对象,因为它不是真正Cmdlet命令(事实上ipconfig是一个单独的程序),真正的 PowerShell 命令返回的数组元素可不止一个字符串,它是一个内容丰富的对象。
1 | PS D:/test> $list=ls |
上面的例子中数组的每一个元素存放的是一个 System.IO.DirectoryInfo 对象。
当我们输出这些对象时,PowerShell 会自动帮我们把它转换成友好的文本格式。
对于任何一个对象都可以使用 Format-List * 来查看它所有的属性和方法。
1 | PS D:/test> $list[0]|fl * |
函数
函数是自定义的 Powershell 代码,有三个原则:
- 简短:函数名简短,并且显而易见。
- 聚合:函数可以完成多个操作。
- 封装和扩展:将一批
Powershell语句进行封装,实现全新的功能需求。
函数的结构由三部分组成:函数名,参数,函数体
定义函数
脚本中函数的定义方法
函数可以在文本编辑器上编写,写完以后复制进 PowerShell 控制台即可。如果控制台设置为快速编辑模式,从记事本复制后,直接在控制台鼠标右键即可完成粘贴(Windows 10默认开启了快速编辑模式)
1 | function FuncName(args[]) #括号可省略 |
控制台上多行输入定义函数
1 | PS C:/PowerShell> function MyPing |
把函数精简成一行
我们可以将一个函数定义在一行上,但是这样阅读和理解起来就不方便,所以要在每条命令后加分号进行分割(最后一句可以不写;)
1 | PS C:/PowerShell> function cd...{ cd.. ; cd.. } |
使用函数作为别名
假如 PowerShell 不支持 Get-SystemVersion 命令,你可以通过定义函数实现这个功能:
1 | function get-systemversion |
更新函数
如果要更新已经定义好的函数,简单的方法是重新定义,这样新的定义会覆盖旧的定义。但是如果函数代码没有保存副本,可以先将函数定义导出到ps文件,然后就可以编辑了。
1 | PS C:/PowerShell> function MyPing |
删除函数
控制台定义的函数只会在当前会话生效,一旦控制台退出,会自动消失。在不关闭控制台的条件下删除一个已经定义好的函数,可是使用虚拟驱动器的方法:
1 | function cc{"hello"} |
输入输出函数
用于脚本文件的编写
输入
PowerShell提供了 Read-Host 命令,可以接收返回用户在控制台输入的字符
1 | $name=read-host "请输入你的名字" |
注意到
- 提示信息(如果有)后面自动加了个冒号;
- 用户键入任何信息都被作为该命令的返回结果;
- 可以把键入的信息传递给一个变量;
输出
有两种输出命令Write-Host和Write-Output
若输出字符串不包含空白字符可以不加引号
Write-Host
当需要展示一个特定信息,比如使用其他颜色来吸引人们的注意力的时候,可使用 Write-Host 命令
Write-Host 和其他Cmdlets一样使用管道,但是它不放置任何数据道管道中。反而会直接写到宿主应用程序的界面。正如此,可以使用-ForegroundColor 和 -BackgroundColor 参数将前景和背景设置为其他颜色:
1 | write-host "啊哈" -ForegroundColor White -BackgroundColor Red |
注:不是每个使用PowerShell的应用程序都支持其他颜色,也并不是每个应用程序都支持所有颜色。
该输出方法不适用于常规的输出结果,因为 Write-Host 命令输出到屏幕的任何东西都无法被捕捉。若执行远程命令或无人值守命令(纯自动化), Write-Host 可能不会按照你的预期工作。因此,此命令仅仅用于与人进行直接交互。
Write-Output
Write-Output命令会将对象发送给管道。由于它不会直接发送到显示界面,所以不允许你指定其他任何的颜色。
它是PowerShell默认使用的一个Cmdlets,默认输出方式即使用该命令,即使你没有指定,PowerShell会在底层将信息传递给Write-Output命令(就是一行直接写一个变量就能直接输出的情况),另外这个命令还有两个别名 write 和 echo
1 | write-host ACB #无空白字符可以不写引号 |
Write-Output输出基本过程为:
Write-Output命令将string类型的对象Hello World!放入管道中;- 管道中只有这个
string对象,其会直接到达管道的末端,也就是Out-Default命令;Out-Default命令将对象传递给Out-Host命令;Out-Host命令要求PowerShell的格式化系统格式化该对象。Out-Host将格式化的结果集放在显示界面上
还有一点,在输出多个对象时,Write-Host会以空格隔开各对象Write-Output会以换行隔开各对象
1 | write-host "ABC" "23232" |
其他的输出方式
Write-Warning/Verbose/Debug/Error
具体参考:微软官方文档
处理函数参数
PowerShell 函数可以接受参数,并对参数进行处理。函数的参数有3个特性:
- 任意参数:内部变量
$args接受函数调用时接受的参数,$args是一个数组类型; - 命名参数:函数的每一个参数可以分配一个名称,在调用时通过名称指定对应的参数;
- 预定义参数:函数在定义参数时可以指定默认值,如果调用时没有专门指定参数的值,就会保持默认值;
$args 万能参数
给一个函数定义参数最简单的是使用$args这个内置的参数。它可以识别任意个参数。尤其适用那些参数可有可无的函数。
1 | function sayHello |
因为 $arg 是一个数组,可以用它很方便的写出求和函数
1 | function Add |
使用固定参数
1 | function StringContact($str1,$str2) |
给参数定义默认值
1 | function stringContact($str1="LN",$str2="P") |
使用强类型参数
通过之前的例子发现将用户的参数传递给函数显得比较混乱。罪魁祸首就是PowerShell的参数解释器,它可以自动处理和分配参数给函数。
函数的参数解释器比较傲慢,它对你提供的参数的信息完全不关心。它只会粗略地将参数进行分割,并且最大限度的进行自动类型转换。事实上,这种类型转换很多时候并不完美。所以最好提前能够对参数进行强类型限制
限制数字类型
下面的函数执行后,会抛出异常
因为 subtract 的参数定义了强类型,参数的类型可能引起函数的处理结果改变。
1 | function subtract([int]$value1,[int]$value2) |
限制日期类型
函数的参数解释器会自动尝试将字符串转换成日期类型,如果转换失败就是抛出异常
看下面的例子
1 | function DayOfWeek([datetime]$date) |
Switch 参数
Powershell 函数最简单的参数类型为布尔类型,除了使用 Bool 类型,也可以使用 Switch 关键字。
下面的函数逆转字符串,但是可以通过 $try 参数进行控制,如果没有指定 $try 的值,默认值为 $false
1 | function tryReverse( [switch]$try , [string]$source ) |
指定函数的返回值
一个或多个返回值
PowerShell 不像其它的编程语言,它的函数可以有多个返回值。如果你直接调用函数,返回值会在控制台输出。当然你也可以将结果存储在一个变量中进一步处理
下面的例子演示返回一个值:
1 | function Square([double]$num) |
下面的例子演示返回多个值
1 | function gbMeasure($amount) |
总结一下,如果一个函数返回一个值,像其它编程语言一样,这个值包括它的类型信息会直接返回。但是如果遇到多个返回值,PowerShell会将所有的返回值自动构造成一个对象数组。
可以通过索引访问数组
Return语句
Powershell 会将函数中所有的输出作为返回值,但是也可以通过return语句指定具体的返回值。
Return 语句会将指定的值返回,同时也会中断函数的执行,return后面的语句会被忽略
看一个例子
1 | function test($num) |
访问返回值
一个函数返回了一个值还是多个值,是可以验证的。下面的例子会产生随机数,如果没有指定个数,默认会返回一个随机数,否则会返回指定个数的随机数
1 | function lottery([int]$number=1) |
从函数的返回值中消除输出
函数默认会将函数中的所有输出作为函数的返回值返回,这样很方便。但有时可能会将不必要的输出误以为返回值。写脚本程序时,可能需要自定义一些函数,这个函数可能只需要一个返回值,但是为了提高函数的可读性,可能会在函数增加一些注释输出行,或者使用write-host
1 | function Test() |
恭喜你!到此 PowerShell 基础入门算是完成了!
之后将介绍 PowerShell 的进阶使用
附录
PowerShell Math类常用函数表
| 函数名 | 调用写法 | 所在类 | 重载 | 描述 | 参数 |
|---|---|---|---|---|---|
| sin | [math]::sin(x) | System.Math | 1 | 返回x弧度的正弦值 | double |
| cos | [math]::cos(x) | System.Math | 1 | 返回x弧度的余弦值 | double |
| abs | [math]::abs(x) | System.Math | 7 | 返回x的绝对值 | 所有数值型 |
| sqrt | [math]::sqrt(x) | System.Math | 1 | 返回x的平方根 | double |
| pow | [math]::pow(x,n) | System.Math | 1 | 返回x的n次幂 | 两参数都是double |
| log | [math]::log(x) | System.Math | 1 | 返回x的自然对数 | double |
| log | [math]::log(x,n) | System.Math | 1 | 返回x的以n为底的对数 | double |
| min | [math]::min(x,y) | System.Math | 11 | 返回x,y中的最小值 | 所有数值型 |
| max | [math]::max(x,y) | System.Math | 11 | 返回x,y中的最大值 | 所有数值型 |
| floor | [math]::ceiling(x) | System.Math | 2 | 返回x向下取整的结果 | double、decimal |
| ceiling | [math]::ceiling(x) | System.Math | 2 | 返回x向上取整的结果 | double、decimal |
math 类其他函数及详细用法参见微软文档: Math类 |