添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
严肃的烤土司  ·  How to Convert String ...·  1 周前    · 
爱喝酒的甜瓜  ·  Get-Date ...·  1 周前    · 
高大的脸盆  ·  NORTHLAND LUTHERAN ...·  3 周前    · 
性感的枇杷  ·  2023 ...·  3 月前    · 
微醺的绿茶  ·  debian-packaging-for-t ...·  3 月前    · 
  • 破天荒的方便

    诸如存储计算中 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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Get-Command *Process
    #结果
    CommandType Name Version Source
    ----------- ---- ------- ------
    Cmdlet Debug-Process 3.1.0.0 Microsoft.PowerShell.Management
    Cmdlet Enter-PSHostProcess 3.0.0.0 Microsoft.PowerShell.Core
    Cmdlet Exit-PSHostProcess 3.0.0.0 Microsoft.PowerShell.Core
    Cmdlet Get-Process 3.1.0.0 Microsoft.PowerShell.Management
    Cmdlet Start-Process 3.1.0.0 Microsoft.PowerShell.Management
    Cmdlet Stop-Process 3.1.0.0 Microsoft.PowerShell.Management
    Cmdlet Wait-Process 3.1.0.0 Microsoft.PowerShell.Management

    得知处理进程的命令有这些
    然后再用 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
    2
    3
    4
    5
    6
    7
    8
    9
    {
    <#代码行1#>
    <#代码行2#>
    {
    <#代码行3#>
    <#代码行4#>
    }
    <#代码行5#>;<#代码行6#>;
    }

    当然 PowerShell 的缩进不是强制的。

    PowerShell 代码中,另一种常见的语句是注释,注释并不是能执行的语句,而是对代码的描述说明性文本。当代码运行时,解释器会忽略这些内容。
    代码最好有注释,特别是处理较复杂的工作时,注释可以为正在进行的操作添加提示,例如“这行代码要求用户输入一个字符”、“此段代码是 LNP 编写的”。
    PowerShell 有两种添加注释方法

  • 行注释: #
  • 块注释: <# #>
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #这是一行注释

    <#
    这是注释块
    123ABC
    #>

    ls #列出当前目录下的文件和文件夹,是Get-ChildItem的别名

    #注意下面语句会产生错误
    <#块注释由"#>"结尾#>

    第一个 #> 后面的部分会被认为是 PowerShell 代码,因此出现错误。

    还有特别的注意一点,** PowerShell 代码是不区分大小写的**,因此只要拼写正确的命令(或变量),而无需关心大小写即可执行,不过最好还是有一定规范。

    PowerShell 脚本的基本结构

    PowerShell Python 一样,允许使用控制台直接输入命令进行交互,也可以事先把代码写入一个文件再作为脚本运行。
    一个 PowerShell 脚本仅仅是一个包含 PowerShell 代码的文本文件。如果这个文本文件执行, PowerShell 解释器会逐行解释并执行它的的语句。 PowerShell 脚本有点像以前 CMD 控制台上的批处理文件。可以通过非常简单的文本编辑工具创建 PowerShell 脚本。

    PowerShell脚本文件的扩展名是 .ps1

    执行策略限制

    PowerShell 一般初始化情况下都会禁止脚本执行。脚本能否执行取决于PowerShell的执行策略。

    1
    2
    3
    4
    5
    6
    7
    8
    PS E:> ./MyScript.ps1

    无法加载文件 E:MyScript.ps1,因为在此系统中禁止执行脚本。有关详细信息,请参阅 "get-help about_signing"
    所在位置 行:1 字符: 15
    + .MyScript.ps1 < <<<
    + CategoryInfo : NotSpecified: (:) [], PSSecurityException
    + FullyQualifiedErrorId : RuntimeException

    只有管理员才有权限更改这个策略。非管理员会报错。

    查看脚本执行策略,可以通过在 PowerShell 控制台直接输入:
    Get-ExecutionPolicy
    更改脚本执行策略,可以管理员启动PowerShell,在控制台输入:
    Set-ExecutionPolicy <策略>
    策略|解释
    -|-
    Unrestricted|权限最高,可以不受限制执行任何脚本。
    Default|为Powershell默认的策略,即Restricted
    Restricted|不允许任何脚本执行
    AllSigned|所有脚本都必须经过签名才能在运行
    RemoteSigned|本地脚本无限制,但是对来自网络的脚本必须经过签名

    如果要使用脚本功能又要兼顾安全性,我们就选择RemoteSigned
    即在以管理员身份允许的 PowerShell 输入
    Set-ExecutionPolicy RemoteSigned

    1
    2
    3

    执行策略可以防止您执行不信任的脚本。更改执行策略可能会使您面临 about_Execution_Policies帮助主题中所述的安全风险。是否要更改执行策略?
    [Y] 是(Y) [N] 否(N) [S] 挂起(S) [?] 帮助 (默认值为“Y”): y

    运行 PowerShell 脚本

    当您的脚本编写成功后您可能第一次会像下面的方式运行它,也就是只输入脚本的文件名,会报错。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PS E:> MyScript.ps1

    无法将“MyScript.ps1”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括
    路径,请确保路径正确,然后重试。
    所在位置 行:1 字符: 13
    + MyScript.ps1 < <<<
    + CategoryInfo : ObjectNotFound: (MyScript.ps1:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    Suggestion [3,General]: 未找到命令 MyScript.ps1,但它确实存在于当前位置。Windows PowerShell 默认情况下不从当前位置加载命令。如果信任此命令,请改为键入 "./MyScript.ps1"。有关更多详细信息,请参阅 "get-h
    elp about_Command_Precedence"

    解决办法很简单,如果脚本在当前工作目录,请在脚本文件明前添加 ./ ,或者使用绝对路径。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    PS E:> .\MyScript.ps1

    2019年3月27日 18:33:03
    C:\Program Files\Common Files
    files count
    20

    PS E:> E:MyScript.ps1

    2019年3月27日 18:33:11
    C:\Program Files\Common Files
    files count
    20
    通过重定向创建脚本

    如果想要执行的脚本不是很长,我们甚至可以直接在控制台中要执行的语句重定向给一个脚本文件。

    1
    2
    3
    PS E:> '"Hello,World!"' > MyScript.ps1
    PS E:> ./MyScript.ps1
    Hello,World!

    这样有个缺点,就是您的代码必须放在闭合的引号中。这样的书写方式一旦在脚本内部也有引号时,是一件很痛苦的事。甚至您还可能希望在脚本中换行。下面的Here-strings例子不错,也就是将脚本文件通过 @' '@ 闭合起来。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    PS E:> @'
    >> Get-Date
    >> $Env:CommonProgramFiles
    >> #Script End
    >> "files count"
    >> (ls).Count
    >> #Script Really End
    >>
    >> '@ > myscript.ps1
    >>
    PS E:> .MyScript.ps1

    2019年3月27日 18:15:10
    C:\Program Files\Common Files
    files count
    20

    Here-String以 @' 开头,以 '@ 结束.任何文本都可以存放在里面,哪怕是一些特殊字符,空号,白空格。但是如果您不小心将单引号写成了双引号, PowerShell 将会把里面的变量进行解析。

    通过编辑器创建脚本

    其实最方便的还是使用文本编辑器直接编写代码,保存成PS1文件,右键即可执行。
    这里推荐使用Visual Studio Code(以下简称VSC),VSC提供了PS1的自动补全(安装插件)、语法高亮、自动缩进、格式化代码、断点调试等功能。

    变量

    变量可以临时保存数据,因此可以把数据保存在变量中,以便进一步操作。 PowerShell 的变量定义非常方便。
    我们可以用 $变量名=初值 的方法定义变量,解释器会根据所赋的初值判断变量类型,类似于C#的 var 关键字或C++11中的 auto 关键字 PowerShell 不需要显示地去声明,可以自动创建变量,只须记住变量的前缀为$.
    创建好了变量后,可以通过变量名输出变量,也可以把变量名存在字符串中。但是有个例外: 单引号中的字符串不会识别和处理变量名。

    选择变量名

    PowerShell 中变量名均是以美元符 $ 开始,剩余字符可以是数字、字母、下划线的任意字符,并且PowerShell变量名也对大小写不敏感( $a $A 是同一个变量)。
    某些特殊的字符(比如 $ 等)在 PowerShell 中有特殊的用途,一般不推荐使用这些字符作为变量名。当然你硬要使用,请把整个变量名后缀用花括号括起来。

    1
    2
    3
    PS C:/> ${"I"like $}=5.1
    PS C:/> ${"I"like $}
    5.1

    不能定义和保留变量名称相同的变量
    使用 ls variable: 列出当前使用的所有变量,刚启动的 PowerShell 执行此命令能看到 PowerShell 的所有自动化变量(一旦打开 Powershell 就会自动加载的变量,后面将会详细解释这些变量的作用)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    Name                           Value
    ---- -----
    $
    ? True
    ^
    args {}
    ConfirmPreference High
    ConsoleFileName
    DebugPreference SilentlyContinue
    Error {}
    ErrorActionPreference Continue
    ErrorView NormalView
    ExecutionContext System.Management.Automation.EngineIntrinsics
    false False
    FormatEnumerationLimit 4
    HOME C:\Users\aaaaa
    Host System.Management.Automation.Internal.Host.InternalHost
    InformationPreference SilentlyContinue
    input System.Collections.ArrayList+ArrayListEnumeratorSimple
    MaximumAliasCount 4096
    MaximumDriveCount 4096
    MaximumErrorCount 256
    MaximumFunctionCount 4096
    MaximumHistoryCount 4096
    MaximumVariableCount 4096
    MyInvocation System.Management.Automation.InvocationInfo
    NestedPromptLevel 0
    null
    OutputEncoding System.Text.ASCIIEncoding
    PID 8796
    PROFILE C:\Users\aaaaa\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    ProgressPreference Continue
    PSBoundParameters {}
    PSCommandPath
    PSCulture zh-CN
    PSDefaultParameterValues {}
    PSEdition Desktop
    PSEmailServer
    PSHOME C:\Windows\System32\WindowsPowerShell\v1.0
    PSScriptRoot
    PSSessionApplicationName wsman
    PSSessionConfigurationName http://schemas.microsoft.com/powershell/Microsoft.PowerShell
    PSSessionOption System.Management.Automation.Remoting.PSSessionOption
    PSUICulture zh-CN
    PSVersionTable {PSVersion, PSEdition, PSCompatibleVersions, BuildVersion...}
    PWD C:\Users\aaaaa
    ShellId Microsoft.PowerShell
    StackTrace
    true True
    VerbosePreference SilentlyContinue
    WarningPreference Continue
    WhatIfPreference False

    查看变量类型

    变量可以自动存储任何 PowerShell 能够识别的类型信息,可以通过 $变量名.GetType() 查看和验证 PowerShell 分配给变量的数据类型

    1
    2
    3
    4
    5
    6
    PS C:/> $num=10
    PS C:/> $num.gettype() #不区分大小写

    IsPublic IsSerial Name BaseType
    -------- -------- ---- --------
    True True Int32 System.ValueType

    删除变量

    如果不想继续使用自定义的变量,可以使用 del variable:变量名 的方法删除变量,注意此处无 $ 符号

    1
    2
    3
    4
    5
    6
    $a=0
    $a -eq $null
    False
    del variable:a
    $a -eq $null
    True

    PowerShell支持的变量类型和C#大体相同(没有了short、uint、ulong等),大多都继承自 System.ValueType 类( .NET类),其基本数据类型包括

    无符号整数(1字节) 0~255之间的整数 System.Byte sbyte 有符号整数(1字节) -128~127之间的整数 System.SByte int16 有符号短整型(2字节) -32768~32767之间的整数 System.Int16 uint16 无符号短整型(2字节) 0~65535之间的整数 System.UInt16 有符号整型 -2147483648~2147483647之间的整数 System.Int32 uint32 无符号整型 0~4294967295之间的整数 System.UInt32 有符号长整数(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$

    近似最小值 近似最大值 float 单精度浮点数 0~$2^{24}$ -149~104 $1.5×10^{-45}$ $3.4×10^{38}$ System.Single double 双精度浮点数 0~$2^{53}$ -1075~970 $5.0×10^{-324}$ $1.7×10^{308}$ System.Double decimal 16字节浮点数 0~$2^{96}$ -28~0 $1.0×10^{-28}$ $7.9×10^{28}$ System.Decimal

    其他简单类型

    除了数值类型以外,还有3种基本类型

    一个Unicode字符,存储0~65535之间的整数 System.Char 布尔值: $true $false (必须加 $ 符号) System.Boolean 限定取值一组命名常量的独特的值类型 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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    #使用char
    PS D:/>[char]$c="A"
    $c
    A
    #使用bool
    PS D:/>$boolean=$true
    $boolean
    True

    #使用enum
    enum fruit
    {
    apple
    banana
    cherry
    durian
    }
    [fruit]$en=[fruit]::apple
    $en
    apple
    $item="cherry"
    [fruit]$enu=[fruit]::($item)
    $enu
    cherry

    #这种使用方法是错误的
    PS D:/> [fruit]$enum=banana

    banana : 无法将“banana”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
    所在位置 行:1 字符: 12
    + [fruit]$en=banana
    + ~~~~~~
    + CategoryInfo : ObjectNotFound: (banana:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    #当尝试使用非枚举值进行赋值时
    PS D:/> [fruit]$en=[fruit]::peach

    由于枚举值无效,无法将 Null 转换为类型“fruit”。请指定以下枚举值之一,然后重试。可能的枚举值为“apple,banana,cherry,durian”。
    所在位置 行:1 字符: 1
    + [fruit]$en=[fruit]::peach
    + ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

    PS D:/> "\n 123 `n 123"
    <#输出
    \n 123
    123
    #>

    PS D:/>$date=get-date
    $date
    $date.gettype()
    <#输出
    2019年3月28日 19:32:30

    IsPublic IsSerial Name BaseType
    -------- -------- ---- --------
    True True DateTime System.ValueType
    #>

    赋值和返回值

    赋值操作符为 = ,几乎可以把任何数据赋值给一个变量,甚至一条cmdlet命令
    ,因为 PowerShell 支持面向对象,对象可以包罗万象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    PS D:\powershell\test> $item=ls
    PS D:\powershell\test> $item


    目录: D:\powershell\test


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a---- 2017/11/24 12:52 136 4-3.cpp
    -a---- 2019/3/27 15:13 65 anapple.txt


    PS D:\powershell\test> $item.gettype()

    IsPublic IsSerial Name BaseType
    -------- -------- ---- --------
    True True Object[] System.Array

    $item为一个对象数组

    弱类型与强类型

    一般对 PowerShell 变量重新赋值时,变量类型会自动改变,这是弱类型语言的特点;
    PowerShell 依托的 .NET是强类型的,所以 PowerShell 可以使用强类型。
    强类型语言在速度上略逊于弱类型语言,但是强类型定义语言带来的严谨性又能避免不必要的错误。
    可以在变量前添加类型限定符使该变量变为强类型,可以确保变量的类型不会随着赋值而改变

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [int]$num=123 #正确
    [int]$num=ls <#错误
    无法将“System.Object[]”类型的“System.Object[]”值转换为“System.Int32”类型。
    所在位置 行:1 字符: 1
    + [int]$num=ls
    + ~~~~~~~~~~~~
    + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException
    #>

    类型转换

    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
    2
    3
    4
    5
    PS D:/test> $s=12.56
    PS D:/test> [int]$s
    13
    PS D:/test> [convert]::ToInt32($s)
    13

    [convert]::ToInt32() 是 .NET System.Convert 类提供的转换函数
    convert 类中的转换函数格式为: TO + 原生类型名() ,这里的原生类型名指的是各个类型实际类名
    常用:

  • [convert]::ToInt32()
  • [convert]::ToSingle()
  • [convert]::ToDouble()
  • [convert]::ToBoolean()
  • [convert]::ToString()
  • convert 类提供了一系列方法来完成不同变量之间的转换,获得函数列表及使用方法请参考微软的 .NET文档 Convert类 方法列表

    运算符

    注意逻辑运算符和比较运算符的写法,不支持 C# && || == != < > >= <= 这些运算符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    #加 减 乘 除 取余
    + - * / %
    #自增、自减运算符,和C#或C++完全一致
    ++$i
    $i++
    $i--
    --$i
    #且
    -and
    #并
    -or
    #非
    -not
    !
    #样例
    $true -and $false -or -not 0
    !$true
    #输出
    True
    False
    #等于 (equal to)
    -eq
    #不等于 (not equal to)
    -nq
    #大于 (greater than)
    -gt
    #大于等于 (greater than or equal to)
    -ge
    #小于 (less than)
    -lt
    #小于等于 (less than or equal to)
    -le

    #对于字符串类型,可以在比较运算符前加i或c表示是否区分大小写,
    #i表示对大小写不敏感,c表示敏感,不写默认不敏感
    "a" -eq "A"
    "a" -ceq "A"
    #输出
    True
    False

    #判断变量是否为兼容类型(同一类型或其父类型),类型格式为 [类型名]
    -is
    #示例
    $a=0
    $a -is [int]
    $b=1,2,3
    $b -is [array]
    $a -is [ValueType]
    #输出
    True
    True
    True # System.Int32类继承自System.ValueType类,因此int是其父类型ValueType的子类型

    条件分支

    if else

    if else 用法和C#完全一样,除了大括号不允许省略,多分支时还多了个 elseif 可用,和 Python elif 作用相同

    1
    2
    3
    4
    5
    6
    7
    8
    9
    if($true -and $true) {
    $a=0
    }
    elseif($a -eq $b) {
    $a=1
    }
    else {
    $a=2
    }

    switch

    PowerShell的 switch 非常灵活,使用起来较为方便
    相对C#或C++,PowerShell的switch不需要写`case:``,但是必须写大括号

    1
    2
    3
    4
    5
    6
    $a="Beijing"
    switch($a)
    {
    "Beijing" {$res="北京"}
    "Shanghai" {$res="上海"}
    }

    默认比较运算符为 -eq ,你也可以使用下面的例子自定义比较条件,必须保证表达式返回boolen类型($true和$false)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $v=18
    switch($v)
    {
    {$_ -lt 10} {"小于10"} # $_ 表示当前的传入的变量 直接写的字符串会被输出
    10 {"等于10"}
    {$_ -gt 10} {"小于10"}
    }
    <#输出
    大于10
    #>

    循环

    接下来介绍循环

    for循环

    PowerShell for 循环类似于 C# ,看一个样例:

    1
    2
    3
    4
    for($i=0;$i -lt 10;$i++)
    {
    Write-Output "Hello"
    }

    do-while循环

    Do While 可能产生死循环,为了防止死循环的发生,因此我们必须确切的指定循环终止的条件。指定了循环终止的条件后,一旦条件不满足就会退出循环。
    do-while() 会先执行再去判断,能保证循环至少执行一次。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    do 
    {
    $n=Read-Host "请输入数字"
    }
    while($n -ne 0)
    <#输出
    请输入数字: 1
    请输入数字: 2
    请输入数字: s
    请输入数字: 0
    #>
    只使用while
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $n=5
    while($n -gt 0)
    {
    $n
    $n=$n-1
    }
    #输出
    5
    4
    3
    2
    1
    跳出循环

    使用 continue 关键字,可以终止当前循环,跳过 continue 后其它语句,重新下一次循环。
    跳出循环语句使用 break 关键字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    $n=1
    while($n -lt 6)
    {
    if($n -eq 4)
    {
    $n=$n+1
    continue

    }
    else
    {
    $n
    }
    $n=$n+1
    }
    1
    2
    3
    5
    $n=1
    while($n -lt 6)
    {
    if($n -eq 4)
    {
    break
    }
    $n
    $n++
    }

    还有一种循环 foreach ,等到我们讲到数组再说

    数组

    定义数组

    PowerShell 中创建数组可以使用逗号

    1
    2
    3
    4
    5
    6
    PS C:/Powershell> $nums=2,0,1,2
    PS C:/Powershell> $nums
    2
    0
    1
    2

    对于连续的数字数组可以使用一个更快捷的方法:

    1
    2
    3
    4
    5
    6
    7
    PS C:/Powershell> $nums=1..5
    PS C:/Powershell> $nums
    1
    2
    3
    4
    5
    对象数组的多态

    像变量一样,如果数组中元素的类型为弱类型,默认可以存储不同类型的值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    PS C:/Powershell> $array=1,"2019",([Guid]::NewGuid()),(get-date)
    PS C:/Powershell> $array
    1
    2019

    Guid
    ----
    ea5f17c6-c0a2-42ba-9de4-e4d03bebffaf

    DisplayHint : DateTime
    Date : 2019/3/29 0:00:00
    Day : 29
    DayOfWeek : Friday
    DayOfYear : 88
    Hour : 23
    Kind : Local
    Millisecond : 120
    Minute : 23
    Month : 3
    Second : 39
    Ticks : 636894986191207086
    TimeOfDay : 23:23:39.1207086
    Year : 2019
    DateTime : 201932923:23:39

    PS C:/Powershell> $array|foreach{$_.gettype()}
    #查看数组各元素类型
    IsPublic IsSerial Name BaseType
    -------- -------- ---- --------
    True True Int32 System.ValueType
    True True String System.Object
    True True Guid System.ValueType
    True True DateTime System.ValueType
    空数组和单元素数组

    对数组元素可以查看它的公有属性,比如长度
    只需要输入 $数组名.Count 即可显示数组长度

    空数组
    1
    2
    3
    4
    5
    PS C:/Powershell> $a=@()
    PS C:/Powershell> $a -is [array]
    True
    PS C:/Powershell> $a.Count
    0
    单元素数组
    1
    2
    3
    4
    5
    PS C:Powershell> $a=,"moss"
    PS C:Powershell> $a -is [array]
    True
    PS C:Powershell> $a.Count
    1

    使用数组

    遍历
    直接法

    将数组作为单独一行将会自动遍历这个数组的所有元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    PS C:/> $a=1..10
    PS C:/> $a
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    for 循环遍历
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PS C:/> $a=1..5
    PS C:/> for($i=0;$i -lt 5;$i++) {
    >> $a[$i] }
    1
    2
    3
    4
    5
    }


    foreach 遍历法

    还有一种遍历的方法,用到了之前提到的 foreach 语句
    意思是使用变量 $n $a 元素进行迭代,这实际上是一种对可迭代对象的访问算法
    C# 也有这种语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $a="A","B","C","D","E"
    foreach($n in $a)
    {
    $n+" "+$n
    }
    #输出
    A A
    B B
    C C
    D D
    E E

    foreach 还有一种遍历的写法

    这里我们需要先了解一下 管道
    管道的符号 |
    管道允许将它左侧命令的输出结果发送到右侧做命令的参数
    管道并不是什么新事物,以前的Cmd控制台也有重定向的命令,例如Dir | More可以将结果分屏显示。
    传统的Cmd管道是基于文本的,但是 PowerShell 是基于对象的

    列出当前目录下的目录和文件,然后根据文件名降序排列,再投影(数据库术语)文件名,文件大小,文件的修改时间:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    PS D:/test> ls | Sort-Object -Descending Name | Select-Object Name,Length,LastWriteTime


    目录: D:/test


    Name Length LastWriteTime
    ---- ------ -------------
    out.txt 523 2019/2/24 22:46:35
    lang.json 6415 2019/2/16 23:49:24
    anapple.txt 65 2019/3/27 15:13:52
    4-3.cpp 136 2017/11/24 12:52:28

    可迭代对象(比如数组)可以由管道送到一些命令上进一步处理
    foreach 就可以接受管道送来的可迭代对象,并进行遍历

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $array="A","B","C","D","E"
    $array|foreach
    {
    $_+"s"
    }
    #输出
    As
    Bs
    Cs
    Ds
    Es
    将数组逆序输出
    1
    2
    3
    4
    5
    PS C:/Powershell> $books="A1","B2","C3"
    PS C:/Powershell> $books[($books.Count)..0]
    C3
    B2
    A1
    访问某些元素

    与C#相同,数组的元素可以使用索引寻址,第一个元素的索引为0,第i个元素的索引为i-1,最后一个元素的索引为Count-1,但是 PowerShell 为了使用方便,直接可以将 -1 作为最后的一个元素的索引(参考了 Python 的语法)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    PS C:/Powershell> $books="1A","2B","3C"
    PS C:/Powershell> $books[0]
    1A
    PS C:/Powershell> $books[1]
    2B
    PS C:/Powershell> $books[($book.Count-1)]
    3C
    PS C:/Powershell> $books[-1]
    3C
    从数组中选择多个元素
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    PS C:/Powershell> $result=ls
    PS C:/Powershell> $result[0,3,5,12]
    Directory: C:Powershell

    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    d---- 2011/11/23 17:25 ABC
    -a--- 2011/11/24 20:04 26384 a.txt
    -a--- 2011/11/24 20:27 12060 alias.ps1
    -a--- 2011/11/24 17:37 7420 name.html
    给数组添加元素

    因为PowerShell数组在内存中是顺序存储的,所以数组的大小必须是确定的,这样才方便分配存储空间,所以给数组增加元素其实相当于创建一个新的数组,只不过之后会把原来的副本删除。在当前数组追加元素可以使用 += 操作符。

    1
    2
    3
    4
    5
    6
    7
    PS C:/Powershell> $books="A1","B2","C3"
    PS C:/Powershell> $books+="D4"
    PS C:/Powershell> $books
    A1
    B2
    C3
    D4
    删除指定位置元素

    采用截断重连法删除指定元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PS C:/Powershell> $num=1..4
    PS C:/Powershell> $num
    1
    2
    3
    4
    PS C:/Powershell> $num=$num[0..1]+$num[3] #相当于删掉了第三项
    PS C:/Powershell> $num
    1
    2
    4

    复制数组

    数组属于引用类型,使用默认的的赋值运算符在两个变量之间赋值只是复制了一个引用,两个变量共享同一份数据。这样的模式有一个弊病如果其中一个改变也会株连到另外一个。所以复制数组最好使用 Clone() 方法( System.Array 类的成员函数),除非有特殊需求。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    PS C:/Powershell> $chs=@("A","B","C")
    PS C:/Powershell> $chsBak=$chs
    PS C:/Powershell> $chsBak[1]="H"
    PS C:/Powershell> $chs
    A
    H
    C
    PS C:/Powershell> $chs.Equals($chsBak)
    True
    PS C:/Powershell> $chsNew=$chs.Clone()
    PS C:/Powershell> $chsNew[1]="Good"
    PS C:/Powershell> $chs.Equals($chsNew)
    False
    PS C:/Powershell> $chs
    A
    H
    C

    强类型数组

    PowerShell 数组一般具有多态性,如果你不指定元素的具体类型,解释器会自动选择合适的类型存储每个元素。如果要统一限制所有元素的类型,可是使用类型名和一对方括号作为数组变量的类型。这样每当赋值时,会自动类型检查。如果目标数据类型不能转换成功,就会抛出一个异常,这样的数组被称为强类型数组
    定义方法 [类型[]]$数组名=初值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    PS C:/Powershell> [int[]] $nums=@()
    PS C:/Powershell> $nums+=2012
    PS C:/Powershell> $nums+=12.3
    PS C:/Powershell> $nums+="999"
    PS C:/Powershell> $nums+="can not convert"
    Cannot convert value "can not convert" to type "System.Int32". Error: "Input string was not in a correct format."
    At line:1 char:6
    + $nums <<<< +="can not convert"
    + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

    命令返回数组

    当我们把一个命令的执行结果保存到一个变量中,可能会认为变量存放的是纯文本。
    但是,事实上 PowerShell 会把文本按每一行作为元素存为数组。如果一个命令的返回值不止一个结果时, PowerShell 也会自动把结果存储为数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    PS C:/Powershell> $IPcfg=ipconfig
    PS C:/Powershell> $IPcfg
    <#输出

    Windows IP 配置


    以太网适配器 以太网:

    媒体状态 . . . . . . . . . . . . : 媒体已断开连接
    连接特定的 DNS 后缀 . . . . . . . : lan

    无线局域网适配器 本地连接* 1:

    媒体状态 . . . . . . . . . . . . : 媒体已断开连接
    连接特定的 DNS 后缀 . . . . . . . :

    无线局域网适配器 本地连接* 2:

    连接特定的 DNS 后缀 . . . . . . . :
    本地链接 IPv6 地址. . . . . . . . : ****
    IPv4 地址 . . . . . . . . . . . . : ****
    子网掩码 . . . . . . . . . . . . : ****
    默认网关. . . . . . . . . . . . . :

    以太网适配器 VMware Network Adapter VMnet8:

    连接特定的 DNS 后缀 . . . . . . . :
    本地链接 IPv6 地址. . . . . . . . : fe80::f88d:cd97:5343:9713%16
    IPv4 地址 . . . . . . . . . . . . : ****
    子网掩码 . . . . . . . . . . . . : ****
    默认网关. . . . . . . . . . . . . :

    无线局域网适配器 WLAN:

    连接特定的 DNS 后缀 . . . . . . . : ****
    本地链接 IPv6 地址. . . . . . . . : fe80::954:3964:3731:997e%18
    IPv4 地址 . . . . . . . . . . . . : ****
    子网掩码 . . . . . . . . . . . . : ****
    默认网关. . . . . . . . . . . . . : ****
    #>
    PS C:/Powershell> $IPcfg.Count
    37
    使用数组存储结果

    判断一个变量是否为数组

    1
    2
    3
    4
    5
    6
    7
    8
    PS C:/Powershell> $ip=ipconfig
    PS C:/Powershell> $ip -is [array]
    True
    PS C:/Powershell> "abac" -is [array]
    False
    PS C:/Powershell> $str="字符串"
    PS C:/Powershell> $str.ToCharArray() -is [array] #转换为字符数组
    True
    使用真实的对象操作

    为什么不愿把IPconfig返回的结果称为对象,因为它不是真正Cmdlet命令(事实上ipconfig是一个单独的程序),真正的 PowerShell 命令返回的数组元素可不止一个字符串,它是一个内容丰富的对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    PS D:/test> $list=ls
    PS D:/test> $list


    目录: D:/test


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a---- 2017/11/24 12:52 136 4-3.cpp
    -a---- 2019/3/27 15:13 65 anapple.txt


    PS D:/test> $list.gettype()

    IsPublic IsSerial Name BaseType
    -------- -------- ---- --------
    True True Object[] System.Array


    PS D:/test> foreach($i in $list){$i.name}
    4-3.cpp
    anapple.txt

    PS D:/test> $list[0].gettype()

    IsPublic IsSerial Name BaseType
    -------- -------- ---- --------
    True True FileInfo System.IO.FileSystemInfo

    上面的例子中数组的每一个元素存放的是一个 System.IO.DirectoryInfo 对象。
    当我们输出这些对象时, PowerShell 会自动帮我们把它转换成友好的文本格式。
    对于任何一个对象都可以使用 Format-List * 来查看它所有的属性和方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    PS D:/test> $list[0]|fl * 
    # "|"符号是管道符,将左边返回结果做参数发送到右侧,fl是Format-List的简称

    PSPath : Microsoft.PowerShell.Core\FileSystem::D:test\4-3.cpp
    PSParentPath : Microsoft.PowerShell.Core\FileSystem::D:\test
    PSChildName : 4-3.cpp
    PSDrive : D
    PSProvider : Microsoft.PowerShell.Core\FileSystem
    PSIsContainer : False
    Mode : -a----
    VersionInfo : File: D:\test\4-3.cpp
    InternalName:
    OriginalFilename:
    FileVersion:
    FileDescription:
    Product:
    ProductVersion:
    Debug: False
    Patched: False
    PreRelease: False
    PrivateBuild: False
    SpecialBuild: False
    Language:

    BaseName : 4-3
    Target : {}
    LinkType :
    Name : 4-3.cpp
    Length : 136
    DirectoryName : D:\test
    Directory : D:\test
    IsReadOnly : False
    Exists : True
    FullName : D:\test\4-3.cpp
    Extension : .cpp
    CreationTime : 2019/3/27 15:07:32
    CreationTimeUtc : 2019/3/27 7:07:32
    LastAccessTime : 2019/3/27 15:07:32
    LastAccessTimeUtc : 2019/3/27 7:07:32
    LastWriteTime : 2017/11/24 12:52:28
    LastWriteTimeUtc : 2017/11/24 4:52:28
    Attributes : Archive

    函数

    函数是自定义的 Powershell 代码,有三个原则:

  • 简短 :函数名简短,并且显而易见。
  • 聚合 :函数可以完成多个操作。
  • 封装和扩展 :将一批 Powershell 语句进行封装,实现全新的功能需求。
    函数的结构由三部分组成:函数名,参数,函数体
  • 定义函数

    脚本中函数的定义方法

    函数可以在文本编辑器上编写,写完以后复制进 PowerShell 控制台即可。如果控制台设置为快速编辑模式,从记事本复制后,直接在控制台鼠标右键即可完成粘贴(Windows 10默认开启了快速编辑模式)

    1
    2
    3
    4
    function FuncName(args[]) #括号可省略
    {
    <#代码段#>
    }
    控制台上多行输入定义函数
    1
    2
    3
    4
    5
    PS C:/PowerShell> function MyPing
    >> {
    >> PING.EXE -n 1 $args
    >> }
    PS C:/PowerShell>
    把函数精简成一行

    我们可以将一个函数定义在一行上,但是这样阅读和理解起来就不方便,所以要在每条命令后加分号进行分割(最后一句可以不写 ; )

    1
    2
    PS C:/PowerShell> function cd...{ cd.. ; cd.. }
    PS C:/PowerShell> cd...
    使用函数作为别名

    假如 PowerShell 不支持 Get-SystemVersion 命令,你可以通过定义函数实现这个功能:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function get-systemversion
    {
    $psversiontable.BuildVersion
    }

    Get-SystemVersion

    Major Minor Build Revision
    ----- ----- ----- --------
    10 0 17134 590
    更新函数

    如果要更新已经定义好的函数,简单的方法是重新定义,这样新的定义会覆盖旧的定义。但是如果函数代码没有保存副本,可以先将函数定义导出到ps文件,然后就可以编辑了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    PS C:/PowerShell> function MyPing
    >> {
    >> PING.EXE -n 1 $args
    >> }

    PS C:/PowerShell> $function:MyPing | Out-File myPing.ps1
    PS C:/PowerShell> $function:MyPing

    PING.EXE -n 1 $args

    PS C:/PowerShell> $function:MyPing | Out-File myPing.ps1
    PS C:/PowerShell> .myPing.ps1
    必须指定 IP 地址。
    PS C:/PowerShell> notepad.exe $$
    删除函数

    控制台定义的函数只会在当前会话生效,一旦控制台退出,会自动消失。在不关闭控制台的条件下删除一个已经定义好的函数,可是使用虚拟驱动器的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function cc{"hello"}
    PS C:/> cc
    hello
    PS C:/> del function:cc
    PS C:/> cc
    cc : 无法将“cc”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
    所在位置 行:1 字符: 1
    + cc
    + ~~
    + CategoryInfo : ObjectNotFound: (cc:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    输入输出函数

    用于脚本文件的编写

    输入

    PowerShell提供了 Read-Host 命令,可以接收返回用户在控制台输入的字符

    1
    2
    3
    4
    5
    6
    7
    $name=read-host "请输入你的名字" 
    #会把提示信息打印到PS控制台,也可以不写提示信息
    <#执行+输入 结果:
    请输入你的名字: Nougat
    #>
    $name
    Nougat
  • 提示信息(如果有)后面自动加了个冒号;
  • 用户键入任何信息都被作为该命令的返回结果;
  • 可以把键入的信息传递给一个变量;
  • 输出

    有两种输出命令
    Write-Host Write-Output
    若输出字符串不包含空白字符可以不加引号

    Write-Host

    当需要展示一个特定信息,比如使用其他颜色来吸引人们的注意力的时候,可使用 Write-Host 命令
    Write-Host 和其他Cmdlets一样使用管道,但是它不放置任何数据道管道中。反而会直接写到宿主应用程序的界面。正如此,可以使用 -ForegroundColor -BackgroundColor 参数将前景和背景设置为其他颜色:

    1
    2
    write-host "啊哈" -ForegroundColor White -BackgroundColor Red
    啊哈

    注: 不是每个使用PowerShell的应用程序都支持其他颜色,也并不是每个应用程序都支持所有颜色
    该输出方法 不适用于常规的输出结果 ,因为 Write-Host 命令输出到屏幕的任何东西都无法被捕捉。若执行远程命令或无人值守命令(纯自动化), Write-Host 可能不会按照你的预期工作。因此,此命令仅仅用于与人进行直接交互。

    Write-Output

    Write-Output 命令会将对象发送给管道。由于它不会直接发送到显示界面,所以不允许你指定其他任何的颜色。

    它是 PowerShell 默认使用的一个Cmdlets,默认输出方式即使用该命令,即使你没有指定, PowerShell 会在底层将信息传递给 Write-Output 命令(就是一行直接写一个变量就能直接输出的情况),另外这个命令还有两个别名 write echo

    1
    2
    3
    4
    5
    6
    write-host ACB #无空白字符可以不写引号 
    ACB
    write "ABC"
    ABC
    echo "ABD"
    ABD

    Write-Output 输出基本过程为:

  • Write-Output 命令将 string 类型的对象 Hello World! 放入管道中;
  • 管道中只有这个 string 对象,其会直接到达管道的末端,也就是 Out-Default 命令;
  • Out-Default 命令将对象传递给 Out-Host 命令;
  • Out-Host 命令要求 PowerShell 的格式化系统格式化该对象。
  • Out-Host 将格式化的结果集放在显示界面上
  • 还有一点,在输出多个对象时, Write-Host 会以空格隔开各对象
    Write-Output 会以换行隔开各对象

    1
    2
    3
    4
    5
    6
    write-host "ABC" "23232"
    ABC 23232

    write-output "ABC" "23232"
    ABC
    23232
    其他的输出方式

    Write-Warning/Verbose/Debug/Error

    具体参考: 微软官方文档

    处理函数参数

    PowerShell 函数可以接受参数,并对参数进行处理。函数的参数有3个特性:

  • 任意参数:内部变量 $args 接受函数调用时接受的参数, $args 是一个数组类型;
  • 命名参数:函数的每一个参数可以分配一个名称,在调用时通过名称指定对应的参数;
  • 预定义参数:函数在定义参数时可以指定默认值,如果调用时没有专门指定参数的值,就会保持默认值;
  • $args 万能参数

    给一个函数定义参数最简单的是使用 $args 这个内置的参数。它可以识别任意个参数。尤其适用那些参数可有可无的函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    function sayHello
    {
    if($args.Count -eq 0)
    {
    "No argument!"
    }
    else
    {
    $args | foreach {"Hello,$($_)"}
    }
    }
    #无参调用
    sayhello
    #输出
    No argument!

    #一参调用
    sayhello "World!" #也可以写成sayhello("World!")
    #输出
    Hello,World!


    #多参数调用
    $str="it's me."
    sayhello 123 "aha" $str #如果字符串不包含空白字符(比如空格),引号可以不写
    <#输出
    Hello,123
    Hello,aha
    Hello,it's me.
    #>

    因为 $arg 是一个数组,可以用它很方便的写出求和函数

    1
    2
    3
    4
    5
    6
    7
    8
    function Add
    {
    $sum=0
    $args | foreach {$sum=$sum+$_}
    $sum
    }
    Add 10 7 3 100
    #120
    使用固定参数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function StringContact($str1,$str2)
    {
    return $str1+$str2
    }

    StringContact LN P
    #StringContact -str1 word -str2 press
    #StringContact("word","press")
    LNP
    wordpress
    给参数定义默认值
    1
    2
    3
    4
    5
    6
    7
    function stringContact($str1="LN",$str2="P")
    {
    return $str1+$str2
    }

    stringContact
    LNP
    使用强类型参数

    通过之前的例子发现将用户的参数传递给函数显得比较混乱。罪魁祸首就是 PowerShell 的参数解释器,它可以自动处理和分配参数给函数。
    函数的参数解释器比较傲慢,它对你提供的参数的信息完全不关心。它只会粗略地将参数进行分割,并且最大限度的进行自动类型转换。事实上,这种类型转换很多时候并不完美。所以 最好提前能够对参数进行强类型限制

    限制数字类型

    下面的函数执行后,会抛出异常
    因为 subtract 的参数定义了强类型,参数的类型可能引起函数的处理结果改变。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    function subtract([int]$value1,[int]$value2)
    {
    return $value1-$value2
    }
    subtract LN P
    #执行结果报错
    subtract : 无法处理对参数“value1”的参数转换。无法将值“LN”转换为类型“System.Int32”。错误:“输入字符串的格式不正确。”
    所在位置 行:1 字符: 10
    + subtract LN P
    + ~~
    + CategoryInfo : InvalidData: (:) [subtract],ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,subtract

    subtract 8.1 7.9
    0
    <#结果为0,这是因为PowerShell对结果整型化时进行了四舍五入
    但是如果将上面的函数的参数定义为Double型#>
    function subtract([double]$value1,[double]$value2)
    {
    return $value1-$value2
    }
    subtract 8.1 7.9
    0.199999999999999
    <#输出 0.199999999999999的原因就是 .NET使用IEEE754标准存储浮点数,
    由于这些小数转化二进制会无限循环,会根据一定精度截取尾数,
    这个问题引发了这种奇怪的结果,
    其实著名的0.1+0.2!=0.3也是这个原因导致的#>
    限制日期类型

    函数的参数解释器会自动尝试将字符串转换成日期类型,如果转换失败就是抛出异常
    看下面的例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function DayOfWeek([datetime]$date)
    {
    return $date.DayOfWeek
    }

    DayofWeek '1927-8-1'
    Monday

    DayofWeek 2008-8-1
    Friday

    DayofWeek 'abc'
    DayOfWeek : 无法处理对参数“date”的参数转换。无法将值“abc”转换为类型“System.DateTime”。错误:“该字符串未被识别为有效的 DateTime。有一个未知单词(从索引 0 处开始)。”
    所在位置 行:1 字符: 12
    + DayofWeek 'abc'
    + ~~~~~
    + CategoryInfo : InvalidData: (:) [DayOfWeek],ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,DayOfWeek
    Switch 参数

    Powershell 函数最简单的参数类型为布尔类型,除了使用 Bool 类型,也可以使用 Switch 关键字。
    下面的函数逆转字符串,但是可以通过 $try 参数进行控制,如果没有指定 $try 的值,默认值为 $false

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function  tryReverse( [switch]$try , [string]$source ) 
    #此处switch完全可以换成bool
    {
    [string]$target=""
    if($try)
    {
    for( [int]$i = $source.length -1; $i -ge 0 ;$i--)
    {
    $target += $source[$i]
    }
    return $target
    }
    return $source
    }
    tryReverse -source www.google.com
    tryReverse -try $true -source www.google.com
    #输出
    www.google.com
    moc.eloog.www

    指定函数的返回值

    一个或多个返回值

    PowerShell 不像其它的编程语言,它的函数可以有多个返回值。如果你直接调用函数,返回值会在控制台输出。当然你也可以将结果存储在一个变量中进一步处理
    下面的例子演示返回一个值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function Square([double]$num)
    {
    return $num*$num
    }
    #在控制台输出结果
    Square 9.87
    97.4169

    #将结果赋值给变量
    $value=Square 9.87
    $value
    97.4169

    #返回值为Double类型
    $value.GetType().FullName
    System.Double

    下面的例子演示返回多个值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    function gbMeasure($amount)
    {
    "$amount GB=$($amount) GB"
    "$amount GB=$($amount*1gb/1mb) MB"
    "$amount GB=$($amount*1gb/1kb) KB"
    "$amount GB=$($amount*1gb) B"
    }

    #函数返回4个值
    gbMeasure 1
    1 GB=1 GB
    1 GB=1024 MB
    1 GB=1048576 KB
    1 GB=1073741824 B

    #将所有的返回值存储在一个变量中
    $result=gbMeasure 1
    $result

    1 GB=1 GB
    1 GB=1024 MB
    1 GB=1048576 KB
    1 GB=1073741824 B

    #所有的返回值会自动存储在一个数组中
    $result=gbMeasure 1
    $result.GetType().Name
    Object[]

    #通过索引访问每个返回值
    $result=gbMeasure 1
    $result[3]
    1 GB=1073741824 B

    总结一下,如果一个函数返回一个值,像其它编程语言一样,这个值包括它的类型信息会直接返回。但是如果遇到多个返回值,PowerShell会将所有的返回值自动构造成一个对象数组。
    可以通过索引访问数组

    Return语句

    Powershell 会将函数中所有的输出作为返回值,但是也可以通过return语句指定具体的返回值。
    Return 语句会将指定的值返回,同时也会中断函数的执行, return后面的语句会被忽略

    看一个例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function test($num)
    {
    1
    9
    return 10
    4
    6
    }

    test
    1
    9
    10
    <# 1 和 9 作为输出会返回
    return语句中的10 也会返回
    return 语句后的4和6会被忽略#>
    访问返回值

    一个函数返回了一个值还是多个值,是可以验证的。下面的例子会产生随机数,如果没有指定个数,默认会返回一个随机数,否则会返回指定个数的随机数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function lottery([int]$number=1)
    {
    $rand = New-Object system.random
    for ($i=1; $i -le $number; $i++)
    {
    $rand.next(1,50)
    }
    }

    # 参数为空时,返回值不是数组:
    $result = lottery
    $result -is [array]
    False

    # 如果指定多个随机数时,返回值是数组类型:
    $result = lottery 10
    $result -is [array]
    True
    $result.count
    10
    从函数的返回值中消除输出

    函数默认会将函数中的所有输出作为函数的返回值返回,这样很方便。但有时可能会将不必要的输出误以为返回值。写脚本程序时,可能需要自定义一些函数,这个函数可能只需要一个返回值,但是为了提高函数的可读性,可能会在函数增加一些注释输出行,或者使用 write-host

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    function Test()
    {
    "Try to calculate."
    "3.1415926"
    "Done."
    }

    #保存在变量中输出,
    $value=Test
    $value
    #输出
    Try to calculate.
    3.1415926
    Done.

    #如果要过滤注释,只输出,不作为返回值,
    #可以使用Write-Host命令
    function Test()
    {
    Write-Host "Try to calculate."
    "3.1415926"
    Write-Host "Done."
    }
    # 在变量值中保存返回值,在控制台输出注释行
    $value=Test
    #控制台输出
    Try to calculate.
    Done.

    # 测试返回值
    $value
    3.1415926

    恭喜你!到此 PowerShell 基础入门算是完成了!
    之后将介绍 PowerShell 的进阶使用

    附录

    PowerShell Math类常用函数表

  • [math]::sin(x) System.Math 返回x弧度的正弦值 double [math]::cos(x) System.Math 返回x弧度的余弦值 double [math]::abs(x) System.Math 返回x的绝对值 所有数值型 [math]::sqrt(x) System.Math 返回x的平方根 double [math]::pow(x,n) System.Math 返回x的n次幂 两参数都是double [math]::log(x) System.Math 返回x的自然对数 double [math]::log(x,n) System.Math 返回x的以n为底的对数 double [math]::min(x,y) System.Math 返回x,y中的最小值 所有数值型 [math]::max(x,y) System.Math 返回x,y中的最大值 所有数值型 floor [math]::ceiling(x) System.Math 返回x向下取整的结果 double、decimal ceiling [math]::ceiling(x) System.Math 返回x向上取整的结果 double、decimal math 类其他函数及详细用法参见微软文档: Math类