PowerShell实战指南 Chapter 3-7

你说彼岸灯火,心之所向;后来渔舟晚唱,烟雨彷徨。

Chapter 3 使用帮助系统

由于其他平台上的PowerShell功能没有Windows上完整,所以在未加特别说明的情况下,后面的截图等均基于Windows平台。

系统版本:

Screen Shot 2018-05-16 at 3.23.13 PM.png

PowerShell版本:

Screen Shot 2018-05-16 at 3.21.20 PM.png

建议刚开始一直输入参数名。

先执行括号里的命令:

Get-EventLog Application -computer (Get-Content names.txt)
# about 主题也有很多信息
help about*
# 如查看关于数组的内容
help Arrays
help about_core_commands

# 可以帮助查找有哪些可能有用的命令,比如找关于进程的
Get-Command *Process*

像下面这样的语法描述,即这个命令适应三种不同的语法规则(参数组合)。你输入的命令应该符合其中一种:

Screen Shot 2018-05-21 at 3.56.08 PM.png

Chapter 4 运行命令

Get-Verb查看可用动词:

PS /Users/rambo> Get-Verb
Enable      e           Lifecycle      Configures a resource to an available...
Verb        AliasPrefix Group          Description
----        ----------- -----          -----------
Add         a           Common         Adds a resource to a container, or attaches an item to another item
Clear       cl          Common         Removes all the resources from a container but does not delete the container
Close       cs          Common         Changes the state of a resource to make it inaccessible, unavailable, or unusable
Copy        cp          Common         Copies a resource to another name or to another container
Enter       et          Common         Specifies an action that allows the user to move into a resource
Exit        ex          Common         Sets the current environment or context to the most recently used context
Find        fd          Common         Looks for an object in a container that is unknown, implied, optional, or specified
Format      f           Common         Arranges objects in a specified form or layout
Get         g           Common         Specifies an action that retrieves a resource
...

PowerShell允许开发人员自己命名名词。

使用New-Alias创建自定义别名,其生命周期为当前Shell。所以如果以后要使用,则需要Export-Alias

Show-Command Get-Process以GUI方式显示命令的用法:

Screen Shot 2018-05-14 at 10.21.30 PM.png

Get-Eventlog -LogName Application -Newest 100

Chapter 5 使用提供程序

这一章的内容较为抽象。简略来说,文件系统、环境变量、PowerShell本身的变量、PowerShell的函数等等这些东西被抽象成Drives,而PSProvider作为访问这些数据介质的适配器。它向PSDrive提供服务。用户则使用Cmdlet去操作PSDrive呈现的数据。

我画了张图来表达自己对上面这些概念的理解(不一定对):

Screen Shot 2018-05-16 at 3.38.03 PM.png

对于数据介质的一个更高级的抽象是“项”(Item)。无论文件系统中的文件、文件夹,还是注册表中的项,在PowerShell都被视为“项”。(注意,注册表和文件系统具有相同的分层结构)这样一来,为数据的访问和操作提供了统一的术语。而相关的Cmdlet也往往是包含Item字符的:

Get-Command -Noun *Item*

Screen Shot 2018-05-16 at 3.17.36 PM.png

所以,在PowerShell的cd或者Set-Location具有了更广泛的含义,它不仅仅是像传统命令行或Bash那样切换工作目录,甚至可以从文件系统切换到注册表中。

一般每个项都有其属性。如文件夹:

Screen Shot 2018-05-16 at 3.49.37 PM.png

再如注册表键:

Screen Shot 2018-05-16 at 3.50.24 PM.png

但有的PSProvider并不具有项属性,如Environment

Screen Shot 2018-05-16 at 3.54.09 PM.png

Get-PSProvider

Screen Shot 2018-05-16 at 3.15.51 PM.png

Get-PSDrive

Screen Shot 2018-05-16 at 3.16.09 PM.png

访问注册表并修改值:

Screen Shot 2018-05-16 at 3.03.08 PM.png

最后别忘了改回默认值。

大部分Cmdlet都包含-Path,且默认情况下支持通配符。如果不希望自己输入的?*被当作通配符,可以使用-LiteralPath代替。

Chapter 6 管道:连接命令

格式化输出结果

输出结果到CSV (Comma-Separated Values):

Get-Process | Export-Csv procs.csv

Screen Shot 2018-05-16 at 4.49.47 PM.png

Screen Shot 2018-05-16 at 4.48.34 PM.png

相比直接在命令行中显示的内容,很明显输出到文件的内容更丰富。

之后可以在别处把procs.csv导入到PowerShell进行查看:

Import-Csv procs.csv | more

Screen Shot 2018-05-16 at 4.53.19 PM.png

注意,与Get-Content相比,Import-Csv会去解析它的格式,以更有序的形式展示出来。

另外也可以导出为XML

Get-Process | Export-Clixml procs.xml

Screen Shot 2018-05-16 at 4.56.18 PM.png

还有其他的各种导出导入:

Screen Shot 2018-05-16 at 4.58.19 PM.png

还有一个对比功能蛮有趣:

Compare-Object或者diff

Compare-Object -ReferenceObject (Import-CliXML procs.xml) -DifferenceObject (Get-Process) -Property Name

Screen Shot 2018-05-16 at 7.21.02 PM.png

=>表示不存在于ReferenceObject的进程,<=表示不存在于DifferenceObject的进程。另外注意小括号()的妙用。

输出到文件或打印机

dir > x.txt这种写法是为了向后兼容。实际上它是以管道实现:dir | Out-File x.txtOut-file默认一行80列)。

输出到HTML

Get-Process | ConvertTo-Html | Out-File procs.html

注意,ConvertTo-意味着只转换,不存储。Export则还会自动帮你存储。但是如果接下来还要用管道处理数据,那么ConvertTo更方便。

修改系统

Get-Process -Name notepad | Stop-Process

这个例子想要说明的是,带有相同名词(如上面的Process)的Cmdlet可以在彼此之间传递信息。

Stop-这种会修改系统的命令,都有impact level,这些level是不可修改的。同时,PowerShell有一个全局的$ConfirmPreference

Screen Shot 2018-05-16 at 7.40.48 PM.png

如果命令的level大于等于全局的,则PowerShell会问你是否确定要这么做。当然,你也可以强制它每次问你一下,即使命令的level小于全局的:

Screen Shot 2018-05-16 at 7.47.22 PM.png

-Confirm会询问,-WhatIf会告诉你将发生什么。

我们之前有提到PSProvider。再次看一下这张图片:

Screen Shot 2018-05-16 at 3.15.51 PM.png

其中,带有ShouldProcessPSProvider支持-WhatIf-confirm参数。

另外,Filter指的是其支持-Filter参数;Credentials指的是“允许使用可变更的凭据连接数据存储。”,即-Credentials参数;Transactions说明其支持事务(即原子操作)。

Chapter 7 扩展命令

由于本章需要的某些模块在之前使用的Windows Server 2008中不存在,故本章采用如下版本的Windows Server 2012 R2PowerShell

Screen Shot 2018-05-19 at 2.40.41 PM.png

Screen Shot 2018-05-19 at 2.41.06 PM.png

本章学习PowerShell的两种扩展:

首先是管理单元。它类似于插件。这种方式正逐渐被微软遗弃。它使用的主要命令是:

Get-PSSnapin
Add-PSSnapin

深入学习模块:

模块不需要注册。PSModulePath定义了PowerShell期望存放模块的路径,路径下的模块会自动被查找:

Screen Shot 2018-05-19 at 2.42.43 PM.png

(图中两个路径分别存放系统和个人的模块)

另外,PSModulePath不能在PowerShell中修改,需要到系统环境变量中修改。

测试:

首先移除所有模块:

Screen Shot 2018-05-19 at 2.52.26 PM.png

之后查找一下network相关命令,可以发现还是可以找到,即使你没有加载那个模块。PowerShell会为你自动发现和加载:

Screen Shot 2018-05-19 at 2.53.47 PM.png

如果模块不在前面的路径下,那么需要手动导入:Import-Module

插件和模块都可以添加PSDrive,所以在加载之后你可以使用Get-PSProvider查看新添加了哪些。

注:如果加载多个模块,其中包含相同命令,那么在使用命令时需要加上模块或插件前缀。例如:

MyCoolPowerShellSnapin\Get-User

小实验:清除DNS缓存

首先查看一下有哪些命令可以用:

Screen Shot 2018-05-19 at 3.05.08 PM.png

发现很多都来自DnsClient模块。我们手动加载一下这个模块试一下(其实没有必要):

Screen Shot 2018-05-19 at 3.02.54 PM.png

试一下Clear-DnsClientCache

Screen Shot 2018-05-19 at 3.03.50 PM.png

Es klappt!

使用配置脚本

这个类似于Shell的profile,这里的主要目的是帮你自动加载插件和模块。

Set-ExecutionPolicy RemoteSigned

动手实验:运行网络故障诊断包

Get-Command搜索network没有找到有用的。看了英文版的题目才知道“网络故障诊断包”是Networking troubleshooting pack,那就找一下trouble吧:

Screen Shot 2018-05-19 at 3.25.01 PM.png

Got it!

但是一开始不太会用这个东西,看一下帮助:

Screen Shot 2018-05-19 at 3.31.20 PM.png

这个好像是声音相关的。那我看一下那个目录下都有什么:

Screen Shot 2018-05-19 at 3.32.22 PM.png

太棒了。

Screen Shot 2018-05-19 at 3.33.08 PM.png

然后把它传给Invoke-

Screen Shot 2018-05-19 at 3.30.36 PM.png

不过,这个功能略鸡肋啊。

补充知识

注:在线教程

交互式

基本C语言中的算术运算符在这里都能用。另外0xdeadbeef这种十六进制也可以用。同时,它还能识别tb/gb/mb/kb,如1gb

Screen Shot 2018-05-28 at 6.45.10 PM.png

通过字符串执行外部程序:

Screen Shot 2018-05-28 at 6.47.09 PM.png

通过Get-Command | gm查看命令集的类型(目前我的环境上有三种):

通过函数来将带有常用参数的命令扩展为别名:

function test-conn { Test-Connection  -Count 2 -ComputerName $args}

注意,$args为占位符。

执行VBS脚本:

cscript.exe .\test.vbs

Powershell调用入口的优先级

默认的安全设置禁止执行脚本:

Screen Shot 2018-05-28 at 6.57.12 PM.png

变量

定义变量

以上特性可以参照下图:

Screen Shot 2018-05-28 at 7.05.34 PM.png

变量被存放在VariableDrive中:

Screen Shot 2018-05-28 at 7.07.17 PM.png

验证变量是否存在:

Screen Shot 2018-05-28 at 7.09.49 PM.png

(这与验证文件是否存在一样,关于原理可以参考Chapter 5 使用提供程序

PowerShell提供5个管理变量的命令:

后两个比较有用。比如:

Screen Shot 2018-05-28 at 7.11.58 PM.png

Screen Shot 2018-05-28 at 7.13.56 PM.png

通过help about_scope可以详细了解。

自动化变量

自动化变量是那些一旦打开Powershell就会自动加载的变量:

Screen Shot 2018-05-28 at 7.15.40 PM.png

可以通过

help about_Automatic_Variables

深入了解。

环境变量

关于环境变量:

Screen Shot 2018-05-28 at 7.22.05 PM.png

借助.Net方法,可以使用户设置的环境变量在系统级别生效:

[environment]::SetEnvironmentvariable("myPath", ";c:\powershellscript", "User")

Screen Shot 2018-05-28 at 7.24.08 PM.png

驱动器变量

可以通过${PATH}直接访问文件内容(其实这也是一切皆为“项”的体现):

Screen Shot 2018-05-28 at 7.27.05 PM.png

甚至函数也可以:

Screen Shot 2018-05-28 at 7.28.47 PM.png

$()子表达式:

Screen Shot 2018-05-28 at 7.30.29 PM.png