函数

函数是一段可以重复使用的代码。

函数定义

语法:

function 函数名称(参数1,参数2,...,参数n)
{
    代码
}
function 函数名称
{
    param(参数1,参数2,...,参数n)

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

return语句不是必须的,PowerShell会将函数的变量输出作为返回值;如果在循环中,返回的是集合。


function Find-File($files)
{
    foreach($file in $files)
    {
        if($file.Name -match "\.ps1$")
        {
            $file
        }
    }
}

Find-File (dir)

如果在循环中使用return返回,只能得到第一条结果。 函数中的代码执行到return后,不再执行之后的代码。

调用函数

调用函数和使用命令相似。

语法


函数名称 -实参名称1 实参1 -实参名称2 实参2 # 命令语法
Add -A 100 -B 200
Add 100 200

显示提示

在函数中,直接使用变量是作为返回值返回给调用者,而非输出文文本。

如果要输出文本,可以在函数中使用Write-Host命令。

function Add([int]$a,[int]$b)
{
    Write-Host "开始调用Add"
    $a + $b
    Write-Host "结束调用Add"
}

参数默认值

可以为函数的参数提供默认值

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

提供默认值的参数调用时可以省略。

Add 100

开关参数

switch类型的参数是开关参数,用来配置选项。

当在参数中存在参数名称时,说明提供了,值为真;否则为没提供,值为假。

function Find-File([string]$path,[string]$pattern,[switch]$recurse)
{
    if($recurse)
    {
        dir $path -Filter $pattern -Recurse
    }else
    {
        dir $path -Filter $pattern
    }
}

Find-File "C:\Windows" "gdi*.dll" # 没提供,不递归查询
Find-File "C:\Windows" "gdi*.dll" -Recurse # 提供了,递归查询

不定参数

可以不为参数定义参数,在函数内部使用$args获取参数。

调用时,可以为函数提供任意个参数。

function Sum()
{
    $sum = 0
    foreach($arg in $args)
    {
        $sum += $arg
    }
    $sum
}

Sum 10 20
Sum 1 2 3 4 5

不定参数可以和一般参数同时使用。

function Sum([switch]$print)
{
    $sum = 0
    foreach($arg in $args)
    {
        if($print)
        {
            Write-Host $arg
        }
        $sum += $arg
    }
    $sum
}

Sum 10 20 -Print

管理函数

通过function:驱动器,可以访问函数。

dir function:

通过Remove-Item命令可以删除函数。

rmdir function:Add

函数删除后,就不可以使用了。

通过Rename-Item可以重命名函数.

Rename-Item function:Add function:NewAdd

覆盖函数

函数定义后,可以重新定义函数覆盖原有定义。

支持管道的函数

我们定义的函数也可以像系统提供的命令一样,支持管道。

系统会上一名命令的结果以$input命名的变量,提供给我们的函数。


function Print-Process()
{
    foreach($item in $input)
    {
        "{0}({1})" -f $item.Name,$item.Id
    }
}

Get-Process | Print-Process

这种模式并不高效,需要将上一命令的所有记录都计算出来并保存,然后传递给我们的函数,而非一条一条传递。

过滤器

过滤器每次处理管道中的一条数据。

不同于函数,过滤器使用filter来定义,并且每一次处理一条记录,记录名称是$_


filter Print-Process()
{
     "{0}({1})" -f $_.Name,$_.Id
}

Get-Process | Print-Process

绑定管道记录到参数

可以将管道记录保存到一个参数,后续可以通过参数来操作管道记录,而不是默认的名称$_。 绑定管道记录使用的是类型说明相似的语法,使用方括号使用属性(Attribute)来修饰参数。 PowerShell中的管道参数一般都命名为InputObject

# 命名的管道参数

filter Print-Process{
    param(
        [Parameter(ValueFromPipeline=$true)]
        $InputObject
    )
    "{0}({1})" -f $InputObject.Name,$InputObject.Id
}

Get-Process | Print-Process

命名之后,仍然可以使用$_访问记录。

管道函数

管道函数比过滤器增加了开始、结束部分,在管道数据开始结束时进行处理。

语法:


function
{
    param(参数列表)

    begin
    {
        初始代码
    }
    process
    {
        处理代码,针对一条记录
    }
    end
    {
        结束代码
    }
}
# 输出进程信息,将符合条件的使用红色文字输出

function Print-Process
{
    param(
        [string]$pattern,
        [Parameter(ValueFromPipeline=$true)]
        $InputObject
    )
    begin
    {
        $ui = $host.ui.rawui # 记录原始颜色
        $color = $ui.ForegroundColor
    }
    process
    {
        if($pattern -and $InputObject.Name -match $pattern)
        {
            $ui.ForegroundColor = "Red"
        }
        $InputObject
        $ui.ForegroundColor = $color
    }
    end
    {
        $ui.ForegroundColor = $color # 恢复颜色
    }
}

Get-Process | Print-Process ".*qq.*"

为函数定义别名

函数可以定义别名,简化代码。像C:这样的切换位置到驱动器实际上是函数,调用了Set-Location

代码块

代码块是一段使用{}包裹的一系列代码。

{
    dir
}

代码快不会默认不会执行,可以使用&操作符执行。

&{
    dir
}

代码块相当于没有名称的函数,其中可以包含参数,并且可以是管道函数。

可以使用变量保存代码块,以供后续使用。代码块的类型是ScriptBlock

$add = {
    param($a,$b)
    $a+$b
}
&$add 100 200

从功能上看,$add相当于委托(函数指针),&是间接调用函数。

很多命令都支持代码块作为参数,比如where

dir | where { $_.Length -gt 1mb}

新版本支持不使用代码块,但只能支持单个条件。 最终也是解释成代码块。

dir | where Length -gt 1mb

如果条件复杂,或者需要重复使用,也可以使用变量保存代码块,然后再需要时提供。

$condition = {
     $_.Length -gt 1mb
}
dir | where $condition