自定义Shell界面

每一个PowerShell进程开启时都是一样的:一样的别名,一样的PSDrives,一样的色彩等。为什么不使用自定义的Shell界面呢?

PowerShell Profile脚本

PowerShell的托管应用程序,比如PowerShell ISE的控制台,是指将命令发送至PowerShell引擎的一种方式。首先PowerShell引擎会执行命令,然后托管应用程序再显示执行结果。托管应用程序的另一个功能是当新开一个Shell窗口时,载入和运行Profile脚本。
这些Profile脚本可被用作自定义PowerShell的运行环境——能够自定义的包括:载入SnapIn管理单元或模块,切换到另外的根路径,定义需要使用的功能等。
例如,下面是一个Profile脚本。
image.png
该Profile载入了常用的两个Shell的扩展程序,并修改根路径为C盘。

在PowerShell中,并没有默认的Profile脚本存在,创建的Profile脚本会依赖于你期望该脚本的工作方式。请执行Help About_Profiles,查看详细信息。
在常规控制台和PowerShell ISE中来回切换时,会希望这两种托管应用程序都运行相同的Profile脚本,所以需要确保在正确的路径下创建正确的Profile脚本。

下面是控制台宿主尝试载入的一些文件,以及尝试载入这些文件的顺序。
1)$PsHome/Profile.PS1:不管使用何种托管应用程序,计算机上的所有用户都会执行该脚本(请记住,PowerShell已经预定义了$PSHome,该变量包含PowerShell的安装文件夹的路径)。
2)$PsHome/Microsoft.PowerShell_Profile.PS1:如果用户使用控制台宿主,那么就会执行该脚本。

  • 如果使用的是PowerShell的ISE,那么会执行$PsHome/Microsoft.PowerShellISE_Profile.ps1脚本。

3)$Home/Documents/WindowsPowerShell/Profile.PS1:无论用户使用的是何种托管应用程序,只有当前用户会执行该脚本(因为该脚本存在于用户的根目录下)。
4)$Home/Documents/WindowsPowerShell/Microsoft.PowerShell_Profile.PS1:只有当前使用PowerShell控制台的用户才会执行该脚本。

  • 如果用户使用的是PowerShell ISE,那么会执行$Home/Documents/WindowsPowerShell/Microsoft.PowerShellISE_Profile. PS1

如果上面脚本中某一个或者几个不存在,那么也没关系。托管应用程序会跳过不存在的脚本,继续寻找下一个可用的脚本。
Tips:

  • 在64位操作系统上,由于存在独立的32位与64位的PowerShell程序,所以脚本也会包括32位与64位的版本。
  • 请不要期望相同的脚本在32位与64位PowerShell中都能正常运行。这意味着,某些模块或者扩展程序仅在某一个架构中才可用,所以请不要尝试使用一个32位的Profile脚本,将某个64位的模块载入32位的PowerShell中,因为这根本不可能成功。

下面是针对该列表的其他一些知识点:

  • $PsHome是包含PowerShell安装路径信息的内置变量;
    • 在大部分操作系统中,该变量的值是C:\Windows\System32\WindowsPowerShell\V1.0(64位版本的PowerShell)。
  • $Home是另一个内置的变量,该变量指向当前用户的配置文件夹(比如C:\Users\Administrator)。
  • 在前面的列表中,使用“Documents”表示文档文件夹,但是在某些版本的Windows系统中可能是“My Documents”。

因为期望将相同的Shell扩展程序载入到PowerShell,而不管是控制台还是ISE,所以我们选择自定义$Home\Documents\WindowsPowerShell\Profile1.PS1。因为该Profile脚本在两种托管应用程序中都可以运行。

请记住,Profile脚本也仅是脚本而已,它会依赖于PowerShell的当前执行策略。如果设置的执行策略是Restricted,那么Profile脚本就无法运行;如果设置的执行策略是AllSigned,那么Profile脚本必须经过签名才能运行。

自定义提示

PowerShell提示,如PS C:>这类字符,是由一个名为提示(Prompt)的内置函数产生的。如果希望自定义该提示,只需要替换该函数即可。可以在Profile脚本中定义一个新的提示函数,这样在每次打开Shell界面的时候都可以采用新的提示函数。
下面是默认的提示函数:
image.png
该函数首先会检测$DebugContext变量,是否被预定义在PowerShell的Variable:Drive中。如果有,那么该函数就会将[DBG]:添加到提示启动阶段。否则,该提示会被定义为PS再加上由Get-Location Cmdlet返回的当前路径(比如PS D:\Test>)。如果该Shell处于嵌套提示中——由内置函数$NestedPromptLevel返回,那么提示中会添加“>>”字样。

下面是自定义的一个提示函数。可以直接将该函数加入到任意Profile脚本中,这样可以保证后续新开启的Shell进程,都会将该提示作为一个标准提示函数使用。

  1. function Prompt {
  2. $Time = (Get-Date).ToShortTimeString()
  3. "$Time [$env:COMPUTERNAME] $(Get-Location)> "
  4. }

image.png

调整颜色

默认的文本前景色与后景色,都可以通过单击PowerShell命令窗口左上角的边框来修改。
image.png
修改错误、警告以及其他信息的颜色略微有点复杂,需要通过运行命令才能实现。但是可以将这部分命令放到Profile脚本中,这样每次进入PowerShell时,都会执行这些命令。
比如可以将错误消息的前景色修改为绿色:(Get-Host).PrivateData.errorforegroundcolor="green"

可以通过命令修改下列设置的颜色:

  • ErrorForegroundColor
  • ErrorBackgroundColor
  • WarningForegroundColor
  • WarningBackgroundColor
  • DebugForegroundColor
  • DebugBackgroundColor``
  • VerboseForegroundColor
  • VerboseBackgroundColor
  • ProgressForegroundColor
  • ProgressBackgroundColor

下面是可以选择的几种颜色:
Red,Yellow,Black,White,Green,Cyan,Magenta,Blue
同时,也存在这些颜色的对应深色颜色:DarkRed, DarkYellow, DarkGreen, DarkCyan, DarkBlue等。

运算符-AS、-IS、-Replace、-Join、-Split、-IN、-Contains

可以通过这些额外的运算符,来处理数据类型、集合与字符串。

–AS和–IS

-AS运算符会将一种已存在的对象转换为新的对象类型,从而产生一个新的对象。例如,如果存在一个包含小数的数字(可能来自一个除法计算),可以通过Converting或者Casting将该数字转化为一个整数。
image.png
语句的结构:首先是一个将被转换的对象,然后是-AS运算符,最后是一个中括号,中括号中包含转化之后的类型。这些类型可以是[String][XML][INT][Single][Double][Datetime]等。在该示例中,将数值转化为整数是指将小数部分通过四舍五入方式转为整数,而并不是简单地将小数部分去掉。

-IS运算符通过类似方式实现。该运算符主要用于判断某个对象是否为特定类型,如果是,则返回True,否则为False。
image.png

–Replace

-Replace运算符主要用于在某个字符串中寻找特定字符(串),最后将该字符(串)替换为新的字符(串)。
image.png
命令的结构:首先是源字符串,之后为-Replace运算符。然后需要提供在源字符串中寻找的字符(串),最后跟上一个逗号外加最新的字符(串)。

–Join和-Split

-Join和-Split运算符,主要用作将数组转化为分隔列表将分隔列表转化为数组

例如,存在包含5个元素的数组,将数组里的值转换为以管道符隔开的字符串:-join

  1. PS C:\> $array="one", "two", "three", "four", "five"
  2. PS C:\> $array
  3. one
  4. two
  5. three
  6. four
  7. five
  8. PS C:\> $array -join "|"
  9. one|two|three|four|five
  10. # 可以将该执行结果存入一个变量,进行复用
  11. PS C:\> $string = $array -join "|"
  12. PS C:\> $string
  13. one|two|three|four|five
  14. # 导出文件
  15. PS C:\> $string | Out-File Data.dat

可以使用-Split运算符实现相反的效果:它会从一个分隔的字符串中产生一个数组。

  1. PS C:\> echo "How are you" >> d:\file.txt
  2. PS C:\> gc D:\file.txt
  3. How are you
  4. PS C:\> $array = (gc D:\file.txt) -split "`t" # 以制表符,进行分割
  5. PS C:\> $array # 未匹配,所以未生效
  6. How are you
  7. PS C:\> $array = (gc D:\file.txt) -split " " # 以空格,进行分割
  8. PS C:\> $array
  9. How
  10. are
  11. you
  12. # 通过索引查询单个元素
  13. PS C:\> $array[1]
  14. are

–Contains和-In

-Contains运算符和-like,容易混淆。

  • -Like运算符用于进行通配符比较运算。
  • -Contains运算符主要用作在一个集合中查找是否存在特定对象。

image.png

-In运算符实现的功能,会颠倒运算对象的顺序。也就是说,集合在右边,而需要检查的对象在左边。
image.png

字符串处理

假如有一个字符串,需要将该字符串全部转化为大写,或者需要取得该字符串的最后3个字符。那么该如何实现?

在PowerShell中,字符串是对象,所以就会存在多种方法(Method)。方法是通知对象去做某项工作的方式,通常是针对对象本身。可以将该对象通过管道发送给Gm查看该对象可用的方法。
image.png
下面是一些比较有用的String方法:
1)IndexOf()会返回特定字符在字符串中的位置。
image.png
2)Split(), Join()和Replace()类似于-Split, -Join和-Replace。但是更倾向于使用PowerShell的运算符。
3)ToLower()和ToUpper()可以将字符串转化为小写或大写。
image.png
4)Trim()会将一个字符串的前后空格去掉;

  • TrimStart()和TrimEnd()会将一个字符串的前面或者后面的空格去掉。

    日期处理

    和String类型对象一样,Date对象也包含多个方法。通过这些方法,可以对日期和时间进行处理和计算。
    image.png
    范例:
    1)访问一个DateTime的部分数据,比如日期、年或者月。
    image.png
    2)获取90天之前的日期,使用AddDays()方法和一个负数参数实现。
    image.png
    3)名称中以“To”开头的方法可以实现将日期以及时间转化为某种特定格式,比如短日期类型。
    image.png

    处理WMI日期

    在WMI中存储的日期和时间格式都难以直接利用。例如,Win32_OperatingSystem类主要用来记录计算机上一次启动的时间,其日期和时间格式如下。 ```python PS C:> Get-WmiObject Win32_OperatingSystem | select LastBootUpTime

LastBootUpTime

20220620103813.500000+480

  1. WMI对象通过管道发送给Gm,请注意观察最后两个方法。<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/635565/1656142776254-5b2b79ad-0dc7-4b68-823b-b15283c6a7e5.png#clientId=u97601627-727e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=434&id=ubcbb1f8a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=543&originWidth=872&originalType=binary&ratio=1&rotation=0&showTitle=false&size=80290&status=done&style=none&taskId=ubb353b7b-50d9-435c-80aa-95f976a532f&title=&width=697.6)<br />在该示例中,获取到的是WMI的日期和时间。假如需要转化为正常的日期和时间格式,请参照下面的命令:
  2. ```python
  3. PS C:\> $OS = Get-WmiObject Win32_OperatingSystem
  4. PS C:\> $OS.ConvertToDateTime($OS.LastBootUpTime)
  5. 2022年6月20日 10:38:13

如果你期望将正常的日期和时间信息放入到一个正常表中,可以通过Select-Object或者Format-Table命令创建自定义计算列以及属性。

PS C:\>  Get-WmiObject Win32_OperatingSystem | select BuildNumber, __Server, @{n='LastBootTime'; e={$_.ConvertToDateTime($_.LastBootUpTime)}}

BuildNumber __SERVER   LastBootTime
----------- --------   ------------
19042       IM20211010 2022/6/20 10:38:13

设置参数默认值

大多数PowerShell命令至少都有几个参数包含默认值。例如,运行Dir命令,默认会指向当前路径,而并不需要指定-Path参数。
在PowerShellv3版及之后的版本,可以对任意命令的任意参数——甚至是针对多个命令,指定自定义的默认值。当运行不带有指定参数的命令时,才会采用设定的默认值;但是当运行命令时手动指定了参数以及对应值,之前设定的默认值会被覆盖。
默认值保存在名为$PSDefaultParameterValues的特殊内置变量中。当每次新开一个PowerShell窗口时,该变量均置空,之后使用一个哈希表填充该变量(可以通过Profile脚本使得默认值始终有效)。

例如,创建一个包含用户名以及密码的凭据对象,然后将该对象设置为所有命令中-Credential参数的默认值。
如果仅希望Invoke-Command Cmdlet每次运行时都提示需要凭据,此时请不要直接分配一个默认值,而是分配一段执行Get-Credential命令的脚本块。
image.png
Add()方法的基本格式:

  • 第一个参数为<Cmdlet>:<Parameter>,该可以接受*等通配符。
  • 第二个参数,可以是直接给出的默认值,或者是执行其他(一个或多个)命令的脚本块。

查看$PSDefaultParameterValues包含的内容:
image.png
可以通过PowerShell中的About_Parameters_Default_Values帮助文档查看该特性更多的知识点。

作用域补充说明

PowerShell的变量由作用域(Scope)控制,同时作用域也会影响参数的默认值。
如果在命令行中设置了$PSDefaultParameterValues,那么该参数会针对本Shell会话中的所有脚本以及命令起作用。但如果仅在一段脚本中设置了$PSDefaultParameterValues,那么只会在该脚本作用域中有用。
这意味着在一段脚本中设置多个参数的默认值,但是并不影响其他脚本或者Shell会话的运行。作用域的核心思想是“无论脚本发生了什么,仅会影响该脚本”。

脚本块

脚本块是PowerShell的一个关键知识点,如下:

  • Where-Object命令的-FilterScript参数会使用脚本块。
  • ForEach-Object命令的-Process参数会使用脚本块。
  • 使用Select-Object或Format-Table创建自定义属性或列的哈希表,都会需要一个脚本块作为E或者Expression的键值。
  • 参数的默认值也可以是一个脚本块。
  • 针对一些远程处理以及Job相关的命令,比如Invoke-Command和Start-Job命令,也需要一个脚本块作为-ScriptBlock参数的值。

那么,什么是脚本块呢?简单来讲,脚本块是指包含在大括号中的全部命令——哈希表除外(哈希表在大括号之前会带有@符号)。你可以在命令行中输入一个脚本块,然后将该脚本块赋值给一个变量,再使用调用运算符&来执行该脚本块
image.png
可以使用脚本块完成更多的工作。如果希望进一步学习脚本块,请参阅PowerShell中的About_Script_Block帮助文档。

其他学习途径

可以订阅我们的Twitter:@jeffhicks@concentrateddon。我们会定期在Twitter上分享一些有用的提示以及小技巧。PowerShell.Org网站上也提供邮件列表定期推送一些小技巧,别忘了还有PowerShell.Org的论坛。