PowerShell 脚本

核心理念: PowerShell 不仅仅是命令提示符的升级版,它是构建于 .NET Framework/.NET Core 之上的自动化引擎和脚本语言,融合了命令行的高效与编程语言的强大。


一、 PowerShell 脚本的本质与优势

  1. 面向对象 (Object-Oriented):
    • 命令 (Cmdlets) 处理的是对象 (如文件、进程、服务),而非纯文本。

    • 输出可通过管道传递对象及其丰富属性 (Get-Member)。

  2. 强大的管道 (Pipeline):
    • 基于对象传递 (Command1 | Command2 | Command3)。

    • 支持流式处理,提高效率。

    • 过滤 (Where-Object) 和操作 (ForEach-Object) 对象极为灵活。

  3. 一致的语法 (Verb-Noun):
    • Cmdlets 命名遵循 动词-名词 模式 (e.g., Get-Process, Set-Service, Stop-Job)。

    • 提高可发现性和可读性。

  4. 深度集成 .NET:
    • 可直接调用 .NET Framework/Core 类库,扩展功能无限。

    • [System.Math]::Sqrt(9)(New-Object System.Net.WebClient).DownloadString('url')

  5. 可发现性:
    • Get-Command: 查找命令。

    • Get-Help: 获取详细帮助 (-Full, -Examples, -Online)。

    • Get-Member: 探索对象属性与方法。


二、 脚本基础:创建与执行

  1. 文件扩展名: .ps1

  2. 创建脚本:

    • 使用任何文本编辑器 (推荐 VS Code + PowerShell 扩展) 或 PowerShell ISE (旧版)。
  3. 执行脚本:

    • 基础方式: .\YourScript.ps1 (注意点号和反斜杠,表示当前目录)。

    • 关键障碍:执行策略 (Execution Policy):

      • 目的:防止无意或恶意脚本运行。

      • 查看:Get-ExecutionPolicy

      • 常见策略:

        • Restricted: (默认) 禁止运行任何脚本。

        • AllSigned: 只运行受信任发布者签名的脚本。

        • RemoteSigned: (推荐) 本地脚本可运行,下载的脚本需签名。

        • Unrestricted: (危险) 允许所有脚本运行(有警告)。

      • 更改 (需管理员权限):Set-ExecutionPolicy RemoteSigned (通常设置作用域 -Scope CurrentUser)。

      • 绕过策略 (单次执行): powershell.exe -ExecutionPolicy Bypass -File .\YourScript.ps1 (慎用)。


三、 脚本核心编程要素

  1. 变量:
    • 定义:$variableName = value (e.g., $count = 10, $files = Get-ChildItem).

    • 弱类型,但可强类型化:[int]$number = "42" (会转换)。

    • 作用域:$global:var, $script:var, $private:var, $local:var (默认)。

  2. 数据类型:
    • 自动推断,也可显式声明:[string], [int], [datetime], [array], [hashtable], 自定义 .NET 类型等。

    • GetType() 方法查看对象类型。

  3. 运算符:
    • 算术:+, -, *, /, %

    • 赋值:=, +=, -=, *=, /=

    • 比较:-eq (等于), -ne, -gt, -lt, -ge, -le, -like (通配符), -match (正则), -contains, -in

    • 逻辑:-and, -or, -not (!)

    • 其他:.. (范围运算符 e.g., 1..5), -is (类型检查), -as (类型转换)。

  4. 控制流:
    • 条件:
      if ($condition) { ... }
      elseif ($otherCondition) { ... }
      else { ... }
      
      • switch 语句:
      switch -Regex ($value) {
          'pattern1' { ... }
          'pattern2' { ... }
          default { ... }
      }
      
    • 循环:
      • foreach ($item in $collection) { ... }

      • For ($i = 0; $i -lt $max; $i++) { ... }

      • While ($condition) { ... }

      • Do { ... } While ($condition) / Do { ... } Until ($condition)

    • 流控制: break, continue, return.
  5. 输入与输出:
    • 输入:
      • 参数 (见函数部分)。

      • Read-Host "Prompt message" (命令行交互)。

      • 管道输入 ($input 自动变量或在函数/脚本块中使用 param() + ValueFromPipeline)。

    • 输出:
      • 任何未捕获或赋值的对象都会输出到管道/控制台。

      • 显式输出:Write-Output (或直接放置对象),Write-Host (直接到主机,不进入管道,通常仅用于用户交互信息)。

      • 格式化输出:Format-Table, Format-List, Format-Wide, Out-GridView (交互式表格)。

      • 导出:Out-File, Export-Csv, Export-Clixml, ConvertTo-Json 等。

  6. 数组与哈希表:
    • 数组: $array = 1, 2, 3$array = @(1, 2, 3)。索引访问 $array[0]。动态增长。

    • 哈希表 (字典): $hash = @{ Key1 = 'Value1'; Key2 = 'Value2' }。访问 $hash['Key1']$hash.Key1。用于键值对存储和参数 splatting (@hash)。


四、 函数:代码复用的基石

  1. 基础函数:
    function Get-Greeting {
        param(
            [string]$Name = "World" # 带默认值的参数
        )
        "Hello, $Name!"
    }
    Get-Greeting -Name "PowerShell"
    
  2. 高级函数:
    • 使用 [CmdletBinding()] 属性,获得类似 Cmdlet 的功能:
      • 支持 -Verbose, -Debug, -ErrorAction, -WhatIf, -Confirm 等通用参数。
      • 显式参数声明 ([Parameter()])。
    function Get-FileInfo {
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
            [string[]]$Path
        )
        process {
            foreach ($p in $Path) {
                $item = Get-Item $p -ErrorAction SilentlyContinue
                if ($item) {
                    [PSCustomObject]@{
                        Name = $item.Name
                        SizeKB = [math]::Round($item.Length / 1KB, 2)
                        LastModified = $item.LastWriteTime
                    }
                } else {
                    Write-Warning "Path '$p' not found."
                }
            }
        }
    }
    Get-ChildItem C:\Temp\*.txt | Get-FileInfo | Format-Table -AutoSize
    
  3. 参数详解:
    • Mandatory=$true: 强制参数。

    • ValueFromPipeline=$true: 接受管道输入。

    • ValueFromPipelineByPropertyName=$true: 输入对象属性名匹配参数名时绑定。

    • Position=0: 位置参数。

    • ValidateSet('Option1', 'Option2'): 验证参数值在集合内。

    • ValidatePattern('regex'): 正则验证。

    • ValidateRange(1, 100): 数值范围验证。

    • [Alias('ShortName')]: 为参数定义别名。

  4. begin, process, end 块:
    • begin: 管道输入开始前执行一次 (初始化)。

    • process: 对管道输入的每个对象执行一次 (核心处理逻辑)。

    • end: 所有管道输入处理完成后执行一次 (清理、汇总)。


五、 错误处理:构建健壮脚本

  1. 错误类型:
    • 终止错误 (Terminating Errors): 严重错误,停止当前命令/脚本执行 (e.g., 语法错误、未捕获异常、throw 语句)。

    • 非终止错误 (Non-Terminating Errors): 可恢复错误,命令继续执行 (e.g., Get-ChildItem 访问部分无权限的文件)。

  2. 错误处理机制:
    • -ErrorAction 参数: 控制命令对非终止错误的处理方式:

      • SilentlyContinue: 静默忽略错误,继续执行。

      • Stop: 将非终止错误转换为终止错误。

      • Continue: (默认) 显示错误并继续。

      • Inquire: 询问用户如何处理。

    • $ErrorActionPreference 变量: 设置当前作用域默认的错误操作首选项。

    • try...catch...finally 块: 捕获和处理终止错误

      try {
          # 可能引发终止错误的代码
          Get-Content -Path "NonexistentFile.txt" -ErrorAction Stop
      }
      catch [System.IO.FileNotFoundException] {
          Write-Host "文件未找到错误: $($_.Exception.Message)"
      }
      catch {
          Write-Host "其他错误: $($_.Exception.GetType().FullName)"
      }
      finally {
          # 无论是否出错都会执行的清理代码 (e.g., 关闭文件、释放资源)
      }
      
    • $Error 自动变量: 包含会话中最近错误的数组 (最新错误在 $Error[0])。$_.Exception 包含异常的详细信息。

    • throw 语句: 主动抛出终止错误。


六、 模块化与代码组织

  1. 模块 (Modules):
    • 封装 PowerShell 功能 (函数、Cmdlets、变量、别名) 的可复用包。

    • 文件扩展名 .psm1 (脚本模块) 或 .dll (二进制模块)。

    • 导入模块: Import-Module ModuleName

    • 查找模块: Find-Module (需注册 PSRepository,默认是 PowerShellGallery) -> Install-Module -> Import-Module

    • 创建模块: 将相关函数保存在 .psm1 文件中,通常伴随一个描述模块的 .psd1 (模块清单) 文件。New-ModuleManifest 创建清单。

  2. 点源加载 (Dot Sourcing):
    • 当前作用域执行另一个脚本文件中的内容 (函数、变量)。

    • 语法:. .\LibraryFunctions.ps1 (注意第一个点后有空格)。

    • 常用于在脚本间共享函数库。


七、 脚本安全最佳实践

  1. 最小特权原则: 脚本运行所需权限。

  2. 代码签名:

    • 使用数字证书 (New-SelfSignedCertificate 或购买商业证书) 对脚本签名 (Set-AuthenticodeSignature)。

    • 设置 AllSigned 执行策略要求所有脚本必须签名。

  3. 输入验证: 对所有外部输入 (参数、文件、用户输入) 进行严格验证。

  4. 避免硬编码敏感信息: 使用安全方式存储凭据:

    • Get-Credential 提示用户输入。

    • Export-Clixml 加密存储 (仅限同一用户同一机器):

      $cred = Get-Credential
      $cred | Export-Clixml -Path "C:\secure\mycred.xml"
      $storedCred = Import-Clixml -Path "C:\secure\mycred.xml"
      
    • 企业环境考虑使用密钥管理系统 (e.g., Azure Key Vault)。

  5. 谨慎处理远程内容: 验证下载脚本/配置的来源和完整性。

  6. 日志记录: 使用 Start-Transcript, Write-Verbose, Write-Debug, Write-Information 或自定义日志函数记录脚本操作和错误。

  7. 代码审查: 对重要脚本进行同行审查。


八、 调试技巧

  1. 集成脚本环境 (ISE) / VS Code:

    • 设置断点、单步执行、查看变量值、调用堆栈。
  2. 命令行调试:

    • Set-PSBreakpoint: 在行、变量、命令上设置断点。
    • Debug-Job: 调试后台作业。
    • -Debug 参数:进入调试模式。
  3. Write-Debug 语句: 在脚本中插入调试信息,仅当 $DebugPreference = 'Continue' 或运行脚本时使用 -Debug 参数时才显示。

  4. $PSBoundParameters / Get-Variable: 查看传入参数或变量值。

  5. Out-GridView / Export-Csv: 将复杂对象输出到可视化表格或文件查看。


九、 进阶主题概览

  1. 后台作业 (Start-Job, Get-Job, Receive-Job, Remove-Job, Wait-Job): 异步执行任务。

  2. 计划任务 (Register-ScheduledJob, Scheduled Tasks): 定时执行脚本。

  3. 远程处理 (Enter-PSSession, Invoke-Command): 在远程计算机上执行命令/脚本 (需启用 WinRM/SSH)。

  4. 工作流 (Workflow): 处理长时间运行、需持久化、可并行/序列化步骤的任务 (注意:PowerShell Workflow 在 7.x 中已弃用,考虑替代方案如 Azure 自动化)。

  5. 类 (class) (PowerShell 5.0+): 支持定义自定义类,面向对象编程。

  6. DSC (Desired State Configuration): 声明式配置管理框架 (虽然核心发展转向云原生方案,但概念仍有价值)。

  7. PowerShell Core (v6+): 跨平台 (Windows, Linux, macOS),基于 .NET Core,是未来发展方向。


十、 学习资源

  1. 官方文档: Microsoft Docs - PowerShell (https://learn.microsoft.com/en-us/powershell/) 是最权威、最全面的资源。

  2. 书籍:

    • "Learn Windows PowerShell in a Month of Lunches" (经典入门)
    • "Windows PowerShell Cookbook" (实用技巧手册)
    • "PowerShell in Depth" (深入详解)
  3. 社区:

  4. 博客: PowerShell Team Blog, 4sysops, Adam the Automator 等。

总结: PowerShell 脚本是强大的自动化工具。掌握其面向对象、管道、函数、错误处理、模块化和安全核心概念,结合实践和社区资源,能显著提升 IT 运维、DevOps 和开发效率。从基础命令开始,逐步构建复杂脚本和模块,是有效的学习路径。始终将安全性和健壮性放在首位。

posted @ 2025-06-29 19:38  kyle_7Qc  阅读(156)  评论(0)    收藏  举报