简短说明
包含管道对象中的当前对象的自动变量。
详细说明
PowerShell 包括 $PSItem 变量及其别名 $_,如处理当前对象的脚本块(如管道)中的自动变量。 本文在示例中使用 $PSItem,但每个示例中都可以将 $PSItem 替换为 $_。
可以在对管道中每个对象执行操作的命令中使用此变量。
              $PSItem 有几个常见用例:
- 在 cmdlet 的 ForEach-Object参数的脚本块中
- 在 cmdlet 的 Where-Object参数的脚本块中
- 在内在方法 ForEach 和 Where 中
- 带有延迟绑定脚本块参数
- 在 switch语句的条件值和关联的脚本块中
- 在函数的 process块中
- 在 filter定义中
- 在 ValidateScript 属性的脚本块中
- 在 catch语句的脚本块中
- 在 -replace运算符的替换操作数脚本块中
本文的其余部分包括对这些用例使用 $PSItem 的示例。
ForEach-Object 进程
ForEach-Object cmdlet 旨在对管道中的对象进行操作,对管道中的每个对象执行一次 Process 参数的脚本块。
可以在 $PSItem 参数的脚本块中使用  ,但不能在 Begin 或 End 参数脚本块中使用。 如果在 $PSItem 或 End 参数脚本块中引用  ,则值为 $null,因为这些脚本块不会对管道中的每个对象进行操作。
$parameters = @{
    Begin   = { Write-Host "PSItem in Begin is: $PSItem" }
    Process = {
        Write-Host "PSItem in Process is: $PSItem"
        $PSItem + 1
    }
    End     = { Write-Host "PSItem in End is: $PSItem" }
}
$result = 1, 2, 3 | ForEach-Object @parameters
Write-Host "Result is: $result"
PSItem in Begin is:
PSItem in Process is: 1
PSItem in Process is: 2
PSItem in Process is: 3
PSItem in End is:
Result is: 2 3 4
Where-Object FilterScript
Where-Object cmdlet 旨在筛选管道中的对象。
可以在 $PSItem 参数的脚本块中使用  ,以对管道中的每个输入对象执行一次。
1, 2, 3 | Where-Object -FilterScript { ($PSItem % 2) -eq 0 }
2
在此示例中,FilterScript 检查当前对象是否为偶数,筛选掉任何奇数值,并且仅从原始列表中返回 2。
ForEach 和 Where 方法
数组的 ForEach 和 Where 内在方法采用脚本块作为输入参数。 可以在这些脚本块中使用 $PSItem 访问当前对象。
@('a', 'b', 'c').ForEach({ $PSItem.ToUpper() }).Where({ $PSItem -ceq 'B' })
B
在此示例中,ForEach 方法的脚本块将当前对象大写。 然后,Where 方法的脚本块仅返回 B。
Delay-bind ScriptBlock 参数
              延迟绑定脚本块可让你使用 $PSItem 定义管道 cmdlet 的参数后再执行它。
dir config.log | Rename-Item -NewName { "old_$($_.Name)" }
Switch 语句 ScriptBlocks
在 switch 语句中,可以在操作脚本块和语句条件脚本块中使用 $PSItem。
$numbers = 1, 2, 3
switch ($numbers) {
    { ($PSItem % 2) -eq 0 } { "$PSItem is even" }
    default { "$PSItem is odd" }
}
1 is odd
2 is even
3 is odd
在此示例中,语句条件脚本块检查当前对象是否为偶数。 即使如此,关联的操作脚本块也会输出一条消息,指示当前对象为偶数。
              default 条件的操作脚本块输出一条消息,指示当前对象为奇数。
函数进程块
定义函数时,可以在 $PSItem 块定义中使用 process,但不能在 begin 或 end 块定义中使用。 如果在 $PSItem 或 begin 块中引用 end,则值为 $null,因为这些块不会对管道中的每个对象进行操作。
在 $PSItem 块定义中使用 process 时,如果管道中调用函数,则值为当前对象,否则为 $null。
function Add-One {
    process { $PSItem + 1 }
}
1, 2, 3 | Add-One
2
3
4
对高级函数使用 Parameter 属性和 cmdlet 绑定使实现比处理当前对象以获取所需值更明确,也更可预测。
高级函数中 $PSItem 的一个很好用法是,当函数具有从管道获取输入的多个参数时,检查当前对象本身进行调试或日志记录。
function Write-JsonLog {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]$Message
    )
    begin {
        $entries = @()
    }
    process {
        $entries += [pscustomobject]@{
            Message   = $Message
            TimeStamp = [datetime]::Now
        }
        if ($PSItem) {
            $props  = $PSItem | ConvertTo-Json
            $number = $entries.Length
            Write-Verbose "Input object $number is:`n$props"
        }
    }
    end {
        ConvertTo-Json -InputObject $entries
    }
}
此示例函数输出包含消息和时间戳的 JSON 对象的数组。 在管道中调用时,它将对每个条目使用当前对象的 Message 属性。 它还将当前对象的 JSON 表示形式写入冗长数据流,因此可以看到与输出日志相比的实际输入。
$Items = @(
    [pscustomobject]@{
        Name    = 'First Item'
        Message = 'A simple note'
    }
    [pscustomobject]@{
        Name    = 'Item with extra properties'
        Message = 'Missing message, has info instead'
        Info    = 'Some metadata'
        Source  = 'Where this came from'
    }
    [pscustomobject]@{
        Name    = 'Last Item'
        Message = 'This also gets logged'
    }
)
$Items | Write-JsonLog -Verbose
VERBOSE: Input object 1 is:
{
    "Name":  "First Item",
    "Message":  "A simple note"
}
VERBOSE: Input object 2 is:
{
    "Name":  "Item with extra properties",
    "Message":  "Missing message, has info instead",
    "Info":  "Some metadata",
    "Source":  "Where this came from"
}
VERBOSE: Input object 3 is:
{
    "Name":  "Last Item",
    "Message":  "This also gets logged"
}
[
    {
        "Message":  "A simple note",
        "TimeStamp":  "\/Date(1670344068257)\/"
    },
    {
        "Message":  "Missing message, has info instead",
        "TimeStamp":  "\/Date(1670344068259)\/"
    },
    {
        "Message":  "This also gets logged",
        "TimeStamp":  "\/Date(1670344068261)\/"
    }
]
筛选器定义
在 $PSItem 定义中使用 filter 时,如果管道中调用筛选器,则该值为当前对象,否则为 $null。
filter Test-IsEven { ($PSItem % 2) -eq 0 }
1, 2, 3 | Test-IsEven
False
True
False
在此示例中,如果当前对象为偶数,则Test-IsEven筛选器输出$true;如果不是偶数,则 $false。
ValidateScript 属性 ScriptBlock
可以在 $PSItem 属性的脚本块中使用 。
与 ValidateScript一起使用时,$PSItem 是正在验证的当前对象的值。 当变量或参数值是数组时,将为数组中的每个对象调用一次脚本块,以 $PSItem 作为当前对象。
function Add-EvenNumber {
    param(
        [ValidateScript({ 0 -eq ($PSItem % 2) })]
        [int[]]$Number
    )
    begin {
        [int]$total = 0
    }
    process {
        foreach ($n in $Number) {
            $total += $n
        }
    }
    end {
        $total
    }
}
Add-EvenNumber -Number 2, 4, 6
Add-EvenNumber -Number 1, 2
12
Add-EvenNumber:
Line |
  24 |  Add-EvenNumber -Number 1, 2
     |                         ~~~~
     | Cannot validate argument on parameter 'Number'. The
" 0 -eq ($PSItem % 2) " validation script for the argument
with value "1" did not return a result of True. Determine
why the validation script failed, and then try the command
again.
在此示例中,ValidateScript 属性的脚本块针对传递给 Number 参数的每个值运行一次,如果没有任何值为偶数则返回错误。
              Add-EvenNumber 函数添加有效的输入数字并返回总计。
              catch语句 ScriptBlock
在 catch 块中,可以使用 $PSItem访问当前错误。 对象的类型 ErrorRecord。
try { NonsenseString }
catch {
    Write-Host "An error occurred:"
    Write-Host $_
}
运行此脚本将返回以下结果:
An Error occurred:
The term 'NonsenseString' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path
was included, verify that the path is correct and try again.
有关更多示例,请参阅 about_Try_Catch_Finally 中的访问异常信息部分。
              -replace运算符的替换 ScriptBlock
从 PowerShell 6 开始,调用 $PSItem 运算符并定义 替换脚本块时,可以使用 。 执行此操作时,$PSItem 的值是当前匹配的值。
$datePattern = '\d{4}-\d{2}-\d{2}'
'Today is 1999-12-31' -replace $datePattern, { [datetime]$PSItem.Value }
Today is 12/31/1999 00:00:00
在此示例中,替换脚本块通过将值强制转换为日期时间,以将原始日期字符串替换为当前区域的默认格式。