PowerShell快速上手(针对有C#经验者)

PowerShell是微软一个非常棒的产品,终于改变了人们对Windows下命令行的一片鄙视。一直以来都很想学学PowerShell,这样我就不用使用Python作为手边的脚本语言了,对进行一些文件操作、系统操作而言PowerShell还是要比Python来的方便。另外由于有不少C#的经验,因此PowerShell能够调用.NET库的特性也能够充分利用起来,并且实际发现C#的经验让我学习PowerShell快了不少(当然使用bash、CMake这些脚本的经验应该也帮上忙了吧)。本文就是一篇针对有C#经验的用户的PowerShell上手教程,当然如果你有F#、IronPython等基于.NET的脚本经验那就更好了。

Note: 后文中PowerShell简称PS。

PowerShell脚本的运行方法

PowerShell本质是一个脚本环境/脚本语言。在PS中,语句从第一行开始依次执行,而不像普通程序一样会有一个显式的程序入口(Entry),并且PS的每一行命令(语句)都不用使用结尾标志(如C家族的;)。因此PS脚本的编写将会非常直观,想要输出Hello World只需一行语句即可:

1
echo "Hello World"

运行一段PS脚本有两种方式,一种是在PS交互命令行中直接将命令输入,例如你可以直接在PS命令行中输入35+2,或者$env:Path.GetType()等复杂语句;另一种则是将脚本写在.ps1文件中,然后运行.ps1文件即可。这与大部分脚本语言运行的方法是一致的。

需要指出的是Windows下PS脚本运行是受到系统的限制的,默认系统配置下,如果再PowerShell窗口中直接运行.ps1脚本,PS会提示File cannot be loaded because running scripts is disabled on this system.。解决这个问题有两种方式

  1. 将系统中Windows PowerShell执行策略改为“Bypass”,这个可以通过在PS中运行以下命令完成

    1
    2
    Set-ExecutionPolicy Bypass -Scope CurrentUser
    Set-ExecutionPolicy Bypass -Scope Process # 仅在当前PS进程中生效。
  2. 使用powershell -noprofile -executionpolicy bypass -file <文件路径> [参数]来运行脚本,这是用户友好的方法。由于该命令可以通过cmd或者PS执行,因此可以通过.bat文件封装这个命令,以达到双击运行的效果。

命令 or 参数 or 字符串?

PowerShell中变量名均以$开头。与bash、CMake风格相似的是,PS中的内容如果不以$或者-开头则默认都是命令或者字符串,例如在echo Hello World这样的语句中,echo是命令,HelloWorld都是命令的参数并且都是字符串类型。在PS中,命令/函数的调用有两种形式:

  1. 命令形式:<命令> [参数1] .. [-参数名2 <参数2>] ..,如Get-ChildItem C:\Windows\* -Include *.exe。在这类形式中,参数默认都是字符串,在不含空格时都可以不打引号。这里的命令主要是PS内置的命令(cmdlet)或者别名(alias),通常是一个首字母大写的单词或者用短横连接的两个首字母大写单词。
  2. 函数形式: [对象.]函数(参数1, 参数2, ..),如"abcd".Endswith("cd")。在这类形式中,参数需要通过引号来明确指定是字符串。通过这样的方法使用的是.NET的函数,写起来就和C#没什么区别。

另外,PowerShell支持管道,因此对于命令形式来说可以通过<命令1> | <命令2> | ..的形式来进行链式调用并且传递参数,而函数形式就没法进行链式调用了。

.NET交互(Interop)

PowerShell本身是用C#编写的,并且其内部运行环境也是基于.NET的,因此PS与.NET交互十分简单。

PowerShell对象

PS中的对象均为.NET中的对象,因此PS变量可以直接当作.NET对象进行操作,例如下列语句:

1
2
3
4
5
6
7
>> 123.ToString()           # 报错,因为123既不是变量也不是命令
>> ([int]123).ToString() # 这里将字符串123转换成了System.Int32变量
123
>> (Dir C:\).GetType().Name
Object[]
>> (Get-Item HKCU:\Software).GetType().FullName
Microsoft.Win32.RegistryKey

PS不仅能操作对象,还能够直接创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
# PS中创建.NET对象
>> New-Object -TypeName System.Version -ArgumentList "1.2.3.4"
Major Minor Build Revision
----- ----- ----- --------
1 2 3 4

# PowerShell中的Object对象操作
>> $var = New-Object object
>> $var.GetType().Name
System.Object
>> Add-Member -InputObject $var -Name Value -Value 123 -MemberType NoteProperty
>> $var.Value
123

通过Add-MemberGet-Member命令,PS不仅能够完成.NET中的反射(Reflection),还能够完成类似匿名对象(Anonymous Object)的创建,这个十分有用!

PowerShell中操作.NET类

在PS中可以直接调用.NET库中的类进行操作

  1. 新建对象:New-Object -TypeName System.Version -ArgumentList "1.2.3.4"
  2. 强制转换:[int]"1234"(等同于[System.Int32]"1234"
  3. 调用静态函数: [System.DateTime]::Parse("2012-10-13 23:42:55")
    有了这些操作,PowerShell已经完全可以当一个C#脚本引擎了~

操作符

在利用PS写逻辑流程时就会发现,除了加减乘除外,C#的很多关键字和操作符都不能直接使用。在PS中,这些操作符都变成了命令或者以-开头的命令符了。下表列出了常用的操作符:

类型PS操作符C#操作符
比较-eq==
比较-ne!=
比较-gt>
比较-ge>=
比较-lt<
比较-le<=
类型-isis
类型-asas
逻辑-and&&
逻辑-or||
逻辑-xor^
逻辑-not!
运算-band&
运算-bnot~
运算-bor|
运算-bxor^
运算-shl<<
运算-shr>>
运算-bxor^

另外需要注意的是>>>等等运算符在PS中是重定向运算符。

尽管名字不一样,但是这些操作符的用法还是一样的。另外PS中还定义了一些.NET中没有的操作符,这些操作符通常很实用,如:

  • -contains:返回集合包含元素
  • -in:返回元素是否被集合包含
  • -like: 返回字符串是否与通配式匹配(Wildcard Pattern
  • -match: 返回字符串是否与正则表达式匹配(Regex
  • -f: 等价于String.Format()

PowerShell“驱动”

“驱动”(Drive)是PowerShell中很有意思的一个概念,PowerShell提供了一种统一的接口来管理层次信息系统,包括文件系统(FileSystem)、注册表(Registry)、证书(Certificate)、环境变量(Environment),甚至包括当前会话的变量(Variable)和函数(Function)。这些“Drive”支持统一的一套接口,这就非常的有趣了233。

通过Get-PSDrive命令我们可以获得当前PowerShell会话支持的驱动,在我的电脑上该命令的运行结果如下(省去部分内容)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Name         Provider      Root 
---- -------- ----
Alias Alias
C FileSystem C:\
Cert Certificate \
D FileSystem D:\
E FileSystem E:\
Env Environment
Function Function
G FileSystem G:\
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
Variable Variable
WSMan WSMan

通过这些驱动,ls env:\Path就能够获取系统环境变量,HKCU:\SOFTWARE就可以获取注册表键,十分方便。但是需要注意的是这些驱动获得的对象的类型是不同的,如文件对象会是System.IO.FileInfo,而注册表键则是Microsoft.Win32.RegistryKey

驱动统一支持的命令接口

CmdletAlias用途
Get-ChildItemdir, ls获取当前位置的所有子项
Set-Locationcd更改当前位置
New-Itemmd, mkdir在指定位置新建对象
Get-Item获取该位置对应的对象
Remove-Itemdel, rm删除指定位置的对象
New-ItemProperty新建对象的属性
Get-ItemProperty获取对象的属性(如文件属性,注册表键)
Set-ItemProperty设置对象的属性
Clear-ItemProperty删除对象的属性
Test-Path判断指定位置是否存在对象



看完这些内容以后你就可以像写C#一样开始写PowerShell啦。更加详细的教程可以参见下方的参考资料~

参考资料

Shoot me some coffee money XD
0%