PowerShell Basic

简要

最初 Windows PowerShell 平台基于 .NET Framework 构建,只能在 Windows 操作系统上运行

但是,在最近的版本中,PowerShell 使用 .NET Core 并且可以在 Windows, macOS, Linux 平台上运行

由于其对多平台的支持,这些最新版本被称为 PowerShell 而不是 Windows PowerShell

Windows PowerShell 取代了 Windows 命令行接口 (cmd.exe) 及其批处理文件脚本语言的有限功能

  • 命令行历史记录
  • Tab 自动补全和预测
  • 支持命令和参数别名
  • 链接使用管道功能的命令
  • 可靠的控制台内帮助系统

与 Windows PowerShell 相比,安装最新版本的 PowerShell 会产生以下结果:

  • 独立的安装路径和可执行文件名

    • Windows PowerShell 5.1 安装在 $env:WINDIR\System32\WindowsPowerShell\v1.0 中,在 Windows PowerShell 中,PowerShell 可执行文件名为 powershell.exe
    • PowerShell 7 安装在 $env:ProgramFiles\PowerShell\7 中,在版本 6 及更高版本中,可执行文件命名为 pwsh.exe
  • 每个版本的独立配置文件

    • 在 Windows PowerShell 5.1 中,配置文件的位置为 $HOME\Documents\WindowsPowerShell
    • 在 PowerShell 7 中,配置文件的位置为 $HOME\Documents\PowerShell
  • 独立的 PSModulePath: Windows PowerShell 和 PowerShell 7 将模块存储在不同的位置

  • 独立的事件日志: Windows PowerShell 和 PowerShell 7 记录事件来分隔 Windows 事件日志

使用 $PSVersionTable 查看将验证安装情况

Name                           Value
----                           -----
PSVersion                      7.1.4
PSEdition                      Core
GitCommitId                    7.1.4
OS                             Linux 5.4.0-1058-azure #60~18.04.1-Ubuntu SMP Tue Aug 31 20:34:4…
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
  • 通过 $PSVersionTable.<Name> 可以进一步调用,比如 $PSVersionTable.PSVersion

基本使用

PowerShell cmdlet

cmdlet(发音为“command-let”)是已编译的命令,下面的 三个核心 cmdlet 可让你深入了解存在哪些 cmdlet 以及它们的作用:

  • Get-Command: Get-Command cmdlet 列出系统上的所有可用 cmdlet,筛选列表以快速找到所需的命令
  • Get-Help: 调用内置帮助系统,还可以运行别名 help 命令来调用 Get-Help,一般使用 Get-Help -Name <cmdlet>
  • Get-Member: 调用命令时,响应是包含多个属性的对象

PowerShell cmdlet 使用的常见格式是 Verb-Noun 表示法

  • Verb: 可以理解为行为,指示该 cmdlet 执行的操作

    • Get: 检索资源
    • Set: 更改与资源相关的数据
    • New: 创建资源
    • Add: 将资源添加到多个资源的容器
    • Remove: 将资源从多个资源的容器中删除
  • Noum: 该 cmdlet 影响的资源或对象的类型

    • 对同一资源运行的所有 cmdlet 应使用相同的名词
    • 名词中还可以包含前缀,可帮助将相关名词按系列分组

cmdlet 的参数

  • 参数名称以短划线 (-) 开头
  • 空格用于分隔要从参数名称传递的值
  • 如果传递的值包含空格,则需用引号将文本括起来
  • 某些参数接受多个值,这些值必须用 , 分隔(不含空格)
  • 参数可以为可选参数或必需参数,如果为必需参数而运行 cmdlet 时没有提供该参数的值,Windows PowerShell 将提示你为其提供值

示例 Get-Command检索/查找【命令】资源

# 查找与文件相关的任何内容,支持模糊匹配
Get-Command -Noun File*

# 进一步筛选响应
Get-Command -Verb Get -Noun File*

获取帮助

默认情况下,PowerShell 的新版本不包含帮助系统

  • 首次运行 Get-Help 时,系统会要求安装帮助文件
  • 可以运行 Update-Help cmdlet 以安装帮助文件
# 获取命令 cmdlet 的帮助信息:Get-Help -Name <cmdlet>
Get-Help -Name Get-Help

# Update-Help 更新帮助文档,记住这个需要以管理员运行
#   -Force              重写此提取行为(Update-Help 命令每日只能提取一次)
#   -UICulture          选项可以指定语言
#   -Verbose            获取更新的帮助文档列表
Update-Help -UICulture zh-CN -Verbose

Get-Help 的输出结果

  • NAME: 提供命令的名称
  • SYNTAX: 介绍如何通过使用标志组合(有时还可使用允许的参数)来调用命令
  • ALIASES: 列出了命令的所有别名
  • REMARKS: 提供有关要运行的命令的信息,以获取有关此命令的更多帮助
  • PARAMETERS: 提供有关参数的详细信息

运行 Get-Help 命令将返回整个帮助页,此页可能无法提供最佳阅读体验

你可能必须滚动查找要阅读的部分,更好的方法是使用 help 别名

使用 Get-Member 检查输出

  • 要传递给 Get-Member 的 对象的类型
  • 可计算的对象的 属性
  • 可执行的对象的 方法
# 通过调用 Get-Process 生成对象结果,使用管道传递给 Get-Member
# 在返回结果中,你将获得一个表(其中包含 Name、MemberType、Definition 列,你还会获得返回对象的类型)
Get-Process -Name 'name-of-process' | Get-Member

# 使用 Select-Object 筛选 Get-Member 结果
Get-Process -Name 'name-of-process' | Get-Member | Select-Object Name, MemberType

# Sort-Object 排序是按升序或降序进行的
#   -Descending         降序
#   -Property           筛选列
Get-Process | Sort-Object -Descending -Property Name, CPU

PowerShell 别名和参数

请务必注意,别名通常不支持原始命令使用的参数

通过使用 Get-Alias <cmdlet>,可以发现别名、别名定义及其运行的命令

  • 建议 Get-Help -Name Get-Alias
  • PowerShell 包含旧批处理和 Linux 命令的别名
  • 不带参数的 Get-Alias 返回所有已定义的别名
  • -Name 参数: 一个位置参数,接受通配符,来查找特定别名的定义

使用 New-Alias <cmdlet> 创建自定义别名,注意:自定义别名不会在 Windows PowerShell 会话之间保存,如果需要保存可以使用 Windows PowerShell 配置文件重新创建别名

编写一个 PowerShell 脚本

PowerShell 被编译成抽象语法树 (AST),首先在内存中,然后运行

  • 但要使用 PowerShell,你不需要在这里进行深入研究
  • 你所需要知道的是,计算机在查找主要问题时首先检查 AST 中的代码
  • 如果一切正常,则程序由计算机运行,而不需要编译的可执行程序

最基本的程序也能执行以下一项或多项任务:

  • 接受来自源的输入
  • 处理信息
  • 输出结果

New-Item 命令在当前目录中创建一个新的 .ps1 文件(.ps1 文件扩展名是用于 PowerShell 脚本的扩展名)

New-Item HelloWorld.ps1

在文件中写入下面内容,然后执行 ./HelloWorld.ps1

# Read-Host         输入,类似 bash 中的 read
#   -Prompt         输入提示
#
# Write-Output      输出,类似 bash 中的 echo
$name = Read-Host -Prompt "Please enter your name"
Write-Output "Congratulations $name! You have written your first code with PowerShell!"

关于 bash 脚本

基本概念

让我们先大致了解一下 PowerShell 脚本语言(不区分大小写)的组成:

  • 变量:你可以使用变量来存储值,还可以将变量用作命令的参数
  • 表达式:你将在 PowerShell 脚本中频繁使用表达式
  • 函数:函数是语句的命名列表
  • 流控制:流控制是通过使用 If、ElseIf 和 Else 之类的构造来控制各种执行路径的方法
  • 循环:循环是允许对数组进行操作、检查各项以及对各项执行某种操作的构造
  • 错误处理:对于脚本编写,可靠性以及处理各种类型错误的能力很重要
  • .NET.NET Core 集成:PowerShell 提供与 .NET 和 .NET Core 的强大集成

PowerShell 尝试通过两种主要方式阻止你执行意外操作:

  • 要求使用完整路径或相对路径来运行脚本
  • 执行策略

变量

若要定义变量,请在其前面加上 $ 字符,使用变量(引号和内插)

# 定义变量
$PI = 3.14

# 要进行内插,需要使用双引号,使用 反引号 (`) 使可以免于内插
Write-Host 'Here is $PI' # Prints Here is $PI
Write-Host "Here is `$PI and its value is $PI" # Prints Here is $PI and its value is 3.14

# 双引号内编写表达式
Write-Host "An expression $($PI + 1)" # Prints An expression 4.14

作用域

  • 全局范围:在此范围内创建类似变量的构造时,它们会在会话结束后继续存在
  • 脚本范围:运行脚本文件时,将创建脚本范围
  • 本地范围:本地范围是当前范围,可以是全局范围或任何其他范围

配置文件是在 PowerShell 启动时运行的脚本

  • 所有用户,所有主机:$PSHOME\Profile.ps1
  • 所有用户,当前主机:$PSHOME\Microsoft.PowerShell_profile.ps1
  • 当前用户,所有主机:$Home[My ]Documents\PowerShell\Profile.ps1
  • 当前用户,当前主机:$Home[My ]Documents\PowerShell\Microsoft.PowerShell_profile.ps1

这里有两个变量:$PSHOME 指向 PowerShell 的安装目录;$Home 为当前用户的主目录

可运行 $Profile | Select-Object * 来查看配置文件类型以及与它们关联的路径

运算符

PowerShell 包含许多逻辑运算符,用于比较值或查找与特定模式匹配的值

操作员 定义
-eq 等于
-ne 不等于
-gt 大于
-ge 大于或等于
-lt 小于
-le 小于或等于
-Like 使用 * 通配符进行匹配
-NotLike 不使用 * 通配符进行匹配
-Match 匹配指定的正则表达式
-NotMatch 不匹配指定的正则表达式
-Contains 确定集合中是否包含指定的值
-NotContains 确定集合是否不包含特定值
-In 确定指定的值是否在集合中
-NotIn 确定指定的值是否不在集合中
-Replace 替换指定的值

参数

创建几个脚本后,你可能会注意到脚本并不灵活,使用参数可以使脚本变得灵活,因为它允许用户选择选项或将输入发送到脚本

# 若要声明参数,需使用关键字 Param 和一对括号
Param (
  $Path
)
New-Item $Path
Write-Host "File $Path was created"

在命令行使用 ./CreateFile.ps1 -Path './newfile.txt' 测试上面内容

你可以使用几种方法提高脚本的安全性,你可以编写自定义代码来检查参数值

  • 使用 If/Else

    Param(
        $Path
    )
    
    # 如果没有为 $Path 提供值,则脚本将运行 Write-Error
    If (-Not $Path -eq '') {
        New-Item $Path
        Write-Host "File created at path $Path"
    } Else {
        Write-Error "Path cannot be empty"
    }
    
  • 使用 Parameter[] 修饰器

    Param(
        [Parameter(Mandatory, HelpMessage = "Please provide a valid path")]
        $Path
    )
    New-Item $Path
    Write-Host "File created at path $Path"
    
  • 分配类型

    Param(
        [string]$Path
    )
    

这三种方法并不互斥,可以将它们组合起来,使脚本更安全

分支结构

使用 If-ElseIf-Else 管理输入和执行流

PowerShell 提供了两个内置参数,用于确定表达式是 True 还是 False:

  • $True 指示表达式为 True
  • $False 指示表达式为 False
# _FullyTax.ps1_
# Possible values: 'Minor', 'Adult', 'Senior Citizen'
$Status = 'Minor'
If ($Status -eq 'Minor')
{
    Write-Host $False
} ElseIf ($Status -eq 'Adult') {
    Write-Host $True
} Else {
    Write-Host $False
}

错误处理

  • 使用 Try-Catch-Finally 管理错误

    Try {
        # 将要运行的代码
    } Catch [System.IO.IOException] {
    Write-Host "Something went wrong"
    }  Catch {
        # 发生错误时,将使用此关键字捕获或管理错误
    } Finally {
        # 不管是否出现错误,此块中的语句都将运行
    }
    
  • 引发错误

    # 非终止错误,可以使用参数(例如 -ErrorAction)来引发
    Try {
        Get-Content './file.txt' -ErrorAction Stop
    } Catch {
        Write-Error "File can't be found"
    }
    
    # 业务规则,可以使用 Throw 块
    # 通常,不要使用 Throw 进行参数验证
    Try {
        If ($Path -eq './forbidden'){
            Throw "Path not allowed"
        }
    } Catch {
        Write-Error "$($_.exception.message)" # Path not allowed.
    }
    

流程控制

ForEach-Object 是用于循环访问管道中的项的 cmdlet

# ForEach-Object 通过管道流式处理对象
# '|' 是管道,shell 一般都具有的特性,属于常识
# $_ 表示当前对象
'ActiveDirectory', 'SQLServer' |
    ForEach-Object {Get-Command -Module $_} |
        Group-Object -Property ModuleName -NoElement |
            Sort-Object -Property Count -Descending

# 也有 foreach 关键字
# 但是 foreach 必须先将所有项存储在内存中,然后才能循环访问这些项,如果不知道要处理的项数,此操作可能会很困难
$ComputerName = 'DC01', 'WEB01'
foreach ($Computer in $ComputerName) {
    Get-ADComputer -Identity $Computer
}

for 循环会进行循环访问

for ($i = 1; $i -lt 5; $i++) {
    Write-Output "Sleeping for $i seconds"
    Start-Sleep -Seconds $i
}

do-untildo-while 在条件比较部分相反

# 指定的条件为 false 时,do-until 运行
$number = Get-Random -Minimum 1 -Maximum 10
do {
    $guess = Read-Host -Prompt "What's your guess?"
    if ($guess -lt $number) {
        Write-Output 'Too low!'
    }
    elseif ($guess -gt $number) {
        Write-Output 'Too high!'
    }
}
until ($guess -eq $number)

# 指定条件的计算结果为 true,do-while 运行
$number = Get-Random -Minimum 1 -Maximum 10
do {
    $guess = Read-Host -Prompt "What's your guess?"
    if ($guess -lt $number) {
        Write-Output 'Too low!'
    } elseif ($guess -gt $number) {
        Write-Output 'Too high!'
    }
}
while ($guess -ne $number)

控制:break、continue、return

# break 旨在中断循环
for ($i = 1; $i -lt 5; $i++) {
    Write-Output "Sleeping for $i seconds"
    Start-Sleep -Seconds $i
    break
}

# continue 旨在跳到循环的下一次迭代
while ($i -lt 5) {
    $i += 1
    if ($i -eq 3) {
        continue
    }
    Write-Output $i
}

# return 旨在退出现有作用域
$number = 1..10
foreach ($n in $number) {
    if ($n -ge 4) {
        Return $n
    }
}

PowerShell 执行策略

PowerShell 中的执行策略旨在最大程度地减少用户无意中运行 PowerShell 脚本的可能性

你可以将其视为一项安全功能,用于控制 PowerShell 加载配置文件和运行脚本的条件

若要标识当前 PowerShell 会话的有效执行策略,请使用以下 cmdlet: Get-ExecutionPolicy

可以配置以下策略设置:

  • AllSigned: 限制所有已签名脚本的脚本执行

    此设置要求所有脚本都由受信任的发布者签名,包括在本地计算机上编写的脚本。 它会在运行来自尚未分类为受信任或不受信任的发布者的脚本之前提示你。 但是,验证脚本的签名并不能消除该脚本是恶意脚本的可能性。 它只是提供额外的检查,以最大限度地减少这种可能性

  • Default: 设置默认执行策略

    • 对于 Windows 客户端: Restricted
    • 对于 Windows Server: RemoteSigned
  • RemoteSigned: 脚本可以运行,但该策略要求受信任的发布者对从 Internet 下载的脚本和配置文件进行数字签名. 注:「此设置不需要对在本地计算机上编写的脚本进行数字签名」

  • Restricted: 它允许运行单个命令,但不允许运行脚本

  • Unrestricted: 这是非 Windows 计算机的默认执行策略,你无法更改该策略。 它允许运行未签名的脚本,此策略在运行并非来自本地 Intranet 区域的脚本和配置文件之前向用户发出警告

  • Undefined: 指示当前范围中未设置执行策略

    如果所有范围中的执行策略都是 Undefined

    • 对于 Windows 客户端,有效执行策略为 Restricted
    • 对于 Windows Server 为 RemoteSigned

更改 PowerShell 中的执行策略,请使用以下命令: Set-ExecutionPolicy -ExecutionPolicy <PolicyName>

如果想学习更多 -> 官方文档