about_Functions

简短说明

介绍如何在 PowerShell 中创建和使用函数。

长说明

函数是具有你分配的名称的 PowerShell 语句的列表。 运行函数时,键入函数名称。 列表中的语句就像在命令提示符处键入它们一样运行。

函数可以简单如下:

function Get-PowerShellProcess { Get-Process PowerShell }

函数也可以像 cmdlet 或应用程序一样复杂。

与 cmdlet 一样,函数可以具有参数。 参数可以是命名参数、位置参数、开关参数或动态参数。 可以从命令行或管道读取函数参数。

函数可以返回可显示、分配给变量或传递给其他函数或 cmdlet 的值。 还可以使用 return 关键字 (keyword) 指定返回值。 关键字 (keyword) return 不会影响或禁止从函数返回的其他输出。 但是,return关键字 (keyword) 退出该行的函数。 有关详细信息,请参阅 about_Return

函数的语句列表可以包含不同类型的语句列表,关键字为 beginprocessendclean。 这些语句以不同的方式列出处理来自管道的输入。

筛选器关键字 (keyword) 用于创建在管道中的每个对象上运行的函数类型。 筛选器类似于一个函数,其所有语句都在 块 process 中。

函数也可以像 cmdlet 一样运行。 可以创建一个函数,该函数的工作方式与 cmdlet 类似,而无需使用 C# 编程。 有关详细信息,请参阅 about_Functions_Advanced

重要

在脚本文件和基于脚本的模块中,必须先定义函数,然后才能调用它们。

语法

下面是函数的语法:

function [<scope:>]<name> [([type]$parameter1[,[type]$parameter2])]
{
  begin {<statement list>}
  process {<statement list>}
  end {<statement list>}
  clean {<statement list>}
}
function [<scope:>]<name>
{
  param([type]$parameter1 [,[type]$parameter2])
  dynamicparam {<statement list>}
  begin {<statement list>}
  process {<statement list>}
  end {<statement list>}
  clean {<statement list>}
}

函数包括以下项:

  • 关键字 (keyword) function
  • 范围 (可选)
  • 你选择的名称
  • 任意数量的命名参数 (可选)
  • 括在大括号中的一个或多个 PowerShell 命令 {}

有关函数中的dynamicparam关键字 (keyword) 和动态参数的详细信息,请参阅 about_Functions_Advanced_Parameters

输入处理方法

本部分所述的方法称为输入处理方法。 对于函数,这三个方法由 函数的 beginprocessend 块表示。 PowerShell 7.3 添加了块 clean 进程方法。

无需在函数中使用任何这些块。 如果不使用命名块,则 PowerShell 会将代码放在函数的 块中 end 。 但是,如果使用这些命名块中的任何一个 dynamicparam ,或定义块,则必须将所有代码放在命名块中。

以下示例演示函数的轮廓,该函数包含一个 begin 用于一次性预处理的块、 process 用于处理多条记录的块和用于一次性后处理的 end 块。

Function Test-ScriptCmdlet
{
[CmdletBinding(SupportsShouldProcess=$True)]
    Param ($Parameter1)
    begin{}
    process{}
    end{}
}

begin

此块用于为函数提供可选的一次性预处理。 PowerShell 运行时对管道中函数的每个实例使用此块中的代码一次。

process

此块用于为 函数提供逐条记录处理。 可以使用 块 process ,而无需定义其他块。 块执行的次数 process 取决于函数的使用方式以及函数接收的输入。

自动变量 $_$PSItem 包含管道中的当前对象,以便在 块中使用 process 。 自动 $input 变量包含仅适用于函数和脚本块的枚举器。 有关详细信息,请参阅 about_Automatic_Variables

  • 在开头或管道外部调用 函数将执行块一 process 次。
  • 在管道中 process ,块对到达函数的每个输入对象执行一次。
  • 如果到达函数的管道输入为空,则process块不会执行。
    • beginendclean 块仍会执行。

重要

如果函数参数设置为接受管道输入,并且 process 未定义块,则逐条记录处理将失败。 在这种情况下,无论输入如何,函数都只会执行一次。

end

此块用于为 函数提供可选的一次性后处理。

clean

clean 已添加到 PowerShell 7.3 中。

clean 块是一种方便用户清理跨 beginprocessend 块的资源的方法。 它在语义上类似于 finally 块,该块涵盖脚本函数或脚本 cmdlet 的所有其他命名块。 对于以下场景,将强制执行资源清理:

  1. 管道执行正常完成,没有终止错误
  2. 管道执行因终止错误而中断
  3. 通过 Select-Object -First 停止管道
  4. 通过 Ctrl+cStopProcessing() 停止管道

注意

添加 clean 块属于一项中断性变更。 由于 clean 是作为关键字分析的,因此它可以阻止用户直接调用名为 clean 的命令作为脚本块中的第一个语句。 但是,这不太可能是个问题。 仍可使用调用运算符 (& clean) 调用命令。

简单函数

函数不必复杂就有用。 最简单的函数具有以下格式:

function <function-name> {statements}

例如,以下函数使用“ 以管理员身份运行” 选项启动 PowerShell。

function Start-PSAdmin {Start-Process PowerShell -Verb RunAs}

若要使用 函数,请键入: Start-PSAdmin

若要向函数添加语句,请在单独的行中键入每个语句,或使用分号 ; 分隔语句。

例如,以下函数查找当前用户目录中在开始日期后更改的所有 .jpg 文件。

function Get-NewPix
{
  $start = Get-Date -Month 1 -Day 1 -Year 2010
  $allpix = Get-ChildItem -Path $env:UserProfile\*.jpg -Recurse
  $allpix | Where-Object {$_.LastWriteTime -gt $Start}
}

可以创建一个包含有用小型函数的工具箱。 如本主题 about_Profiles 及更高版本中所述,将这些函数添加到 PowerShell 配置文件。

函数名称

可以将任何名称分配给函数,但与其他人共享的函数应遵循已为所有 PowerShell 命令建立的命名规则。

函数名称应包含谓词-名词对,其中谓词标识函数执行的操作,名词标识 cmdlet 对其执行操作的项。

函数应使用已批准用于所有 PowerShell 命令的标准谓词。 这些谓词可帮助我们保持命令名称的一致且便于用户理解。

有关标准 PowerShell 谓词的详细信息,请参阅 批准的谓词

带参数的函数

可以将参数与函数一起使用,包括命名参数、位置参数、开关参数和动态参数。 有关函数中的动态参数的详细信息,请参阅 about_Functions_Advanced_Parameters

命名的参数

可以定义任意数量的命名参数。 可以包括命名参数的默认值,如本主题后面部分所述。

可以使用 关键字 (keyword) 在大括号param内定义参数,如以下示例语法所示:

function <name> {
  param ([type]$parameter1 [,[type]$parameter2])
  <statement list>
}

还可以在大括号外定义参数,而不Param关键字 (keyword) ,如以下示例语法所示:

function <name> [([type]$parameter1[,[type]$parameter2])] {
  <statement list>
}

下面是此替代语法的示例。

function Add-Numbers([int]$one, [int]$two) {
    $one + $two
}

虽然第一种方法是首选方法,但这两种方法之间没有区别。

运行函数时,为参数提供的值将分配给包含参数名称的变量。 该变量的值可以在 函数中使用。

以下示例是一个名为 的 Get-SmallFiles函数。 此函数具有 $Size 参数。 函数显示小于 参数值 $Size 的所有文件,并排除目录:

function Get-SmallFiles {
  Param($Size)
  Get-ChildItem $HOME | Where-Object {
    $_.Length -lt $Size -and !$_.PSIsContainer
  }
}

在 函数中,可以使用 $Size 变量,它是为 参数定义的名称。

若要使用此函数,请键入以下命令:

Get-SmallFiles -Size 50

还可以为不带参数名称的命名参数输入值。 例如,以下命令提供与命名 Size 参数的命令相同的结果:

Get-SmallFiles 50

若要定义参数的默认值,请在参数名称后面键入等号和值,如示例的以下变体 Get-SmallFiles 所示:

function Get-SmallFiles ($Size = 100) {
  Get-ChildItem $HOME | Where-Object {
    $_.Length -lt $Size -and !$_.PSIsContainer
  }
}

如果在键入 Get-SmallFiles 时没有值,则函数会将 100 分配给 $size。 如果提供值,则函数将使用该值。

(可选)你可以提供描述参数默认值的简短帮助字符串,方法是将 PSDefaultValue 属性添加到参数的说明中,并指定 PSDefaultValueHelp 属性。 若要提供描述函数中 Get-SmallFilesSize 参数的默认值 (100) 的帮助字符串,请添加 PSDefaultValue 属性,如以下示例所示。

function Get-SmallFiles {
  param (
      [PSDefaultValue(Help = '100')]
      $Size = 100
  )
}

有关 PSDefaultValue 属性类的详细信息,请参阅 PSDefaultValue 特性成员

位置参数

位置参数是没有参数名称的参数。 PowerShell 使用参数值顺序将每个参数值与函数中的参数相关联。

使用位置参数时,请在函数名称后面键入一个或多个值。 位置参数值分配给 $args 数组变量。 函数名称后面的值分配给数组$args[0]中的$args第一个位置 。

以下 Get-Extension 函数将 .txt 文件扩展名添加到你提供的文件名中:

function Get-Extension {
  $name = $args[0] + ".txt"
  $name
}
Get-Extension myTextFile
myTextFile.txt

开关参数

开关是不需要值的参数。 请改为键入函数名称,后跟 switch 参数的名称。

若要定义 switch 参数,请在参数名称之前指定类型 [switch] ,如以下示例所示:

function Switch-Item {
  param ([switch]$on)
  if ($on) { "Switch on" }
  else { "Switch off" }
}

在函数名称后键入 On switch 参数时,函数将显示 Switch on。 如果不使用 switch 参数,则显示 Switch off

Switch-Item -on
Switch on
Switch-Item
Switch off

运行函数时,还可以将 布尔 值分配给开关,如以下示例所示:

Switch-Item -on:$true
Switch on
Switch-Item -on:$false
Switch off

使用 Splatting 表示命令参数

可以使用 splatting 来表示命令的参数。 此功能在 Windows PowerShell 3.0 中引入。

在调用会话中的命令的函数中使用此技术。 无需声明或枚举命令参数,也不需要在命令参数更改时更改函数。

下面的示例函数调用 Get-Command cmdlet。 命令使用 @Args 来表示 的参数 Get-Command

function Get-MyCommand { Get-Command @Args }

调用 Get-MyCommand 函数时,可以使用 的所有参数Get-Command。 参数和参数值使用 @Args传递给命令。

Get-MyCommand -Name Get-ChildItem
CommandType     Name                ModuleName
-----------     ----                ----------
Cmdlet          Get-ChildItem       Microsoft.PowerShell.Management

该功能 @Args 使用 $Args 自动参数,该参数表示未声明的 cmdlet 参数和来自其余参数的值。

有关详细信息,请参阅 about_Splatting

将对象管道连接到函数

任何函数都可以从管道获取输入。 可以使用 、processendclean 关键字控制函数处理来自管道begin的输入的方式。 以下示例语法显示了这些关键字:

语句 process 列表针对管道中的每个对象运行一次。 process块运行时,每个管道对象都分配给$_自动变量,一次一个管道对象。

以下函数使用 process 关键字 (keyword) 。 函数显示管道中的值:

function Get-Pipeline
{
  process {"The value is: $_"}
}

1,2,4 | Get-Pipeline
The value is: 1
The value is: 2
The value is: 4

如果需要一个可以接受管道输入或参数输入的函数,则 process 块需要处理这两种情况。 例如:

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

    begin { $retValue = 0 }

    process {
        if ($null -ne $Numbers) {
           foreach ($n in $Numbers) {
               $retValue += $n
           }
        } else {
           $retValue += $_
        }
    }

    end { $retValue }
}

PS> 1,2,3,4 | Get-SumOfNumbers
10
PS> Get-SumOfNumbers 1,2,3,4
10

在管道中使用函数时,通过管道传递给函数的对象将 $input 分配给自动变量。 函数在任何对象来自管道之前,使用 关键字 (keyword) 运行语句begin。 从管道接收所有对象后,end函数使用 关键字 (keyword) 运行语句。

以下示例显示了具有 beginend 关键字的$input自动变量。

function Get-PipelineBeginEnd {
    begin   { "Begin: The input is $input" }
    end     { "End:   The input is $input" }
}

如果此函数是使用管道运行的,则它将显示以下结果:

1,2,4 | Get-PipelineBeginEnd
Begin: The input is
End:   The input is 1 2 4

begin当 语句运行时,函数没有来自管道的输入。 语句 end 在函数具有 值后运行。

如果该函数具有process关键字 (keyword) ,则 中的$input每个对象都会从 $input 中删除并分配给 $_。 以下示例包含语句 process 列表:

function Get-PipelineInput
{
    process {"Processing:  $_ " }
    end     {"End:   The input is: $input" }
}

在此示例中,通过管道传递给函数的每个对象都发送到 process 语句列表。 语句 process 在每个对象上运行,一次一个对象。 当$input函数到达关键字 (keyword) 时,end自动变量为空。

1,2,4 | Get-PipelineInput
Processing:  1
Processing:  2
Processing:  4
End:   The input is:

有关详细信息,请参阅 使用枚举器

PowerShell 7.3 添加了 clean 块。 clean 块是一种方便用户清理 beginprocessend 块中创建和使用的资源的方法。 它在语义上类似于 finally 块,该块涵盖脚本函数或脚本 cmdlet 的所有其他命名块。 对于以下场景,将强制执行资源清理:

  1. 管道执行正常完成,没有终止错误
  2. 管道执行因终止错误而中断
  3. 通过 Select-Object -First 停止管道
  4. 当管道被 Ctrl+C 停止时或 StopProcessing()

注意

添加 clean 块属于一项中断性变更。 由于 clean 是作为关键字分析的,因此它可以阻止用户直接调用名为 clean 的命令作为脚本块中的第一个语句。 但是,这不太可能是个问题。 仍可使用调用运算符 (& clean) 调用命令。

筛选器

筛选器是在管道中的每个对象上运行的函数类型。 筛选器类似于一个函数,其所有语句都在 块 process 中。

筛选器的语法如下所示:

filter [<scope:>]<name> {<statement list>}

以下筛选器从管道中获取日志条目,然后显示整个条目或仅显示条目的消息部分:

filter Get-ErrorLog ([switch]$Message)
{
  if ($Message) { Out-Host -InputObject $_.Message }
  else { $_ }
}

使用方法如下所示:

Get-WinEvent -LogName System -MaxEvents 100 | Get-ErrorLog -Message

函数范围

函数存在于创建该函数的范围中。

如果函数是脚本的一部分,该函数可用于该脚本中的 语句。 默认情况下,脚本中的函数在该脚本之外不可用。

可以指定函数的范围。 例如, 函数添加到以下示例中的全局范围:

function global:Get-DependentSvs {
  Get-Service | Where-Object {$_.DependentServices}
}

当函数在全局范围内时,可以在脚本、函数和命令行中使用该函数。

函数创建新的范围。 在函数中创建的项(如变量)仅存在于函数范围内。

有关详细信息,请参阅 about_Scopes

使用函数:驱动器查找和管理函数

PowerShell 中的所有函数和筛选器都自动存储在驱动器中 Function: 。 此驱动器由 PowerShell 函数 提供程序公开。

引用 Function: 驱动器时,在 Function 后面键入冒号,就像引用 C 计算机的 或 D 驱动器一样。

以下命令显示 PowerShell 当前会话中的所有函数:

Get-ChildItem function:

函数中的命令作为脚本块存储在函数的定义属性中。 例如,若要在 PowerShell 附带的帮助函数中显示命令,请键入:

(Get-ChildItem function:help).Definition

还可以使用以下语法。

$function:help

有关驱动器的详细信息 Function: ,请参阅 函数 提供程序的帮助主题。 键入 Get-Help Function

在新会话中重用函数

在 PowerShell 命令提示符下键入函数时,该函数将成为当前会话的一部分。 该函数在会话结束之前可用。

若要在所有 PowerShell 会话中使用函数,请将函数添加到 PowerShell 配置文件。 有关配置文件的详细信息,请参阅 about_Profiles

还可以将函数保存在 PowerShell 脚本文件中。 在文本文件中键入函数,然后使用文件扩展名保存该文件 .ps1

编写函数帮助

cmdlet Get-Help 获取函数以及 cmdlet、提供程序和脚本的帮助。 若要获取函数的帮助,请键入 Get-Help 后跟函数名称。

例如,若要获取函数的 Get-MyDisks 帮助,请键入:

Get-Help Get-MyDisks

可以使用以下两种方法之一为函数编写帮助:

  • 函数 Comment-Based 帮助

    在注释中使用特殊关键字Create帮助主题。 若要为函数创建基于注释的帮助,必须将注释放置在函数主体的开头或末尾,或者放置在函数关键字 (keyword) 前面的行上。 有关基于注释的帮助的详细信息,请参阅 about_Comment_Based_Help

  • 函数 XML-Based 帮助

    Create基于 XML 的帮助主题,例如通常为 cmdlet 创建的类型。 如果要将帮助主题本地化为多种语言,则需要基于 XML 的帮助。

    若要将函数与基于 XML 的帮助主题相关联,请使用基于注释的.EXTERNALHELP帮助关键字 (keyword) 。 如果没有此关键字 (keyword) ,Get-Help则找不到函数帮助主题,并且对 函数的调用Get-Help仅返回自动生成的帮助。

    有关关键字 (keyword) 的详细信息.EXTERNALHELP,请参阅 about_Comment_Based_Help。 有关基于 XML 的帮助的详细信息,请参阅 如何编写 Cmdlet 帮助

另请参阅