跳到主要内容

函数

函数是可重用代码块的基本单元。PowerShell 函数支持参数定义、参数验证、管道输入等特性,是模块化编程的基础。

基本函数定义

使用 function 关键字定义函数:

function SayHello {
Write-Host "Hello, PowerShell!"
}

SayHello

带参数的函数:

function Greet {
param(
[string]$Name
)
Write-Host "Hello, $Name!"
}

Greet -Name "张三"

参数定义

基本参数

使用 param() 块定义参数:

function Add {
param(
[int]$a,
[int]$b
)
return $a + $b
}

Add -a 5 -b 3

默认参数值

function Greet {
param(
[string]$Name = "World"
)
Write-Host "Hello, $Name!"
}

Greet
Greet -Name "PowerShell"

位置参数

参数可以按位置传递:

function Add {
param(
[Parameter(Position=0)]
[int]$a,

[Parameter(Position=1)]
[int]$b
)
return $a + $b
}

Add 5 3

强制参数

使用 Mandatory 标记必填参数:

function Get-UserInfo {
param(
[Parameter(Mandatory=$true)]
[string]$Username,

[Parameter(Mandatory=$false)]
[int]$Age
)
Write-Host "用户: $Username, 年龄: $Age"
}

Get-UserInfo -Username "张三"

参数别名

为参数定义别名:

function Get-FileContent {
param(
[Parameter(Mandatory=$true)]
[Alias("Path", "File")]
[string]$FilePath
)
Get-Content $FilePath
}

Get-FileContent -Path "C:\test.txt"
Get-FileContent -File "C:\test.txt"

参数验证

PowerShell 提供多种参数验证属性:

ValidateSet:限制参数值为指定集合:

function Set-LogLevel {
param(
[ValidateSet("Debug", "Info", "Warning", "Error")]
[string]$Level
)
Write-Host "日志级别设置为: $Level"
}

Set-LogLevel -Level "Info"
Set-LogLevel -Level "Critical"

ValidateRange:限制数值范围:

function Set-Port {
param(
[ValidateRange(1, 65535)]
[int]$Port
)
Write-Host "端口: $Port"
}

Set-Port -Port 8080
Set-Port -Port 70000

ValidateLength:限制字符串长度:

function Set-Username {
param(
[ValidateLength(3, 20)]
[string]$Username
)
Write-Host "用户名: $Username"
}

ValidatePattern:正则表达式验证:

function Set-Email {
param(
[ValidatePattern("^\w+@\w+\.\w+$")]
[string]$Email
)
Write-Host "邮箱: $Email"
}

ValidateNotNullOrEmpty:不允许空值或空字符串:

function Process-Data {
param(
[ValidateNotNullOrEmpty()]
[string]$Data
)
Write-Host "处理数据: $Data"
}

ValidateScript:自定义验证脚本:

function Test-Path {
param(
[ValidateScript({
if (Test-Path $_) { $true }
else { throw "路径不存在: $_" }
})]
[string]$Path
)
Write-Host "有效路径: $Path"
}

返回值

return 语句

return 返回值并退出函数:

function Add {
param($a, $b)
return $a + $b
}

$result = Add 5 3
Write-Host $result

多返回值

函数可以返回多个值,实际返回的是数组:

function Get-MinMax {
param([int[]]$Numbers)

$min = $Numbers | Measure-Object -Minimum | Select-Object -ExpandProperty Minimum
$max = $Numbers | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum

return $min, $max
}

$result = Get-MinMax -Numbers 3, 1, 4, 1, 5, 9, 2, 6
Write-Host "最小值: $($result[0]), 最大值: $($result[1])"

输出到管道

函数中任何未捕获的输出都会进入管道:

function Get-Numbers {
1
2
3
}

Get-Numbers | ForEach-Object { $_ * 2 }

使用 Write-Output 显式输出:

function Get-Greeting {
Write-Output "Hello"
Write-Output "World"
}

禁止输出

使用 [void]Out-Null 丢弃输出:

function Test-Function {
[void](Get-Process)
Get-Process | Out-Null
return "完成"
}

管道函数

管道输入

函数可以接收管道输入,使用 ValueFromPipeline 参数:

function Get-Doubled {
param(
[Parameter(ValueFromPipeline=$true)]
[int]$Number
)

process {
return $Number * 2
}
}

1..5 | Get-Doubled

begin、process、end 块

管道函数支持三个块:

function Measure-Text {
param(
[Parameter(ValueFromPipeline=$true)]
[string]$Text
)

begin {
$totalLength = 0
$count = 0
Write-Host "开始统计..."
}

process {
$totalLength += $Text.Length
$count++
Write-Host "处理: '$Text' (长度: $($Text.Length))"
}

end {
Write-Host "-------------------"
Write-Host "总条目: $count"
Write-Host "总长度: $totalLength"
Write-Host "平均长度: $([math]::Round($totalLength / $count, 2))"
}
}

"Hello", "PowerShell", "World" | Measure-Text

begin 块:管道开始前执行一次,用于初始化。

process 块:每个管道对象执行一次。

end 块:管道结束后执行一次,用于汇总。

管道输入属性名

从管道对象的属性获取值:

function Format-ProcessInfo {
param(
[Parameter(ValueFromPipelineByPropertyName=$true)]
[string]$Name,

[Parameter(ValueFromPipelineByPropertyName=$true)]
[int]$Id
)

process {
Write-Host "进程: $Name (PID: $Id)"
}
}

Get-Process | Select-Object -First 5 | Format-ProcessInfo

高级函数

CmdletBinding 属性

添加 [CmdletBinding()] 使函数支持通用参数:

function Get-Data {
[CmdletBinding()]
param(
[string]$Name
)

Write-Verbose "正在获取 $Name 的数据..."
Write-Debug "调试信息"
return "数据: $Name"
}

Get-Data -Name "test" -Verbose
Get-Data -Name "test" -Debug

通用参数包括:

  • -Verbose:显示详细信息
  • -Debug:显示调试信息
  • -ErrorAction:错误处理方式
  • -WarningAction:警告处理方式
  • -ErrorVariable:存储错误的变量
  • -OutVariable:存储输出的变量

SupportsShouldProcess

支持 -WhatIf-Confirm 参数:

function Remove-OldFiles {
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[string]$Path,
[int]$Days = 30
)

$cutoffDate = (Get-Date).AddDays(-$Days)
$files = Get-ChildItem $Path | Where-Object { $_.LastWriteTime -lt $cutoffDate }

foreach ($file in $files) {
if ($PSCmdlet.ShouldProcess($file.FullName, "删除文件")) {
Remove-Item $file.FullName -Force
Write-Host "已删除: $($file.FullName)"
}
}
}

Remove-OldFiles -Path "C:\Temp" -Days 7 -WhatIf
Remove-OldFiles -Path "C:\Temp" -Days 7 -Confirm

输出类型声明

使用 [OutputType()] 声明函数返回类型:

function Get-ServerInfo {
[OutputType([hashtable])]
[CmdletBinding()]
param(
[string]$ComputerName = $env:COMPUTERNAME
)

return @{
ComputerName = $ComputerName
OS = (Get-CimInstance Win32_OperatingSystem).Caption
CPU = (Get-CimInstance Win32_Processor).Name
Memory = [math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory / 1GB, 2)
}
}

函数作用域

局部变量

函数内定义的变量默认是局部的:

$x = 10

function Test-Scope {
$x = 20
Write-Host "函数内 x = $x"
}

Test-Scope
Write-Host "函数外 x = $x"

输出:

函数内 x = 20
函数外 x = 10

访问外部变量

使用 $script:$global: 访问外部变量:

$counter = 0

function Increment-Counter {
$script:counter++
Write-Host "计数器: $counter"
}

Increment-Counter
Increment-Counter
Increment-Counter

作用域修饰符

修饰符说明
$global:全局作用域
$script:脚本作用域
$local:当前作用域
$private:私有作用域

实用示例

日志函数

function Write-Log {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Message,

[ValidateSet("Info", "Warning", "Error")]
[string]$Level = "Info",

[string]$LogFile = "C:\Logs\app.log"
)

$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logEntry = "[$timestamp] [$Level] $Message"

switch ($Level) {
"Info" { Write-Host $logEntry -ForegroundColor Green }
"Warning" { Write-Host $logEntry -ForegroundColor Yellow }
"Error" { Write-Host $logEntry -ForegroundColor Red }
}

if (Test-Path (Split-Path $LogFile)) {
Add-Content -Path $LogFile -Value $logEntry
}
}

Write-Log -Message "服务启动成功" -Level "Info"
Write-Log -Message "磁盘空间不足" -Level "Warning"
Write-Log -Message "连接数据库失败" -Level "Error"

批量操作函数

function Invoke-BatchOperation {
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[string[]]$ComputerName,

[Parameter(Mandatory=$true)]
[scriptblock]$ScriptBlock,

[pscredential]$Credential
)

begin {
$results = @()
Write-Host "开始批量操作..."
}

process {
foreach ($computer in $ComputerName) {
if ($PSCmdlet.ShouldProcess($computer, "执行操作")) {
try {
$params = @{
ComputerName = $computer
ScriptBlock = $ScriptBlock
ErrorAction = "Stop"
}
if ($Credential) {
$params.Credential = $Credential
}

$result = Invoke-Command @params
$results += [PSCustomObject]@{
Computer = $computer
Status = "Success"
Result = $result
}
}
catch {
$results += [PSCustomObject]@{
Computer = $computer
Status = "Failed"
Result = $_.Exception.Message
}
}
}
}
}

end {
Write-Host "操作完成"
return $results
}
}

下一步

掌握了函数后,接下来学习 管道与对象,深入理解 PowerShell 的核心特性。