Windows Powershell变量的力量

Don Jones

如果使用基于 Windows 的脚本语言(如 VBScript 或 KiXtart),您会习惯于认为变量只不过是一种数据存储机制。Windows PowerShell 也具有变量,但这些变量要比早期脚本语言中的变量强大得多。Windows

PowerShell 变量实际上映射到 Microsoft® .NET Framework 中的基础类。在 Framework 中,变量是对象,这就意味着变量可以存储数据,也可以通过多种方法进行处理。实际上,正是由于 Windows PowerShell™ 中变量的强大功能,使得 Windows PowerShell 脚本语言不包含任何内部数据处理函数。它根本不需要这些函数,因为变量本身就已经提供了这种功能。

声明变量

尽管 Windows PowerShell 中的 New-Variable cmdlet 确实允许您声明变量并为其赋予初始值,但您并不一定要使用 cmdlet。作为一种替代方式,您只需通过为变量赋值即可即时地创建新的变量:

$var = "Hello"

在 Windows PowerShell 中,变量名始终以一个美元符号 ($) 开头,并可以混合使用字母、数字、符号、甚至空格(但如果使用空格,则需要将变量括在花括号中,例如 ${My Variable} = "Hello")。此示例创建了一个名为 $var 的新变量,并为其赋予初始值 "Hello"。因为本例中的变量值是字符串,所以 Windows PowerShell 会使用 String 数据类型来存储该值。在 .NET Framework 中,这些字符串变量对应于 System.String 类。System.String 类或许拥有任何变量类型的大部分内置功能。假设我要查看 $var 值的全小写版本,则可以执行以下命令:

PS C:\> $var.ToLower()
hello
PS C:\>

ToLower 方法内置于 System.String 类中,可以使字符串的值以全小写形式来表示。但它并不更改变量 $var 的实际内容。要查看 System.String 类所有功能的完整列表,请像下面这样通过管道将一个字符串变量传递给 Get-Member cmdlet:

$var | get-member

图 1 显示了输出结果,其中包含许多用于处理字符串的方法。在 Windows PowerShell 中,VBScript 字符串处理函数所提供的几乎所有功能都改由字符串变量方法来提供。

Figure 1 A look at the System.String class output

Figure 1** A look at the System.String class output **(单击该图像获得较大视图)

在管理上下文中,字符串变量的许多功能比语言(如 VBScript)中的字符串函数要有用得多。假设您编写了一个用于从文件中读入通用命名约定 (UNC) 路径并对其进行操作的脚本。在尝试使用路径之前,您可能要验证所读入的每个路径是否为 UNC 路径。可通过 StartsWith 方法来确认字符串值是否以 UNC 所必需的反斜线字符开头:

PS C:\> $path = "\\Server\Share"
PS C:\> $path.StartsWith("\\")
True
PS C:\>

由于 StartsWith 返回 True 或 False 值,因此可将其用在逻辑构造中:

if ($path.StartsWith("\\")) {
 # code goes here
}

Windows PowerShell 甚至还提供了一种自动完成变量方法的形式,从而减少了必要的键入工作量。如果 $var 包含一个字符串,您可以键入

$var. 

然后按 Tab,这样会弹出 $var 变量的第一个方法名。再按一次 Tab 键可移到下一个方法,而按 Shift+Tab 会调出前一个方法。您可以通过这种方式遍历所有可用的方法,直到找到您想要的那一个。

变量混淆

到目前为止,我的示例一直在让 Windows PowerShell 来确定变量的数据类型。将字符串赋给变量实质上会强制变量成为 System.String 类。而另一方面,将数字赋给变量通常会使变量成为 Integer(或者更确切地说,是成为 Int32,其可以存储特定范围的值)。例如,考虑以下脚本:

PS C:\> $int = 5
PS C:\> $int | get-member

  TypeName: System.Int32

这一被截断的输出说明 Windows PowerShell 将 $int 视为 Int32,Int32 有其自己的方法和属性集。而实际上,其方法和属性要比 String 类型的方法和属性少得多。

将 $int 作为 Int32 是因为其值没有括在引号中而且仅由数字组成。如果将其值括在引号中,则它会被视为 System.String。

让 Windows PowerShell 来决定要使用的数据类型并不是总能达到您所希望的效果。假设您要从文件读取变量值,而又希望这些值始终被视为字符串。但是,其中一些值可能只包含数字,这就增加了 Windows PowerShell 将其视为 Int32 或其他数字类型的可能性。这样可能会使脚本出现问题。如果 Windows PowerShell 不将值识别为字符串,则 System.String 类的所有方法都无法使用(而您的脚本可能要依赖于这些无法使用的方法中的一个)。

要解决这一问题,可以在第一次使用变量时声明其类型,从而强制 Windows PowerShell 将变量按该特定类型处理。示例如下:

[string]$var = 5

$var 通常应为 Int32 类型,但在此示例中我强制 Windows PowerShell 将 $var 作为 String,从而确保了我可以使用与 System.String 类相关的所有方法。变量类型声明也提供了一种便捷的代码自我文档化方式,因为现在哪种类型的数据要进入 $var 中是显而易见的。实际上,我已经养成了为所有变量声明特定类型的习惯,而完全不管是不是在 Windows PowerShell 中。这使得我脚本的行为更加可以预测,在许多情况下为我节省了大量的调试时间。

正如您所料,尽管强制声明变量未必不好,但也确实会产生影响。以下面的代码为例,代码中未声明变量的类型:

PS C:\> $me = 5
PS C:\> $me = "Don"

$me 变量最初为 Int32 类型,但在添加了值“Don”后 Windows PowerShell 将该变量改为 String 类型。如果变量尚未被明确地设置为某个特定的类型,Windows PowerShell 可以根据需要更改变量的类型。

在本例中,我使用 [int] 类型名将 $me 强制为 Int32 类型:

PS C:\> [int]$me = 5
PS C:\> $me = "Don"
Cannot convert value "Don" to type 
"System.Int32". Error: "Input string 
was not in a correct format."
At line:1 char:4
+ $me <<<< = "Don"

然后,当我尝试为其赋予字符串值时,会出现一条错误消息。因为我已明确地将 $me 强制为 Int32 类型,所以 Windows PowerShell 要将字符串“Don”转换为整型值。然而这样做是不可能的,而且将 $me 的类型更改为 String 也是不可能的。

许多类型

Windows PowerShell 中提供了很多的类型。实际上,您可以使用任何的 .NET Framework 类型(可用的类型有数百个)。但 Windows PowerShell 为常见的数据类型定义了许多快捷方式。图 2 只是部分列表,显示了 10 个最常用类型的快捷方式。有关完整列表,请参考 Windows PowerShell 文档。

Figure 2 常见类型快捷方式

快捷方式 数据类型
[datetime] 日期或时间
[string] 字符串
[char] 单个字符
[double] 双精度浮点数
[single] 单精度浮点数
[int] 32 位整数
[wmi] Windows Management Instrumentation (WMI) 实例或集合
[adsi] Active Directory 服务对象
[wmiclass] WMI 类
[Boolean] True 或 False 值

您还可以使用完整的 .NET Framework 类名来声明变量的类型,如下所示:

[System.Int32]$int = 5

您可以通过这一技术来使用存在于 .NET Framework 中但在 Windows PowerShell 中没有特定快捷方式的类型。

扩展类型

Windows PowerShell 最爽的地方或许就是它能够扩展这些变量类型的功能。在 Windows PowerShell 安装文件夹(通常在 %systemroot\system32\windowspowershell\v1.0 中,但在 64 位系统上您会发现此路径略有不同)中,您会找到名为 types.ps1xml 的文件。可以在记事本或 XML 编辑器(如 PrimalScript)中编辑此文件。默认情况下,尽管其中列出了许多其他类型,但并未列出 System.String 类。但我可以向 System.String 类型添加新的功能,只需将其扩展添加到 types.ps1xml 文件中即可实现。

进行更改后,需要关闭 Windows PowerShell,然后再重新打开。我还需要确保本地脚本执行策略允许执行未签名的脚本,因为我未对 types.ps1xml 进行签名:

Set-executionpolicy remotesigned

现在,只要重新启动 Windows PowerShell,我就可以使用新功能了,如下所示:

PS C:\> [string]$comp = "localhost"
PS C:\> $comp.canping
True
PS C:\>

正如您所看到的那样,我已经将 CanPing 属性添加到 System.String 类。这样会返回 True 或 False 值,来指示本地计算机能否 ping 字符串中所含的地址。在图 3 中,您会注意到 WMI 查询使用了一个特殊的变量 $this。$this 变量代表字符串中所含的当前值,也是字符串变量内容传递给 WMI 查询的方式。

Figure 3 扩展 System.String 类型

<Type>
  <Name>System.String</Name>
  <Members>
    <ScriptProperty>
      <Name>CanPing</Name>
      <GetScriptBlock>
      $wmi = get-wmiobject -query "SELECT *
FROM Win32_PingStatus WHERE Address = '$this'"
      if ($wmi.StatusCode -eq 0) {
        $true
      } else {
        $false
      }
      </GetScriptBlock>
    </ScriptProperty>
  </Members>
</Type>

让变量工作

Windows PowerShell 提供了灵活的、功能众多的变量类型,也提供了同样灵活的类型功能扩展系统。这些功能使您可以很容易地为您的脚本注入大量的功能。实际上,变量可以成为复杂脚本中的主要构建基块,在许多情况下提供着通常在更为复杂的函数中才能找到的高级功能。

在线了解更多信息

请加入我于每月第二个星期二举办的系列网络广播,在网络广播中我们将继续探究 Windows PowerShell 所提供的丰富脚本功能。请访问 microsoft.com/events/series/donjonesscripting.mspx 立即注册。

2007 年 2 月 20 日 Windows PowerShell:脚本速成课程

请加入此网络广播以了解 Windows PowerShell 中的变量、语言构造、脚本和函数。在这一小时的速成课程中,我们将演示 Windows PowerShell 中简单但很有效的脚本语言如何加快 Windows® 的管理自动化进程。我们还将探究一些能够尽可能简化 Windows PowerShell 脚本的第三方工具。

2007 年 3 月 20 日 Windows PowerShell:函数、筛选器和效率

学习在 Windows PowerShell 函数和筛选器中创建有效的、模块化的代码。我们将探讨 Windows PowerShell 中能够让您完全封装函数和筛选器的强大作用域规则,并将说明如何轻松地在项目之间重复使用这些函数和筛选器。我们还会以实例说明如何将自己自定义的函数添加到 Windows PowerShell 中的全局作用域,从而可以轻松地组建一个随时可用的有用工具函数库。

2007 年 4 月 17 日 Windows PowerShell 和 Windows Management Instrumentation

Windows PowerShell 可以访问 Windows Management Instrumentation(也称 WMI)的所有功能。我们不仅将介绍如何使用 Windows PowerShell 来访问 WMI,而且还会探讨如何通过 Windows PowerShell 管道传递 WMI 对象和集合。我们将探究如何在 Windows PowerShell 脚本中利用 WMI 属性和方法,并举例说明 WMI 中的基础安全和配置功能。

2007 年 5 月 22 日 Windows PowerShell:从 VBScript 转换

想要将您的脚本甚至是您的技能从 VBScript 转换到 Windows PowerShell 吗?请加入本网络广播进行学习。我们将探究 Windows PowerShell 如何包含 VBScript 的所有主要构造和功能,使您能够轻松地将 VBScript 技能转换到这一新的管理环境。我们将举例说明如何将 VBScript 中的工具转换为 Windows PowerShell 中原本的脚本语言。我们还将分析 Windows PowerShell 中的唯一结构,并为您展示如何开始使用 Windows PowerShell 脚本语言来提高工作的效力与效率。

2007 年 6 月 19 日 Windows PowerShell:深层次的扩展

在此网络广播中,我们将探究 Windows PowerShell 如何利用强大而又灵活的 .NET Framework 来处理数据,从而为您提供数百个内置函数来管理字符串、日期和其他数据类型。但您知道吗,您可以使用 Windows PowerShell 脚本扩展这些函数。我们会为您展示如何使字符串变量不仅包含计算机名称而且还可以告诉您计算机是否已经启动并运行。您将学习如何创建无需使用外部函数即可自动设置数据格式的日期和时间变量。请加入此会话,来了解如何在短短几分钟内将所有类型的新功能构建到 Windows PowerShell 中,从而使 Windows 管理更加快速和简单。

Don Jones是 SAPIEN Technologies 的项目和服务主管,也是《Windows PowerShell:TFM》(SAPIEN Press) 的合著者。请通过 www.ScriptingAnswers.com 与他联系。

© 2008 Microsoft Corporation 与 CMP Media, LLC.保留所有权利;不得对全文或部分内容进行复制.