目录
- PowerShell 管道
- 管道输出
- 控制管道输出的格式设置
- Format-List
- Format-Table
- Format-Wide
- 管道选择、排序和度量对象
- 排序和分组
- Sort-Object
- Format 的 GroupBy分组
- 度量管道中的对象
- Select-Object
- Unique去重
- Property
- 自定义属性并设置表达式与格式
- 从管道中筛选对象
- 比较运算符
- 基本筛选器语法
- 高级筛选器语法
- 组合多个条件
- True 或 False 的属性筛选使用技巧
- 高级筛选不受简单筛选限制
- 优化筛选器性能
- 枚举
- 传递管道对象
- ByValue 传递数据
- ByPropertyName 传递数据
- 展开属性值
- 深入了解Powershell脚本
- 开发生命周期与安全强化
- PowerShellGet 模块
- 执行策略
- 以数字方式对脚本进行签名
- 进阶语法
- ForEach 循环
- If 构造
- Switch 构造
- For 构造
- 其他循环构造
- Do..While
- Do..Until
- While
- Break 和 Continue
- 导入数据
- Get-Content
- Import-Csv
- Import-Clixml
- ConvertFrom-Json
- Invoke-RestMethod
- 接受用户输入
- Credential凭证使用
- Get-Credential
- Export-Clixml
- 脚本故障排除与错误处理
- 输出命令的层次与用途
- 脚本中使用断点
- 根据行进行断点
- 根据命令进行断点
- 根据特定变量进行断点
- 错误操作
- 函数与模块
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列进行展示- Get-Service | fw -Property Name -Column 3
复制代码 管道选择、排序和度量对象
排序和分组
Sort-Object
Sort-Object 命令接受一个或多个属性名作为排序依据, 默认情况下,命令按升序排序- 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参数- 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递归读取)- Get-ChildItem -File -Recurse | Measure -Property Length -Sum -Average -Minimum -Max
复制代码 效果如下图:
Select-Object
- Select-Object 命令具有别名 Select。
复制代码 这个命令比较简单,用法如下:
用Property指定要选择的对象即可,多个就用逗号隔开- Get-Process | Select-Object -Property 列名1,列名2
复制代码- Get-Process | Sort-Object –Property VM | Select-Object –First 10
复制代码- Get-Service | Sort-Object –Property Name | Select-Object –Last 10
复制代码
- 选择 CPU 用量最少的五个进程,并跳过使用最少 CPU 的那一个进程
- Get-Process | Sort-Object –Property CPU –Descending | Select-Object –First 5 –Skip 1
复制代码 Unique去重
只需要在指定对象后添加多一个-Unique参数即可
- Get-ADUser -Filter * -Property Department | Sort-Object -Property Department | Select-Object Department -Unique
复制代码 Property
没啥好说的,就是select-object 的 参数Property 指定显示的进程属性即可
- 显示一个表,其中包含本地计算机上运行的所有进程的名称、进程 ID、虚拟内存大小、分页内存大小和 CPU 使用率:
- Get-Process | Select-Object –Property Name,ID,VM,PM,CPU | Format-Table
复制代码
- -Property 参数适用于 -First 或 -Last 参数。 以下命令返回具有最大 CPU 使用率的 10 个进程的名称和 CPU 使用率:
- 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:这将指定设置计算属性值的表达式。
- 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- 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去取你想要的属性或者激活方法)- Get-Process |
- Select-Object Name,
- ID,
- @{n='VirtualMemory(MB)';e={$PSItem.VM / 1MB}},
- @{n='PagedMemory(MB)';e={$PSItem.PM / 1MB}}
复制代码 生成的值有几个小数位,这在视觉上是不理想的。
若要改进输出,请进行以下更改:- 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] }}
复制代码 上一个示例中的语法可能看起来令人困惑,因为它包含许多标点符号。 从基本表达式开始:- '{0:N2}' –f ($PSItem.VM / 1MB)
复制代码 上一个表达式将 VM 属性除以 1 MB,然后将结果格式化为最多两个小数位的数字。 然后将该表达式放入哈希表中:
该哈希表创建名为 VirtualMemory(MB) 的自定义属性。- @{n='VirtualMemory(MB)';e={'{0:N2}' –f ($PSItem.VM / 1MB) }}
复制代码 从管道中筛选对象
比较运算符
操作DESCRIPTION-eq等于-ne不等于-gt大于-lt小于-le小于或等于-ge大于或等于在powershell中默认是不区分大小写,但是在比较的时候难免希望对大小写的区分
所以我们可以在操作中添加一个前缀c作为比较区分大小写的标志- -ceq
- -cne
- 不仅仅上述的运算符,其他也都可以加c
- 当然还有like也可以用来区分大小写去匹配,因为-like 运算符类似于 -eq
- -clike
复制代码 其他更高级的运算符存包括:
- -in 和 -contains 运算符,用于测试集合中是否存在对象。
- -as 运算符,用于测试对象是否为指定类型。
- 将字符串与正则表达式进行比较的 -match 和 -cmatch 运算符。
- 还包含许多运算符来反转比较的逻辑,例如 -notlike 和 -notin。
简单案例:- PS C:\> 100 -gt 10
- True
- PS C:\> 'hello' -eq 'HELLO'
- True
- PS C:\> 'hello' -ceq 'HELLO'
- False
复制代码 基本筛选器语法
Where-Object 命令及其别名 Where
- Get-Service | Where Status –eq Running
复制代码 基本语法的限制
只能对单个比较使用基本语法。 例如,无法显示已停止且具有“自动”启动模式的服务列表,因为需要两个比较。
不能将基本语法用于复杂表达式。 例如,服务对象的 Name 属性由一串字符组成。 PowerShell 使用 System.String 对象包含该串字符,而 System.String 对象具有 Length 属性。 以下命令不适用于基本筛选语法:- Get-Service | Where Name.Length –gt 5
复制代码 目的是显示名称超过五个字符的所有服务。 但是,此命令永远不会生成输出。 一旦超过基本语法的能力,必须改用高级筛选语法。
高级筛选器语法
高级语法使用筛选器脚本
使用 -FilterScript 参数传递该脚本块
对于通过管道传递到命令的每个对象,筛选器脚本都会运行一次。 当筛选器脚本返回 True 时,该对象将作为输出传递到管道中,当筛选器脚本返回 False 时,将从管道中删除该对象。
以下两个命令具有相同的功能。 第一个命令使用基本语法,第二个命令使用高级语法执行相同的操作:- 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 中只允许使用 $_。
以下命令执行与前两个命令相同的任务:- Get-Service | Where {$PSItem.Status –eq 'Running'}
- Get-Service | ? {$_.Status –eq 'Running'}
复制代码 组合多个条件
高级语法允许通过使用 -and 和 -or 布尔值或逻辑运算符来组合多个条件。 下面是一个示例:- Get-EventLog –LogName Security –Newest 100 |
- Where { $PSItem.EventID –eq 4672 –and $PSItem.EntryType –eq 'SuccessAudit' }
复制代码 逻辑运算符的任意一侧都必须是一个完整的比较式子,下面给几个错误示范,请不要犯错:- 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。
获取正在响应的进程的列表,可以使用以下命令之一:- Get-Process | Where { $PSItem.Responding –eq $True }
- Get-Process | Where { $PSItem.Responding }
复制代码 在第一个命令中,特殊 shell 变量 $True 用于表示布尔值 True。 第二个命令未包含任何比较,但它是有效的,因为 Responding 属性已包含 True 或 False
这类似于反向逻辑,仅列出未响应的进程:- Get-Process | Where { -not $PSItem.Responding }
复制代码 在前面的示例中,-not 逻辑运算符将 True 更改为 False,并将 False 更改为 True。 因此,如果进程未响应,则其 Responding 属性为 False。 -not 运算符将结果更改为 True,这会使进程被传递到管道中,并包含在命令的最终输出中。
高级筛选不受简单筛选限制
现在再去根据字符长度来筛选就没问题了- Get-Service | Where {$PSItem.Name.Length –gt 8}
复制代码
优化筛选器性能
说是优化,但其实都是靠编写脚本自己的功底
Get-随便 对于下面两个示例,你认为哪一个速度更快?- Get-随便 | Sort-Object –Property Letter | Where-Object –FilterScript { $PSItem.Color –eq 'Red' }
- Get-随便 | Where-Object –FilterScript { $PSItem.Color –eq 'Red' } | Sort-Object –Property Letter
复制代码 第二个命令速度更快,因为他先是移除了不要的再进行排序,这加速了排序,但是如果你排序了再移除就表示你排序排了没用的东西,然后还要移除,那就慢了。
再比如下面这个查找文件,一看就知道是第二个块了,内置的直接使用更快- Get-ChildItem | Where { -not $PSItem.PSIsContainer }
- Get-ChildItem -File
复制代码 枚举
这里的枚举是说powershell取出来的对象在管道中每一个都传递给下一个cmdlet去操作。
比如:停止计算机上每个正在运行的记事本进程,则可以运行以下两个命令之一- 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就是一个方法(加密),所以我们就相当于给当前遍历的对象执行了该方法,以此类推每一个对象都会执行一次。- 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
复制代码 你可以特地去查看下是否有该方法:- Get-ChildItem | Get-Member -Name Encry*
复制代码
高级语法:就是使用脚本块
使用高级语法加密一组文件- Get-ChildItem –Path C:\ToEncrypt\ -File | ForEach-Object –Process { $PSItem.Encrypt() }
复制代码 范围运算符是两个句点 (..),中间没有空格,range 运算符生成从 1 到 3 的整数对象,这 3 个对象通过管道传递给 ForEach-Object,迫使脚本块运行 3 次- 1..3 | ForEach-Object { Get-Random }
复制代码 写入到文件
Out-File就相当于cmd里面的文本重定向运算符 > 和 >>,这些运算符可作为 Out-File 的别名,管道末尾的大于号 (>) 将输出定向到文件,从而覆盖内容,两个连续的大于号 (>>) 将输出定向到文件,从而将输出附加到文件中已有的任何文本。
例如:
下面这个虽然说输出到csv文件,但其实就是文本格式输入进去,没有csv格式- 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解决- Get-Service | ConvertTo-Csv | Out-File Services.csv
复制代码 使用 Export(如 Export-Csv)的命令执行两项作:它会转换数据,然后将数据写入外部存储,例如磁盘上的文件- 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 的别名,两者功能相同
逐页查看系统进程列表- Get-Process | Out-Host -Paging
- # 也可以使用更简洁的more
- Get-Process | more
复制代码 Out-Printer:打印输出
- Out-Printer 允许你将命令的输出直接发送到打印机。
- 默认行为:不使用参数时,输出会发送到默认打印机
- -Name 参数:指定目标打印机的名称,打印机名称需与系统中安装的打印机名称匹配(可通过 Get-Printer cmdlet 查看所有可用打印机)
打印当前运行的进程列表到默认打印机- Get-Process | Out-Printer
复制代码 将系统服务状态发送到特定打印机(假设打印机名为 "HP-LaserJet"):- Get-Service | Out-Printer -Name "HP-LaserJet"
复制代码 打印到虚拟打印机(如生成PDF):如果你安装了 Microsoft Print to PDF 这类虚拟打印机,也可以使用 -Name 参数指定它来生成PDF文件。- 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 等命令保存数据。
可视化并筛选系统服务:- # 查看所有服务
- 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
复制代码
在弹出的窗口中,你可以进一步点击“状态”列排序,或在“名称”列筛选器输入更多关键字。
分析进程资源占用:- Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 | Out-GridView -Title "CPU占用最高的10个进程"
复制代码 自定义列顺序:如果你使用 Select-Object 选择并排序了属性,Out-GridView 会遵循这个顺序显示列- 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- 'BITS','WinRM' | Get-Service
复制代码 是否成功前可以看下Get-Service接受哪些类型的管道输入- Get-Help Get-Service -Full
复制代码
包含string那就可以传入了
但是这种就不行:- Get-LocalUser | Stop-Process
复制代码 首先我们看下Stop-Process的接受类型- Get-Help Stop-Process -Full
复制代码
接着再看Get-LocalUser的输出是否符合Stop-Process的输入类型- Get-Help Get-LocalUser -Full
复制代码 下图可以看到明显不符合,输出的是Object,传到Stop-Process的时候就肯定报错了
如何解决?那就交给ByPropertyName,指定输出一个属性内容即可
ByPropertyName 传递数据
这里感觉没啥好说的,就是在ByValue不成立的时候,我们就需要特别指定某个属性给到下一个要执行的命令,但是前提是左边和右边的属性名字要相同,否则在匹配的时候就不知道该属性给哪个。
(有一个特殊情况就是希望将左边的A属性值传递给右边的B属性,两个名字不一样的时候就需要重命名)
重命名方式,这种就比较特殊
- Get-Process 有一个参数 -ComputerName,它支持通过 ByPropertyName 接收输入。
- 但 Get-ADComputer 返回的计算机对象有一个叫 Name 的属性,没有叫 ComputerName 的属性。
- 因此,Name 属性无法自动传递给 -ComputerName 参数
这样就需要重命名了:
- Get-ADComputer -Filter * | Select-Object @{Name='ComputerName'; Expression={$_.Name}} | Get-Process
复制代码 若是说在 ByPropertyName 的时候,两边的属性名相同那就会自动匹配去执行操作了(这种就不详细说了)
展开属性值
先看一个动作:- Get-Process –ComputerName (Get-LocalUser –Filter *)
复制代码 这个是想要将Get-LocalUser给到Get-Process的ComputerName参数
先看Get-Process的ComputerName接受什么输入- Get-Help Get-Process -Full
复制代码 可以看到只接受string类型,那我们直接将整个Get-LocalUser东西穿进去肯定不行
再看看这样行不行
回答:看似可以,其实也不行- Get-Process –ComputerName (Get-LocalUser –Filter * | Select-Object –Property Name)
复制代码 我们要看这个–Property Name输出的到底是不是string- $(Get-LocalUser | Select-Object –Property Name -First 1).GetType()
复制代码 查看后发现还是不是string,那这时候就需要用到展开属性的操作了
其实就是改了个参数名:
将Property改为ExpandProperty,下面这样就可以了- $(Get-LocalUser | Select-Object –ExpandProperty Name -First 1).GetType()
复制代码 为什么可以,我们直接看下取出来的Name是不是string即可
复习提问:
在命令行接口将对象从一个命令传递到管道中的另一个命令时,Windows PowerShell 总是优先尝试使用哪种技术?深入了解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,请运行以下命令:- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
复制代码 若要在计算机上永久解决此问题,需要创建注册表项。 可以运行以下两个命令来创建必要的密钥:- 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获取并安装了代码签名证书,可以用以下命令查找:- # 在当前用户的证书存储中查找所有可用于代码签名的证书
- $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 执行以下命令
- $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 来加载它:- # 会弹窗提示输入密码
- $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)后,就可以用它来签名脚本了。官网的例子是基础,但强烈建议添加时间戳服务器参数。- # 基础签名(官网示例)
- 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
复制代码 签名完成后,务必检查一下:- Get-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1"
复制代码 查看输出中的 Status 属性:
- Valid:签名有效且受信任。
- UnknownError:签名无效或证书不受信任(常见于自签名证书)。
- NotSigned:脚本未签名。
让系统信任你的签名
!!!!!记住这里是验证,不是用来签名,前面说的都是pxf和p12证书,这里讲的是cer文件!!!!!!!!
对于自签名证书,由于它不是公共CA颁发的,你需要将你的自签名证书**导入到“受信任的根证书颁发机构”或“受信任的发布者”存储区。否则,在其他计算机上运行时会显示 UnknownError。
- 将你的证书导出为 .cer 文件(只包含公钥)。
- 在需要运行此脚本的计算机上,将这个 .cer 文件导入到“受信任的根证书颁发机构”或“受信任的发布者”(对于代码签名证书,通常是“受信任的发布者”)。
你可以使用 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 参数配合使用。- $users | ForEach-Object -Parallel { Set-ADUser $user -Department "Marketing" }
复制代码 默认情况下,-Parallel 参数支持一次处理五个项,可以使用 -ThrottleLimit 参数将其修改为更大或更小的值。
If 构造
举例子:如果可用磁盘空间不足,则可以使用 If 语句显示警告- 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 构造
- 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 参数通过正则表达式执行匹配。- 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 构造
- For($i=1; $i -le 10; $i++) {
- Write-Host "Creating User $i"
- }
复制代码- 处理对象数组时,最好使用 ForEach 构造,因为在处理之前不需要计算数组中的项数。
复制代码 其他循环构造
Do..While
Do..While 构造运行脚本块,直到指定条件为false
此构造保证脚本块至少运行一次- Do {
- Write-Host "Script block to process"
- } While ($answer -eq "go")
复制代码 Do..Until
Do..Until 构造运行脚本块,直到指定条件为 true
此构造保证脚本块至少运行一次- Do {
- Write-Host "Script block to process"
- } Until ($answer -eq "stop")
复制代码 While
While 构造运行脚本块,直到指定条件为 false
虽然它类似于 Do..While 构造,但它不能保证脚本块的运行- While ($answer -eq "go") {
- Write-Host "Script block to process"
- }
复制代码 Break 和 Continue
使用 Continue 可阻止修改要修改的用户列表中的管理员用户帐户:- ForEach ($user in $users) {
- If ($user.Name -eq "Administrator") {Continue}
- Write-Host "Modify user object"
- }
复制代码 Break 用于在最大帐户数已修改时结束循环:- ForEach ($user in $users) {
- $number++
- Write-Host "Modify User object $number"
- If ($number -ge $max) {Break}
- }
复制代码 导入数据
Get-Content
直接读取文件内容进来- $computers = Get-Content C:\Scripts\computers.txt
复制代码 可在 Get-Content 的路径中使用通配符,以便一次获得多个文件的数据
可使用 -Include 和 -Exclude 参数修改所选文件- Get-Content -Path "C:\Scripts\*" -Include "*.txt","*.log"
复制代码 可以使用 -TotalCount 和 -Tail 参数限制使用 Get-Content 检索的数据量
- -TotalCount 参数指定应从文件开头检索多少行
- -Tail 参数指定从文件末尾检索多少行
例如:
- Get-Content C:\Scripts\computers.txt -TotalCount 10
复制代码 Import-Csv
- $users = Import-Csv C:\Scripts\Users.csv
复制代码 输出示例:- First,Last,UserID,Department
- Amelie,Garner,AGarner,Sales
- Evan,Norman,ENorman,Sales
- Siu,Robben,SRobben,Sales
复制代码 当我们存进一个变量后,也可以通过变量访问某个数据Import-Csv 默认分隔符是逗号,有的文件不是以逗号进行分割的话你也可以使用Import-Csv,只要格式相同分隔符不同也可以用这个,前提是你要自己加参数去修改分隔符:
比如说分隔符是分号- Import-Csv -Path .\1.csv -Header h1,h2,h3 -Delimiter ';'
复制代码
Import-Clixml
- $users = Import-Clixml C:\Scripts\Users.xml
复制代码 使用 -First 和 -Skip 参数来限制 Import-Clixml 检索的数据
- -First 参数指定仅从 XML 文件的开头检索指定数量的对象
- -Skip 参数指定从 XML 文件开头忽略指定数量的对象,并检索所有剩余的对象。
ConvertFrom-Json
- $users = Get-Content C:\Scripts\Users.json | ConvertFrom-Json
复制代码 Invoke-RestMethod
Invoke-RestMethod 能够处理JSON、 XML、RSS 源和 ATOM 源。- $users = Invoke-RestMethod "https://hr.adatum.com/api/staff"
复制代码 接受用户输入
Read-Host
这种会在How many das后加上冒号然后提示用户输入:- $answer = Read-Host "How many days"
复制代码 下面这种会先打印How many days? ,-NoNewline就是不换行,然后也是等待用户输入
这种就没有冒号- Write-Host "How many days? " -NoNewline
- $answer = Read-Host
复制代码 -MaskInput 或 -AsSecureString 参数在提示符处屏蔽输入用户,这种偏向于输入密码的时候不会直接显示在终端上- $answer = Read-Host "How many days" -AsSecureString
复制代码 具体使用哪个看情况了,我的电脑使用AsSecureString才行
Credential凭证使用
Get-Credential
它的核心作用就是安全地弹窗收集用户凭据(用户名和密码),并将其封装在一个 PSCredential 对象中,供其他需要凭据的 cmdlet 使用。
基础用法:
这会弹出一个标准对话框,让你输入用户名和密码。高级用法(自定义提示和用户名):
- -Message:让提示更清晰,指导用户输入什么凭据。
- -UserName:预填用户名字段,用户只需要输入密码即可。$env:COMPUTERNAME 是环境变量,代表本机计算机名,这在工作组环境下至关重要。
- # 自定义提示信息并预填用户名
- $cred = Get-Credential -Message "请输入本地管理员权限凭据" -UserName "$env:COMPUTERNAME\Administrator"
复制代码 远程管理另一台工作组计算机
假设你想从计算机 CLIENT-A 远程管理计算机 CLIENT-B- # 在 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
复制代码 本地脚本临时提权
你用自己的标准用户账户登录,但脚本中的某些操作(如修改系统设置)需要管理员权限。- # 检查当前用户权限,如果不是管理员则请求凭据
- 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
- }
复制代码 访问受保护的网络共享
挂载一个需要特定用户名和密码才能访问的局域网共享文件夹。- $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
首次保存凭据(在一台电脑上):- # 弹窗输入一次凭据
- $cred = Get-Credential -Message "输入要保存的凭据" -UserName "MyPC\Admin"
- # 将加密后的凭据保存到文件(只能由你在本机解密)
- $cred | Export-Clixml -Path "C:\Users\$env:USERNAME\Documents\secureCred.xml"
复制代码 后续脚本中自动使用保存的凭据:- # 无需弹窗,直接读取加密文件获取凭据对象
- $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):- [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 "脚本执行完毕。"
复制代码 如何使用这个脚本:
- .\Test-Service -ServiceName "WinRM"
- # 输出: 服务 'WinRM' 正在运行。
复制代码- .\Test-Service -ServiceName "WinRM" -Verbose
- # 输出:
- # 详细: 脚本开始执行,传入的服务名参数为: WinRM
- # 详细: 服务状态: Running
- # 服务 'WinRM' 正在运行。
- # 详细: 脚本执行完毕。
复制代码- .\Test-Service -ServiceName "SomeService" -Debug
复制代码 运行后会首先显示 Write-Debug 的信息,并暂停,提示你:- 调试: Get-Service 查询结果:
- (这里会显示Get-Service返回的详细对象信息)
- 继续执行?
- [Y] 是(Y) [A] 全是(A) [N] 否(N) [L] 全否(L) [S] 暂停(S) [?] 帮助 (默认值为“Y”):
- 按 `Y` 继续执行每一步,按 `A` 让它自动执行完所有调试步骤。这让你可以一步步观察脚本的执行流程。
复制代码 使用 $VerbosePreference 和 $DebugPreference 进行全局控制
在当前会话中开启所有Verbose输出:- $VerbosePreference = "Continue" # 默认是 "SilentlyContinue"
- .\Test-Service -ServiceName "WinRM"
- # 现在即使不加 -Verbose,也会输出Verbose信息
复制代码 在脚本开头强制开启调试(常用于日志记录):- [CmdletBinding()]
- param()
- # 在脚本内部设置,强制记录详细信息到日志文件
- $VerbosePreference = "Continue"
- Write-Verbose "$(Get-Date): 脚本启动..."
- # ... 脚本逻辑 ...
复制代码 脚本中使用断点
根据行进行断点
可使用 Set-PSBreakPoint cmdlet 设置断点
可以基于脚本行、正在使用的特定命令或正在使用的特定变量来设置断点
以下示例描述如何在脚本的特定行处设置断点:- Set-PSBreakPoint -Script "MyScript.ps1" -Line 23
复制代码 根据命令进行断点
- Set-PSBreakPoint -Command "Set-ADUser" -Script "MyScript.ps1"
复制代码 基于命令设置断点时,可以包含通配符。 例如,可以使用值 *-ADUser 为 Get-ADUser、Set-ADUser、New-ADUser 和 Remove-ADUser 触发断点。
根据特定变量进行断点
- Set-PSBreakPoint -Variable "computer" -Script "MyScript.ps1" -Mode ReadWrite
复制代码 可以使用变量的 -Mode 参数来确定是否要在读取和/或写入变量值时中断。 有效值为 Read、Write 和 ReadWrite。
以上是终端中运行脚本的时候设置的断点,其实我们可以用:
- Powershell ISE 图形化工具进行根据行去断点
- VScode 中也能够进行更多高级的断点方式
错误操作
$ErrorActionPreference
内置全局变量。 当命令生成非终止错误时,命令会检查此变量来决定该执行的操作
变量可具有下面 4 个可能值之一:
- Continue 是默认值,它告知命令显示错误消息并继续运行。
- SilentlyContinue 告知命令不显示错误消息,但要继续运行。
- Inquire 告知命令显示提示,询问用户要做什么。
- Stop 告知命令将错误视为终止错误并停止运行。
若要设置 $ErrorActionPreference 变量,请使用以下语法:- $ErrorActionPreference = 'Inquire'
复制代码 -ErrorAction
所有 Windows PowerShell 命令都有 –ErrorAction 参数。 此参数具有别名 –EA
当你使用他的时候,会覆盖$ErrorActionPreference但可以设置一样的类型,该参数仅针对当前使用的cmdlet
函数与模块
有参函数:- Function Get-SecurityEvent {
- Param (
- [string]$ComputerName
- ) #end Param
- Get-EventLog -LogName Security -ComputerName $ComputerName -Newest 10
- }
复制代码 无参函数就很简单了,不写接受参数的变量即可
函数调用如下:- Get-SecurityEvent -ComputerName LON-DC1
复制代码 变量范围
使用范围修饰符 (Scope Modifiers) 指定目标作用域
这是修改其他作用域中变量的关键方法。通过在变量名前加修饰符来指定目标作用域
修饰符作用语法示例说明$global:修改全局作用域中的变量。$global:MyVariable = "新值"在任何地方(函数、脚本)都能访问和修改这个全局变量。慎用,容易造成污染。$script:修改脚本作用域中的变量。$script:MyVariable = "新值"在当前脚本文件的任何函数内部修改在脚本顶层定义的变量。这是最常用、最安全的方式。$using:在远程命令或脚本块中引用当前局部作用域的变量。Invoke-Command { ... -Name $using ocalVar }用于将本地变量的值传递到远程会话或新脚本块中,而不是在远程会话中修改它。$private:在当前作用域创建变量,且该变量不会传递到更高级的作用域。$private:TempVar = "值"用于限制变量范围,确保其不会影响父作用域。较少用。示例:
假设您在脚本顶层定义了 $configPath,现在需要在一个函数里修改它:
Set-Variable指定作用域
- Set-Variable -Name "MyVariable" -Value "新的值" -Scope <ScopeName>
复制代码 -Scope 参数值:
- 'Global': 修改全局作用域。
- 'Script': 修改脚本作用域。
- 'Local': 修改当前局部作用域(默认值)。
- 'Private': 修改为私有作用域。
绝大多数情况下,您应该使用 $script: 修饰符
这是在函数内修改脚本级变量的最标准、最可读且副作用最小的方式。
类似指针修改
使用[ref]去拿到真实的那个变量在函数里面去修改,而不是说每次修改的都是函数内部接受到的值,他会直接影响到函数外部那个传进来的变量的值- function Modify-ByReference {
- param (
- [ref]$RefValue
- )
- $RefValue.Value = "在函数内部被修改了" # 注意:是修改 .Value 属性
- }
- $OriginalVariable = "原始值"
- Modify-ByReference -RefValue ([ref]$OriginalVariable)
- Write-Host $OriginalVariable # 输出:在函数内部被修改了
复制代码 但是我们是避免这样去修改变量的,要改的话最好是通过return返回值,然后在函数外部去改变某个变量
return
好像没啥好说的,就是return值- function xxx{
- xxx
- return($var) # return "xxx" return $var
- }
- $ch = xxx()
复制代码 创建模块
你必须创建与该文件同名的子文件夹,并将文件放在该子文件夹中
例如,如果你有一个名为 AdatumFunctions.psm1 的模块,
则将其放置在 C:\Program Files\WindowsPowerShell\Modules\AdatumFunctions 中。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |