前言
与你进行交互的对象称为宿主应用程序。当运行PowerShell.exe时,你看到的命令行控制台称为控制台主机。图形化的PowerShell ISE通常被称为ISE主机或者图形化主机。其他非微软的应用程序也可以调用PowerShell的引擎。你与宿主应用程序进行交互,之后宿主应用程序将执行的命令传递给该引擎。宿主应用程序会展现引擎产生的结果集。
PowerShell引擎和多种宿主应用程序之间的关系:
每个宿主应用程序负责图形化展现引擎产生的任何输出结果,同时负责通过界面收集引擎需要的任何输入信息。也就意味着,PowerShell可以通过多种方式展现执行结果和收集输入信息。实际上,控制台主机和ISE使用不同的方法收集输入信息:控制台主机会在命令行中展现一个文本的提示框,但是ISE会弹出一个会话框,该会话框中包含文本区域一个“OK”按钮。
为什么一个命令在命令行中的行为与在ISE中的行为大相径庭?这是因为你与Shell交互的方式由宿主应用程序决定,并不是由PowerShell本身决定。
Read-Host命令
Read-Host Cmdlet的功能是展示一个文本提示框,然后收集来自用户的输入信息。
该示例突出了Cmdlet的两个重要的事实。
- 提示信息的最后添加了一个冒号。
- 用户键入的任何信息,都会作为该Cmdlet的返回结果(严格来说,键入的信息被放进了管道)。
图形界面输入框
借助于.Net Framework
本身,创建一个图形界面的输入框:
# 执行一次即可
PS C:\> [void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
PS C:\> $computername = [Microsoft.VisualBasic.Interaction]::InputBox('Enter a computer name', 'Computer Name', 'localhost')
PS C:\> $computername
localhost
该命令会载入.Net Framework中的一个组件Microsoft.VisualBasic
,实际上PowerShell并不会自动载入该组件。该Framework组件包含了大量的VisualBasic核心的框架元素,其中就包括图形化输入框。
让我们看看该命令是怎么实现的:
[Void]
部分将命令的返回结果转化为**[Void]**
类型。- Void数据类型是一种特定的类型,意味着“抛弃产生的结果”。
- 不想看到命令的执行结果,可将其转化为Void类型。等同于将结果集通过管道传递给
Out-Null
。
- 接下来会访问
System.Reflection.Assembly
类型,该类型代表应用程序(这里就是PowerShell)。- 将该类型名称放在一个方括号内,犹如申明了一个该类型的变量。
- 但这里并不是真正申明一个变量,而是用了两个冒号来访问该类型的静态方法。
- 静态方法并不依赖于创建一个该类型的实例而存在。
- 这里使用的静态方法是
LoadWithPartialName()
,该方法用来接收需要添加的Framework组件名称。
一旦该Framework组件被载入,就可以使用它:
在该示例中,再次使用了一个静态方法,这一次是Microsoft .VisualBasic. InteraAction
类型。使用前面的命令,将其载入到内存中。
这里可以修改的地方是InputBox()
方法的3个参数:
- 第一个参数是提示框中的文本信息。
- 第二个参数是提示对话框的标题。
- 第三个参数是显示在输入框中的默认值,其可以是空白或者完全省略。
Write-Host命令
Write-Host会和其他Cmdlet一样使用管道,但是它并不会放置任何数据到管道中。相反,它会直接写到宿主应用程序的界面。正因为可以这样做,所以我们可以使用命令行中的-ForegroundColor
和-BackgroundColor
参数,来将前景和背景设置为其他颜色。
Write-Host会绕开管道,直接写到宿主应用程序的显示界面:
Tips:不是每个使用PowerShell的应用程序都支持其他颜色,也并不是每个应用程序都支持所有颜色。
当需要展示一个特定的信息,比如使用其他颜色来吸引人们的注意力时,应该使用Write-Host命令。但是针对使用脚本或者命令来产生常规的输出结果而言,这并不是一个恰当的方法。还需要记住通过-Host命令输出到屏幕的任何东西都无法被捕捉。-Host命令仅仅用于与人进行直接交互。
Write-Verbose命令
经常看到有人使用Write-Host命令来显示“温暖和模糊”的信息——比如“now connecting to Server-2”“testing for folder”等。现在有更恰当的方法来实现这些功能,就是**Write-Verbose**
。
Write-Verbose命令,默认情况下不会返回任何结果。
如果要使用Write Cmdlet,首先需要打开它们:
- 启用
Write-Verbose
:执行$VerbosePreference="Continue"
- 截断输出:
$VerbosePreference="SilentlyContinue"
针对Write-Debug($DebugPreference)和Write-Warning($WarningPreference)命令也存在类似的“Preference”变量。
Write-Output命令
与Write-Host命令不同,**Write-Output**
命令可以将对象发送给管道。因为它不会直接写到显示界面,所以不允许指定其他任何的颜色。实际从技术来说,Write-Output(别名Write)根本不是被设计出来用于展示结果的。
Tips:Write-Output将对象放入管道,在某些情况下,最终会导致对象被展示出来。
Write-Output命令的工作原理:
将对象从管道传递给显示界面的基本过程:
1)Write-Output
命令将String类型的对象Hello放入到管道中。
2)因为管道中不存在其他对象,Hello会到达管道的末端,也就是Out-Default
命令的位置。
3)Out-Default
命令将对象传递给Out-Host
命令。
4)Out-Host
命令要求PowerShell的格式化系统格式化该对象。
- 因为该示例中为简单的String对象,所以格式化系统会返回该String对象的文本信息。
和Write-Host命令区别
Write-Output执行的结果,类似使用Write-Host命令的返回结果,但是该对象通过不同的路径到达最后阶段。该路径是非常重要的,因为在管道中可以包含其他的对象。
例如,下面的命令:
该命令没有返回任何结果集:
1)“Hello”字符被放进管道,但是在它到达Out-Default命令之前,它必须经由Where-Object命令,该命令会去除长度(Length)属性小于或者等于10的对象。
2)在该示例中,字符对象是“Hello”,所以此时该对象就会从管道中被筛选掉。由于在管道中不存在任何对象可以被传递给Out-Default,因此最终也就没有对象传递给Out-Host命令,那么也就不会显示任何的信息。
将前一个命令与下面的命令进行对比:
该示例中,“Hello”字符会直接被传递给显示界面,而不会进入管道中。Where-Object命令并没有任何传入数据,因此也就不会有任何信息经由Out-Default和Out-Host展现出来。但是由于“Hello”字符已经被直接传递给显示界面,所以我们仍然可以看到它。
Write-Output
是PowerShell默认使用的一个Cmdlet。当你通知PowerShell去完成某项功能(但是又不是使用命令)时,PowerShell会在底层将你键入的任意信息,传递给Write-Output命令。
其他输出方式
PowerShell中也存在其他方法产生输出结果。这些方法都不会像Write-Host那样向管道写入某些信息,它们看起来更像是Write-Host命令。但是它们可以通过可被截断的方式产生结果。
PowerShell针对每种输出方法都有对应的内置配置变量:
- 如果配置变量设置为“Continue”,那么展示的命令就会真正产生输出结果。
- 如果配置变量被设置为“SilentlyContinue”,那么关联的输出命令就不会产生任何信息。
Write-Error命令会有点不一样,它会将错误信息写入PowerShell的错误流中。
为了使用这些Cmdlet,首先需要确保关联的配置变量设置为“Continue”(如果上面的Cmdlet配置变量保留默认值SilentlyContinue,将不会有任何的输出结果)。之后,就可以使用该Cmdlet来输出一些信息。
Write-Information命令
PowerShell v5引入了一个新的命令:Write-Information
。该命令将信息写入一个在Shell中唯一、结构化的流中,从而使得在PowerShell v5中既可以写入结构化数据也可以写入信息消息。
Write-Host底层使用Write-Information命令。点击此处,阅读关于该命令的更新信息。
Write-Information -MessageData "Processes starting with 'P'" -InformationAction Continue
Get-Process -Name p*
进度条命令 - Write-Progress
PowerShell还存在一个Cmdlet Write-Progress
,该Cmdlet可以展示进度条,但是实现原理完全不一样。
for ($i = 1; $i -le 100; $i++ )
{
Write-Progress -Activity "Search in Progress" -Status "$i% Complete:" -PercentComplete $i
Start-Sleep -Milliseconds 250
}