目录
- [PowerShell 管道](#PowerShell 管道)
- 管道输出
- 控制管道输出的格式设置
- 管道选择、排序和度量对象
- 排序和分组
- Sort-Object
- [Format 的 GroupBy分组](#Format 的 GroupBy分组)
- 度量管道中的对象
- Select-Object
- Unique去重
- Property
- 自定义属性并设置表达式与格式
- 排序和分组
- 从管道中筛选对象
- 枚举
- 传递管道对象
- [ByValue 传递数据](#ByValue 传递数据)
- [ByPropertyName 传递数据](#ByPropertyName 传递数据)
- 展开属性值
- 深入了解Powershell脚本
- 开发生命周期与安全强化
- [PowerShellGet 模块](#PowerShellGet 模块)
- 执行策略
- 以数字方式对脚本进行签名
- 进阶语法
- [ForEach 循环](#ForEach 循环)
- [If 构造](#If 构造)
- [Switch 构造](#Switch 构造)
- [For 构造](#For 构造)
- 其他循环构造
- [Break 和 Continue](#Break 和 Continue)
- 导入数据
- 接受用户输入
- Credential凭证使用
- 脚本故障排除与错误处理
- 输出命令的层次与用途
- 脚本中使用断点
- 错误操作
- [ErrorActionPreference](#ErrorActionPreference)
- 函数与模块
- 开发生命周期与安全强化
PowerShell 管道
管道输出
PowerShell 命令不会生成文本作为输出,而是会生成对象,对象是描述内存中数据结构的通用词。
运行 Get-Service 命令时,它会返回服务对象的集合,每个对象都包含 Name、DisplayName 和 Status 等名称的属性。
控制管道输出的格式设置
格式设置 cmdlet 为:
-
Format-List
-
Format-Table
-
Format-Wide
-
Format-Custom
Format-Custom cmdlet 需要创建定义格式的自定义 XML 配置文件。 该 cmdlet 不经常使用。
Format-List
Format-List cmdlet 将命令的输出格式化为一个简单的属性列表,其中每个属性显示在一个新行上。
如果将输出传递给 Format-List 的命令返回多个对象,则会为每个对象显示单独属性列表。
当命令返回大量很难以表格格式查看的属性时,列表格式尤其有用。
Format-List cmdlet 的别名是 fl。
Format-Table
Format-Table cmdlet 将输出格式化为表格,其中每一行表示一个对象,每一列表示一个属性。
这个输出的效果和默认的没啥效果,多了一个就是你可以选择参数来进行定义你输出的效果,下面介绍参数↓↓↓
可使用多种参数修改此格式,例如:
-
-AutoSize。 此参数可根据数据的宽度来调整列的大小和数量。 在 Windows PowerShell 5.0 及更高版本中,-AutoSize 默认设置为 true。 在更低版本的 Windows PowerShell 中,默认值可能会截断表中的数据。
-
-HideTableHeaders。 此参数会从输出中移除表标头。
-
-Wrap。 此参数会使超出列宽的文本换行到下一行。
Format-Table cmdlet 的别名是 ft。
Format-Wide
Format-Wide cmdlet 的输出是单个列表中分多列显示的单个属性。
这个其实只需要知道:使用 -Property 参数,指定一个属性去进行多个列展示,不用单个列展示这么难看
下面展示的就是服务的所有名字,但是我们是用3列进行展示
powershell
Get-Service | fw -Property Name -Column 3
管道选择、排序和度量对象
排序和分组
Sort-Object
Sort-Object 命令接受一个或多个属性名作为排序依据, 默认情况下,命令按升序排序
powershell
Get-Service | Sort-Object --Property Name --Descending
Get-Service | Sort Name --Desc
Get-Service | Sort Status,Name
默认情况下,字符串属性的排序不考虑大小写。
(但是Sort-Object 也有参数去支持指定区分大小写的排序、特定区域性的排序规则和其他选项)
Format 的 GroupBy分组
Format-List、Format-Table 和 Format-Wide 格式设置 cmdlet 具有接受属性名的 -GroupBy 参数。 通过使用 -GroupBy 参数,可以按指定属性对输出进行分组。
注意:这里说的是Format的几个格式设置的分组,所以要用格式cmdlet然后再使用这个GroupBy参数
powershell
Get-Service | Sort-Object Status,Name | fw -GroupBy Status
-GroupBy 参数的运行方式与 Group-Object 命令类似。 Group-Object 命令接受管道输入,让你可以更好地控制对象分组。 Group-Object 具有别名 group。
度量管道中的对象
Measure-Object 默认情况下,该命令会对集合中的对象数进行计数,并生成包含计数的测量对象。
使用 Measure-Object 的 -Property 参数可指定单个属性,该属性必须包含数值。 随后,可以添加 -Sum、-Average、-Minimum 和 -Maximum 参数,以计算指定属性的这些聚合值。
(通常可注意到 -Sum、-Average、-Minimum 和 -Maximum 参数被截断为 -Sum、-Ave、-Min 和 -Max)
以下命令计算文件夹中的文件数,并显示文件大小的最小、最大和平均值:
(Recurse递归读取)
powershell
Get-ChildItem -File -Recurse | Measure -Property Length -Sum -Average -Minimum -Max
效果如下图:
Select-Object
Select-Object 命令具有别名 Select。
这个命令比较简单,用法如下:
用Property指定要选择的对象即可,多个就用逗号隔开
powershell
Get-Process | Select-Object -Property 列名1,列名2
- 选择最少虚拟内存使用量排名前 10 的进程
powershell
Get-Process | Sort-Object --Property VM | Select-Object --First 10
- 选择最后 10 个正在运行的服务并按名称排序
powershell
Get-Service | Sort-Object --Property Name | Select-Object --Last 10
- 选择 CPU 用量最少的五个进程,并跳过使用最少 CPU 的那一个进程
powershell
Get-Process | Sort-Object --Property CPU --Descending | Select-Object --First 5 --Skip 1
Unique去重
只需要在指定对象后添加多一个-Unique
参数即可
- 显示某个用户在每个部门中的用户信息
powershell
Get-ADUser -Filter * -Property Department | Sort-Object -Property Department | Select-Object Department -Unique
Property
没啥好说的,就是select-object 的 参数Property 指定显示的进程属性即可
- 显示一个表,其中包含本地计算机上运行的所有进程的名称、进程 ID、虚拟内存大小、分页内存大小和 CPU 使用率:
powershell
Get-Process | Select-Object --Property Name,ID,VM,PM,CPU | Format-Table
- -Property 参数适用于 -First 或 -Last 参数。 以下命令返回具有最大 CPU 使用率的 10 个进程的名称和 CPU 使用率:
powershell
Get-Process | Sort-Object --Property CPU --Descending | Select-Object --Property Name,CPU --First 10
自定义属性并设置表达式与格式
- 定义属性的名字:
- label、l、name 或 n:这指定计算属性的标签或名称。 由于小写字母 l 在某些字体中类似于数字 1,因此请尝试使用 name、n 或 label。
- 设置属性计算的式子:
- expression 或 e:这将指定设置计算属性值的表达式。
powershell
Get-Process |
Select-Object Name,ID,@{n='VirtualMemory';e={$PSItem.VM}},@{n='PagedMemory';e={$PSItem.PM}}
$PSItem
是由 Windows PowerShell 创建的特殊变量。 它表示通过管道传输到 Select-Object
命令中的任何对象。 在上一个示例中,这是一个 Process
对象。 $PSItem
之后的句点允许访问对象的单个成员。 在此示例中,一个计算属性使用 VM
属性,另一个使用 PM
属性。
当我们输入正常的Get-Process
并获取他的所有属性的时候你会看到VM
这个属性,所以我们$PSItem.VM
是能够获取到的
检查一下是否有VM
powershell
Get-Process | Get-Member | Select-Object -Property Name | Format-Wide -Column 5
下图可以看到确实有VM
属性

- 为什么用@{}
解释:还记不记得之前创建空数组是用@(),这里是创建hash表,所以用@{},n是属性名,对应键,e是计算式子相当于值,所以说我们还能知道在自定义的时候不能定义同一个名字的属性
计算
你可能想要修改前面的命令以显示内存值(以兆字节 (MB) 为单位)。 PowerShell 将缩写 KB、MB、GB、TB 和 PB 分别表示千字节、兆字节、千兆字节、兆兆字节和拍字节。 因此,可以按如下所示修改命令:
($PSItem
是接收传过来的对象,$_
也是一样的, 用的比较多的是$_
,所以说我们可以在Get-Process出来的对象中一个个用$PSItem
去取你想要的属性或者激活方法)
powershell
Get-Process |
Select-Object Name,
ID,
@{n='VirtualMemory(MB)';e={$PSItem.VM / 1MB}},
@{n='PagedMemory(MB)';e={$PSItem.PM / 1MB}}
生成的值有几个小数位,这在视觉上是不理想的。
若要改进输出,请进行以下更改:
powershell
Get-Process |
Select-Object Name,
ID,
@{n='VirtualMemory(MB)';e={'{0:N2}' --f ($PSItem.VM / 1MB) -as [Double] }},
@{n='PagedMemory(MB)';e={'{0:N2}' --f ($PSItem.PM / 1MB) -as [Double] }}
上一个示例中的语法可能看起来令人困惑,因为它包含许多标点符号。 从基本表达式开始:
powershell
'{0:N2}' --f ($PSItem.VM / 1MB)
上一个表达式将 VM 属性除以 1 MB,然后将结果格式化为最多两个小数位的数字。 然后将该表达式放入哈希表中:
该哈希表创建名为 VirtualMemory(MB) 的自定义属性。
powershell
@{n='VirtualMemory(MB)';e={'{0:N2}' --f ($PSItem.VM / 1MB) }}
从管道中筛选对象
比较运算符
操作 | DESCRIPTION |
---|---|
-eq | 等于 |
-ne | 不等于 |
-gt | 大于 |
-lt | 小于 |
-le | 小于或等于 |
-ge | 大于或等于 |
在powershell中默认是不区分大小写,但是在比较的时候难免希望对大小写的区分
所以我们可以在操作中添加一个前缀c
作为比较区分大小写的标志
powershell
-ceq
-cne
不仅仅上述的运算符,其他也都可以加c
当然还有like也可以用来区分大小写去匹配,因为-like 运算符类似于 -eq
-clike
其他更高级的运算符存包括:
- -in 和 -contains 运算符,用于测试集合中是否存在对象。
- -as 运算符,用于测试对象是否为指定类型。
- 将字符串与正则表达式进行比较的 -match 和 -cmatch 运算符。
- 还包含许多运算符来反转比较的逻辑,例如 -notlike 和 -notin。
简单案例:
powershell
PS C:\> 100 -gt 10
True
PS C:\> 'hello' -eq 'HELLO'
True
PS C:\> 'hello' -ceq 'HELLO'
False
基本筛选器语法
Where-Object 命令及其别名 Where
- 仅显示正在运行的服务的列表
powershell
Get-Service | Where Status --eq Running
基本语法的限制
只能对单个比较使用基本语法。 例如,无法显示已停止且具有"自动"启动模式的服务列表,因为需要两个比较。
不能将基本语法用于复杂表达式。 例如,服务对象的 Name 属性由一串字符组成。 PowerShell 使用 System.String 对象包含该串字符,而 System.String 对象具有 Length 属性。 以下命令不适用于基本筛选语法:
powershell
Get-Service | Where Name.Length --gt 5
目的是显示名称超过五个字符的所有服务。 但是,此命令永远不会生成输出。 一旦超过基本语法的能力,必须改用高级筛选语法。
高级筛选器语法
高级语法使用筛选器脚本
使用 -FilterScript
参数传递该脚本块
对于通过管道传递到命令的每个对象,筛选器脚本都会运行一次。 当筛选器脚本返回 True 时,该对象将作为输出传递到管道中,当筛选器脚本返回 False 时,将从管道中删除该对象。
以下两个命令具有相同的功能。 第一个命令使用基本语法,第二个命令使用高级语法执行相同的操作:
powershell
Get-Service | Where Status --eq Running
Get-Service | Where-Object --FilterScript { $PSItem.Status --eq 'Running' }
-FilterScript
参数是位置参数,大多数用户会省略它。 大多数用户还会使用 Where
别名或 ?
别名,此名称长度更短。
推荐使用 $_
变量而不是 $PSItem
,因为在 Windows PowerShell 1.0 和 Windows PowerShell 2.0 中只允许使用 $_
。
以下命令执行与前两个命令相同的任务:
powershell
Get-Service | Where {$PSItem.Status --eq 'Running'}
Get-Service | ? {$_.Status --eq 'Running'}
组合多个条件
高级语法允许通过使用 -and 和 -or 布尔值或逻辑运算符来组合多个条件。 下面是一个示例:
powershell
Get-EventLog --LogName Security --Newest 100 |
Where { $PSItem.EventID --eq 4672 --and $PSItem.EntryType --eq 'SuccessAudit' }
逻辑运算符的任意一侧都必须是一个完整的比较式子,下面给几个错误示范,请不要犯错:
powershell
Get-Process | Where { $PSItem.CPU --gt 30 --and VM --lt 10000 }
Get-Service | Where { $PSItem.Status --eq 'Running' --or 'Starting' }
True 或 False 的属性筛选使用技巧
Get-Process 生成的对象具有名为"Responding"的属性,此属性包含 True 或 False。
获取正在响应的进程的列表,可以使用以下命令之一:
powershell
Get-Process | Where { $PSItem.Responding --eq $True }
Get-Process | Where { $PSItem.Responding }
在第一个命令中,特殊 shell 变量 $True
用于表示布尔值 True。 第二个命令未包含任何比较,但它是有效的,因为 Responding 属性已包含 True 或 False
这类似于反向逻辑,仅列出未响应的进程:
powershell
Get-Process | Where { -not $PSItem.Responding }
在前面的示例中,-not 逻辑运算符将 True 更改为 False,并将 False 更改为 True。 因此,如果进程未响应,则其 Responding 属性为 False。 -not 运算符将结果更改为 True,这会使进程被传递到管道中,并包含在命令的最终输出中。
高级筛选不受简单筛选限制
现在再去根据字符长度来筛选就没问题了
powershell
Get-Service | Where {$PSItem.Name.Length --gt 8}

优化筛选器性能
说是优化,但其实都是靠编写脚本自己的功底
Get-随便
对于下面两个示例,你认为哪一个速度更快?
powershell
Get-随便 | Sort-Object --Property Letter | Where-Object --FilterScript { $PSItem.Color --eq 'Red' }
Get-随便 | Where-Object --FilterScript { $PSItem.Color --eq 'Red' } | Sort-Object --Property Letter
第二个命令速度更快,因为他先是移除了不要的再进行排序,这加速了排序,但是如果你排序了再移除就表示你排序排了没用的东西,然后还要移除,那就慢了。
再比如下面这个查找文件,一看就知道是第二个块了,内置的直接使用更快
powershell
Get-ChildItem | Where { -not $PSItem.PSIsContainer }
Get-ChildItem -File
枚举
这里的枚举是说powershell取出来的对象在管道中每一个都传递给下一个cmdlet去操作。
比如:停止计算机上每个正在运行的记事本进程,则可以运行以下两个命令之一
powershell
Get-Process --Name Notepad | Stop-Process
Stop-Process --Name Notepad
比如Get-Process 筛选了名字为Notepad的,那就可能会出现很多个进程,那给到管道后面的Stop-Process来说,他就是在枚举每一个Notepad进程然后执行停止进程操作
枚举管道对象语法
这里官网分了基本语法和高级语法,但其实枚举管道都支持
基本和高级的区分就是:基本的不用脚本,高级的用脚本块
查看下ForEach-Object
的帮助文档:
可以看到有两个参数,一个是接脚本块的,一看就是高级用法
基本用法应该就是下面的-MemberName
指定属性或方法名的了
基本语法:
两个常见别名: ForEach 和 % 。 与 Where-Object 一样, ForEach-Object 具有基本语法和高级语法。
下面三个都一样,原理都是将Get-ChildItem取出来的对象 ([System.IO.FileInfo]
)进行For枚举出来然后参数-MemberName
就是取属性或者方法,那我们给的Encrypt
就是一个方法(加密),所以我们就相当于给当前遍历的对象执行了该方法,以此类推每一个对象都会执行一次。
powershell
Get-ChildItem --Path C:\Encrypted\ -File | ForEach-Object -MemberName Encrypt
# 使用了别名和忽略了参数
Get-ChildItem --Path C:\Encrypted\ -File | ForEach Encrypt
# 使用了别名和忽略了参数
Get-ChildItem --Path C:\Encrypted\ -File | % Encrypt
你可以特地去查看下是否有该方法:
powershell
Get-ChildItem | Get-Member -Name Encry*

高级语法:就是使用脚本块
使用高级语法加密一组文件
powershell
Get-ChildItem --Path C:\ToEncrypt\ -File | ForEach-Object --Process { $PSItem.Encrypt() }
范围运算符是两个句点 (..),中间没有空格,range 运算符生成从 1 到 3 的整数对象,这 3 个对象通过管道传递给 ForEach-Object,迫使脚本块运行 3 次
powershell
1..3 | ForEach-Object { Get-Random }
写入到文件
Out-File
就相当于cmd里面的文本重定向运算符 >
和 >>
,这些运算符可作为 Out-File 的别名,管道末尾的大于号 (> ) 将输出定向到文件,从而覆盖内容,两个连续的大于号 (>>) 将输出定向到文件,从而将输出附加到文件中已有的任何文本。
例如:
下面这个虽然说输出到csv文件,但其实就是文本格式输入进去,没有csv格式
powershell
Get-Service |
Sort-Object --Property Status, Name |
Select-Object --Property DisplayName,Status |
Out-File --FilePath ServiceList.csv
转换为其他形式的数据表示形式
PowerShell 使用两个不同的谓词进行转换: ConvertTo 和 Export
Csv
使用 ConvertTo 的命令(如 ConvertTo-Csv )接受来自管道的对象作为输入,并将转换后的数据作为输出生成到管道
切记:这个是将对象转换成了csv格式,但是你直接输入进文件可能会存在各种问题,比如ConvertTo-Csv
生成的 CSV 包含类型信息行(如 #TYPE System.ServiceProcess.ServiceController
),这不是标准 CSV 的一部分,可能会干扰某些应用程序的解析,这就需要Export-Csv
解决
powershell
Get-Service | ConvertTo-Csv | Out-File Services.csv
使用 Export(如 Export-Csv)的命令执行两项作:它会转换数据,然后将数据写入外部存储,例如磁盘上的文件
powershell
Get-Service | Export-Csv Services.csv
XML
ConvertTo-Clixml 和 Export-Clixml
Json
ConvertTo-Json 命令创建 JSON 格式的数据,必须使用 Out-File 或文本重定向运算符之一将 JSON 数据发送到文件
HTML
ConvertTo-Html 命令支持此功能,必须使用 Out-File 或其别名之一来定向输出。
ConvertTo-Html 创建编码为 HTML 的简单列表或表,您可以通过各种参数以有限的方式控制HTML格式,例如:
- ‑Head。 指定 HTML 头 节的内容。
- ---标题 。 设置 HTML 标题 标记的值。
- -PreContent。 定义应在表或列表输出之前显示的任何内容。
- -PostContent。 定义应在表或列表输出之后显示的任何内容。
其他输出选项
Out-*
命令的核心功能、常见参数和典型使用场景:
Cmdlet | 核心功能 | 常用参数 | 典型应用场景 |
---|---|---|---|
Out-Host |
将输出发送到主机(控制台)进行显示 | -Paging (强制分页显示) |
逐页查看长输出,避免滚动过快错过信息 |
Out-Printer |
将输出发送到打印机进行打印 | -Name (指定打印机名称) |
打印命令结果、报告或配置清单 |
Out-GridView |
在交互式表格窗口中显示输出,支持排序、筛选和复制 | -Title (设置窗口标题) |
可视化数据分析、快速筛选和分享信息,但无法直接保存 |
Out-Host:控制台输出管理
Out-Host
是 PowerShell 默认的输出方式,即直接将结果呈现在控制台。它的特殊之处在于你可以通过-Paging
参数手动控制输出分页-Paging
参数 :强制对输出进行分页,显示一页后暂停,按空格键查看下一页,按 Q 键退出- 与
more
命令的关系 :在 PowerShell 中,more
是一个内置函数,它本质上是Out-Host -Paging
的别名,两者功能相同
逐页查看系统进程列表
powershell
Get-Process | Out-Host -Paging
# 也可以使用更简洁的more
Get-Process | more
Out-Printer:打印输出
Out-Printer
允许你将命令的输出直接发送到打印机。- 默认行为 :不使用参数时,输出会发送到默认打印机
-Name
参数 :指定目标打印机的名称,打印机名称需与系统中安装的打印机名称匹配(可通过Get-Printer
cmdlet 查看所有可用打印机)
打印当前运行的进程列表到默认打印机
powershell
Get-Process | Out-Printer
将系统服务状态发送到特定打印机(假设打印机名为 "HP-LaserJet"):
powershell
Get-Service | Out-Printer -Name "HP-LaserJet"
打印到虚拟打印机 (如生成PDF):如果你安装了 Microsoft Print to PDF 这类虚拟打印机,也可以使用 -Name
参数指定它来生成PDF文件。
powershell
Get-Service | Where-Object {$_.Status -eq 'Running'} | Out-Printer -Name "Microsoft Print to PDF"
Out-GridView:交互式表格输出
Out-GridView
(通常简称 OGV )是一个非常强大的工具,它会在一个新窗口中以交互式表格的形式显示输出 。你可以:- 点击列名进行排序(升序/降序)。
- 使用顶部的筛选框对任何列进行筛选(支持包含、不包含等条件)。
- 选中行并复制(Ctrl+C),然后粘贴到 Excel 或其他应用程序中。
- 多选 (Ctrl+点击 或 Shift+点击)。
重要限制 :正如你所读到的,无法直接从 GridView 窗口保存数据 。你需要先通过复制粘贴,或在命令行中就使用Export-Csv
等命令保存数据。
可视化并筛选系统服务:
powershell
# 查看所有服务
Get-Service | Out-GridView
# 仅查看正在运行的服务,并自定义窗口标题
Get-Service | Where-Object Status -eq 'Running' | Out-GridView -Title "当前运行的服务"
# 结合筛选器:找出所有正在运行且名称中包含 "windows" 的服务
Get-Service | Where-Object { $_.Status -eq 'Running' -and $_.Name -like '*windows*' } | Out-GridView

在弹出的窗口中,你可以进一步点击"状态"列排序,或在"名称"列筛选器输入更多关键字。
分析进程资源占用:
powershell
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 | Out-GridView -Title "CPU占用最高的10个进程"
自定义列顺序 :如果你使用 Select-Object
选择并排序了属性,Out-GridView
会遵循这个顺序显示列
powershell
Get-Service | Select-Object Name, Status, DisplayName, StartType | Out-GridView
传递管道对象
管道传递数据可以有两种方式:ByValue 和 ByPropertyName
它们最根本的区别在于匹配的依据:
- ByValue :依据管道对象的整体类型进行匹配。
- ByPropertyName :依据管道对象的属性名称 进行匹配。
例如运行:Get-Help Stop-Process -Full
必须看输入支持哪种类型:那我们只能输入下面的这几种了
那既然我们要传数据给Stop-Process的话那我们就需要知道左边的那个输出符不符合这里面的输入,下面详细讲一下这个!
ByValue 传递数据
直接将String类型传给Get-Service
powershell
'BITS','WinRM' | Get-Service
是否成功前可以看下Get-Service接受哪些类型的管道输入
powershell
Get-Help Get-Service -Full

包含string那就可以传入了
但是这种就不行:
powershell
Get-LocalUser | Stop-Process
首先我们看下Stop-Process的接受类型
powershell
Get-Help Stop-Process -Full

接着再看Get-LocalUser的输出是否符合Stop-Process的输入类型
powershell
Get-Help Get-LocalUser -Full
下图可以看到明显不符合,输出的是Object,传到Stop-Process的时候就肯定报错了
如何解决?那就交给ByPropertyName,指定输出一个属性内容即可
ByPropertyName 传递数据
这里感觉没啥好说的,就是在ByValue不成立的时候,我们就需要特别指定某个属性给到下一个要执行的命令,但是前提是左边和右边的属性名字要相同,否则在匹配的时候就不知道该属性给哪个。
(有一个特殊情况就是希望将左边的A属性值传递给右边的B属性,两个名字不一样的时候就需要重命名)
重命名方式,这种就比较特殊
Get-Process
有一个参数-ComputerName
,它支持通过 ByPropertyName 接收输入。- 但
Get-ADComputer
返回的计算机对象有一个叫Name
的属性,没有叫ComputerName
的属性。 - 因此,
Name
属性无法自动传递给-ComputerName
参数
这样就需要重命名了:
powershell
Get-ADComputer -Filter * | Select-Object @{Name='ComputerName'; Expression={$_.Name}} | Get-Process
若是说在 ByPropertyName 的时候,两边的属性名相同那就会自动匹配去执行操作了(这种就不详细说了)
展开属性值
先看一个动作:
powershell
Get-Process --ComputerName (Get-LocalUser --Filter *)
这个是想要将Get-LocalUser给到Get-Process的ComputerName参数
先看Get-Process的ComputerName接受什么输入
powershell
Get-Help Get-Process -Full
可以看到只接受string类型,那我们直接将整个Get-LocalUser东西穿进去肯定不行
再看看这样行不行
回答:看似可以,其实也不行
powershell
Get-Process --ComputerName (Get-LocalUser --Filter * | Select-Object --Property Name)
我们要看这个--Property Name输出的到底是不是string
powershell
$(Get-LocalUser | Select-Object --Property Name -First 1).GetType()
查看后发现还是不是string,那这时候就需要用到展开属性的操作了
其实就是改了个参数名:
将Property改为ExpandProperty,下面这样就可以了
powershell
$(Get-LocalUser | Select-Object --ExpandProperty Name -First 1).GetType()
为什么可以,我们直接看下取出来的Name是不是string即可
复习提问:
在命令行接口将对象从一个命令传递到管道中的另一个命令时,Windows PowerShell 总是优先尝试使用哪种技术?
powershell
ByValue
深入了解Powershell脚本
开发生命周期与安全强化
PowerShellGet 模块
Cmdlet | 说明 |
---|---|
Find-Module | 使用此 cmdlet 在 PowerShell 库中搜索 Windows PowerShell 模块。 最简单的用法是根据模块名进行搜索,但也可以根据命令名、版本、DscResource 和 RoleCapability 进行搜索。 |
Find-Script | 使用此 cmdlet 在 PowerShell 库中搜索 Windows PowerShell 脚本。 最简单的用法是根据脚本名进行搜索,但也可以根据版本进行搜索。 |
PowerShell 库需要使用传输层安全性 (TLS) 1.2 来帮助保护通信。 默认情况下,Windows 10 和 Windows Server 2016 不支持在 Windows PowerShell 中使用 TLS 1.2。 因此,需要启用 TLS 1.2 才能下载 PowerShell 库内容。 |
若要为当前 PowerShell 提示启用 TLS 1.2,请运行以下命令:
powershell
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
若要在计算机上永久解决此问题,需要创建注册表项。 可以运行以下两个命令来创建必要的密钥:
powershell
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319'-Name 'SchUseStrongCrypto' -Value '1' -Type DWord
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
执行策略
确保当前配置,可以使用:Get-ExecutionPolicy
执行策略的选项包括:
- Restricted:不允许运行任何脚本。
- AllSigned:仅当脚本经过数字签名后才能运行。
- RemoteSigned:下载的脚本只有在经过数字签名后才能运行。
- Unrestricted:可以运行所有脚本,但在运行下载但未签名的脚本时会显示确认提示。
- Bypass:运行所有脚本且不显示提示。
以数字方式对脚本进行签名
使用现有的代码签名证书(如果你有)
如果你已经从公共证书颁发机构(CA)或企业的内部CA获取并安装了代码签名证书,可以用以下命令查找:
powershell
# 在当前用户的证书存储中查找所有可用于代码签名的证书
$certs = Get-ChildItem -Path "Cert:\CurrentUser\My" -CodeSigningCert
# 如果你确定只有一个,可以直接赋值
$cert = Get-ChildItem -Path "Cert:\CurrentUser\My" -CodeSigningCert
Cert:\CurrentUser\My
是 PowerShell 证书驱动器(PSDrive)中的一个路径,指向当前用户的"个人"证书存储区域。-CodeSigningCert
参数是Get-ChildItem
在证书驱动器中专用的,用于筛选出具有"代码签名"用途的证书。
创建自签名证书(用于测试和学习)
在生产环境中,你需要一个受信任的CA颁发的证书。但在测试和学习时,可以快速创建一个自签名证书
powershell
# 以管理员身份运行 PowerShell 执行以下命令
$certParams = @{
Type = 'CodeSigningCert'
Subject = 'CN=PowerShell Scripting Test' # 证书主题,CN是通用名
KeyUsage = 'DigitalSignature' # 密钥用法:数字签名
KeyExportPolicy = 'Exportable' # 密钥可导出,方便备份和转移
CertStoreLocation = 'Cert:\CurrentUser\My' # 证书存储位置
HashAlgorithm = 'sha256' # 哈希算法
# FriendlyName 是可选的,便于在证书管理中识别
FriendlyName = 'My PowerShell Test Signing Certificate'
}
$cert = New-SelfSignedCertificate @certParams
重要提示 :自签名证书仅用于测试 。因为它不是由受信任的根证书颁发机构颁发的,所以其他计算机默认不会信任它。
(你自己创建的,你自己使用的时候就导入即可,不用设置密码啥的,因为是你自己创建你自己用,除非你导出的时候就要设置密码,因为你导出肯定是要给其他计算机使用)
从证书文件导入
如果你有 .pfx
或 .p12
格式的证书文件(通常包含私钥),可以使用 Get-PfxCertificate
cmdlet 来加载它:
powershell
# 会弹窗提示输入密码
$cert = Get-PfxCertificate -FilePath "C:\Path\To\Your\CodeSigningCert.pfx"
# 或者使用SecureString自动输入密码(注意密码安全)
$securePassword = ConvertTo-SecureString -String "YourCertificatePassword" -Force -AsPlainText
$cert = Get-PfxCertificate -FilePath "C:\Path\To\Your\CodeSigningCert.pfx" -Password $securePassword
加载的时候需要密码,这需要在证书持有者导出证书的时候设置的那个密码,然而这个pdx或者p12文件是用来签名的,不是用来验证的,用来验证的那个是cert,这也是为啥要输入密码的原因了,这个证书是拿来公章签名的。
拿到证书对象($cert
)后,就可以用它来签名脚本了。官网的例子是基础,但强烈建议添加时间戳服务器参数。
powershell
# 基础签名(官网示例)
Set-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1" -Certificate $cert
# 推荐的签名方式(添加时间戳)
$signParams = @{
FilePath = "C:\Scripts\MyScript.ps1" # 要签名的脚本路径
Certificate = $cert # 之前获取的证书对象
HashAlgorithm = 'Sha256' # 哈希算法,建议使用Sha256
# 添加时间戳至关重要!即使证书过期,时间戳也能证明签名时证书是有效的。
TimestampServer = 'http://timestamp.digicert.com'
# -IncludeChain 参数可选,默认是 'NotRoot'(包含除根CA以外的所有证书)
# -Force 参数可选,如果脚本已有签名,强制替换
}
Set-AuthenticodeSignature @signParams
签名完成后,务必检查一下:
powershell
Get-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1"
查看输出中的 Status
属性:
Valid
:签名有效且受信任。UnknownError
:签名无效或证书不受信任(常见于自签名证书)。NotSigned
:脚本未签名。
让系统信任你的签名
!!!!!记住这里是验证,不是用来签名,前面说的都是pxf和p12证书,这里讲的是cer文件!!!!!!!!
对于自签名证书 ,由于它不是公共CA颁发的,你需要将你的自签名证书**导入到"受信任的根证书颁发机构"或"受信任的发布者"存储区。否则,在其他计算机上运行时会显示 UnknownError
。
- 将你的证书导出为
.cer
文件(只包含公钥)。 - 在需要运行此脚本的计算机上,将这个
.cer
文件导入到"受信任的根证书颁发机构 "或"受信任的发布者 "(对于代码签名证书,通常是"受信任的发布者")。
你可以使用 PowerShell 自动化导入信任证书的过程
powershell
$certPath = "C:\Path\To\Exported\Certificate.cer"
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("TrustedPublisher", "LocalMachine")
$store.Open("ReadWrite")
$store.Add((New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath)))
$store.Close()
进阶语法
ForEach 循环
在某些情况下,可能需要使用 ForEach-Object cmdlet 来处理管道中的数据。 将数据存储在数组中时,ForEach 构造支持处理数组中的每个项。
powershell ForEach ($user in $users) { Set-ADUser $user -Department "Marketing" }
在 PowerShell 7 中,已将 -Parallel 参数添加到 ForEach-Object cmdlet。 这样,管道就可以同时处理多个对象。 相较于标准 ForEach 循环,同时处理多个对象所提供的性能更佳。 如果使用的是 PowerShell 7,应考虑这一点。 以下示例说明了如何将 ForEach-Object 与 -Parallel 参数配合使用。
powershell
$users | ForEach-Object -Parallel { Set-ADUser $user -Department "Marketing" }
默认情况下,-Parallel 参数支持一次处理五个项,可以使用 -ThrottleLimit 参数将其修改为更大或更小的值。
If 构造
举例子:如果可用磁盘空间不足,则可以使用 If 语句显示警告
powershell
If ($freeSpace -le 5GB) {
Write-Host "Free disk space is less than 5 GB"
} ElseIf ($freeSpace -le 10GB) {
Write-Host "Free disk space is less than 10 GB"
} Else {
Write-Host "Free disk space is more than 10 GB"
}
同时也学到大小是可以直接使用MB、GB等单位直接比较
Switch 构造
powershell
Switch ($choice) {
1 { Write-Host "You selected menu item 1" }
2 { Write-Host "You selected menu item 2" }
3 { Write-Host "You selected menu item 3" }
Default { Write-Host "You did not select a valid option" }
}
可以使用 -wildcard 参数,以与 -like 运算符相同的语法来执行模式匹配。 或者,可以使用 -regex 参数通过正则表达式执行匹配。
powershell
Switch -WildCard ($ip) {
"10.*" { Write-Host "This computer is on the internal network" }
"10.1.*" { Write-Host "This computer is in London" }
"10.2.*" { Write-Host "This computer is in Vancouver" }
Default { Write-Host "This computer is not on the internal network" }
}
For 构造
powershell
For($i=1; $i -le 10; $i++) {
Write-Host "Creating User $i"
}
处理对象数组时,最好使用 ForEach 构造,因为在处理之前不需要计算数组中的项数。
其他循环构造
Do..While
Do..While 构造运行脚本块,直到指定条件为false
此构造保证脚本块至少运行一次
powershell
Do {
Write-Host "Script block to process"
} While ($answer -eq "go")
Do..Until
Do..Until 构造运行脚本块,直到指定条件为 true
此构造保证脚本块至少运行一次
powershell
Do {
Write-Host "Script block to process"
} Until ($answer -eq "stop")
While
While 构造运行脚本块,直到指定条件为 false
虽然它类似于 Do..While 构造,但它不能保证脚本块的运行
powershell
While ($answer -eq "go") {
Write-Host "Script block to process"
}
Break 和 Continue
使用 Continue 可阻止修改要修改的用户列表中的管理员用户帐户:
powershell
ForEach ($user in $users) {
If ($user.Name -eq "Administrator") {Continue}
Write-Host "Modify user object"
}
Break 用于在最大帐户数已修改时结束循环:
powershell
ForEach ($user in $users) {
$number++
Write-Host "Modify User object $number"
If ($number -ge $max) {Break}
}
导入数据
Get-Content
直接读取文件内容进来
powershell
$computers = Get-Content C:\Scripts\computers.txt
可在 Get-Content 的路径中使用通配符,以便一次获得多个文件的数据
可使用 -Include 和 -Exclude 参数修改所选文件
powershell
Get-Content -Path "C:\Scripts\*" -Include "*.txt","*.log"
可以使用 -TotalCount 和 -Tail 参数限制使用 Get-Content 检索的数据量
- -TotalCount 参数指定应从文件开头检索多少行
- -Tail 参数指定从文件末尾检索多少行
例如:
powershell
Get-Content C:\Scripts\computers.txt -TotalCount 10
Import-Csv
powershell
$users = Import-Csv C:\Scripts\Users.csv
输出示例:
powershell
First,Last,UserID,Department
Amelie,Garner,AGarner,Sales
Evan,Norman,ENorman,Sales
Siu,Robben,SRobben,Sales
当我们存进一个变量后,也可以通过变量访问某个数据
powershell
$users[2].UserID
Import-Csv 默认分隔符是逗号,有的文件不是以逗号进行分割的话你也可以使用Import-Csv,只要格式相同分隔符不同也可以用这个,前提是你要自己加参数去修改分隔符:
比如说分隔符是分号
powershell
Import-Csv -Path .\1.csv -Header h1,h2,h3 -Delimiter ';'

Import-Clixml
powershell
$users = Import-Clixml C:\Scripts\Users.xml
使用 -First 和 -Skip 参数来限制 Import-Clixml 检索的数据
- -First 参数指定仅从 XML 文件的开头检索指定数量的对象
- -Skip 参数指定从 XML 文件开头忽略指定数量的对象,并检索所有剩余的对象。
ConvertFrom-Json
powershell
$users = Get-Content C:\Scripts\Users.json | ConvertFrom-Json
Invoke-RestMethod
Invoke-RestMethod 能够处理JSON、 XML、RSS 源和 ATOM 源。
powershell
$users = Invoke-RestMethod "https://hr.adatum.com/api/staff"
接受用户输入
Read-Host
这种会在How many das后加上冒号然后提示用户输入:
powershell
$answer = Read-Host "How many days"
下面这种会先打印How many days? ,-NoNewline就是不换行,然后也是等待用户输入
这种就没有冒号
powershell
Write-Host "How many days? " -NoNewline
$answer = Read-Host
-MaskInput 或 -AsSecureString 参数在提示符处屏蔽输入用户,这种偏向于输入密码的时候不会直接显示在终端上
powershell
$answer = Read-Host "How many days" -AsSecureString
具体使用哪个看情况了,我的电脑使用AsSecureString才行
Credential凭证使用
Get-Credential
它的核心作用就是安全地弹窗收集用户凭据(用户名和密码) ,并将其封装在一个 PSCredential
对象中,供其他需要凭据的 cmdlet 使用。
基础用法:
这会弹出一个标准对话框,让你输入用户名和密码。
powershell
$cred = Get-Credential
高级用法(自定义提示和用户名):
-Message
:让提示更清晰,指导用户输入什么凭据。-UserName
:预填用户名字段,用户只需要输入密码即可。$env:COMPUTERNAME
是环境变量,代表本机计算机名,这在工作组环境下至关重要。
powershell
# 自定义提示信息并预填用户名
$cred = Get-Credential -Message "请输入本地管理员权限凭据" -UserName "$env:COMPUTERNAME\Administrator"
远程管理另一台工作组计算机
假设你想从计算机 CLIENT-A
远程管理计算机 CLIENT-B
powershell
# 在 CLIENT-A 上运行
# 1. 获取 CLIENT-B 的本地管理员凭据
$cred = Get-Credential -Message "请输入CLIENT-B的本地管理员凭据" -UserName "CLIENT-B\Administrator"
# 2. 建立远程会话 (PSRemoting)
$session = New-PSSession -ComputerName "CLIENT-B" -Credential $cred
# 3. 在远程会话中执行命令(例如:检查磁盘空间)
Invoke-Command -Session $session -ScriptBlock { Get-Volume }
# 4. 关闭会话
Remove-PSSession $session
本地脚本临时提权
你用自己的标准用户账户登录,但脚本中的某些操作(如修改系统设置)需要管理员权限。
powershell
# 检查当前用户权限,如果不是管理员则请求凭据
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Warning "此操作需要管理员权限。"
$adminCred = Get-Credential -Message "请提供本地管理员密码以继续" -UserName "$env:COMPUTERNAME\Administrator"
# 使用 Start-Process 以管理员身份启动一个新进程来运行命令
$scriptBlock = {
# 这里放需要提权的命令,例如安装Windows功能
Enable-WindowsOptionalFeature -Online -FeatureName "Microsoft-Hyper-V" -All
}
Start-Process "pwsh" -ArgumentList "-Command", $scriptBlock -Credential $adminCred -Wait -NoNewWindow
} else {
# 如果已经是管理员,直接执行命令
Enable-WindowsOptionalFeature -Online -FeatureName "Microsoft-Hyper-V" -All
}
访问受保护的网络共享
挂载一个需要特定用户名和密码才能访问的局域网共享文件夹。
powershell
$netCred = Get-Credential -Message "请输入访问共享\\FileServer\Data$的凭据" -UserName "FileServer\SomeUser"
# 将凭据映射到驱动器号
New-PSDrive -Name "Z" -PSProvider "FileSystem" -Root "\\FileServer\Data$" -Credential $netCred -Persist
# 现在可以像访问本地磁盘一样访问 Z:\
Get-ChildItem Z:\
# 使用完毕后断开
Remove-PSDrive -Name "Z"
Export-Clixml
首次保存凭据(在一台电脑上):
powershell
# 弹窗输入一次凭据
$cred = Get-Credential -Message "输入要保存的凭据" -UserName "MyPC\Admin"
# 将加密后的凭据保存到文件(只能由你在本机解密)
$cred | Export-Clixml -Path "C:\Users\$env:USERNAME\Documents\secureCred.xml"
后续脚本中自动使用保存的凭据:
powershell
# 无需弹窗,直接读取加密文件获取凭据对象
$savedCred = Import-Clixml -Path "C:\Users\$env:USERNAME\Documents\secureCred.xml"
# 使用凭据执行需要权限的操作,例如重启远程计算机
Restart-Computer -ComputerName "192.168.1.100" -Credential $savedCred -Force
脚本故障排除与错误处理
错误发生时,它们将存储在 $Error
数组中。 最近的错误始终在索引零处。 新错误生成时,会插入到 $Error[0]
处,其他错误的索引将增加一。 每当需要查看以前的错误消息时,查看 $Error
中的错误会很有帮助。 例如,如果清除屏幕,则可以通过 $Error
查看最近的错误消息。
输出命令的层次与用途
PowerShell 的输出命令不是一个简单的"打印"功能,而是一个完整的信息流系统。理解不同命令的定位是关键。
命令 | 用途 | 输出位置 | 是否受 *Preference 变量影响 |
适用场景 |
---|---|---|---|---|
Write-Host |
直接与用户交互 | 控制台 (主机) | 否 | 显示进度、美观的标题、即时提示。谨慎使用。 |
Write-Output |
将对象放入输出管道 | 管道 / 控制台 | 否 | 脚本的主要输出结果。通常隐式使用(如 "Hello" )。 |
Write-Verbose |
输出详细信息 | 控制台 ( verbose流) | 是 | 调试、记录脚本执行的详细步骤。 |
Write-Debug |
输出调试信息 | 控制台 (debug流) | 是 | 更深入的调试,可在运行时暂停脚本。 |
Write-Warning |
输出警告信息 | 控制台 (warning流) | 是 | 提示用户潜在的问题,但脚本会继续执行。 |
Write-Error |
输出错误信息 | 控制台 (error流) | 是 | 报告错误,但不终止脚本执行。 |
Throw |
抛出终止错误 | 控制台 (error流) | - | 报告严重错误,并立即终止当前函数/脚本。 |
Write-Verbose
和 Write-Debug
:真正的调试利器
这两个命令的强大之处在于它们的可控性 。默认情况下它们是静默的,只在需要时通过参数开启。
示例脚本 (Test-Service.ps1
):
powershell
[CmdletBinding()] # 启用高级功能,支持 -Verbose 和 -Debug 参数
param (
[Parameter(Mandatory=$true)]
[string]$ServiceName
)
Write-Verbose "脚本开始执行,传入的服务名参数为: $ServiceName"
# 检查服务是否存在
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
Write-Debug "Get-Service 查询结果: $($service | Out-String)"
if (-not $service) {
Write-Error "错误: 找不到名为 '$ServiceName' 的服务。"
exit 1
}
Write-Verbose "服务状态: $($service.Status)"
if ($service.Status -ne 'Running') {
Write-Warning "服务 '$ServiceName' 当前未运行。"
# 尝试启动服务
try {
Start-Service -Name $ServiceName
Write-Host "服务已成功启动。" -ForegroundColor Green
}
catch {
Throw "启动服务失败: $($_.Exception.Message)"
}
} else {
Write-Output "服务 '$ServiceName' 正在运行。"
}
Write-Verbose "脚本执行完毕。"
如何使用这个脚本:
- 默认运行(只看到基本输出):
powershell
.\Test-Service -ServiceName "WinRM"
# 输出: 服务 'WinRM' 正在运行。
- 查看详细信息(使用
-Verbose
):
powershell
.\Test-Service -ServiceName "WinRM" -Verbose
# 输出:
# 详细: 脚本开始执行,传入的服务名参数为: WinRM
# 详细: 服务状态: Running
# 服务 'WinRM' 正在运行。
# 详细: 脚本执行完毕。
- 进行深度调试(使用
-Debug
):
powershell
.\Test-Service -ServiceName "SomeService" -Debug
运行后会首先显示 Write-Debug
的信息,并暂停,提示你:
text
调试: Get-Service 查询结果:
(这里会显示Get-Service返回的详细对象信息)
继续执行?
[Y] 是(Y) [A] 全是(A) [N] 否(N) [L] 全否(L) [S] 暂停(S) [?] 帮助 (默认值为"Y"):
按 `Y` 继续执行每一步,按 `A` 让它自动执行完所有调试步骤。这让你可以一步步观察脚本的执行流程。
使用 $VerbosePreference
和 $DebugPreference
进行全局控制
在当前会话中开启所有Verbose输出:
powershell
$VerbosePreference = "Continue" # 默认是 "SilentlyContinue"
.\Test-Service -ServiceName "WinRM"
# 现在即使不加 -Verbose,也会输出Verbose信息
在脚本开头强制开启调试(常用于日志记录):
powershell
[CmdletBinding()]
param()
# 在脚本内部设置,强制记录详细信息到日志文件
$VerbosePreference = "Continue"
Write-Verbose "$(Get-Date): 脚本启动..."
# ... 脚本逻辑 ...
脚本中使用断点
根据行进行断点
可使用 Set-PSBreakPoint cmdlet 设置断点
可以基于脚本行、正在使用的特定命令或正在使用的特定变量来设置断点
以下示例描述如何在脚本的特定行处设置断点:
powershell
Set-PSBreakPoint -Script "MyScript.ps1" -Line 23
根据命令进行断点
powershell
Set-PSBreakPoint -Command "Set-ADUser" -Script "MyScript.ps1"
基于命令设置断点时,可以包含通配符。 例如,可以使用值 *-ADUser 为 Get-ADUser、Set-ADUser、New-ADUser 和 Remove-ADUser 触发断点。
根据特定变量进行断点
powershell
Set-PSBreakPoint -Variable "computer" -Script "MyScript.ps1" -Mode ReadWrite
可以使用变量的 -Mode 参数来确定是否要在读取和/或写入变量值时中断。 有效值为 Read、Write 和 ReadWrite。
以上是终端中运行脚本的时候设置的断点,其实我们可以用:
- Powershell ISE 图形化工具进行根据行去断点
- VScode 中也能够进行更多高级的断点方式
错误操作
$ErrorActionPreference
内置全局变量。 当命令生成非终止错误时,命令会检查此变量来决定该执行的操作
变量可具有下面 4 个可能值之一:
- Continue 是默认值,它告知命令显示错误消息并继续运行。
- SilentlyContinue 告知命令不显示错误消息,但要继续运行。
- Inquire 告知命令显示提示,询问用户要做什么。
- Stop 告知命令将错误视为终止错误并停止运行。
若要设置 $ErrorActionPreference
变量,请使用以下语法:
powershell
$ErrorActionPreference = 'Inquire'
-ErrorAction
所有 Windows PowerShell 命令都有 --ErrorAction 参数。 此参数具有别名 --EA
当你使用他的时候,会覆盖$ErrorActionPreference
但可以设置一样的类型,该参数仅针对当前使用的cmdlet
函数与模块
有参函数:
powershell
Function Get-SecurityEvent {
Param (
[string]$ComputerName
) #end Param
Get-EventLog -LogName Security -ComputerName $ComputerName -Newest 10
}
无参函数就很简单了,不写接受参数的变量即可
函数调用如下:
powershell
Get-SecurityEvent -ComputerName LON-DC1
变量范围
使用范围修饰符 (Scope Modifiers) 指定目标作用域
这是修改其他作用域中变量的关键方法。通过在变量名前加修饰符来指定目标作用域
修饰符 | 作用 | 语法示例 | 说明 |
---|---|---|---|
$global: |
修改全局作用域中的变量。 | $global:MyVariable = "新值" |
在任何地方(函数、脚本)都能访问和修改这个全局变量。慎用,容易造成污染。 |
$script: |
修改脚本作用域中的变量。 | $script:MyVariable = "新值" |
在当前脚本文件的任何函数内部修改在脚本顶层定义的变量。这是最常用、最安全的方式。 |
$using: |
在远程命令或脚本块中引用当前局部作用域的变量。 | Invoke-Command { ... -Name $using:LocalVar } |
用于将本地变量的值传递到远程会话或新脚本块中,而不是在远程会话中修改它。 |
$private: |
在当前作用域创建变量,且该变量不会传递到更高级的作用域。 | $private:TempVar = "值" |
用于限制变量范围,确保其不会影响父作用域。较少用。 |
示例:
假设您在脚本顶层定义了 $configPath
,现在需要在一个函数里修改它:
Set-Variable指定作用域
powershell
Set-Variable -Name "MyVariable" -Value "新的值" -Scope <ScopeName>
-Scope
参数值:
'Global'
: 修改全局作用域。'Script'
: 修改脚本作用域。'Local'
: 修改当前局部作用域(默认值)。'Private'
: 修改为私有作用域。
绝大多数情况下,您应该使用 $script:
修饰符
这是在函数内修改脚本级变量的最标准、最可读且副作用最小的方式。
类似指针修改
使用[ref]
去拿到真实的那个变量在函数里面去修改,而不是说每次修改的都是函数内部接受到的值,他会直接影响到函数外部那个传进来的变量的值
powershell
function Modify-ByReference {
param (
[ref]$RefValue
)
$RefValue.Value = "在函数内部被修改了" # 注意:是修改 .Value 属性
}
$OriginalVariable = "原始值"
Modify-ByReference -RefValue ([ref]$OriginalVariable)
Write-Host $OriginalVariable # 输出:在函数内部被修改了
但是我们是避免这样去修改变量的,要改的话最好是通过return
返回值,然后在函数外部去改变某个变量
return
好像没啥好说的,就是return值
powershell
function xxx{
xxx
return($var) # return "xxx" return $var
}
$ch = xxx()
创建模块
你必须创建与该文件同名的子文件夹,并将文件放在该子文件夹中
例如,如果你有一个名为 AdatumFunctions.psm1
的模块,
则将其放置在 C:\Program Files\WindowsPowerShell\Modules\AdatumFunctions
中。