当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 管道就绪:高级 PowerShell 功能

作者:精品下载站 日期:2024-12-14 05:33:05 浏览:12 分类:玩电脑

管道就绪:高级 PowerShell 功能


[玩转系统] 管道就绪:高级 PowerShell 功能

使用 PowerShell 管道非常高效,您想了解有关管道的更多信息吗?在这篇博文中,菲利普·洛伦茨 (Philip Lorenz) 深入探讨了这个主题。

介绍

管道是 PowerShell 中的一个核心概念,它允许将一个函数或 cmdlet 的输出作为输入传递给另一个函数或 cmdlet。通过允许将单独的、明确定义的任务链接在一起,创建了一种灵活且高效的数据处理方法。 “一次一个”原则使得以资源高效的方式处理大量数据成为可能。在“高效使用 PowerShell 管道:管理员指南”一文中,我已经向您展示了如何使用管道来链接现有 cmdlet。在这篇博文中,我将向您展示如何使您自己的函数做好管道准备!

将管道支持集成到您自己的函数中不仅是良好的实践,而且还扩展了代码的功能和可重用性。在您自己的函数中提供管道支持需要了解管道机制以及适当参数和处理技术的应用。在本文中,我们将从基本功能到高级功能解释这些概念,并说明如何最大限度地提高脚本中的管道效率。

管道支持基础知识

要有效地使用 PowerShell 中的管道,了解一些基础知识非常重要。这里的两个关键元素是过滤关键字和特殊变量$_。在创建提供管道支持的简单函数时,它们发挥着至关重要的作用。

PowerShell 中的filter 关键字可以创建一种专门用于处理管道输入的函数。过滤器从管道获取输入,对其进行处理并将某些内容返回到管道。 $_ 变量表示管道中正在处理的当前对象。这是一个简单的函数,展示了如何使用过滤器关键字和 $_ 变量:

Filter Convert-ToUpperCase {
 Write-Output "Input in uppercase: $($_.ToUpper())"
}

在此示例中,我们创建了一个名为 Convert-ToUpperCase 的过滤器。此过滤器从管道中获取文本条目,对于每个条目,调用 ToUpper 方法将文本转换为大写。还有一个直接输出到控制台。如果您在管道中使用此过滤器,每个文本条目都会单独处理并以大写字母转发到输出:

"hello", "world" | Convert-ToUpperCase

输出将是:

Input in uppercase: HELLO
Input in uppercase: WORLD

使用过滤器和 $_ 是将管道支持集成到函数中的简单而有效的方法。它提供了一种清晰且易于理解的方式,从管道中获取对象、处理它们并传递它们,这构成了更复杂的函数和管道操作的基础。

在下一节中,我们将了解命名参数并创建一个超出简单函数范围的高级函数,并提供更多与管道交互的方法。

具有命名参数的高级函数

虽然简单的函数和过滤器足以完成许多任务,但 PowerShell 中的高级函数可以提供更好的控制和灵活性,特别是在使用管道时。此高级功能的关键之一是命名参数

命名参数

命名参数使我们能够以结构化且易于理解的方式控制数据输入。您不仅可以指定输入参数的类型,还可以定义默认值并添加验证。

以下是带有命名参数的高级函数的示例:

function Get-ModifiedFiles {
  param (
    [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
    [string]$Path,
   
    [datetime]$Since
  )
 
  process {
    $files = Get-ChildItem -Path 
    $Path -Recurse | 
    Where-Object { $_.LastWriteTime -gt $Since }
    $files
  }
}

在此Get-ModifiedFiles函数中,我们定义了两个命名参数$Path$Since。参数$Path是强制性的,接受来自管道的输入,而$Since是可选的。在流程块中,我们使用Get-ChildItem获取指定路径下的所有文件,并使用Where-Object过滤指定日期之后修改的文件。

这是一个示例调用:

"./" | Get-ModifiedFiles -Since (Get-Date).AddDays(-7)

输出 :

[玩转系统] 管道就绪:高级 PowerShell 功能

在此调用中,当前目录作为简单字符串传递给 Get-ModifiedFiles 函数,并返回过去 7 天内修改过的所有文件。

命名参数提供了一种清晰明确的方法来控制函数输入,并允许对函数内的数据处理进行更精细的控制。

在下一章中,我们将研究具有 BeginProcessEndClean 块的结构化函数。

使用 BeginProcessEndClean 块构建函数

使用 PowerShell 7.3 中的 Begin、Process、End 块和新引入的 Clean 块构建函数,为处理管道数据和清理资源提供了强大的方法。这些块使得可以将代码划分为逻辑段,这些逻辑段在函数执行期间的不同时间被调用。

  • Begin 块在函数开始时执行一次,适合初始化操作。
  • Process 块针对通过管道传递的每个对象执行,是数据处理的主要位置。
  • End 块在所有管道对象处理完毕后执行一次,适合最终操作。

PowerShell 7.3 中引入的Clean 块提供了一种清理跨Begin、ProcessEnd 块的资源的方法。从语义上讲,它类似于 Finally 块,并涵盖函数的所有其他命名块。在各种情况下都会强制执行资源清理,例如管道执行正常完成、因终止错误而中断、被 Select-Object -First 停止或被 CTRL+C 或 StopProcessing 终止时()

这是一个演示所有块的使用的示例:

function Get-Size {
 param (
   [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
   [string]$Path
 )

 begin {
   # Initializing variables
   $totalSize = 0
   $tempDirectory = "./tmp"

   # Initialization: Creating temporary directory
   if (-not (Test-Path $tempDirectory)) {
     New-Item -Path $tempDirectory -ItemType Directory | Out-Null
   }
 }

 process {
   # Checking if the path exists and is a file
   if (Test-Path $Path -PathType Leaf) {
     $fileInfo = Get-Item $Path     $fileSize = $fileInfo.Length
     $totalSize += $fileSize

     # Writing file information to a temporary file
     $outputPath = Join-Path $tempDirectory ($fileInfo.Name + ".txt")
     $fileInfo | Out-File $outputPath
   }
 }
 end {
   # Outputting the total size of all processed files
   Write-Output "Total size of all processed files: $($totalSize / 1MB) MB"
 }

 clean {
   # Deleting temporary directory
   Remove-Item $tempDirectory -Recurse -Force
 }
}
  • Begin 创建一个在处理过程中使用的临时目录。
  • Process 块检查传递的路径是否是文件,收集有关文件的信息,更新总大小并将文件信息存储在临时文件中。
  • Der End 块输出所有已处理文件的总大小。
  • Der Clean 块会在处理完成后删除临时目录,以确保不会留下不需要的数据。

执行以下代码:

$files = @()
$files += "/Users/philip/Code/blog-post-code-examples/blog.docx"
$files += "/Users/philip/Code/blog-post-code-examples/image.dmg"
$files | Get-Size

并得到以下输出:

Total size of all processed files: 615.562695503235 MB

通过使用Begin、Process、EndClean块,该函数被结构化并且能够实现高效的处理和清理。

在自己的函数中实现ByPropertyName

到目前为止,我们已经处理了将值ByValue传递给函数。不过,PowerShell 还提供了传递 ByPropertyName 值的选项。这使得与功能的交互更加灵活和直观。

按属性名称与按值

  • ByValue:在这里,参数的值直接传递给函数的相应参数。这很简单,但在参数关系不清楚的情况下可能会导致混乱。
  • ByPropertyName:使用此方法,根据参数名称传递参数值。如果该函数具有许多参数,或者如果该函数在管道中使用,其中前一个 cmdlet 的输出用作下一个 cmdlet 的输入,则这会特别有用。

下面是一个演示 ByPropertyName 实现的示例:

function Get-FileDetail {
  param (
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]$FullName
  )
 
  process {
    $fileInfo = Get-Item $FullName
    $fileDetail = @{
      Name = $fileInfo.Name
      Size = $fileInfo.Length
      LastModified = $fileInfo.LastWriteTime
    }
    $fileDetail
  }
}

Get-ChildItem -Path "./" | Get-FileDetail

控制台显示如下:

[玩转系统] 管道就绪:高级 PowerShell 功能

Get-FileDetail函数中,我们定义了参数$FullName和属性ValueFromPipelineByPropertyName=$true。这允许函数接受来自管道的基于 $FullName 参数名称分配的值。在示例调用中,Get-ChildItem 的输出被转发到 Get-FileDetail,其中输出对象的 FullName 属性 > Get-ChildItem 映射到 Get-FileDetail$FileName 参数。

通过使用ByPropertyName,可以在管道中更直观、更灵活地使用函数,并且为函数分配输入值变得更加透明。

在下一段中,我们将了解 $Input 自动变量,它提供了另一种处理管道输入的方法,特别是当输入被视为一个块而不是单个项目时。

$Input自动变量

虽然许多 PowerShell 开发人员熟悉 $_ pipeline 变量,但 $Input 不太为人所知,但在某些情况下提供了有价值的功能。

$Input 变量允许将整个管道输入视为枚举器。这意味着您可以访问整个输入,而不是依次处理管道的每个元素。这在您想要将输入视为块的情况下非常有用,例如对数据进行排序或分组时。

需要注意的是,$Input是一个枚举器,不能直接用作数组。要将$Input用作实际数组,可以将其包含在@()中。

这是一个简单的例子:

function Sort-InputData {
  process {
    $dataArray = @($Input)
    $sortedData = $dataArray | Sort-Object
    $sortedData
  }
}

# Beispielaufruf
1, 5, 3, 4, 2 | Sort-InputData

在此 Soft-InputData 函数中,我们首先将所有管道输入收集到数组 $dataArray 中,然后对这些数据进行排序。结果是一个排序的数字列表。

何时使用$Input

当您想要对整个管道输入执行多个操作而不单独处理每个值时,使用 $Input 特别有用。但是,了解 $Input$_ 之间的区别并为场景选择正确的变量非常重要。

结论

PowerShell管道无疑是PowerShell最重要的功能之一。它们能够在不同的 cmdlet 和函数之间高效、无缝地传输数据,这使它们有别于其他脚本语言。对于任何希望自动化复杂任务和优化工作流程的 IT 专业人员来说,它们是不可或缺的工具。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯