[TOC]

0x00 PS 编程基础

脚本注释

  • 在PS中采用 #字符进行注释


调用优先级
Powershell调用入口的优先级:

  • 别名:控制台首先会寻找输入是否为一个别名,如果是执行别名所指的命令。因此我们可以通过别名覆盖任意powershell命令,因为别名的优先级最高
  • 函数:如果没有找到别名会继续寻找函数,函数类似别名,只不过它包含了更多的powershell命令。因此可以自定义函数扩充cmdlet 把常用的参数给固化进去。
  • 命令:如果没有找到函数,控制台会继续寻找命令,即cmdlet,powershell的内部命令。
  • 脚本:没有找到命令,继续寻找扩展名为“.ps1”的Powershell脚本。
  • 文件:没有找到脚本,会继续寻找文件,如果没有可用的文件,控制台会抛出异常。


PS运行其他脚本

PS运行文件和脚本

  • 脚本和批处理都属于伪可执行文件,它们只是包含了若干命令行解释器能够解释和执行的命令行代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#1.执行批处理文件:批处理是扩展名为”.bat”的文本文件,它可以包含任何cmd控制台能够处理的命令
PS C:\PS> ./ping #实际执行ping.bat
batch File Test
Press any key to continue . . .
Volume in drive C has no label.
Volume Serial Number is 4E9B-D846


#2.执行VB脚本文件,执行.\test.vbs 会遍历当前Win32进程,并把每个进程的详细信息通过窗口显示出来。
Set wmi = GetObject("winmgmts:")
Set collection = wmi.ExecQuery("select * from Win32_Process")
For Each process in collection
WScript.Echo process.getObjectText_
Next

PS C:\PS> cscript.exe .test.vbs #PS执行VB脚本


#3.执行powershell脚本扩展名为“.ps1”
PS C:\PS> echo "dir;Get-PSProvider;help dir" >test.ps1
PS C:\PS> Get-Content ./test.ps1
dir;Get-PSProvider;help dir
PS C:\PS> ./test.ps1

注意事项:

  • 初次执行PS1脚本时可能会碰到一个异常,由于默认安全设置禁用了执行脚本,要启用这个功能需要拥有管理员的权限。

0x01 PS 管道

Q:什么是管道?
答:管道的行为就像一系列连接的管道段一样,沿着管道移动的项会通过每个管道段;

描述:在PS 中创建管道,请使用管道运算符“|”将命令连接在一起,每个命令的输出都将被用作下一命令的输入,与Linux中Shell使用类似但是不同的是它传递的数据不是文本而是对象;

管道中的每个命令(称为管道元素)将其输出逐项传递到管道中的下一个命令

  • 传统的Cmd管道是基于文本的,但是Powershell是基于对象。
  • 管道中传递是对象可以作为下一个cmdlet的参数
  • 可以减少使用复杂命令的工作量,更轻松地查看命令的工作流程
  • 少了资源消耗,并且能够立即开始获取输出提高执行效率

管道的处理模式

  • 顺序模式(较慢):在顺序模式中管道中同一时间只执行一条命令,只有当前一条命令的所有执行完毕,才会把所有结果交付给下一条命令。
    • 优缺点:速度慢并且耗内存,因为需要很多次分配空间存储中间结果。
  • 流模式(较快):流模式会立即执行所有命令,同一时间可能在执行多条命令。
    • 优缺点: 比较节省内存,可能管道的某个任务还在执行,但是已经有部分结果输出了,减少了中间结果的保存。

注意事项:

  • 管道命令也是存在的阻塞,比如在对递归的文件进行排序的时候,需要获取全部文件后才能进行排序; (Dir C: -recurse | Sort-Object)


常用的管道命令:

  • Compare-Object: 比较两组对象。
  • ConvertTo-Html: 将 Microsoft .NET Framework 对象转换为可在 Web 浏览器中显示的 HTML。
  • Export-Clixml: 创建对象的基于 XML 的表示形式并将其存储在文件中。
  • Export-Csv: 将 Microsoft .NET Framework 对象转换为一系列以逗号分隔的、长度可变的 (CSV) 字符串,并将这些字符串保存到
  • 一个 CSV 文件中。
  • ForEach-Object: 针对每一组输入对象执行操作。
  • Format-List: 将输出的格式设置为属性列表,其中每个属性均各占一行显示。
  • Format-Table: 将输出的格式设置为表。
  • Format-Wide: 将对象的格式设置为只能显示每个对象的一个属性的宽表。
  • Get-Unique: 从排序列表返回唯一项目。
  • Group-Object: 指定的属性包含相同值的组对象。
  • Import-Clixml: 导入 CLIXML 文件,并在 Windows PowerShell 中创建相应的对象。
  • Measure-Object: 计算对象的数字属性以及字符串对象(如文本文件)中的字符数、单词数和行数。
  • more: 对结果分屏显示。
  • Out-File: 将输出发送到文件。
  • Out-Null: 删除输出,不将其发送到控制台。
  • Out-Printer: 将输出发送到打印机。
  • Out-String: 将对象作为一列字符串发送到主机。
  • Select-Object: 选择一个对象或一组对象的指定属性。它还可以从对象的数组中选择唯一对象,也可以从对象数组的开头或末尾选
  • 择指定个数的对象。
  • Sort-Object: 按属性值对象进行排序。
  • Tee-Object: 将命令输出保存在文件或变量中,并将其显示在控制台中。
  • Where-Object: 创建控制哪些对象沿着命令管道传递的筛选器。

扩展类型系统”Extended Type System (ETS),ETS会对管道中对象转换成文本的机制进行宏观调控。
ETS由两部分组成:

  • 一部分控制对象的版式:
  • 一部分控制对象的属性: 在管道中将对象结果转换成文本后,不能再将文本转换成对象,因为ETS不能处理文本。

扩充ETS:ETS配置中包含的类型对象会以最佳的方式转换成文本,我们可以ETS配置中包含的类型对象会以最佳的方式转换成文本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#首先确定命令返回结果的对象类型
PS > $object = Get-WmiObject Win32_Processor | Select-Object -first 1
PS > $object.GetType().FullName
System.Management.ManagementObject #发现目标类型为:System.Management.ManagementObject

#其次创建一个配置文件:Win32_Processor.format.ps1xml
System.Management.ManagementObject
<label>Name</label>
<label>Description</label>
<label>ID</label>

PS > Update-FormatData .Win32_Processor.format.ps1xml #加载进ETS
PS > Get-WmiObject win32_processor
# Name Description ID
# ---- ----------- --
# CPU0 x64 Family 6 Model 15 Stepp... BFEBFBFF000006FD

补充:
这样的定义可能有个缺点,当我们获取其它WMI对象时,也会根据我们定义的规则显示。


基础实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#0.键入以下内容看到可读形式的完整列表,通过管道符号传递给其他cmdlet并进行使用
Get-Command -Noun Variable | Format-Table -Property Name,Definition -AutoSize -Wrap
# Clear-Variable [-Name] <string[]> [-Include <string[]>] [-Exclude <string[]>] [-Force] [-PassThru] [-Sc
# ope <string>] [-WhatIf] [-Confirm] [<CommonParameters>]

#1.例如如果使用 Out-Host 来强制逐页显示来自于另一个命令的输出(看起是传递的文本)
Get-ChildItem -Path F: | Out-Host -Paging
Get-ChildItem F: | Out-Host -Paging
<SPACE> next page; <CR> next line; Q quit
# 目录: F:\
# Mode LastWriteTime Length Name
# ---- ------------- ------ ----
# d----- 2019/7/11 12:29 BadUSB-code


#2.如果运行 Get-Location,而当前位置是 C 驱动器的根路径
PS C:\Users\WeiyiGeek> gl
Path #文本输出是信息摘要,而非 Get-Location 返回的对象的完整表示形式
----
C:\Users\WeiyiGeek
#输出中的标题通过格式化屏幕显示数据的过程添加,可以获取有关 Get-Location 返回的对象信息。
Get-Location | Get-Member -MemberType Property
Get-Location | Get-Member -Name Path
# TypeName: System.Management.Automation.PathInfo
# Name MemberType Definition
# ---- ---------- ----------
# Equals Method bool Equals(System.Object obj)

备注:

  • 1.分页还会降低 CPU 利用率,因为准备好显示完整页面时,会转为处理 Out-Host 管道中位于前面的 cmdlet 暂停执行,直到输出的下一页可用。
  • 2.并非所有的PS主机都支持 Paging 参数 例如当你尝试在 PowerShell ISE 中使用 Paging 参数时,会看到以下错误:
WeiyiGeek.

WeiyiGeek.


0x02 PS 对象使用

描述:我们在学习C++和Java/PHP都遇到过面向对象编程,同样在PS也是基于对象来运行的脚本语言;

简单的说 对象=属性+方法:

  • 属性可以描述一个对象,对象的属性可以被PS自动转换成文本,并且输出到控制;

    • 只读属性:一个构造器中只有Get方法,没有Set方法
    • 读写属性:一个构造器中只有Get/Set方法
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      $Host | Get-Member -MemberType Property #查看你对象的属性

      #(1)输出的第一列为对象的属性,第二列为文本形式的属性值
      PS > $host.Version
      Major Minor Build Revision # 包含 Major,Minor,Build,Revision四个属性
      ----- ----- ----- --------
      2 0 -1 -1 # 值Value
      PS > $host.Version.Major #通过对象属性里面的对象进行调用
      5
      PS > [System.Version]'2019.12.20.1234' #可以通过这个类型构造新的对象或者进行类型转换
      Major Minor Build Revision
      ----- ----- ----- --------
      2019 12 20 1234


      #(2)$host的CurrentCulture访问当前系统的本地化信息和该信息的类型:
      PS > $Host.CurrentCulture
      LCID Name DisplayName
      ---- ---- -----------
      2052 zh-CN 中文(中华人民共和国)
      #通过MSDN查看System.Globalization.CultureInfo的构造函数可知,可以将国家代码和国家名称标志字符串转换成一个新的CultureInfo对象。
      PS > [System.Globalization.CultureInfo]'zh-tw'
      LCID Name DisplayName
      ---- ---- -----------
      1028 zh-TW 中文(繁体,中国台湾)
  • 方法定义了一个对象可以做什么事情,当你把一个对象输出在控制台时它的属性可能会被转换成可视的文本,但是它的方法却不可见

    • 标准方法:几乎每个对象都有一些继承自父类的方法,这些方法并不是该对象所特有的方法,而是所有对象共有的方法。
    • Equals 比较两个对象是否相同
    • GetHashCode 返回一个对象的数字格式的指纹
    • GetType 返回一个对象的数据类型
    • ToString 将一个对象转换成可读的字符串
      1
      2
      3
      4
      5
      6
      7
      8
      PS > $Host | Get-Member -MemberType Method #查看对象的方法

      #Get_ 和 Set_ 方法
      PS > $Host.get_Version()
      # Major Minor Build Revision
      # ----- ----- ----- --------
      # 5 1 18362 145
      $Host.UI.WriteDebugLine("Hello 2012 !") #实用的调用输出调试(而不像输出错误的信息)
1.创建对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#(1) New-Object可以创建一个对象,空对象什么都没有,如果调用它不会返回任何东西。
PS > $obj = New-Object object #空对象
PS > $obj
System.Object

#(2) 增加对象属性
PS > Add-Member -MemberType NoteProperty -InputObject $obj -Name Color -Value "Red"
PS > Add-Member -MemberType NoteProperty -InputObject $obj -Name Name -Value "WeiyiGeek"
PS > $obj
# Color Name
# ----- ----
# Red WeiyiGeek

#(3) 增加方法 -memberType 选项使用ScriptMethod。
PS > Add-member -MemberType ScriptMethod -InputObject $obj script {"I'm is function, $obj.name "}
PS > Add-Member -memberType ScriptMethod -InputObject $obj -Name fun -Value { "I'm whittling now" }
PS > $obj | Add-Member ScriptMethod corkscrew { "Pop! Cheers!" } #直接通过管道增加一个新方法

#(4)调用属性和方法
PS > $obj | get-Member #获取对象的属性和方法
PS > $obj
PS > $obj.Name
WeiyiGeek
PS > $obj.script()
I'm is function, System.Object.name'

#(5)对象删除调用对象的Delete方法:
PS > Test-Path $obj
True
PS > $obj.Delete()
PS > Test-Path $obj
False


2.特殊对象

描述:一个NoteProperty包含了静态的数据,一个ScriptProperty中包含了一段脚本,通过脚本计算出属性的值;

1
2
3
4
5
6
7
PS > $obj=New-Object PSobject
PS > $obj | Add-Member -MemberType NoteProperty -Name AddTime -Value (get-date)
PS > $obj | Add-Member -MemberType ScriptProperty -Name CurrentTime -Value {get-date}
#CurrentTime属性会自动更新,AddTime则不会。
AddTime CurrentTime
------- -----------
2012/1/11 14:35:38 2012/1/11 14:36:35 #每次执行会进行改变!


3.静态方法

描述:每一个类型都可以包含一些静态的方法,可以通过方括号和类型名称得到类型对象本身

1
2
3
4
PS > [System.DateTime] | Get-Member -static -memberType *Method
#System.DateTime类支持的静态方法非常实用使用Parse方法将一个字符串转换成DateTime类:
[System.DateTime]::Parse("2012-10-13 23:42:55")
[System.DateTime]::IsLeapYear(1988) #IsLeapYear方法判断闰年


4.对象实例
1
2
3
4
5
6
7
8
9
#根据类型创建实例
$LocalName="c:\PS\Index.php"
$DownUrlFile="https://weiyigeek.com/Index.php"
if(!Test-Path $LocalName){
$webClient=New-Object Net.WebClient;$webClient.DownloadFile($DownUrlFile,$LocalName)
if(Test-Path $LocalName){
Write-Ouput "下载完成"
}
}

0x03 PS 变量

描述:变量Variable在任何一门脚本语言或者说是编程语言中都是存在的,其本质是不相上下的;

  • PS可以创建称为”变量”的命名对象,变量名称可以包含下划线字符任何字母数字字符,且变量名大小写不敏感($a和$A 是同一个变量)
  • 使用变量名称后跟的$字符调用指定变量(与世界上最好的语言相似-你懂的),或者采用${变量名}进行赋值调用,还可以将某些特殊的字符作为变量但是在实际开发中不推荐;
  • 赋值操作符不仅能给一个变量赋值,还可以同时给多个变量赋相同的值,交换变量的值PS只需要两步
  • 变量可以自动存储任何Powershell能够识别的类型信息
  • 采用`或者’’包含变量的都不能进行解析调用变量,只会原样进行输出;
  • 变量会在PS退出或关闭时自动清除

PS变量类型:

  • 自定义变量
  • 自动化变量
  • 环境变量: env:
  • 驱动器变量: varaible:


1.自定义变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#**创建变量**
#0.创建不同类型的变量(int/String/Boolen/float)
PS > $var=1;$var;$var="String";$var;$var='TRUE';$var;$var=3.14159267;$var
# 1
# String
# TRUE
# 3.14159267

#1.将当前位置存储在变量 $loc 中
PS > $loc = Get-Location
PS > $loc #键入 $loc 将显示当前位置:

#2.防止变量名与其他字符串混淆使用${}
PS > $var="Test variable"
PS > $var
Test variable
PS > ${var}
Test variable


#3.某些特殊的字符在PS中有特殊的用途,一般不推荐使用这些字符作为变量名。
PS C:\test> ${"I"like $}="mossfly" #请把整个变量名后缀用花括号括起来
PS C:\test> ${"I"like $}
mossfly


#4.PS给多个变量同时赋值
PS C:\test> $a=$b=$c=123


#5.交换两个变量的值
PS C:\test> $value1=10
PS C:\test> $value2=20
PS C:\test> $value1,$value2=$value2,$value1


#5.采用cmdlet声明变量
New-Variable num -Value 100 -Force -Option readonly #变量写保护
New-Variable num -Value 100 -Force -Option constant -Description "This is my name" #声明常量并且进行描述


#6.变量不解析
PS C:\> Write-Host the '$HOME' is $home
PS C:\> Write-Host the `$HOME is $home
the $HOME is C:\Users\WeiyiGeek


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#**操作变量:**
#1.显示使用驱动器变量和环境变量:
Get-ChildItem variable: #PS将变量的相关信息的记录存放在名为variable:的驱动中
Get-ChildItem variable:value* #查找变量
Get-ChildItem env: #使用任何 Windows 进程可用的相同环境变量,其中包括 cmd.exe

#2.用 env: 驱动器前缀访问环境变量,由于用 env: 驱动器前缀访问环境变量
#例如,cmd.exe 中的 %SystemRoot% 变量包含操作系统的根目录名称
PS > $env:SystemRoot
C:\Windows
PS > $env:JAVA_HOME
Programs\java\jdk

#4.示例创建一个新的环境变量
$env:LIB_PATH='/usr/local/lib'
PS > $env:WEIYIGEEK=$env:PATH
PS > $env:WEIYIGEEK
# C:\Python27\;C:\Python27\Scripts;

#5.示例或者改变更新变量PS中是 + 作为评卷符号
PS > $env:WEIYIGEEK=$env:PATH + ";c:\test"
PS > $env:WEIYIGEEK
# C:\Python27\;C:\Python27\Scripts;c:\test\


#6.验证一个变量是否存在,仍然可以象验证文件系统那样
PS C:\test> Test-Path variable:value1
True
PS C:\test> Test-Path variable:valueUnkonw
False

#7.删除变量
PS C:\test> Test-Path variable:value1
True
PS C:\test> del variable:value1 -Force #强制删除
PS C:\test> Test-Path variable:value1
False
WeiyiGeek.

WeiyiGeek.


2.自动化变量

描述:一旦打开Powershell就会自动加载的变量,并且某些自动化变量只读不能写,一般存放的内容包括:

  • 用户信息:例如用户的根目录$home
  • 配置信息:例如powershell控制台的大小,颜色,背景等。
  • 运行时信息:例如一个函数由谁调用,一个脚本运行的目录等。
1
2
3
4
5
6
7
8
9
10
11
12
13
PS> $HOME
C:\Users\test

PS> $currentProcessID=$pid;$currentProcessID
5356

PS> Get-Process -Id $pid
# Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
# ------- ------ ----- ----- ----- ------ -- -----------
# 390 10 30604 33100 172 1.11 5356 powershell

PS> $PROFILE
C:\Users\test\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

详细说明-自动变量的列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
$$ : 包含会话所收到的最后一行中的最后一个令牌。

$? : 包含最后一个操作的执行状态。如果最后一个操作成功,则包含 TRUE,失败则包含 FALSE。

$^ : 包含会话所收到的最后一行中的第一个令牌。

$_ : 包含管道对象中的当前对象。在对管道中的每个对象或所选对象执行操作的命令中,可以使用此变量。

$Args : 包含由未声明参数和/或传递给函数、脚本或脚本块的参数值组成的数组。
在创建函数时可以声明参数,方法是使用 param 关键字或在函数名称后添加以圆括号括起、逗号
分隔的参数列表。

$ConsoleFileName : 包含在会话中最近使用的控制台文件 (.psc1) 的路径。在通过 PSConsoleFile 参数启动
Windows PowerShell 或使用 Export-Console cmdlet 将管理单元名称导出到控制台文件
时,将填充此变量。
在使用不带参数的 Export-Console cmdlet 时,它自动更新在会话中最近使用的控制台文件。
可以使用此自动变量确定要更新的文件。

$Error : 包含错误对象的数组,这些对象表示最近的一些错误。最近的错误是该数组中的第一个错误对象
($Error[0])。

$Event :包含一个 PSEventArgs 对象,该对象表示一个正在被处理的事件。
此变量只在事件注册命令(例如 Register-ObjectEvent)的 Action 块内填充。
此变量的值是 Get-Event cmdlet 返回的同一个对象。
因此,可以在 Action 脚本块中使用 $Event 变量的属性(例如
$Event.TimeGenerated)。

$EventSubscriber : 包含一个 PSEventSubscriber 对象,该对象表示正在被处理的事件的事件订阅者。
此变量只在事件注册命令的 Action 块内填充。此变量的值
是 Get-EventSubscriber cmdlet 返回的同一个对象。

$ExecutionContext : 包含一个 EngineIntrinsics 对象,该对象表示 Windows PowerShell 主机的执行上下文。
可以使用此变量来查找可用于 cmdlet 的执行对象。

$False : 包含 FALSE。可以使用此变量在命令和脚本中表示 FALSE,而不是使用字符串”false”。如果
该字符串转换为非空字符串或非零整数,则可将该字符串解释为 TRUE。

$ForEach : 包含 ForEach-Object 循环的枚举数。可以对 $ForEach 变量的值使用枚举数的属性和方法。
此变量仅在运行 For 循环时存在,循环完成即会删除。

$Home : 包含用户的主目录的完整路径。此变量等效于 %homedrive%%homepath% 环境变量。

$Host : 包含一个对象,该对象表示 Windows PowerShell 的当前主机应用程序。可以使用此变量在命
令中表示当前主机,或者显示或更改主机的属性,如 $Host.version、$Host.CurrentCulture
$host.ui.rawui.setbackgroundcolor(“Red”)。

$Input : 一个枚举数,它包含传递给函数的输入。$Input 变量区分大小写,只能用于函数和脚本块。(脚本块本质上是未命名的函数。)在函数的 Process 块中,$Input 变量包含当前位于管道中的对象。在 Process 块完成后,$Input 的值为 NULL。如果函数没有 Process 块,则 $Input的值可用于 End 块,它包含函数的所有输入。

$LastExitCode : 包含运行的最后一个基于 Windows 的程序的退出代码。

$Matches : $Matches 变量与 -match 和 -not match 运算符一起使用。
将标量输入提交给 -match 或 -notmatch 运算符时,如果检测到匹配,则会返回一个布尔值,并使用由所有匹配字符串值组成的哈希表填充 $Matches 自动变量。

$MyInvocation : 包含一个对象,该对象具有有关当前命令(如脚本、函数或脚本块)的信息。可以使用该对象中的信息(如脚本的路径和文件名 ($myinvocation.mycommand.path) 或函数的名称
($myinvocation.mycommand.name))来标识当前命令。对于查找正在运行的脚本的名称,这非常有用。

$NestedPromptLevel : 包含当前提示级别。值 0 指示原始提示级别。该值在进入嵌套级别时递增,在退出嵌套级别时递减。
例如,在使用 $Host.EnterNestedPrompt 方法时,Windows PowerShell 会出现嵌套命令提示符。在 Windows PowerShell 调试程序中到达断点时,Windows PowerShell 也会出现嵌套命令提示符。在进入嵌套提示时,Windows PowerShell 暂停当前命令,保存执行上下文,并递增
$NestedPromptLevel 变量的值。要创建更多嵌套命令提示符(最多 128 级)或返回到原始命令提示符,请完成命令,或键入”exit”。
$NestedPromptLevel 变量有助于跟踪提示级别。可以创建包含此值的备用 WindowsPowerShell 命令提示符,以使此值始终可见。

$NULL: 包含 NULL 或空值。可以在命令和脚本中使用此变量表示 NULL,而不是使用字符串”NULL”。
如果该字符串转换为非空字符串或非零整数,则可将该字符串解释为 TRUE。

$PID : 包含承载当前 Windows PowerShell 会话的进程的进程标识符 (PID)。

$Profile : 包含当前用户和当前主机应用程序的 Windows PowerShell 配置文件的完整路径。可以在命令
中使用此变量表示配置文件。例如,可以在命令中使用此变量确定是否已创建某个配置文件:
也可以在命令中使用此变量创建配置文件: new-item -type file -path $pshome -force 此外,还可以在命令中使用此变量在记事本中打开配置文件:
notepad $profile

$PSBoundParameters
包含活动参数及其当前值的字典。只有在声明参数的作用域(如脚本或函数)中,
此变量才有值。可以使用此变量显示或更改参数的当前值,也可以将参数值传递给
其他脚本或函数。

例如:
function test {
param($a, $b)

# Display the parameters in dictionary format.
$psboundparameters

# Call the Test1 function with $a and $b.
test1 @psboundparameters
}

$PsCmdlet : 包含一个对象,该对象表示正在运行的 cmdlet 或高级函数。
可以在 cmdlet 或函数代码中使用该对象的属性和方法来响应使用的条件。例如,ParameterSetName 属性包含正在使用的参数集的名称,而 ShouldProcess 方法将 WhatIf和 Confirm 参数动态添加到 cmdlet。
有关 $PSCmdlet 自动变量的详细信息,请参阅 about_Functions_Advanced。

$PsCulture : 包含操作系统中当前所用的区域性的名称。区域性确定数字、货币和日期等项的显示格式。这是系统的System.Globalization.CultureInfo.CurrentCulture.Name 属性的值。要获取系统的 System.Globalization.CultureInfo 对象,请使用 Get-Culture cmdlet。

$PSDebugContext : 在调试期间,此变量包含有关调试环境的信息
在其他时间,此变量包含 NULL 值。因此,可以使用此变量指示调试程序是否拥有控制权。填充之后,此变量包含一个具有 Breakpoints 和InvocationInfo 属性的 PsDebugContext 对象。InvocationInfo 属性有多个十分有用的属性,包括 Location 属性。Location 属性指示正在调试的脚本的路径。

$PsHome
包含 Windows PowerShell 的安装目录的完整路径(通常为%windir%System32WindowsPowerShellv1.0)。可以在 Windows PowerShell 文件的路径中使用此变量。例如,下面的命令在概念性帮助主题中搜索”variable”一词:
select-string -pattern variable -path $pshome*.txt

$PSScriptRoot :包含要从中执行脚本模块的目录。通过此变量,脚本可以使用模块路径来访问其他资源。

$PsUICulture
包含操作系统中当前所用的用户界面 (UI) 区域性的名称。UI 区域性确定哪些文本字符串用于用户
界面元素(如菜单和消息)。这是系统的
System.Globalization.CultureInfo.CurrentUICulture.Name 属性的值。要获取系统
的 System.Globalization.CultureInfo 对象,请使用 Get-UICulture cmdlet。

$PsVersionTable
包含一个只读哈希表,该哈希表显示有关在当前会话中运行的 Windows PowerShell 版本的详
细信息。
该表包括下列项:
CLRVersion: 公共语言运行时 (CLR) 的版本
BuildVersion: 当前版本的内部版本号
PSVersion: Windows PowerShell 版本号
WSManStackVersion: WS-Management 堆栈的版本号
PSCompatibleVersions: 与当前版本兼容的 Windows PowerShell 版本
SerializationVersion :序列化方法的版本
PSRemotingProtocolVersion:Windows PowerShell 远程管理协议的版本

$Pwd : 包含一个路径对象,该对象表示当前目录的完整路径。

$Sender : 包含生成此事件的对象。此变量只在事件注册命令的 Action 块内填充。
此变量的值也可在 Get-Event 返回的 PSEventArgs
(System.Management.Automation.PSEventArgs) 对象的 Sender 属性中找到。

$ShellID : 包含当前 shell 的标识符。

$SourceArgs : 包含表示正在被处理的事件的事件参数的对象。此变量只在事件注册命令的 Action
块内填充。此变量的值也可在 Get-Event 返回的 PSEventArgs
(System.Management.Automation.PSEventArgs) 对象的 SourceArgs 属性中找到。

$SourceEventArgs : 包含一个对象,该对象表示从正在被处理的事件的 EventArgs 中派生出的
第一个事件参数。此变量只在事件注册命令的 Action 块内填充。
此变量的值也可在 Get-Event 返回的 PSEventArgs
(System.Management.Automation.PSEventArgs) 对象的 SourceArgs 属性中找到。

$This : 在定义脚本属性或脚本方法的脚本块中,$This 变量引用要扩展的对象。
$True : 包含 TRUE。可以在命令和脚本中使用此变量表示 TRUE。


3.环境变量

描述:环境存在于操作系统之中,但是如果环境变量被更新了其它程序也可以更新调用它。

基础实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#1.读取特殊的环境变量
PS> ls $env:
PS> $env:windir
C:\Windows
PS> $env:ProgramFiles
C:\Program Files


#2.为了和其它变量保持一致,你可以把它插入到文本中。
PS> "My computer name $env:COMPUTERNAME"
My computer name MYHome-test-01


#3.创建新的环境变量
PS> $env:TestVar1="This is my environment variable"
PS> $env:TestVar2="Hollow, environment variable"
PS> $env:Path+=";C:\\python\\"


#4.环境变量更新生效
# .NET方法[environment]::SetEnvironmentvariable操作可以立刻生效。
PS> [environment]::SetEnvironmentvariable("Path", ";c:\WeiyiGeek", "User")
PS> [environment]::GetEnvironmentvariable("Path", "User")
;c:\WeiyiGeek

备注:

  • 尽管没有要求,但环境变量名称通常使用全部大写字母。


4.驱动器变量

描述:PS中所有不是我们自己的定义的变量都属于驱动器变量(比如环境变量),它的前缀只是提供给我们一个可以访问信息的虚拟驱动器.。

基础实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#0.查看你PS支持的驱动器
PS > Get-PSDrive
# Name Used (GB) Free (GB) Provider Root CurrentLocation
# ---- --------- --------- -------- ---- ---------------
# C 58.24 91.76 FileSystem C:\ Users\WeiyiGeek
# Cert Certificate \
# D 11.76 249.24 FileSystem D:\
# E 19.07 240.93 FileSystem E:\
# Env Environment
# F 88.83 171.46 FileSystem F:\
# Function Function
# G FileSystem G:\
# HKCU Registry HKEY_CURRENT_USER
# HKLM Registry HKEY_LOCAL_MACHINE
# I FileSystem I:\
# Variable Variable
# WSMan WSMan


#1.$后花括号中的路径必须是具体的路径,而不能带返回值。
PS> Invoke-Expression "`${$env:HOMEDRIVE/Powershell/ping.bat}" #反引号"\`"放在$前,会把$解析成普通字符,解释器会继续去解析第二个$
#参数=${C:/Powershell/ping.bat}


5.变量作用域

描述:PS所有的变量都有一个决定变量是否可用的作用域,有了作用域就可以限制变量的可见性了,尤其是在函数和脚本中。
PS支持四个作用域:全局、当前、私有和脚本

设置单个变量的作用域:

  • $global 全局变量,在所有的作用域中有效,如果你在脚本或者函数中设置了全局变量,即使脚本和函数都运行结束这个变量也任然有效。
  • $script 脚本变量,只会在脚本内部有效,包括脚本中的函数,一旦脚本运行结束变量就会被回收。
  • $private 私有变量,只会在当前作用域有效,不能贯穿到其他作用域。
  • $local 默认变量,可以省略修饰符,在当前作用域有效,其它作用域只对它有只读权限。

总结:

  • 本地变量会从全局变量继承值,但是本地变量的更改不会影响全局变量,除非显示制定global;

利用”.”来更改变量的可见性,加强变量可见性限制的优点清空初始化环境,注意点:如果定义的是一个自读的常量的时候,这个是不能操作和删除的;

1
2
3
4
5
6
7
8
9
10
11
12
13
#1.对比案例-脚本里面的变量不影响交互式环境中的变量
PS E:\WeiyiGeek> $DemoVar="This is a Demo"
PS E:\WeiyiGeek> .\Demo1.ps1
D:\Programs\java\jdk
PS E:\WeiyiGeek> $DemoVar
This is a Demo


#2.点"."来运行脚本,该符号域Linux中的source命令有异曲同工之妙;
PS E:\WeiyiGeek> . .\Demo1.ps1
D:\Programs\java\jdk
PS E:\WeiyiGeek> $DemoVar
D:\Programs\java\jdk #关键点

单个变量作用域实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#1.在当前控制台只存在一个作用域,通过修饰符访问,其实访问的是同一个变量:
PS C:\Users\WeiyiGeek> $var="WeiyiGeek"
PS C:\Users\WeiyiGeek> $private:var
WeiyiGeek
PS C:\Users\WeiyiGeek> $script:var
WeiyiGeek
PS C:\Users\WeiyiGeek> $global:var
WeiyiGeek
PS C:\Users\WeiyiGeek> $local:var="WeiyiGeek"
WeiyiGeek


#2.Private修饰符在控制台中的变量保护起来,不让它在函数和脚本中被访问,但他可以被Global修饰符修改;
function fun() {"DemoVar=$DemoVar";$DemoVar="Function Inner";$DemoVar;}
$Private:DemoVar="this is private"
fun;$DemoVar
$Global:DemoVar="This is global"
fun;$DemoVar
$Private:DemoVar

# 执行结果
# DemoVar=
# Function Inner
# this is private
# DemoVar=
# Function Inner
# this is global
# This is global

#3.Global修饰符中验证对private修饰符的影响
function fun() {"DemoVar=$DemoVar";$Global:DemoVar="This is Global";$DemoVar;}
$Private:DemoVar="this is private"
$DemoVar
fun #对后续变量存在影响
$DemoVar
# 执行结果
# this is private
# DemoVar=this is private
# This is Global
# This is Global


#4.Local修饰符可以通过$global修饰符修饰的变量
function fun() {"DemoVar=$DemoVar";$Global:DemoVar="This is Global";$DemoVar;}
$Local:DemoVar="this is Local"
$DemoVar
fun
$Local:DemoVar
# 执行结果
# this is Local
# DemoVar=this is Local
# This is Global
# This is Global


6.变量类型转换

PS弱类型和强类型
描述:PS给数据分配一个最佳的数据类型也称作“弱类型”,如果一个整数超出了32位整数的上限([int32]::MaxValue),它就会分配一个64位整数的数据类型;同样如果是小数,字符串,日期时间也会分配成为该对应的数据类型,使用时候非常的方便;

弱类型带来的风险:
例如:有一个变量要存储的是即将拷贝文件的个数,可是在赋值时付了一个字符串,Powershell不会去做过多的判断,它会更新这个变量的类型,并且存储新的数据。

通过$variable的GetType().Name查看和验证PS分配给变量的数据类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PS C:\Users\WeiyiGeek> $var=1024;$var.GetType().name
Int32
PS C:\Users\WeiyiGeek> (999999999999999).GetType().name
Int64
PS C:\Users\WeiyiGeek> (99999999999999999999).GetType().name
Decimal
PS C:\Users\WeiyiGeek> (3.14).GetType().name
Double
PS C:\Users\WeiyiGeek> (3.14d).GetType().name
Decimal
PS C:\Users\WeiyiGeek> ("String").GetType().name
String
PS C:\Users\WeiyiGeek> (date).GetType().name
DateTime
PS C:\Users\WeiyiGeek> (get-date).GetType().name
DateTime

强类型的优点:

  • 严谨防止程序异常,不会根据数据进行转换数据类型,
  • 手动地定义类型的一个重要原因是每个特殊的数据类型都有自己的特殊命令和特殊方法,
  • PS中使用它的另一个原因是每一个数据类型都有属于自己的函数;

Powershell 默认支持的.NET类型如下:

  • [Byte] [sbyte]
  • [Char]
  • [Bool]
  • [Int] [Int16] [Int32] [Int64]
  • [uint16] [uint32] [uint64]
  • [float]
  • [double]
  • [array]
  • [string]
  • [long]
  • [Decimal]
  • [timespan]
  • [DateTime]
  • [type]
  • [switch]
  • [guid]
  • [nullable]
  • [hashtable]
  • [psobject]
  • [regex]
  • [scriptblock]
  • [single]
  • [Xml]

指定类型定义变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#1.例如定义一个Byte类型的变量,因为Byte的定义域为[0,255],一旦尝试使用一个不在定义域中的值赋给该变量就会显示一条错误信息。
PS C:\Users\WeiyiGeek> [byte]$b=254
PS C:\Users\WeiyiGeek> $b.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Byte System.ValueType


#2.DateTime类型对象的属性的使用
PS C:\Users\WeiyiGeek> [DateTime]$date="2019-11-27 09:19:20"
PS C:\Users\WeiyiGeek> $date
2019年11月27日 9:19:20
PS C:\Users\WeiyiGeek> $date.DayOfWeek
Wednesday
PS C:\Users\WeiyiGeek> $date.DayOfyear
331
PS C:\Users\WeiyiGeek> $date.AddDays(-10)
2019年11月17日 9:19:20


#3.XML类型对象的使用查询.exe 和 .dll结点
PS > [XML]$xml=(Get-Content .\Demo2.xml)
PS > $xml
# logotest
# --------
# logotest
PS > $xml.FirstChild
# extensions unextensions
# ---------- ------------
# extensions unextensions
PS > $xml.logotest.extensions.e
# .exe
# .dll


变量强弱类型转换
描述:每个变量的都有自己的类型,这个具体的类型存放在PsVariable对象的Attributes[System.Management.Automation.PSVariableAttributeCollection]属性,如果这个Attributes为空,可以给这个变量存放任何类型的数据,PS会自己选择合适的类型。

注意事项: 一旦Attribute属性确定下来就不能随意存储其他类型的数据;

  • 例如给$var存放一个整数,属于弱类型,所以Attributes属性为空,这时还可以给它赋值一个字符串。但是如果给$var增加强类型,存放一个整数,再给它赋值一个其它类型,解释器会自动尝试转换,如果不能转换就会抛出异常。

解决办法:使用 (Get-Variable var).Attributes.Clear() 清空Attributes,此时强类型又转变成为弱类型了;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#1.默认申明的变量是弱类型
PS C:\Users\WeiyiGeek> $var=1024
PS C:\Users\WeiyiGeek> (Get-variable var).Attributes
PS C:\Users\WeiyiGeek> $var.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int32 System.ValueType

PS C:\Users\WeiyiGeek> $var=3.14
PS C:\Users\WeiyiGeek> $var.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Double System.ValueType


#2.强类型转弱类型
PS C:\Users\WeiyiGeek> [Int]$var=1024

PS C:\Users\WeiyiGeek> (Get-variable var).Attributes
TransformNullOptionalParameters TypeId
------------------------------- ------
True System.Management.Automation.ArgumentTypeConverterAttribute

PS C:\Users\WeiyiGeek> $var=3.14;$var
3

PS C:\Users\WeiyiGeek> $var="2019 IS END"
#无法将值“2019 IS END”转换为类型“System.Int32”。错误:“输入字符串的格式不正确。”

PS C:\Users\WeiyiGeek> (Get-variable var).Attributes.clear()#关键点-强类型清除
PS C:\Users\WeiyiGeek> $var="2019 IS END";$var
2019 IS END


6.变量验证检查

描述:变量PSVariable对象的Attributes属性能够存储一些附件条件
常用的变量内容验证分别为:

  • ValidateLengthAttribute:限制变量的长度
  • ValidateNotNullAttribute:限制变量不能为空
  • ValidateNotNullOrEmptyAttribute:限制变量不等为空,不能为空字符串,不能为空集合
  • ValidatePatternAttribute:限制变量要满足制定的正则表达式
  • ValidateRangeAttribute:限制变量的取值范围
  • ValidateSetAttribute:限制变量的取值集合

基础实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#1.ValidateLengthAttribute 限制一个字符串变量的长度为位于2-5之间
PS> $var="限制变量"
PS> $condition= New-Object System.Management.Automation.ValidateLengthAttribute -ArgumentList 2,5 #关键点
PS> (Get-Variable var).Attributes.Add($condition)
PS> $var="射雕英雄传" #变量长度位于2-5之间


#2.ValidateNotNullAttribute 例子
PS> $a=123
PS> $con=New-Object System.Management.Automation.ValidateNotNullAttribute
PS> (Get-Variable a).Attributes.Add($con)
PS> $a=$null #无法验证此变量,因为值 不是变量 a 的有效值。


#3.ValidateNotNullOrEmptyAttribute 例子 注意@()为一个空数组。
PS> $con=New-Object System.Management.Automation.ValidateNotNullOrEmptyAttribute
PS> (Get-Variable a).Attributes.clear()
PS> (Get-Variable a).Attributes.add($con)
PS> $a=$null


#4.ValidatePatternAttribute 例子利用正则表达式验证Email格式
PS> $email="[email protected]"
PS> $con=New-Object System.Management.Automation.ValidatePatternAttribute "[A-Z0-9._%+-][email protected][A-Z0-9.-]+.[A-Z]{2,4}"
PS> (Get-Variable email).Attributes.Add($con)
PS> $email="[email protected]"


#5.ValidateRangeAttribute 例子验证月份1-12
PS> $month=1
PS> (Get-Variable month).Attributes.Add($(New-Object System.Management.Automation.ValidateRangeAttribute -ArgumentList 1,12))
PS> $month=10


0x04 PS 运算

描述:我们可以把PS看作是一个非常强大的计算器,除了支持数学表达式运算符还支持计算机容量单位和HEX进制转换;

运算符号表:

1
2
3
4
5
6
- ()
- +
- -
- *
- /
- %

计算机容量单位:

1
2
3
4
5
- KB
- MB
- GB
- TB
- PB

基础实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#1.四则运算(交换式)
PS > 3.14*10*10
314
PS > 1+3-(2.4-5)*(7.899-4.444)
12.983
#由 $+圆括号+表达式 构成的变量属于子表达式变量,这样的变量会先计算表达式,然后把表达式的值返回。
PS C:\Users\WeiyiGeek> $((3+9)/3)
4

#2.十六进制转换
PS > 0xA
10
PS > 0xB
11
PS > 0xff
255


#3.自动识别计算机容量单位
PS > 1kb
1024
PS > 1GB
1073741824
PS > 1gb
1073741824
PS > 1gb/1kb
1048576
PS > 1gb/20mb*10kb
524288

#4.假如一个网站每个页面大小为80kb,统计显示每天的PV操作为800,1个月下来占用的带宽:
PS C:\pstest> 80kb*800*30/1gb
1.8310546875