前言
文档是参考《Windows PowerShell实战指南》(第3版),进行整理成册。
英文名:《Learn Windows PowerShell in a Month of Lunches》, Third Edition
书中的相关代码下载:https://www.manning.com/(找到本书后进行下载)
本书作者的YouTube频道:
PowerShell.org频道:https://www.youtube.com/powershellorg
Petro IT知识库:https://petri.com/
PowerShell社区:https://powershell.org/
PowerShell跨平台版本:http://github.com/PowerShell/PowerShell
如果想要检查最新的PowerShell可用版本或下载PowerShell,请访问http://msdn.microsoft.com/owershell。该官方PowerShell主页,有一个指向最新版本Windows管理框架(WMF)安装包的链接,该安装包用于安装PowerShell与其相关功能。
初识PowerShell
Tab键一般有4种补全场景:(Tab 和 Shift + Tab)
- 补全命令:如输入“Get-S”,然后按几下Tab键,再按Shift+Tab组合键。
- 遍历当前目录文件:如输入“Dir”,按空格键,然后输入“C:\”,再按Tab键。
- 遍历可用参数:
- 输入“Set-Execu”,按Tab键,然后输入一个空格和横杠(-),再开始按Tab键;
- 可以看到PowerShell循环显示当前命令的所有可用参数。
- 遍历参数值:
- 再次输入“Set-Execu”,按Tab键,再按空格键,然后输入“-E”,再次按Tab键;
- 然后按一次空格键,再按Tab键。PowerShell会循环显示关于这些参数的合法值。
查看版本:$PSVersionTable
显式指定运行v2版本:PowerShell.exe –version 2.0
PS C:\Users\Administrator> PowerShell.exe –version 2.0
Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.
PS C:\Users\Administrator> $PSVersionTable
Name Value
---- -----
CLRVersion 2.0.50727.9151
BuildVersion 6.1.7600.16385
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1
新版本的Windows默认会安装新版的PowerShell,但可能会包含PowerShell v2引擎。如果需要,可以在PowerShell中运行Add-WindowsFeature powershell –v2
来安装v2引擎。
使用帮助
Windows的PowerShell提供了Get-Help
这个Cmdlet命令访问帮助系统。你可能看到很多示例(特别是在互联网)都是使用“Help”或“Man”(来自UNIX,指代Manual)关键字来代替Get-Help。Man和Help都不是原生的Cmdlet命令,而是对核心Cmdlet命令进行封装后的函数。
Help的工作原理类似Get-Help,但它可以把输出的信息通过管道传送给More命令。
- 相当于:
Get-Help Get-Content | More
微软的PowerShell帮助文件已经在http://github.com/powershell开源。该网址是查看最新源码的好地方,该部分帮助可能在PowerShell中无法下载。
常用命令
查看命令本机帮助信息:help Get-Service
- 支持正则查找:
help *log*
查看命令在线帮助信息:help Get-Service -Online
查看命令帮助示例信息:help Get-EventLog -examples
查看命令指定参数帮助信息:help Get-EventLog -Parameter newest
Help invoke* -Parameter AsJob
Help * -Parameter AsJob
查看详细帮助信息:
help Get-Service -full
help Get-EventLog -detailed
通过GUI查看帮助:help Get-EventLog -ShowWindow
(前提是底层帮助XML文件的质量)
更新命令帮助文档:Update-Help
(这些文件存储在System32这个目录下,因此Shell必须在更高特权下运行)
更新指定模块:Update-Help -Module Microsoft.PowerShell*
下载帮助文档至本地:Save-Help 'D:\(tmp\'
- 可将下载的文档存放至服务器,本机若未联网,可直接访问该服务器。
Update-Help -SourcePath \\Server01\Share\PSHelp
帮助详解
下面以Get-EventLog
的语法帮助部分为例: ```powershell PS C:\Users\Administrator> help Get-EventLog
名称 Get-EventLog
摘要 Gets the events in an event log, or a list of the event logs, on the local computer or remote computers.
语法
Get-EventLog [-LogName]
Get-EventLog [-AsString] [-ComputerName <System.String[]>] [-List] [<CommonParameters>]
该命令在语法部分出现了两次,这表示这个命令提供了两个不同的参数集。有些参数是这两个参数集共享的,如都包含-ComputerName参数。
- 若使用所有参数集中共有的参数,Shell通常会选择第一个参数集。
- 命令不能跨参数集使用参数,如选择使用-List参数,那么够使用的其他参数就只能是-AsString和-ComputerName。
在每个PowerShell的Cmdlet参数的结尾都有`[<Common-Parameters>]`。不管你以何种方式使用Cmdlet,这泛指每个Cmdlet命令,都是使用的一组包含8个参数的集合。
<a name="W7BAE"></a>
### 可选和必选参数
PowerShell的帮助文档把可选参数放到一个方括号中。例如,`[-ComputerName <string[]>]`表示整个-ComputerName参数是可选的。你可以不使用该参数,因为在没有为该参数指定一个具体值的时候,Cmdlet会默认为本地计算机。<br />必选参数放到一个尖括号中,如`[-LogName] <System.String>`。如果不为必选参数输入值,在运行时,会进行提示。
<a name="rtxiY"></a>
### 位置参数
位置参数意味着只要你把参数值放在正确的位置,就可以只提供这个参数值,而不需要输入具体的参数名。<br />比如,查看Get-EventLog的第一个参数集的前两个参数。
```powershell
Get-EventLog [-LogName] <System.String> [[-InstanceId] <System.Int64[]>]
第一个参数:-LogName,它是必选参数。因为它的参数名称和参数值不在一个方括号里面。
第二个参数:-InstanceId,它是可选的。
- 因为它的参数名称与参数值位于同一个方括号内。在方括号内,-InstanceId本身又处在一个方括号里,意味着它同时还是一个位置参数。
- 它出现在第二个位置,所以我们省略这个参数名称,就必须在该位置提供一个参数值。
在上述语法中,-Path和-Filter参数是位置参数,这是由于参数名称被中括号给括了起来。Get-ChildItem [[-Path] <System.String[]>] [[-Filter] <System.String>] [-Attributes {Archive | C
ompressed | Device | Directory | Encrypted | Hidden | IntegrityStream | Normal | NoScrubData |
NotContentIndexed | Offline | ReadOnly | ReparsePoint | SparseFile | System | Temporary}] [-Dep
th <System.UInt32>] [-Directory] [-Exclude <System.String[]>] [-File] [-Force] [-Hidden] [-Incl
ude <System.String[]>] [-Name] [-ReadOnly] [-Recurse] [-System] [-UseTransaction] [<CommonParam
eters>]
上述帮助明显解释了-Path参数在位置1。对于位置参数来说,你无须输入参数名称——仅需要在正确的位置提供参数值,例如:PS C:\> Get-ChildItem -Path c:/
# 等同于
PS C:\> Get-ChildItem c:/
范例:
Get-EventLog -newest 20 -Log Application # -Log是-LogName缩写
Get-EventLog Application -InstanceId 0 -Newest 10
# 在容易使人混淆的命令行中,建议显式指定参数名称,不要省略
# move C:\devlist.txt d:\
move -Path C:\devlist.txt -Destination d:\
move Destination d:\ -Path C:\devlist.txt
参数值
帮助文档同样给你提供了每个参数的数据类型。有些参数被称为开关参数,无需任何输入值。如Get-EventLog [-AsString]
,详细语法如下:
通过[<SwitchParameter>]
可以确认这是一个开关参数,并不需要任何输入值。开关参数的位置可以随意放置,你必须输入参数名(或者至少是一个缩写)。
其他参数希望获得的数据类型,通常会跟在参数名称之后,并使用空格与参数名称分开。在缩写语法里面,输入的类型使用尖括号表明,如[-LogName] <System.String>
。
通常的输入类型
- string:一系列字母和数字,有些时候也会包含空格符。
- 如果出现空格符,那么全部字符串必须包含在引号内。
- 如:
"C:\Program Files (x86)"
- Int、Int32或Int64:一个整数类型(整个数字不包含小数)。
- DateTime:通常,基于你本地计算机的时区配置,字符串被解释成的日期会有所不同。
- 在美国,通过的日期格式为10-10-2010,即月-日-年。
对于有些值包含多个方括号,如[-ComputerName <System.String[]>]
。string后面的方括号,并不意味着某些东西是可选的。事实上,string[]
意味着该参数可以接受数组、集合,或者是一个列表类型的字符串。
下面以查看Security日志为例:
Get-EventLog Security # 查看本机
Get-EventLog Security -ComputerName vpn-server
Get-EventLog Security -ComputerName vpn-server,dc1,'dns-server'
PowerShell把以逗号为分隔符的列表作为数组值对待。任何一个单一值中如果包含了空格,就必须使用引号。但是作为一个整体的列表,不需要使用引号,只有单一值才需要使用引号。
另外一种提供列表值的方式,是把它们输入到一个文本文件中,每一个值一行。
vpn-server
dc1
'dns-server'
接着,可以使用Get-Content
来读取该文件的内容,并且发送这些内容到-computerName
参数中。
Get-EventLog Security -ComputerName (Get-Content name.txt)
对于接受多个值的参数,你可以输入第一个值并按回车键,继续输入直到完成,最后空白处按回车键,这将告诉PowerShell已经完成输入。
访问“关于”主题
PowerShell的帮助系统包含许多背景主题,可以用来帮助定位指定的Cmdlet命令。这些背景主题通常被称为“关于”主题,因为它们都是以“about_”开头的。
- 查看关于数组的帮助主题信息:
help *array*
或help about_arrays
```powershell PS C:\Users\Administrator> help about*
Name Category Module Synopsis
about_Aliases HelpFile about_Alias_Provider HelpFile about_Arithmetic_Operators HelpFile about_Arrays HelpFile about_Assignment_Operators HelpFile about_Automatic_Variables HelpFile about_Break HelpFile about_Certificate_Provider HelpFile about_CimSession HelpFile about_Classes HelpFile ——-More——-
前面介绍过,所有的Cmdlet命令都提供一个通用参数集。那么,怎样才能更多了解这些常见的参数?<br />执行`help *common*`,这只会在帮助主题中匹配到一条记录:`About_common_parameters`。该主题将会自动显示,因为只有唯一一条配置的主题。浏览显示的帮助主题,你会发现如下8个通用参数。<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/635565/1653190950255-e0ce7355-892c-43d1-96e0-2e305b09ca47.png#clientId=u0dd2614c-1757-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=211&id=u58f67ee8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=271&originWidth=254&originalType=binary&ratio=1&rotation=0&showTitle=false&size=14426&status=done&style=none&taskId=u63d8c75a-c7d7-43a6-9033-9ec4131f39f&title=&width=198)
<a name="CocFQ"></a>
## 查找命令
与Help这个命令一样,Get-Command接受通配符,意味着你可以运行`Gcm *event*` 查看所有名称包含“event”的命令。不管怎么样,这个返回的列表将不止包含Cmdlet命令,还会包含一些不一定有用的外部命令,如netevent.dll。<br />一个比较好的方式是使用“-名词”或者“-动词”参数。因为只有Cmdlet名的名称有名词和动词,返回的结果将会限制为Cmdlet命令。
- `Get-Command -noun *event*`将会返回一个关于事件命令的列表;
- 查找文件和打印机相关命令:`gcm -Noun file,printer`
- `Get-Command -verb Get`将会返回一个具有检索能力的列表。
以上两个参数也可结合使用:
- 查找可以向事件日志写入数据的命令:`gcm -Noun eventlog -Verb write`
<a name="onVTD"></a>
### 根据命令类型查找
你也可以使用`-CommandType`参数来指定命令的类型。比如`Get-Command *log* -type Cmdlet` ,将会返回一个所有命令名称包含“log”的命令列表,并且这个列表不会包括任何其他扩展应用程序或者扩展命令。
```powershell
# -CommandType 等同于 -type
PS C:\Users\Administrator> Get-Command *log* -CommandType Cmdlet
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Clear-EventLog 3.1.0.0 Microsoft.PowerShell.Management
Cmdlet Disable-AppBackgroundTaskDiagnosticLog 1.0.0.0 AppBackgroundTask
Cmdlet Enable-AppBackgroundTaskDiagnosticLog 1.0.0.0 AppBackgroundTask
Cmdlet Export-BinaryMiLog 1.0.0.0 CimCmdlets
PS C:\Users\Administrator> Get-Command log* -type Application
CommandType Name Version Source
----------- ---- ------- ------
Application logagent.exe 12.0.19... C:\windows\system32\logagent.exe
Application logman.exe 10.0.19... C:\windows\system32\logman.exe
Application logoff.exe 10.0.19... C:\windows\system32\logoff.exe
Application LogonUI.exe 10.0.19... C:\windows\system32\LogonUI.
Cmdlet命名惯例
Cmdlet是一个原生的PowerShell命令行工具。该术语仅仅存在于PowerShell和类似C#的.Net Framework语言中。
微软已经为Cmdlet建了一个命名惯例。因此同样的命名规则也应该被用于函数和工作流。虽然微软并没有强制要求,但开发人员应该遵循该惯例。规则应该以标准的动词开始,比如Get、Set、New或Pause。
你可以运行Get-Verb
,查看允许使用的动词列表。
PS C:\> Get-Verb | more
Verb Group
---- -----
Add Common
Clear Common
Close Common
Copy Common
Enter Common
Exit Common
Find Common
Format Common
Get Common
Hide Common
Join Common
Lock Common
-- More --
由于PowerShell允许开发人员自己命名名词,因此并没有一个“Get-Noun”的Cmdlet来显示所有名词。
运行命令
别名
命令别名
查看命令别名:
PS C:\> Get-Alias -Definition "Get-Service"
CommandType Name Version Source
----------- ---- ------- ------
Alias gsv -> Get-Service
你可以使用New-Alias
创建自定义别名,使用Export-Alias
导出别名列表。
当创建一个别名时,其生命周期只能持续到当前的Shell会话结束。一旦关闭窗口,别名就会不复存在。这也是你需要导出别名的原因,以便后续重新导入。
参数别名
尽管参数的别名不在帮助文件或任何方便查阅的地方而难以识别,但参数也拥有别名。比如说,Get-EventLog命令有-ComputerName参数。可以运行下述命令,查阅该参数别名。
PS C:\> (Get-Command Get-EventLog | select -ExpandProperty parameters).ComputerName.Aliases
Cn
数据结果展示了-Cn是-computerName的别名,所以你可以运行下述命令。
PS C:\Windows\system32> Get-EventLog -LogName Security -Cn im20211010 -Newest 10
Show-Command
PowerShell v3(以及更新版本)提供的一个非常棒的特性是Show-Command
commlet。
Show-Command将成为你的助手,该命令允许指定你无法用对的命令名称,并以图形化的方式将命令的参数名称展示出来。
如图所示,参数集分布于不同的选项卡(在前一章学到的),因此不同参数集之间的参数不会搞混——选择一个选项卡并仅一次只使用一个选项卡。
可以单击运行执行命令,或单击复制将完成后的命令复制到剪贴板,返回Shell,将命令粘贴(右击控制台,或是在ISE中使用Ctrl+V组合键)到Shell中进行查看。
Show-Command一次只能展示一个命令。因此,当希望了解多个命令时,只能逐个使用该命令。
对命令扩展的支持
大约400个Cmdlet被集成到Windows客户端操作系统中,上千个被集成到Windows服务器版本的操作系统中,并且你还能添加更多——类似ExchangeServer、Sharepoint Server和SQL Server都包含数以百计的额外Cmdlet。
包括Ping、Nslookup、Ipconfig、Net等。由于这些都不是原生PowerShell Cmdlet,因此你可以按照原来使用这些命令的方法继续使用这些命令。PowerShell将会在后台启动Cmd.exe。
New-PSDrive命令
Net Use命令在PowerShell中也能正常工作。但PowerShell v3证实微软开始寻找合适的时机推出PowerShell风格的方式来完成这些传统任务。
从PowerShell v3开始,现在你可以发现New-PSDrive命令多了一个-Persisit参数,该参数决定是否启用文件系统提供程序。这样一来,新的磁盘将会在文件资源管理器中被查看到。
Test-Connection命令
关于Ping命令,在PowerShell可以使用Test-Connection代替。原生的Test-Connection
Cmdlet相比之前的提供了更多选项和更灵活的输出方式。
外部命令支持
当一个外部命令拥有很多参数时,PowerShell在大多数场景下无法工作。但可以提供类型下面的命令,从而确保运行一个命令且其参数可以准确无误。
以名为vcbMounter.exe的外部命令为例,该命令接受6个参数。
- -h:用于指定主机名称。
- -u:用于指定用户名。
- -p:用于指定密码。
- -s:用于指定服务器名称。
- -r:用于指定区域。
- -t:用于指定备份类型。
我们所做的是将不同的元素——可执行路径和名称,以及所有的参数值放入$容器。然后使用调用操作符(&),将可执行程序的名称以及所有参数名称与参数值传递给该操作符。任何可以在PowerShell中运行的命令行工具,都可以使用这种方式在PowerShell中调用。
另一种办法
仅需要在外部命令名称之后加两个破折号。如果你这么做,PowerShell甚至不会解析该命令,仅仅是将该命令传递到Cmd.exe中。这意味着你基本上可以使用Cmd.exe的语法在PowerShell中运行任何命令,而不用担心该命令在PowerShell中解析的实现细节。
PS C:\> C:\Windows\System32\sc.exe --% qc bits
[SC] QueryServiceConfig 成功
SERVICE_NAME: bits
TYPE : 20 WIN32_SHARE_PROCESS
START_TYPE : 3 DEMAND_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : C:\Windows\System32\svchost.exe -k netsvcs -p
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : Background Intelligent Transfer Service
DEPENDENCIES : RpcSs
SERVICE_START_NAME : LocalSystem
# 加破折号后,PowerShell不再解析破折号后的命令
PS C:\> $n="bits"
PS C:\> C:\Windows\System32\sc.exe --% qc $n
[SC] OpenService 失败 1060:
指定的服务未安装。