简短说明
介绍如何在 PowerShell 中创建和使用函数。
详细说明
函数是 PowerShell 语句的列表,其中包含分配的名称。 运行函数时,请键入函数名称。 列表中的语句会运行,就像在命令提示符处键入了这些语句一样。
函数可以像以下一样简单:
function Get-PowerShellProcess { Get-Process PowerShell }
函数也可以像 cmdlet 或应用程序一样复杂。
与 cmdlet 一样,函数可以具有参数。 参数可以命名、位置、开关或动态参数。 可以从命令行或管道读取函数参数。
函数可以返回可显示、赋给变量或传递给其他函数或 cmdlet 的值。 还可以使用 return 关键字指定返回值。 该 return 关键字不会影响或禁止显示从函数返回的其他输出。 但是,return 关键字会在该行退出函数。 有关详细信息,请参阅 about_Return。
函数的语句列表可以包含带有关键字 Begin、Process 和 End 的不同类型的语句列表。 这些语句列表以不同的方式处理来自管道的输入。
过滤器是一种使用关键字的特殊 Filter 函数。
函数也可以像 cmdlet 一样运行。 可以创建一个像 cmdlet 一样工作的函数,而无需使用 C# 编程。 有关详细信息,请参阅 about_Functions_Advanced。
重要
在脚本文件和基于脚本的模块中,必须先定义函数,然后才能调用它们。
语法
下面是函数的语法:
function [<scope:>]<name> [([type]$parameter1[,[type]$parameter2])]
{
  begin {<statement list>}
  process {<statement list>}
  end {<statement list>}
}
function [<scope:>]<name>
{
  param([type]$parameter1 [,[type]$parameter2])
  dynamicparam {<statement list>}
  begin {<statement list>}
  process {<statement list>}
  end {<statement list>}
}
函数包含以下各项:
- 
              Function关键字
- 作用域(可选)
- 选择的名称
- 任意数量的命名参数(可选)
- 括在大括号中的一个或多个 PowerShell 命令 {}
有关函数中的 Dynamicparam 关键字和动态参数的详细信息,请参阅 about_Functions_Advanced_Parameters。
简单的函数
函数不必很复杂才有用。 最简单的函数采用以下格式:
function <function-name> {statements}
例如,以下函数使用 Run as Administrator (以管理员身份运行) 选项启动 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}
}
可以创建一个包含实用小型函数的工具箱。 将这些函数添加到 PowerShell 配置文件,如本主题的 about_Profiles 及稍后部分所述。
函数名称
可以将任何名称分配给函数,但与其他人共享的函数应遵循为所有 PowerShell 命令建立的命名规则。
函数名称应由动词-名词对组成,其中动词标识函数执行的作,名词标识 cmdlet 对其执行作的项。
函数应使用已批准用于所有 PowerShell 命令的标准谓词。 这些动词帮助我们保持命令名称简单、一致且易于用户理解。
有关标准 PowerShell 谓词的详细信息,请参阅 Microsoft 文档中 的已批准谓 词。
具有参数的函数
可以结合参数使用函数,包括命名参数、位置参数、开关参数和动态参数。 有关函数中动态参数的详细信息,请参阅 about_Functions_Advanced_Parameters。
命名参数
可以定义任意数量的命名参数。 可以包括命名参数的默认值,如本主题后面部分所述。
可以使用 param 关键字在大括号内定义参数,如以下示例语法所示:
function <name> {
  param ([type]$parameter1 [,[type]$parameter2])
  <statement list>
}
还可以在大括号之外定义参数而不使用 Param 关键字,如以下示例语法所示:
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 属性添加到参数描述中并指定 PSDefaultValue 的 Help 属性来提供描述参数默认值的简短帮助字符串。 若要提供描述  函数中 Get-SmallFiles 参数的默认值 (100) 的帮助字符串,请添加 PSDefaultValue 属性,如以下示例所示。
function Get-SmallFiles {
  param (
      [PSDefaultValue(Help = '100')]
      $Size = 100
  )
}
有关 PSDefaultValue 属性类的详细信息,请参阅 PSDefaultValue 属性成员。
位置参数
位置参数是没有参数名称的参数。 PowerShell 使用参数值顺序将每个参数值与函数中的参数关联。
使用位置参数时,请在函数名称后面键入一个或多个值。 位置参数值赋给 $args 数组变量。
函数名称后面的值赋给 $args 数组中的第一个位置 $args[0]。
以下 Get-Extension 函数将 .txt 文件扩展名添加到您提供的文件名中:
function Get-Extension {
  $name = $args[0] + ".txt"
  $name
}
Get-Extension myTextFile
myTextFile.txt
开关参数
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 表示命令参数
可以使用散列传递来表示命令的参数。 此功能在 Windows PowerShell 3.0 中引入。
在会话中调用命令的函数中使用此技术。 您无需声明或枚举命令参数,也无需在命令参数更改时更改函数。
以下示例函数调用 Get-Command cmdlet。 该命令使用 @Args 来表示 Get-Command 的参数。
function Get-MyCommand { Get-Command @Args }
您可以在调用Get-Command函数时使用 的所有参数Get-MyCommand。 参数和参数值使用 @Args 传递给命令。
Get-MyCommand -Name Get-ChildItem
CommandType     Name                ModuleName
-----------     ----                ----------
Cmdlet          Get-ChildItem       Microsoft.PowerShell.Management
              @Args 功能使用 $Args 自动参数,该参数表示未声明的 cmdlet 参数和剩余参数的值。
有关展开的更多信息,请参阅 about_Splatting。
将对象管道到函数
任何函数都可以从管道获取输入。 可以使用 Begin、Process 和 End 关键字来控制函数如何处理来自管道的输入。 以下示例语法显示了三个关键字:
function <name> {
  begin {<statement list>}
  process {<statement list>}
  end {<statement list>}
}
语句列表 Begin 仅在函数开始时运行一次。
重要
如果您的函数定义了 Begin, Process 或 End 块,则所有代码都必须位于这些块内。 如果定义了 任何 块,则不会识别块外部的任何代码。
              Process 语句列表针对管道中的每个对象运行一次。
当 Process 块运行时,每个管道对象都被分配给 $_ 自动变量,一次分配一个管道对象。
在函数收到管道中的所有对象后, End 语句 list 将运行一次。 如果未Begin使用、 、 ProcessEnd 或 关键字,则所有语句都被视为语句End列表。
以下函数使用 Process 关键字。 该函数显示管道中的示例:
function Get-Pipeline
{
  process {"The value is: $_"}
}
要演示此功能,请输入一个以逗号分隔的数字列表,如以下示例所示:
1,2,4 | Get-Pipeline
The value is: 1
The value is: 2
The value is: 4
在管道中使用函数时,传递给函数的对象将分配给 $input 自动变量。 该函数在任何对象来自管道之前,使用 Begin 关键字运行语句。 函数在从管道接收所有对象后,使用 End 关键字运行语句。
以下示例显示了具有 $input 和 Begin 关键字的 End 自动变量。
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 关键字,$input 中的每个对象都会从 $input 中移除并分配给 $_。 以下示例包含 Process 语句列表:
function Get-PipelineInput
{
  process {"Processing:  $_ " }
  end {"End:   The input is: $input" }
}
在此示例中,通过管道传输到函数的每个对象都发送到 Process statement list。 
              Process 语句在每个对象上运行,一次运行一个对象。 当函数到达 $input 关键字时,End 自动变量为空。
1,2,4 | Get-PipelineInput
Processing:  1
Processing:  2
Processing:  4
End:   The input is:
有关详细信息,请参阅使用枚举器
过滤 器
筛选器是在管道中的每个对象上运行的函数类型。 筛选器类似于 Process 块中具有其所有语句的函数。
筛选器的语法如下所示:
filter [<scope:>]<name> {<statement list>}
以下筛选器从管道获取日志条目,然后显示整个条目或仅显示条目的消息部分:
filter Get-ErrorLog ([switch]$message)
{
  if ($message) { Out-Host -InputObject $_.Message }
  else { $_ }
}
函数范围
函数存在于创建它的范围内。
如果函数是脚本的一部分,该函数可用于该脚本中的语句。 默认情况下,脚本中的函数在命令提示符处不可用。
可以指定函数的作用域。 例如,该函数将添加到以下示例中的全局作用域:
function global:Get-DependentSvs {
  Get-Service | Where-Object {$_.DependentServices}
}
当函数位于全局作用域内时,可以在脚本、函数和命令行中使用函数。
函数通常会创建一个范围。 在函数中创建的项(如变量)仅存在于函数作用域中。
有关 PowerShell 中的范围的详细信息,请参阅 about_Scopes。
使用函数查找和管理函数:驱动器
PowerShell 中的所有函数和筛选器都自动存储在 Function: 驱动器中。 此驱动器由 PowerShell Function 提供程序公开。
引用 Function: 驱动器时,请在 Function 后键入冒号,就像引用计算机的 C 或 D 驱动器那样。
以下命令显示 PowerShell 当前会话中的所有函数:
Get-ChildItem function:
函数中的命令作为脚本块存储在函数的定义属性中。 例如,若要在 PowerShell 附带的 Help 函数中显示命令,请键入:
(Get-ChildItem function:help).Definition
还可以使用以下语法。
$function:help
有关 Function: 驱动器的详细信息,请参阅 函数 提供程序的帮助主题。 键入 Get-Help Function。
在新会话中重用函数
在 PowerShell 命令提示符下键入函数后,该函数将成为当前会话的一部分。 在会话结束之前,它一直可用。
若要在所有 PowerShell 会话中使用函数,请将该函数添加到 PowerShell 配置文件。 有关配置文件的详细信息,请参阅 about_Profiles。
还可以将函数保存在 PowerShell 脚本文件中。 在文本文件中键入您的函数,然后使用文件扩展名保存文件 .ps1 。
编写函数帮助
              Get-Help cmdlet 获取函数以及 cmdlet、提供程序和脚本的帮助。 若要获取有关某个函数的帮助,请键入 Get-Help,后跟函数名称。
例如,若要获取有关 Get-MyDisks 函数的帮助,请键入:
Get-Help Get-MyDisks
您可以使用以下两种方法之一为函数编写帮助:
- 基于注释的函数帮助 - 通过在注释中使用特殊关键字创建帮助主题。 若要为函数创建基于注释的帮助,必须将注释放在函数正文的开头或末尾,或放在函数关键字前面的行上。 有关基于注释的帮助的详细信息,请参阅 about_Comment_Based_Help。 
- 基于 XML 的函数帮助 - 创建基于 XML 的帮助主题,例如通常为 cmdlet 创建的类型。 如果要将帮助主题本地化为多种语言,则需要基于 XML 的帮助。 - 若要将函数与基于 XML 的帮助主题相关联,请使用基于注释的帮助关键字 - .ExternalHelp。 如果没有此关键字,- Get-Help则无法找到函数帮助主题,并且对函数的- Get-Help调用仅返回自动生成的帮助。- 有关 - ExternalHelp关键字的详细信息,请参阅 about_Comment_Based_Help。 有关基于 XML 的帮助的详细信息,请参阅 如何编写 Cmdlet 帮助。