Powershell 进阶语(三)
目录[*]PowerShell 管道
[*]管道输出
[*]控制管道输出的格式设置
[*]Format-List
[*]Format-Table
[*]Format-Wide
[*]管道选择、排序和度量对象
[*]排序和分组
[*]Sort-Object
[*]Format 的 GroupBy分组
[*]度量管道中的对象
[*]Select-Object
[*]Unique去重
[*]Property
[*]自定义属性并设置表达式与格式
[*]计算
[*]从管道中筛选对象
[*]比较运算符
[*]基本筛选器语法
[*]高级筛选器语法
[*]组合多个条件
[*]True 或 False 的属性筛选使用技巧
[*]高级筛选不受简单筛选限制
[*]优化筛选器性能
[*]枚举
[*]枚举管道对象语法
[*]写入到文件
[*]转换为其他形式的数据表示形式
[*]Csv
[*]XML
[*]Json
[*]HTML
[*]其他输出选项
[*]传递管道对象
[*]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
[*]接受用户输入
[*]Read-Host
[*]Credential凭证使用
[*]Get-Credential
[*]Export-Clixml
[*]脚本故障排除与错误处理
[*]输出命令的层次与用途
[*]脚本中使用断点
[*]根据行进行断点
[*]根据命令进行断点
[*]根据特定变量进行断点
[*]错误操作
[*]$ErrorActionPreference
[*]-ErrorAction
[*]函数与模块
[*]变量范围
[*]
[*]Set-Variable指定作用域
[*]类似指针修改
[*]return
[*]创建模块
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
[*]选择最少虚拟内存使用量排名前 10 的进程
Get-Process | Sort-Object –Property VM | Select-Object –First 10
[*]选择最后 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 1Unique去重
只需要在指定对象后添加多一个-Unique参数即可
[*]显示某个用户在每个部门中的用户信息
Get-ADUser -Filter * -Property Department | Sort-Object -Property Department | Select-Object Department -UniqueProperty
没啥好说的,就是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 }},
@{n='PagedMemory(MB)';e={'{0:N2}' –f ($PSItem.PM / 1MB) -as }}上一个示例中的语法可能看起来令人困惑,因为它包含许多标点符号。 从基本表达式开始:
'{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}https://img2024.cnblogs.com/blog/3392862/202509/3392862-20250928210714044-439251236.png
优化筛选器性能
说是优化,但其实都是靠编写脚本自己的功底
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取出来的对象 ()进行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.csvXML
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 | moreOut-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 总是优先尝试使用哪种技术?
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,请运行以下命令:
::SecurityProtocol = ::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 10Import-Csv
$users = Import-Csv C:\Scripts\Users.csv输出示例:
First,Last,UserID,Department
Amelie,Garner,AGarner,Sales
Evan,Norman,ENorman,Sales
Siu,Robben,SRobben,Sales当我们存进一个变量后,也可以通过变量访问某个数据
$users.UserIDImport-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-JsonInvoke-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 使用。
基础用法:
这会弹出一个标准对话框,让你输入用户名和密码。
$cred = Get-Credential高级用法(自定义提示和用户名):
[*]-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 ( ::GetCurrent()).IsInRole( "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 处,其他错误的索引将增加一。 每当需要查看以前的错误消息时,查看 $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):
# 启用高级功能,支持 -Verbose 和 -Debug 参数
param (
$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' 正在运行。
[*]查看详细信息(使用 -Verbose):
.\Test-Service -ServiceName "WinRM" -Verbose
# 输出:
# 详细: 脚本开始执行,传入的服务名参数为: WinRM
# 详细: 服务状态: Running
# 服务 'WinRM' 正在运行。
# 详细: 脚本执行完毕。
[*]进行深度调试(使用 -Debug):
.\Test-Service -ServiceName "SomeService" -Debug运行后会首先显示 Write-Debug 的信息,并暂停,提示你:
调试: Get-Service 查询结果:
(这里会显示Get-Service返回的详细对象信息)
继续执行?
是(Y) 全是(A) 否(N) 全否(L) 暂停(S)[?] 帮助 (默认值为“Y”):
按 `Y` 继续执行每一步,按 `A` 让它自动执行完所有调试步骤。这让你可以一步步观察脚本的执行流程。使用 $VerbosePreference 和 $DebugPreference 进行全局控制
在当前会话中开启所有Verbose输出:
$VerbosePreference = "Continue" # 默认是 "SilentlyContinue"
.\Test-Service -ServiceName "WinRM"
# 现在即使不加 -Verbose,也会输出Verbose信息在脚本开头强制开启调试(常用于日志记录):
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 (
$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:LocalVar }用于将本地变量的值传递到远程会话或新脚本块中,而不是在远程会话中修改它。$private:在当前作用域创建变量,且该变量不会传递到更高级的作用域。$private:TempVar = "值"用于限制变量范围,确保其不会影响父作用域。较少用。示例:
假设您在脚本顶层定义了 $configPath,现在需要在一个函数里修改它:
Set-Variable指定作用域
Set-Variable -Name "MyVariable" -Value "新的值" -Scope <ScopeName>-Scope 参数值:
[*]'Global': 修改全局作用域。
[*]'Script': 修改脚本作用域。
[*]'Local': 修改当前局部作用域(默认值)。
[*]'Private': 修改为私有作用域。
绝大多数情况下,您应该使用 $script: 修饰符
这是在函数内修改脚本级变量的最标准、最可读且副作用最小的方式。
类似指针修改
使用去拿到真实的那个变量在函数里面去修改,而不是说每次修改的都是函数内部接受到的值,他会直接影响到函数外部那个传进来的变量的值
function Modify-ByReference {
param (
$RefValue
)
$RefValue.Value = "在函数内部被修改了" # 注意:是修改 .Value 属性
}
$OriginalVariable = "原始值"
Modify-ByReference -RefValue ($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 中。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]