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

[玩转系统] Powershell 功能入门指南

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

Powershell 功能入门指南


一旦习惯了编写 PowerShell 脚本,您就需要了解代码模块化。模块化只是在构建块中创建代码的一个花哨的词。在 PowerShell 世界中,PowerShell 函数是实现此目的的最佳方法之一。

当您编写 PowerShell 脚本时,您可以选择多种编写代码的方式。您可以编写一千行代码来执行数百项任务,所有这些都在一个不间断的代码块中。那将是一场灾难。相反,您应该编写函数。

函数极大地提高了代码的可用性和可读性,使其更易于使用。在本教程中,您将学习编写函数、添加和管理函数的参数以及设置函数以接受管道输入。但首先,让我们看一些术语。

这篇文章摘自我的书《PowerShell for Sysadmins: Workflow Automation Made Easy》。如果您在本教程中学到了一些东西,请务必查看这本书以了解有关函数和更多 PowerShell 优点的更多信息。

函数与 Cmdlet

函数的概念可能听起来很熟悉,因为它听起来有点像您可能已经使用过的 cmdlet。例如,像 Start-ServiceWrite-Host 这样的命令与函数类似。这些被命名为解决单个问题的代码片段。函数和 cmdlet 之间的区别在于这些构造的构建方式。

cmdlet 不是用 PowerShell 编写的。它是用另一种语言编写的,通常是 C# 等。然后,该 cmdlet 会被编译并在 PowerShell 中可用。

另一方面,函数是用 PowerShell 编写的;不是用另一种语言。

您可以使用 Get-Command cmdlet 及其 CommandType 参数查看哪些命令是 cmdlet,哪些是函数,如下所示

Get-Command -CommandType Function

上面的命令返回当前加载到 PowerShell 会话中或 PowerShell 可用的模块内部的所有函数。

相关:了解和构建 PowerShell 模块

先决条件

如果您想了解所有示例,请确保您有可用的 PowerShell 版本。本教程没有特定的版本要求。另外,请确保您有一个很好的代码编辑器(例如 Visual Studio Code)来复制、粘贴和运行一些代码片段。

构建一个简单的函数

在使用函数之前,您需要定义它。要定义函数,请使用 function 关键字,后跟用户定义的描述性名称,最后是一组花括号。大括号内是您希望 PowerShell 执行的脚本块。

下面您可以看到一个基本函数以及执行该函数。该函数称为 Install-Software,使用 Write-Host 在控制台中显示消息。定义后,您可以使用该函数的名称来执行其脚本块内的代码。

PS> function Install-Software { Write-Host 'I installed some software. Yippee!' }
PS> Install-Software
I installed some software, Yippee!

用动词-名词命名

函数的名称很重要。 您可以随意命名函数,但名称应始终描述函数的功能。PowerShell 中的函数命名约定是动词-名词语法。

您应该始终以动词开头,后跟破折号和名词。要查找“已批准”动词的列表,请使用 Get-Verb cmdlet。

改变函数行为

如果您想更改函数的行为,只需更改函数执行的代码即可,如下所示。

PS> function Install-Software { Write-Host 'You installed some software, Yay!' }
PS> Install-Software
You installed some software, Yay!

现在您已经更改了函数内部的代码,它将显示略有不同的消息。

定义高级函数

您可以在许多不同的地方定义函数。在上一节中,本教程假设您刚刚将代码直接复制并粘贴到 PowerShell 控制台中。但这不是唯一的方法。您也可以在脚本中定义函数。

在上一节中,您正在使用一个小函数,因此在控制台中定义它并不是什么大问题。但大多数时候,你会拥有更大的功能。在脚本或模块中定义这些函数,然后调用该脚本或模块以将函数加载到内存中会更容易。

正如您可能想象的那样,每次您想要调整其功能时重新输入更大的函数可能会有点令人沮丧。

我建议您现在打开您最喜欢的编辑器,并将函数存储在 .ps1 文件中,同时完成本教程的其余部分。

向函数添加参数

PowerShell 函数可以有任意数量的参数。当您创建自己的函数时,您可以选择包含参数并决定这些参数的工作方式。这些参数可以是强制的,也可以是可选的,它们可以接受任何内容,也可以强制接受有限的可能参数列表之一。

相关:您想了解的有关 PowerShell 参数的一切

例如,您之前通过Install-Software功能安装的虚构软件可能有多个版本。但目前,Install-Software 功能无法让用户指定他们想要安装的版本。

如果您是唯一使用该函数的人,则每次需要特定版本时都可以更改其中的代码,但这会浪费时间。这个过程也很容易出现潜在的错误,更不用说您希望其他人能够使用您的代码。

在函数中引入参数可以使其具有可变性。正如变量允许您编写可以处理同一情况的多个版本的脚本一样,参数允许您编写一个以多种方式完成一件事的函数。

在这种情况下,您希望它安装同一软件的多个版本,并在许多计算机上执行此操作。

首先,我们向该函数添加一个参数,使您或用户能够指定要安装的版本。

创建一个简单的参数

在函数上创建参数需要 param 块。 param 块保存函数的所有参数。使用 param 关键字后跟括号定义 param 块,如下所示。

function Install-Software {
	[CmdletBinding()]
	param()

	Write-Host 'I installed software version 2. Yippee!'
}

此时,您的函数的实际功能并没有发生任何变化。您刚刚安装了管道,为参数准备了函数。

目前,该功能实际上并未安装任何软件。它只是使用 Write-Host cmdlet 来模拟软件安装,以便您可以专注于编写函数。

添加 param 块后,您可以通过将其放在 param 块的括号内来创建参数,如下所示。

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter()]
		[string] $Version
	)
	
	Write-Host "I installed software version $Version. Yippee!"

}

在上面的 param 块内,您首先需要定义 Parameter 块。像这样使用 Parameter() 块会将其变成“高级参数”。像这里这样的空参数块什么也不做,但却是必需的;我将在下一节中解释如何使用它。

让我们关注参数名称前面的 [string] 类型。通过将参数的类型放在参数变量名称之前的方括号中,可以将参数的值转换为特定类型。 PowerShell 将始终尝试将传递给此参数的任何值转换为字符串(如果还不是字符串)。上面,任何作为 $Version 传入的内容都将始终被视为字符串。

将参数转换为类型不是强制性的,但我强烈鼓励这样做。它明确定义了类型,并将显着减少将来的错误。

您现在还可以将 $Version 添加到 Write-Host 语句中。这意味着当您使用 Version 参数运行 Install-Software 函数并向其传递版本号时,您应该得到一条语句,如下所示。

PS> Install-Software -Version 2
I installed software version 2. Yippee!

现在让我们看看您可以使用此参数做什么。

强制参数属性

您可以使用参数块来控制各种参数属性,这将允许您更改参数的行为。例如,如果您想确保调用该函数的任何人都必须传递给定参数,您可以将该参数定义为“强制”。

默认情况下,参数是可选的。让我们通过在参数块中使用 Mandatory 关键字来强制用户传递版本,如下所示。

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory)]
		[string]$Version
	)

	Write-Host "I installed software version $Version. Yippee!"

}

如果运行上面的函数,您应该得到以下提示:

[玩转系统] Powershell 功能入门指南

设置 Mandatory 属性后,执行不带参数的函数将停止执行,直到用户输入值。该函数现在会等待,直到用户指定 Version 参数的值。输入后,PowerShell 就会执行该函数。

为了避免强制参数提示,只需在调用函数时向参数传递一个值,如下所示。

Install-Software -Version 2

默认参数值

例如,如果您发现自己一遍又一遍地传递相同的参数值,则可以定义默认参数值。当您大多数时候期望参数具有特定值时,默认参数非常有用。

例如,如果您希望在 90% 的情况下安装此软件的版本 2,并且您不想每次运行此函数时都设置该值,则可以将默认值 2 分配给 $Version 参数。您可以在下面看到这个示例。

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter()]
		[string]$Version = 2
	)

	Write-Host "I installed software version $Version. Yippee!"

}

拥有默认参数并不妨碍您传入参数。您传入的值将覆盖默认值。

添加参数验证属性

限制可以通过参数传递给函数的值总是一个好主意。最好的方法是使用参数验证属性。

限制用户(甚至您!)可以传递给您的函数或脚本的信息将消除函数内不必要的代码。例如,假设您将值 3 传递给 Install-Software 函数,并知道版本 3 是现有版本。

您的函数假设每个用户都知道存在哪些版本,因此它不会考虑当您尝试指定版本 4 时会发生的情况。在这种情况下,该函数将无法找到适当的文件夹,因为它不存在。

没有参数验证的生活

当您在文件路径中使用 $Version 字符串时,请查看下面的示例。如果有人传递的值未完成现有文件夹名称(例如 SoftwareV3 或 SoftwareV4),则代码将失败。

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[string]$Version
	)

	Get-ChildItem -Path \SRV1\Installers\SoftwareV$Version

}

[玩转系统] Powershell 功能入门指南

您可以编写错误处理代码来解决此问题,也可以通过要求用户仅传递软件的现有版本来将问题消灭在萌芽状态。要限制用户的输入,请添加参数验证。

添加参数验证

存在各种类型的参数验证,但对于 Install-Software 函数,[ValidateSet 属性](https://adamtheautomator.com/powershell-validateset/)效果最好。 ValidateSet 验证属性使您能够指定参数允许的值列表。如果您只考虑字符串 12,您将确保用户只能指定这些值;否则,该功能将立即失败并通知用户原因。

在原始 Parameter 块下方的 param 块内添加参数验证属性,如下所示。

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version
	)

	Get-ChildItem -Path \SRV1\Installers\SoftwareV$Version

}

通过在 ValidateSet 属性的尾括号内添加一组项目(12),这会告诉 PowerShell,唯一对 ValidateSet 有效的值代码>版本为12。如果用户尝试传递集合中的内容之外的内容,他们将收到如下所示的错误消息,通知他们只有特定数量的可用选项。

[玩转系统] Powershell 功能入门指南

ValidateSet 属性是常见的验证属性,但也可以使用其他属性。有关限制参数值的所有方式的完整详细信息,请查看 Microsoft 文档。

接受管道输入

到目前为止,您已经创建了一个带有参数的函数,该参数只能使用典型的 -ParameterName 语法进行传递。这可行,但您还可以选择使用 PowerShell 管道将值传递给参数。让我们将管道功能添加到安装软件功能中。

相关:在 ATA PowerShell 参数文章中接受管道输入

首先,在代码中添加另一个参数,指定要安装软件的计算机。另外,将该参数添加到您的 Write-Host 引用中以模拟安装。

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[string]$Version
		[ValidateSet('1','2')],
		
		[Parameter(Mandatory)]
		[string]$ComputerName
	)

	Write-Host "I installed software version $Version on $ComputerName. Yippee!"

}

ComputerName 参数添加到函数后,您现在可以迭代计算机名称列表,并将计算机名称和版本的值传递给 Install-Software 函数,如下所示。

$computers = @("SRV1", "SRV2", "SRV3")
foreach ($pc in $computers) {
	Install-Software -Version 2 -ComputerName $pc
}

您应该学习使用管道,而不是执行所有这些操作。

使函数管道兼容

不幸的是,您无法仅通过之前构建的简单函数来利用 PowerShell 管道。您必须决定希望函数接受和实现哪种类型的管道输入。

PowerShell 函数使用两种管道输入:ByValue(整个对象)和 ByPropertyName(单个对象属性)。在这里,由于 $computers 数组仅包含字符串,因此您将通过 ByValue 传递这些字符串。

要添加管道支持,请使用以下两个关键字之一将参数属性添加到所需的参数:ValueFromPipelineValueFromPipelineByPropertyName,如下所示。

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version,

		[Parameter(Mandatory, ValueFromPipeline)]
		[string]$ComputerName
	)

	Write-Host "I installed software version $Version on $ComputerName. Yippee!"

}

加载更新 Instal-Software 函数后,请像这样调用它:

$computers = @("SRV1", "SRV2", "SRV3")
$computers | Install-Software -Version 2

再次运行该脚本,您应该得到如下结果:

I installed software version 2 on SRV3. Yippee!

请注意,Install-Software 仅针对数组中的最后一个字符串执行。您将在下一节中看到如何解决此问题。

添加进程块

要告诉 PowerShell 对每个进入的对象执行此函数,您必须包含一个进程块。在进程块内,放置每次函数接收管道输入时要执行的代码。将进程块添加到脚本中,如下所示。

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version,

		[Parameter(Mandatory, ValueFromPipeline)]
		[string]$ComputerName
	)

	process {
		Write-Host "I installed software version $Version on $ComputerName. Yippee!"
	}
}

现在再次调用该函数,就像之前所做的那样。 Install-Software 函数现在将返回三行(每个对象一行)。

I installed software version 2 on SRV1. Yippee!
I installed software version 2 on SRV2. Yippee!
I installed software version 2 on SRV3. Yippee!

进程块包含您要执行的主要代码。您还可以使用 beginend 块来执行将在函数调用开始和结束时执行的代码。您可以通过 Microsoft 文档了解有关 beginprocessend 块的更多信息。

下一步

函数允许您将代码划分为离散的构建块。它们不仅可以帮助您将工作分解为更小、更易于管理的块,还迫使您编写可读且可测试的代码。

现在,我要求您查看一些旧脚本,看看可以在哪里添加 PowerShell 函数。寻找代码中的模式。从这些模式构建一个函数。注意您在哪里复制/粘贴代码片段并将其转换为 PowerShell 函数!

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

取消回复欢迎 发表评论:

关灯