2016 年 10 月

第 31 卷,第 10 期

此文章由机器翻译。

基本 .NET - PowerShell 正在日臻完善

作者 Mark Michaelis | 2016 年 10 月

Mark Michaelis我最近都在着重介绍 .NET Core,但是,在本月的基本 .NET 专栏中,我将一改往日的不同,着重介绍一系列新功能,这些新功能显著增强了 Windows PowerShell 的威力。对我来说,最显著的改进就是跨平台支持 - 是的,PowerShell 现在运行于 Linux。不仅如此,它还迁移至 GitHub 上的开源 (github.com/PowerShell/PowerShell),以便大型社区可以着手增强其功能。太棒了!!

但是最近的公告并未介绍全部信息。二月的时候发布了 PowerShell 5.0,它包括以下方面新的或增强的支持:类和枚举声明、模块和脚本发现、程序包管理和安装、OData 终结点访问、增强的脚本和记录等。在本文中,我将回顾所有这些功能并举例进行说明。

PowerShell 跨平台

首先,请看一看下面的命令脚本(该脚本通过 Windows PowerShell 主机在 Ubuntu 14.04 上安装 PowerShell),以及图 1 中 Windows Bash 的执行会话的屏幕快照(对于不熟悉在 Windows 10 Anniversary Update 上运行 Ubuntu 的 Bash 的用户,请参阅“在 Windows 10 上安装 Bash”。):

wget -O powershell.deb https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.9/powershell_6.0.0-alpha.9-1ubuntu1.14.04.1_amd64.deb
sudo apt-get install libunwind8 libicu52
sudo dpkg -i powershell.deb
powershell

通过 Windows 上的 Ubuntu 的 Bash 在 Ubuntu 14.04 上安装并运行 Windows PowerShell
图 1 通过 Windows 上的 Ubuntu 的 Bash 在 Ubuntu 14.04 上安装并运行 Windows PowerShell

请注意,命令脚本专门针对 Ubuntu 14.04。对于其他平台,deb 包 URL 和必备版本会有所不同。有关你的特定平台的说明,请参阅 bit.ly/2bjAJ3H

多年前,Jeffrey Snover 曾在微博上说 PowerShell 预计会出现在 Linux 上,时隔这么久实现了,而且一直以来有关此进展的报道也很少,甚至今天在使用它时,我自己还是感到不可思议。喔,这一切都是真的吗? 我在运行于 Windows 的 Ubuntu 之上运行 Bash(未利用任何虚拟化技术)并且(假设我并不想将 PowerShell 直接安装到同一 Bash 实例)利用 SSH 将其连接到远程 Bash 会话,其中我可以安装 PowerShell 并在 Bash shell 内的命令之间传输 .NET 对象。

如果我在多年前暗示可以这样做,我怀疑很多人都会相信我。

在 Windows 10 上安装 Bash

从 Windows 10 Anniversary Edition 开始,你可以使用以下 Windows PowerShell 命令将 Bash 安装到本机的 Windows:

Get-WindowsOptionalFeature -Online -FeatureName *linux* | Enable-WindowsOptionalFeature -NoRestart -all –online

但是,需要注意的一点是,此功能仍在测试中,因此,只能在开发人员模式下启用(使用“Get-Help WindowsDeveloper”查看如何探索开发人员模式)。

遗憾的是,此功能不要求重新启动,但是我加入了 -NoRestart 选项以便启用该功能不会直接触发重新启动。

PowerShell 存储库和 PowerShell 库

可以编写你自己的脚本和库是很棒,但社区中的有些人可能已经完成了类似的工作,你可以进行利用并改进。但是,在 PowerShell 库出现前 (PowerShellGallery.com),你需要搜寻 Internet 找到可能有用的脚本和模块 - 不管它们来自社区贡献还是官方 PowerShell 产品发布(如 Pscx 或 Posh-Git 模块)。PowerShell 其中一项最新的改进(PowerShell 5.0 的一部分)是新存储库支持,尤其是 PowerShell 库(我已完全依赖此功能)。例如,设想你编写 PowerShell 已有一段时间,为此,你已了解有很多要避免的缺陷,要是有一种方法可以分析你的代码并从中找到这些缺陷就好了。因此,你可以浏览至 PowerShell 库并搜索要安装的分析模块。或者,更好的方法(因为你或许已打开了 PowerShell 窗口)是你可以利用 PowerShellGet 模块的 Find-Module 命令(包含在 PowerShell 5.0 中):

Find-Module *Analyze* | Select-Object Name,Description

图 2 中显示了该命令的输出。

Find-Module 命令的输出
图 2 Find-Module 命令的输出

请注意,如果你未安装最新的 NuGet 版本,利用 PowerShellGet 模块将会触发 NuGet 包更新。

假设你找到了想要的模块,则可以通过 Save-Module 命令查看其内容。若要安装该模块,请使用 Install-Module(在本示例中,则为 Install-Module PSScriptAnalyzer)命令。此命令将为你下载并安装模块,使模块中包含的所有功能均可用。安装 PSScriptAnalyzer 模块后,你可以调用 Invoke-ScriptAnalyzer $profile 来扫描你的配置文件,并确定分析器认为不理想的方面。(请注意,不再需要导入模块即可进行访问。模块功能将自动编制索引,这样一来,当调用模块功能时,将自动导入模块,从而方便根据需要进行访问。)

请注意,PowerShell 库在默认情况下被配置为存储库:

>Get-PSRepository
Name         InstallationPolicy   SourceLocation
----         ------------------   --------------
PSGallery    Untrusted            https://www.powershellgallery.com/api/v2/

因此,Find-Module 可以正常运行。但是,Install-Module 将会向您发出存储库不受信任的警告。为避免这种情况,假设你确实信任此存储库,则可以使用以下命令将其设置为受信任:

Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

适用于包含 PowerShell 程序包管理的 Windows 的 Apt-Get

对于像你这样长期在 Linux 环境中工作的 IT 专业人员来说,无疑会将 apt-get 视为理所当然( 可能使用他们在启动新的 Linux 实例时会启动其环境的安装脚本)。对于不在 Linux 环境中工作的用户来说,apt-get 是可以通过命令行快速并轻松地从 Internet 下载并安装程序/程序包以及任何依赖项的命令行方法。图 1 简单演示了这样一种安装,利用 apt-get 安装 PowerShell 所依赖的 libunwind8 libicu52(在 Ubuntu 14.04 上)。通过 PowerShell 5.0,Windows 上将会有相同的功能(我真不知道该大喊一声“太棒了!”还是怒叹一声“终于实现了!”,也或许两者皆会做吧)。

就像 PowerShell 模块具有存储库(如 PowerShell 库),PowerShell 5.0 也包括对管理程序(在 Windows 中称为程序包)的支持。其中一种程序包管理器是 Chocolatey (chocolatey.org),你可以使用以下命令将其添加为程序包存储库:

Get-PackageProvider -Name chocolatey

此命令允许你使用 PowerShell 来查找已部署到 Chocolatey 中的程序包。例如,如果你想要安装 Visual Studio Code,只需输入以下命令:

Find-Package V*S*Code | Install-Package

如图所示,支持通配符。

需要熟悉的其他 Package 命令可使用以下命令获取,结果如图 3 中所示:

Get-Help "-package" | Select-Object Name,Synopsis

可用的 Windows PowerShell 程序包命令
图 3 可用的 Windows PowerShell 程序包命令

如你所见,你既可以获取程序包,也可以进行卸载。Get-Package 列出了控制面板的“程序和功能”中的所有可用程序(以及更多)。因此,例如,如果你想要卸载 Notepad2,可以使用以下命令:

Get-Package Notepad2* | Uninstall-Package

此命令为自动化 Windows 计算机设置带来了巨大的易用性。多年来,我一直热衷于 Chocolatey,而此命令将 Chocolatey 支持直接集成到 Windows 中。它最终将程序包管理引入 Windows 中,这与 Apt-Get 在 Linux 上执行的操作几乎相同。

需要考虑的一点是,不仅可以通过 *-package* PowerShell 命令访问 Chocolatey 存储库,而且还可以直接安装 Chocolatey。直接安装 Chocolatey 偶尔会提供程序包管理的一组更强大的功能(并非必需)。幸运的是(或者说讽刺的是),安装 Chocolatey 只是调用 Install-Package Chocolatey 的过程,但是(这是 Chocolatey 和 *-Package 行为之间的差异示例)默认的安装位置将取决于所用的安装引擎。查看 chocolatey.org/install 可获取 Chocolatey 工具集的详细信息,其中包括针对你环境的安装说明。

Export-ODataEndpointProxy 的 OData

另一项值得一提的 PowerShell 5.0 功能是可以生成一组访问 OData 数据源(如 Visual Studio Team Services (VSTS))的方法。图 4 演示了在 OData 服务上运行 Export-ODataEndpointProxy(在本例中为公用示例 Northwind OData 服务)。

生成和调用 OData Proxy
图 4 生成和调用 OData Proxy

如果浏览生成的模块命令,你将注意到为每个实体(通告、类别、人员等)生成了单独的命令以及对应的操作(获取、新建、删除、设置)。

关于图 4 中的命令行,需要注意的一点是 -AllowUnsecureConnection 参数的使用。这一点很有必要,因为此示例中使用的 OData 服务不需要身份验证或加密。

使用 ConvertFrom-String 将文本转换为对象

在 PowerShell 5.0 中出现的另一新命令是 ConvertFrom-String。它旨在设计为将结构化文本作为输入并插入结构以便基于解析文本输出对象。例如,你可以使用此功能来解析平面文件或(这恰恰是我发现它极为有用的地方)将文本输出从可执行内容转换为对象。

例如,请考虑 SysInternal 的 handle.exe 程序(你可以使用 Install-Package Handle 命令安装该程序,利用前面部分中讨论的程序包管理)。正如命令行实用程序的输出那样,它将文本写出到 stdout,在本例中则是与名称相关联的开放句柄列表。但是,在 PowerShell 中,你已经习惯了通过对象工作。并且,若要将文本输出转换为对象,请使用 ConvertFrom-String 函数,如图 5 中所示。

利用 ConvertFrom-String 将 stdout 解析到对象
图 5 利用 ConvertFrom-String 以将 stdout 解析到对象

图 5 从显示 handle.exe 实用程序的原始输出开始。接下来,它演示了没有任何参数的 ConvertFrom-String。结果,ConvertFrom-String 实用程序仅基于空格拆分每行上的文本。

在第三个示例中,我介绍了指定正则表达式拆分模式以优化解析的选项。但是,请注意,并不一定要熟悉正则表达式。你可以指定模板(或者更准确地说是指定文件或字符串示例,其中你手动解析前几个项目)。然后,ConvertFrom-String 利用已解析示例的内容并解释如何解析其余输入。

在最后一个示例中,我添加了 -PropertyNames 参数以向输出分配有意义的名称。

最后,ConvertFrom-String 消除了传统进程 stdout 基于文本的环境与构建于对象之上的 PowerShell 环境的阻抗失配。在本示例中,我可以将输出以管道形式传输到 Stop-Process -Id,将 pid 值映射到 -Id 参数值。

类和枚举

最后,下面是有关新类和枚举支持的概要。在 PowerShell 5.0 中,两个新的关键字添加到相应的两个结构中,以便你现在可以在 PowerShell 中直接声明类或枚举(而非使用 Add-Type 并传送 C# 代码或可能实例化 PSCustom­Object)。语法正是你所期望的 - 参阅图 6

图 6 在 Windows PowerShell 中声明类和枚举

enum CustomProcessType {
  File
  Section
}
class CustomProcess {
  [string]$ProcessName;
  hidden [string]$PIDLabel;
  [int]$PID;
  hidden [string]$TypeLabel;
  [CustomProcessType]$Type;
  [int]$Handle;
  [string]$Path;
  CustomProcess(
    [string]$processName,[string]$pidLabel,[int]$pid,
    [string]$typeLabel,[string]$type,[int]$handle,[string]$path) {
    $this.ProcessName = $processName;
    $this.PIDLabel=$pidLabel;
    $this.PID=$pid;
    $this.TypeLabel=$typeLabel;
    $this.Type=$type;
    $this.Handle=$handle;
    $this.Path=$path;
  }
  CustomProcess() {}
  GetProcess() {
    Get-Process -Id $this.PID
  }
  static StopProcess([CustomProcess]$process) {
    Stop-Process -Id $process.PID
  }
}

尤其需要注意的是,属性和方法均受支持。此外,还具有声明修改工具(如静态和隐藏),将对相关的构造进行相应地指定。此外,继承受与 C# 非常类似的语法的支持:

class Employee : Person {}

最后,可声明构造函数(在图 6 中也进行了演示)。在此示例中,我声明一个默认构造函数(不使用参数)和采用所有参数的第二个构造函数。构造函数通过 New-Object 命令进行调用,方法是指定 ArgumentList 参数(其中列出一组构造函数参数)或通过 -Property 参数传递的 HashTable 参数。

总结

这并未包含 PowerShell 5.0 中的新增功能的完全列表。其他显著的项目包括:

  • 通过 Compress-Archive 和 Expand-Archive 命令进行存档集成(.zip 文件支持)。
  • Get-Clipboard 和 Set-Clipboard 命令也适用于管道运算符。
  • Out-File、Add-Content 和 Set-Content 包括 –NoNewline 参数,允许省略新行字符的文件内容。
  • New-TemporaryFile 命令与 [System.IO.Path]::GetTempFileName 的工作方式类似(尽管并非完全相同)。与其 .NET 等效项类似,New-TemporaryFile 不会删除临时文件,因此请务必保存输出,以便在完成操作后可立即删除文件。
  • 现在,可以从 PowerShell cmdlets New-Item 和 Remove-Item 直接管理 SymbolicLinks。
  • PowerShell 集成脚本环境 (ISE) 现在支持通过 Start/Stop/Search-Transcript 函数记录(以前从 PowerShell ISE 进行调用时,此函数出现错误)。

此外,尽管 PowerShell 的开源版本中未立即支持,但 Microsoft 彻底打算支持 Open SSH,以便其成为 PowerShell 以及 Windows 远程管理中的远程传输选项(在本文章发布后不久)。

所有这些均表明,PowerShell 真的是日臻完善。如果你还不清楚,现在就开始了解吧。


Mark Michaelis 是 IntelliTect 的创始人,担任首席技术架构师和培训师。在近二十年的时间里,他一直是 Microsoft MVP,并且自 2007 年以来一直担任 Microsoft 区域总监。Michaelis 还是多个 Microsoft 软件设计评审团队(包括 C#、Microsoft Azure、SharePoint 和 Visual Studio ALM)的成员。他在开发者会议上发表了演讲,并撰写了大量书籍,包括最新的“必备 C# 6.0(第 5 版)”。  在 Twitter 上与他联系:@markmichaelis 或通过电子邮件,邮件地址是 mark@IntelliTect.com

感谢以下 IntelliTect 技术专家对本文的审阅: Kevin Bost、Phil Spokas 和 Michael Stokesbary