PowerShell 脚本编写与命令执行全解析
1. PowerShell 类型扩展
PowerShell 在其安装目录下的
types.ps1xml
文件中添加了多个类型扩展。这个文件是很好的示例来源,但不要直接修改它。建议创建一个新的文件,并使用
Update-TypeData
cmdlet 加载自定义内容。以下命令从配置文件所在目录加载
Types.Custom.Ps1Xml
:
$typesFile = Join-Path (Split-Path $profile) "Types.Custom.Ps1Xml"
Update-TypeData -PrependPath $typesFile
2. 脚本、函数和脚本块的编写
当你想要打包和复用命令时,最佳的方式是将它们放在脚本、函数和脚本块中。
-
脚本
:脚本是包含一系列 PowerShell 命令的文本文件。编写脚本时,在文本编辑器中编写 PowerShell 命令,然后将文件保存为
.ps1
扩展名。
-
函数
:函数可以将紧密相关的命令打包成一个可通过名称访问的单元。函数的定义语法如下:
function SCOPE:name(parameters)
{
statement block
}
或者使用过滤器形式:
filter SCOPE:name(parameters)
{
statement block
}
有效的作用域名称包括
global
(创建对整个 shell 可用的函数)、
script
(创建仅对当前脚本可用的函数)、
local
(创建仅对当前作用域和子作用域可用的函数)和
private
(创建仅对当前作用域可用的函数),默认作用域是
local
。
函数支持
$args
数组、形式参数、
$input
枚举器、cmdlet 关键字、管道输出和等效的返回语义。常见的错误是像调用方法一样调用函数,例如:
$result = GetMyResults($item1, $item2)
正确的方式应该是:
$result = GetMyResults $item1 $item2
过滤器是一种特殊的函数,其语句被视为包含在
process
语句块中。
为了使大型脚本更易于理解,可以采用以下结构:
function Main
{
(...)
HelperFunction
(...)
}
function HelperFunction
{
(...)
}
. Main
- 脚本块 :脚本块就像没有名称的函数和脚本。定义脚本块的语法如下:
$objectReference =
{
statement block
}
脚本块支持
$args
数组、形式参数、
$input
枚举器、cmdlet 关键字、管道输出和等效的返回语义。可以直接调用脚本块(
& { "Hello" }
)或调用包含它的变量(
& $objectReference
)。
3. 命令的运行
执行命令(脚本、函数或脚本块)有两种方式:调用和点源。
-
调用
:调用命令会运行其中的命令。除非使用
GLOBAL
作用域关键字明确定义,否则脚本中定义的变量和函数在脚本退出后不会保留。默认情况下,PowerShell 的执行策略会阻止脚本运行,需要使用
Set-ExecutionPolicy
cmdlet 更改设置,例如:
Set-ExecutionPolicy RemoteSigned
如果命令名没有空格,直接输入其名称;如果命令名有空格或命令是脚本块,则使用调用运算符
&
。示例如下:
c:\temp\Invoke-Commands.ps1 parameter1 parameter2 ...
Invoke-MyFunction parameter1 parameter2 ...
& "C:\Script Directory\Invoke-Commands.ps1" parameter1 parameter2 ...
$scriptBlock = { "Hello World" }
& $scriptBlock parameter1 parameter2 ...
如果要在模块的上下文中调用命令,需要提供对该模块的引用:
$module = Get-Module PowerShellCookbook
& $module Invoke-MyFunction parameter1 parameter2 ...
& $module $scriptBlock parameter1 parameter2 ...
-
点源
:点源命令也会运行其中的命令,但与调用不同的是,脚本中定义的变量和函数在脚本退出后会保留。使用点运算符
.进行点源操作,示例如下:
. "C:\Script Directory\Invoke-Commands.ps1" Parameters
. Invoke-MyFunction parameters
. $scriptBlock parameters
同样,如果要在模块的上下文中点源命令,也需要提供对该模块的引用。
4. 参数的使用
需要或支持用户输入的命令通过参数来实现。可以使用
Get-Command
cmdlet 查看命令支持的参数,例如:
PS > Get-Command Stop-Process -Syntax
Stop-Process [-Id] <int[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [...]
Stop-Process -Name <string[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [...]
Stop-Process [-InputObject] <Process[]> [-PassThru] [-Force] [-WhatIf] [...]
为参数提供值的方式有多种:
- 使用连字符、参数名、空格和参数值,例如:
Stop-Process -Id 1234
。
- 如果参数值包含空格,用引号括起来,例如:
Stop-Process -Name "Process With Spaces"
。
- 如果变量包含参数值,使用 PowerShell 的常规变量引用语法,例如:
$name = "Process With Spaces"
Stop-Process -Name $name
-
如果要使用其他 PowerShell 语言元素作为参数值,用括号括起来,例如:
Get-Process -Name ("Power" + "Shell")。 -
可以只提供足够的参数名来区分它与其他参数,例如:
Stop-Process -N "Process With Spaces"。 -
如果命令语法中参数名在方括号中(如
[-Id]),则该参数是位置参数,可以省略参数名,只提供值,例如:Stop-Process 1234。 - 还可以使用哈希表定义参数,并使用展开运算符,例如:
$parameters = @{
Path = "c:\temp"
Recurse = $true
}
Get-ChildItem @parameters
可以通过为
PSDefaultParameterValues
哈希表赋值来定义命令参数的默认值,例如:
PS > $PSDefaultParameterValues["Get-Process:ID"] = $pid
PS > Get-Process
PS > $PSDefaultParameterValues["Get-Service:Name"] = {
Get-Service -Name * | Foreach-Object Name | Get-Random }
PS > Get-Service
5. 命令输入的提供方式
PowerShell 提供了多种处理命令输入的选项。
-
参数数组
:要按位置访问命令行参数,可以使用 PowerShell 放在
$args
特殊变量中的参数数组,示例如下:
$firstArgument = $args[0]
$secondArgument = $args[1]
$argumentCount = $args.Count
- 形式参数 :定义支持简单参数的命令语法如下:
param(
[TypeName] $VariableName = Default,
...
)
定义支持高级功能的命令语法如下:
[CmdletBinding(cmdlet behavior customizations)]
param(
[Parameter(Mandatory = $true, Position = 1, ...)]
[Alias("MyParameterAlias")]
[...]
[TypeName] $VariableName = Default,
...
)
[CmdletBinding()]
属性的元素描述了脚本或函数与系统的交互方式,包括
SupportsShouldProcess
、
DefaultParameterSetName
和
ConfirmImpact
等。
[Parameter()]
属性的元素主要定义了参数与其他参数的关系,包括
Mandatory
、
Position
、
ParameterSetName
等。
PowerShell 还允许应用其他属性来为参数添加行为或验证约束,例如
[Alias()]
、
[AllowNull()]
、
[ValidateCount()]
等。
-
管道输入
:要访问通过管道传递给命令的数据,可以使用 PowerShell 放在
$input特殊变量中的输入枚举器,示例如下:
foreach($element in $input)
{
"Input was: $element"
}
如果需要以非结构化方式访问管道输入,可以将输入枚举器转换为数组:
$inputArray = @($input)
6. 命令中的 cmdlet 关键字
当管道输入是命令的核心场景时,可以包含标记为
begin
、
process
和
end
的语句块:
param(...)
begin
{
...
}
process
{
...
}
end
{
...
}
PowerShell 在加载命令时执行
begin
语句,为管道传递的每个项目执行
process
语句,在处理完所有管道输入后执行
end
语句。在
process
语句块中,
$_
(或
$PSItem
)变量表示当前管道对象。
7.
$MyInvocation
自动变量
$MyInvocation
自动变量包含脚本运行的上下文信息,包括命令的详细信息(
MyCommand
)、定义它的脚本(
ScriptName
)等。
8. 命令输出的检索
PowerShell 提供了三种主要方式来检索命令的输出:
-
管道输出
:脚本的返回值或输出是它生成但未捕获的任何数据。例如:
"Text Output"
5*5
将该命令的输出分配给变量会创建一个包含
Text Output
和
25
两个值的数组。
-
返回语句
:
return value
语句是管道输出的简写形式,例如:
return $false
以下是一个简单的 mermaid 流程图,展示命令执行的两种方式:
graph LR
A[执行命令] --> B{调用}
A --> C{点源}
B --> D[变量和函数不保留]
C --> E[变量和函数保留]
表格总结参数传递方式:
| 传递方式 | 示例 |
| ---- | ---- |
| 直接指定参数名和值 |
Stop-Process -Id 1234
|
| 用引号括起含空格的值 |
Stop-Process -Name "Process With Spaces"
|
| 使用变量 |
$name = "Process With Spaces"; Stop-Process -Name $name
|
| 使用括号包含 PowerShell 元素 |
Get-Process -Name ("Power" + "Shell")
|
| 省略部分参数名 |
Stop-Process -N "Process With Spaces"
|
| 位置参数 |
Stop-Process 1234
|
| 使用哈希表和展开运算符 |
$parameters = @{Path = "c:\temp"; Recurse = $true}; Get-ChildItem @parameters
|
PowerShell 脚本编写与命令执行全解析
9. 参数属性及验证属性详解
在使用 PowerShell 编写脚本和函数时,参数的属性和验证属性起着至关重要的作用,它们能确保输入的合法性和有效性,下面详细介绍这些属性。
9.1
[CmdletBinding()]
属性
| 属性名 | 作用 | 示例 |
|---|---|---|
SupportsShouldProcess
|
若为
$true
,启用
-WhatIf
和
-Confirm
参数,提示用户命令会修改系统,可在实验模式下运行。使用时需在修改系统状态前调用
$psCmdlet.ShouldProcess()
方法。默认值为
$false
。
|
[CmdletBinding(SupportsShouldProcess = $true)]
|
DefaultParameterSetName
| 定义命令的默认参数集名称,用于解决参数声明多个参数集且用户输入信息不足时的歧义问题。未指定时,命令无默认参数集名称。 |
[CmdletBinding(DefaultParameterSetName = "Set1")]
|
ConfirmImpact
|
定义命令的确认影响级别,有
Low
、
Medium
和
High
三种。当命令的影响级别大于偏好变量时,PowerShell 会自动生成确认消息。默认值为
Medium
。
|
[CmdletBinding(ConfirmImpact = "High")]
|
9.2
[Parameter()]
属性
| 属性名 | 作用 | 示例 |
|---|---|---|
Mandatory
| 定义参数为必需参数,若用户未提供值,PowerShell 会自动提示输入。默认情况下,参数为可选参数。 |
[Parameter(Mandatory = $true)]
|
Position
| 定义参数的位置,适用于用户不指定参数名而直接提供值的情况。PowerShell 会按位置顺序将值分配给参数。 |
[Parameter(Position = 1)]
|
ParameterSetName
| 定义参数所属的参数集,参数的行为特定于该参数集,且仅存在于定义的参数集中。 |
[Parameter(ParameterSetName = "Set1")]
|
ValueFromPipeline
| 声明参数可直接接受管道输入,若用户通过管道传递数据,PowerShell 会将输入分配给该参数。 |
[Parameter(ValueFromPipeline = $true)]
|
ValueFromPipelineByPropertyName
| 声明参数可接受管道输入,前提是传入对象的属性名与参数名匹配。 |
[Parameter(ValueFromPipelineByPropertyName = $true)]
|
ValueFromRemainingArguments
| 声明参数接受所有未分配给位置或命名参数的剩余输入,一个命令中只能有一个参数具有此属性。 |
[Parameter(ValueFromRemainingArguments = $true)]
|
9.3 参数验证属性
| 属性名 | 作用 | 示例 |
|---|---|---|
[Alias()]
| 为参数定义别名,方便使用长且描述性强的参数名。 |
[Alias("AliasName")]
|
[AllowNull()]
|
允许参数接受
$null
值,仅对必需参数有意义。
|
[AllowNull()]
|
[AllowEmptyString()]
| 允许字符串参数接受空字符串值,仅对必需参数有意义。 |
[AllowEmptyString()]
|
[AllowEmptyCollection()]
| 允许集合参数接受空集合值,仅对必需参数有意义。 |
[AllowEmptyCollection()]
|
[ValidateCount()]
| 限制集合参数中元素的数量范围。 |
[ValidateCount(1, 10)]
|
[ValidateLength()]
| 限制字符串参数的长度范围。 |
[ValidateLength(1, 20)]
|
[ValidatePattern()]
| 强制字符串参数的输入必须匹配指定的正则表达式。 |
[ValidatePattern("^[a-zA-Z]+$")]
|
[ValidateRange()]
| 限制数值参数的取值范围。 |
[ValidateRange(1, 100)]
|
[ValidateScript()]
| 确保参数输入满足脚本块中指定的条件。 |
[ValidateScript({ $_ -gt 0 })]
|
[ValidateSet()]
| 确保参数输入等于集合中的某个选项。 |
[ValidateSet("Option1", "Option2")]
|
[ValidateNotNull()]
|
确保参数输入不为
null
,对可选参数有用。
|
[ValidateNotNull()]
|
[ValidateNotNullOrEmpty()]
|
确保参数输入不为
null
或空,对可选参数有用。
|
[ValidateNotNullOrEmpty()]
|
10. 综合示例:编写一个带参数验证的函数
下面是一个综合示例,展示如何编写一个带参数验证的函数:
function Get-ProcessByName {
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")]
param(
[Parameter(Mandatory = $true, Position = 0)]
[ValidateNotNullOrEmpty()]
[string]$ProcessName,
[Parameter()]
[ValidateRange(1, 10)]
[int]$MaxResults = 5
)
if ($psCmdlet.ShouldProcess("Getting processes named $ProcessName")) {
Get-Process -Name $ProcessName | Select-Object -First $MaxResults
}
}
# 调用函数
Get-ProcessByName -ProcessName "powershell" -MaxResults 3
在这个示例中,
Get-ProcessByName
函数接受两个参数:
ProcessName
和
MaxResults
。
ProcessName
是必需参数,且使用
[ValidateNotNullOrEmpty()]
属性确保输入不为空。
MaxResults
是可选参数,使用
[ValidateRange(1, 10)]
属性限制其取值范围在 1 到 10 之间。函数还使用了
[CmdletBinding()]
属性,支持
-WhatIf
和
-Confirm
参数,在执行操作前会提示用户确认。
11. 总结与最佳实践
通过以上内容的学习,我们了解了 PowerShell 脚本编写、命令执行、参数使用、输入输出处理等方面的知识。以下是一些总结和最佳实践:
-
脚本结构
:对于大型脚本,采用
Main函数和辅助函数的结构,使代码更易于理解和维护。 - 参数使用 :合理使用参数属性和验证属性,确保输入的合法性和有效性。使用展开运算符简化参数传递。
- 命令执行 :根据需求选择调用或点源命令,注意变量和函数的作用域。
- 输入输出处理 :利用管道输入和输出,提高代码的灵活性和可复用性。
以下是一个 mermaid 流程图,展示编写一个完整 PowerShell 脚本的主要步骤:
graph LR
A[定义需求] --> B[规划脚本结构]
B --> C[编写函数和脚本块]
C --> D[设置参数和验证]
D --> E[处理输入和输出]
E --> F[测试和调试]
F --> G[优化和完善]
表格总结编写 PowerShell 脚本的最佳实践:
| 方面 | 最佳实践 |
| ---- | ---- |
| 脚本结构 | 使用
Main
函数和辅助函数,提高代码可读性。 |
| 参数使用 | 合理使用参数属性和验证属性,简化参数传递。 |
| 命令执行 | 根据需求选择调用或点源,注意作用域。 |
| 输入输出处理 | 利用管道输入输出,提高灵活性和可复用性。 |
希望这些内容能帮助你更好地掌握 PowerShell 脚本编写和命令执行的技巧,提升工作效率。
超级会员免费看
1045

被折叠的 条评论
为什么被折叠?



