Windows PowerShell: 脚本速成课程
08/17/2016
本文内容
这一扩展的 Windows PowerShell 栏将迅速提升您对这一强大技术的认识。
Don Jones
多个您是习惯于 Windows PowerShell,并意识到其优势。这一点后,本月的专栏将一个很长。这是 Windows PowerShell 脚本,闪电概述,其中包括如何生成参数化的脚本。在今后几个月,我将重点在这一基础构建的特定主题。
如果您不习惯于运行 Windows PowerShell 命令,在控制台中,您可能发现这太高级,但要仍要通过绘制。应该有深入了解的 Windows PowerShell 安全功能。已应了解的有关执行策略,并知道什么设置您正在使用。如果您尚不知道"RemoteSigned"和"AllSigned,"之间的差异和位置可能比其他更好的原因,您可能无法做好以下材料。
您还应该知道如何在外壳中,执行脚本,并应撤回必须始终以执行一个脚本提供的路径和文件名。最后,您还应知道运行脚本的集成脚本编写环境 (ISE) 和控制台之间的差异。ISE,在全局范围中运行脚本。在正常外壳控制台中,脚本获取它们自己的范围。我将回顾作用域,但您应该已经了解它的含义,以及它的作用。
如果您不感到相当熟练,看一看我的书,"月的食谱中了解 Windows PowerShell"(Manning 发布,2011年)、 和 助理网站 ,看看如果这些资源可以帮助您构建一个更好的基础。
请尝试按照您阅读此列。请尝试示例。如果您键入 (或复制并粘贴) 到第 1 行上启动 Windows PowerShell ISE 脚本示例,然后您行号将对应的说明中的行号。
Windows PowerShell 脚本文件
Windows PowerShell 脚本文件仅仅是具有纯文本格式的文件。PS1 文件扩展名。"1"未引用的版本的 Windows PowerShell,但而是语言引擎的版本。Windows PowerShell 版本 1 和 2 使用语言引擎版本 1。这就是为什么外壳的两个版本安装到在 \Windows\System32\WindowsPowerShell 下 v1.0 文件夹。
Windows PowerShell 脚本不是命令行的批处理文件,与完全一样,不运行脚本是精确与自己相同的顺序运行相同的命令相同。例如,打开控制台窗口并运行以下内容,并在每行之后按 Enter 键 (记住: 不到键入的行号):
Get-Service
Get-Process
现在到脚本文件或 ISE 脚本编辑窗格中,然后运行该脚本,键入这些精确的同一行。 您将获得外观不同的结果。 每次点击 Enter Windows PowerShell,在您启动新的管道。 您键入的任何命令运行该单个管道中。 在管线的结束时,Windows PowerShell 将其内容转换为其文本显示。 运行时在两个命令在普通控制台中,您已经在两个不同的管道中。
Windows PowerShell 就能够构造的输出每组唯一的显示。 输入一个脚本,但是,这两个命令运行在同一管道中。 不完善的格式设置系统 Windows PowerShell 足够构造相同唯一两个不同的结果集的输出。 尝试运行此控制台中:
Get-Service;Get-Process
在运行包含那些两个命令的脚本时一样,这些结果应查找相同。 在这种情况下,这两个命令运行的一条管线。 这就是当您运行该脚本时,发生了什么变化。
所有的实际获得这是脚本应该生成的输出的只有一种。 不是系统的好主意,由于很大一部分的格式设置限制。 还有其他考虑事项,以及。 您不希望脚本转储到管线的几种不同的事情,在同一时间。
重点,通常我们将介绍的所有内容。 脚本应生成输出,且仅有一个的类型。 唯一的例外就是它是否被用作存储库的多个函数的脚本。 在这种情况下,每个函数应生成输出,且仅有一个的类型。
变量
将变量视为一个框。 您可以将一个或多个邮件放在甚至不同的事项,此框中。 框中有一个名称,并在 Windows PowerShell 中,该名称可以包括几乎所有内容。 "Var"可以将一个变量的名称,作为可以"{我变量}"。 在该第二个示例中,大括号括起包含空格,这是非常非常不好的变量名。 作为一个好的做法,坚持包括字母、 数字和下划线的变量名称。
使用变量的名称引用整个"机箱"。如果要引用框中的内容,请添加美元符号: $ 时间差异 通常,您将看到前面有美元符号,因为整个使用一种一点内容时获得的 Windows PowerShell 变量。 但是,请记住,将美元符号不是变量的名称的一部分,这一点至关重要。 它是只是一个提示告诉 Windows PowerShell 所需内容,而不是与框本身。 例如:
$var = 'hello'
$number = 1
$numbers = 1,2,3,4,5,6,7,8,9
这些示例显示了如何将项目放置到变量使用赋值运算符 (=)。 该最后一个示例创建数组,因为 Windows PowerShell 数组或项的集合,作为解释所有以逗号分隔的列表。 第一个示例将指定字符串对象,用引号括起来的字符串中的字符。
没有可以混淆新手的 Windows PowerShell 的一个方面。 Windows PowerShell 都不"了解"任何含义,您可能会将变量名称相关联。 像 $ 计算机名不能"告诉"外壳该变量将包含一个计算机名称的变量。
同样,$数字不会"告诉"外壳变量将包含多个号码。 如果您使用复数的变量名称,不在意外壳。 语句
$numbers = 1
同样有效到外壳,原样
$numbers = 'fred.'
当变量不会包含多个值时,但是,可以使用特殊语法来访问它们的不仅仅是单个的一个。 您将使用 $数字 [0] 第一项、 $数字 [1] 是第二、 $数字 [-1] 是最后、 $数字-[2] 是倒数第二个,依此类推。
引号
作为最佳操作,请来分隔变量,除非有特殊原因,否则使用单引号。 有三个特定实例,您可能希望使用双引号引起来。
首先,当您需要将变量的内容插入到字符串时。 仅双引号引起来,Windows PowerShell 将寻找 $,并将假定 $,达是非法的变量的名称,在第一个字符之后的所有内容都是一个变量的名称。 在变量名和 $,则将替换该变量的内容:
$name = 'Don' $prompt = "My name is $name"
$提示符现在将包含"我的名字是堂",因为 $名称将替换变量的内容。 这是一个重要的窍门,用于将字符串连接起来,而不必将它们连接起来。
双引号引起来,Windows PowerShell 还将查找其转义字符,以反引号或音符,并采取相应的措施。 下面是几个例子:
$debug = "`$computer contains $computer"
$head = "Column`tColumn`tColumn"
在第一个示例中,第一个 $ 是"转义。"将被取消其作为一个变量的访问器的特殊含义。 如果 $计算机包含服务器, 然后 $调试都包含"$ 计算机包含服务器"。
在第二个示例中,' t 表示水平制表符字符,因此 Windows PowerShell 将放置的每一列之间的一个选项卡。 您可以阅读有关的 shell 中其他特殊转义字符 about_escape_characters 帮助主题。
最后,当字符串需要包含单引号,请使用双引号引起来:
$filter1 = "name='BITS'"
$computer = 'BITS'
$filter2 = "name='$computer'"
在此示例中,字符串是名称 = 位。双引号引起来包含整个网页。 准确美元和 filter2 美元到头来包含完全相同的目标,但是美元 filter2 获取那里使用变量替换这一轮的双引号引起来。 注意,只有最外面的一对引号实际上很重要。 在字符串中的单引号不会影响到 Windows PowerShell。 这些单引号都只是原义字符。 Windows PowerShell 不会将它们解释。
对象成员和变量
在 Windows PowerShell 中的所有内容都是一个对象。 System.String 类型的对象,如"名称"甚至一个简单的字符串。 可以管道任何对象来获取成员以查看其类型名称 (即,它是的对象的类型),以及其成员,其中包括其属性和方法:
$var = 'Hello'
$var | Get-Member
使用变量名称之后的一段告诉外壳,"我不想要访问此变量内的整个对象。 我需要访问只是其属性或方法之一。段后,提供的属性或方法的名称。
方法名称总是跟一对括号。 某些方法接受输入的参数,并以逗号分隔的列表中的括号内的那些转。 其他方法要求没有参数,并因此括号是空的但别忘了括号:
$svc = Get-Service
$svc[0].
name
$name = $svc[1].
name
$name.length
$name.ToUpper()
请注意两行。 它通过访问 $svc 变量中的第一项开始。 期间表示,"我不希望整个对象。 我只需要一种属性或方法。这将访问只是 name 属性。 行 5 说明了如何访问方法,通过它的名称提供一段时间后, 跟圆括号。
一段通常是在变量名称中的非法字符,因为期限表示,我们想要访问属性或方法。 这意味着在下面的示例行两个将不起作用的方式,您可能希望:
$service = 'bits'
$name = "Service is $service.ToUpper()"
$upper = $name.ToUpper()
$name = "Service is $upper"
在两行中,$名称将包含"服务是位。"ToUpper() 而在行四 $名称将包含"服务是位。
括号
除了从与对象方法及其用法,括号行为还作为序执行标记为 Windows PowerShell,就像代数。 换句话说,括号告诉外壳程序"执行此第一个"。由该表达式产生的任何替换整个带括号的表达式。 以下是 mind-bending 的几个示例:
$name = (Get-Service)[0].
name
Get-Service -computerName (Get-Content names.txt)
上一个行,$名称将包含在系统上的第一个服务的名称。在阅读本文只需付出的工作量。带括号的表达式的开头。这是什么 Windows PowerShell 将启动与也。"Get-服务"解析为集合或数组,服务。[0] 访问数组中的第一个项目,因此,将第一个服务。因为它跟一个句点,我们知道我们所访问的属性或方法的该服务,而不是整个服务对象。最后,我们拉出不仅仅是服务的名称。
在两行中,带括号的表达式读取文本文件的内容。假定该文件包含一个计算机名称,每行,"获取内容""将返回计算机名称的数组。那些将送纸方式"–computerName"参数的"Get-服务"。在这种情况下,外壳可以进任何带括号的表达式,可返回以字符串数组
"–computerName"参数,因为该参数为了接受字符串的数组。
范围
作用域是作为 containerization 系统的编程概念。诸如变量、 别名、 PSDrives 和其他 Windows PowerShell 元素都存储在一个作用域。外壳程序维护层次结构的作用域,并有一套规则,以确定如何进行交互作用域并互相共享信息。
外壳本身是单个作用域,称为全局作用域。当您运行一个脚本时,它构造新的作用域和脚本运行中的。任何由该脚本,一个新变量,如创建存储脚本的作用域内。它不能访问顶级解释程序。
在脚本结束运行时,其范围将被丢弃,并且内创建的任何内容的范围就会消失。例如,创建一个包含下面的脚本 (不要忘记键入行号),然后从控制台窗口中运行该脚本:
New-PSDrive -PSProvider FileSystem -Root C:\ -Name Sys
Dir SYS:
在运行该脚本后,手动运行"Dir SYS:",您应看到一个错误。 这是因为 SYS: 驱动器) 所创建的脚本。 后脚本已完成,它创建的所有内容都将被放弃。 SYS: 驱动器不再存在。 在外壳中不是全部的范围。 在所有时间全局处理如模块项目。 脚本可以加载的模块和脚本完成后,模块将保持已加载。
如果作用域尝试访问不是由创建该范围内的某些内容,Windows PowerShell 将查找到下一个较高的作用域 ("父"范围)。 这就是为什么 Dir 别名起作用,因为脚本您刚输入。 目录不存在该脚本的作用域中,尽管它存在下一个较高的范围内: 全局作用域。 作用域是自由创建从较高级别的作用域,但具有相同的名称,作为一项的项。 以下是要尝试另一个脚本:
Dir
New-Alias Dir Get-Alias
Dir
可能看起来有点儿古怪,但它不存在第一次运行"Dir,"该脚本的作用域中。 它使用的更高级别的 Dir 别名。 该别名指向 Get-ChildItem,因此它显示熟悉的目录列表。
然后,该脚本创建一个新别名命名目录 此指针指向 Get 别名。 这是什么运行第二次。 影响任何这样的顶级目录别名。 尝试运行外壳程序中的 Dir 运行前面的脚本后,您仍旧会收到一个目录列表。
说到变量范围可以是尤其令人困惑。 一般来说,给定的范围应永远不会访问超出范围的项目,尤其是变量。 对于此操作,如使用全局 $语法: var 强行访问全局作用域的 $var 变量,但这是非常特殊的情况下除外不良做法。
Windows PowerShell 脚本语言
Windows PowerShell 包含少于两个十几个关键字非常简化脚本语言。 这就是完整的编程语言如 VBScript,其中包含约 300 关键字来形成鲜明对比。
尽管它可能是简化,Windows PowerShell 语言足以多个执行该作业。 虽然您总是可以获得更多的帮助,这些通过读取相应的"关于"外壳程序内的主题,我将现在,回顾其主要的脚本构造。 例如,帮助 about_switchcontains 有关交换机结构中,同时帮助 about_if 包含有关 If 构造。 有关运行帮助 * 所有"关于"主题的列表。
If 构造
这是 Windows PowerShell 的主要决策构造。 以其完整形式,它如下所示:
If ($this -eq $that) {
# commands
} elseif ($those -ne $them) {
# commands
} elseif ($we -gt $they) {
# commands
} else {
# commands
}
"If"关键字是强制此构造的一部分。 带括号的表达式如下的计算结果必须为 True 或 False。 为 False,零和任何非零值为 True,则始终将解释 Windows PowerShell。
Windows PowerShell 还将识别为表示这些布尔值的内置变量 $True 和 $False。 如果在括号中的表达式为 True 正常工作,将执行下面的一组用大括号中的命令。 如果表达式为 False,则不会执行命令。 这就是所有您需要为有效 If 构造。
您可以通过提供一个或多个"ElseIf"节有点进一步转。 相同方式作为 If 构造这些工作。 他们得到他们自己带括号的表达式。 如果其值为 True,则将执行以下的大括号内的命令。 如果不是,他们不会。
您可以总结与 Else 块,它将执行如果无前面块的执行。 将执行只与第一个真表达式关联的块。 例如,如果 $这没有等于 $,和 $那些没有不等于的 $它们,然后在四行上的命令将执行 — 和执行其他任何操作。 Windows PowerShell 甚至不会计算行 5 上的第二个 elseif 表达式。
# 字符是一个注释字符,使 Windows PowerShell 实质上是一个回车符直到忽略任何从那里返回。 此外请注意这些构造格式化的护理。 您可能还会看到有些人从格式如下:
无论用大括号所在的位置。 但是,什么不会影响此操作是: 您是一致您放置在使脚本易于阅读。 也很重要,到完全相同的级别,每一行缩进大括号内。
Windows PowerShell ISE 使您可以为此目的,使用 Tab 键,则它默认为四个字符缩进。 缩进代码是一种核心的最佳做法。 如果不这样做,您就会有困难的时间,正确匹配的开始标记和结束复杂脚本中的大括号。 此外,所有其他 Windows PowerShell 孩子将使您的乐趣。 请考虑以下差已格式化的脚本:
function mine {
if ($this -eq $that){
get-service
}}
这是很难阅读、 调试、 疑难解答和维护。 右括号后面的空格并不是必需的虽然它不会使脚本易于阅读。 缩进的代码并不是必需的但还可以容易地按照您的脚本。 而应考虑以下情况:
function mine {
if ($this -eq $that){
get-service
}
}
行上放置一个右大括号,本身不所需的外壳,但它由人类的眼睛感谢。 是巧妙的格式化程序,并且您将在脚本中有较少的问题。
不要在构造
这是在 Windows PowerShell 中的循环构造。 它旨在重复的命令块,只要某些条件为 True,或直到条件变为 True。 以下是基本用法:
Do {
# commands
} While ($this -eq $that)
在这一构造的变化,在大括号内的命令将始终至少执行一次。 While 之后第一次执行之前不计算条件。 您可以移动时,在这种情况下命令才会执行如果条件为 True 的第一个位置:
While (Test-Path $path) {
# commands
}
注意第二个示例中不能使用比较运算符 (例如-均衡 这是因为测试路径 cmdlet 会首先返回 True 或 False。 没有必要进行比较,为 True 或 False 以便处理表达式。
括号表达式只是使用这些脚本构造需要简化向下为 True 或 False。 如果您使用的命令 (如测试路径,它始终返回 True 或 False,这就是您所有需要。 与以往一样,演示如何使用此结构的其他方法的 shell 中是一个"关于"的主题。
ForEach 构造
此构造是类似于 ForEach 对象 cmdlet 的操作中。 它仅在其语法存在差异。 ForEach 的目的是获取数组 (或集合,它在 Windows PowerShell 与数组相同),并枚举对象的数组,以便您可以使用一次:
$services = Get-Service
ForEach ($service in $services) {
$service.Stop()
}
很容易 overthink 此构造方面的新手。 请记住,复数的英语单词"服务"并不意味着任何要 Windows PowerShell。 该变量的名称用于提醒我们有它包含一个或多个服务。 只是因为它为复数形式不会使外壳程序以特殊的方式工作。
在两行上的"in"关键字是 ForEach 语法的一部分。 $服务变量由组成。 它无法轻松地被的 $fred 或 $咖啡,它会起作用中一样的方式。
Windows PowerShell 将重复的构造命令 — 包含在大括号内的那些 — — 第二个变量 ($服务) 中每个对象的一次。 每次,它将采取单个对象从第二个变量 ($服务),并将其放置在第一个变量 ($服务)。
在此构造,使用第一个变量 ($服务) 处理的单个对象。 行三、 句点表示"我不想使用的整个对象,只是其成员之一 — Stop 方法。"
有的时间时使用 ForEach 是不可避免而且符合需要。 但是,如果您有少量编程或脚本的经验,您可以有时 leap 使用 ForEach 时它不是最好的方法。 前面的示例中不是使用 ForEach 有充分的理由。 这不是更容易:
Get-Service | Stop-Service
这里的要点是要评估您的 ForEach 使用。 请确保它是完成手头的任务的唯一方法。 下面是某些情况下 ForEach 可能是唯一的方法:
当您需要执行针对一组对象的方法,并且没有任何 cmdlet 的执行等效的操作。
您有一组对象,需要执行几项的连续操作,对于每个。
当有只可以执行一次对一个对象的操作,但您的脚本可能使用一个或多个对象,和您无法提前知道。
其他构造
Windows PowerShell 有几个其他脚本构造,包括交换机,为,等等。 这些是所有记录在"关于"外壳程序内的帮助主题。 有时,您可以使用此处介绍的内容来替换那些其他构造的构造。 例如,您可以使用 If 替换交换机使用多个 ElseIf 节的构造。 您可以替换为与 ForEach,或甚至 ForEach 对象 cmdlet。 例如,有一个循环,将执行完全 10 次:
1..10 | ForEach-Object -process {
# code here will repeat 10 times
# use $_ to access the current iteration
# number
}
由您来选择最佳的结构,以完成工作。 如果您在浏览互联网的脚本,准备运行跨所有变体。
函数
函数是构造的一种特殊用于包含一组执行单个的特定任务的相关命令。 通常情况下,可以采取任何 Windows PowerShell 脚本和"包装"函数中:
function Mine {
Get-Service
Get-Process
}
Mine
这将定义一个新函数,名为"我"。基本上变成我一个命令,这意味着您可以运行该函数只需通过输入其名称。 这是哪一行五那样。 它将运行函数。
函数通常包含在脚本文件中。 单个脚本可以包含多个函数。 函数可以自己甚至包含其他功能。
但是,函数是指定了作用域的项目。 这意味着您只能在其中创建它在相同范围内使用函数。 如果将函数放入一个脚本,然后运行该脚本,此函数将只是提供的脚本中使用,并且仅用于脚本的期间。 当脚本完成运行,该函数 — 该脚本的作用域中喜欢其他所有内容 — 消失了。 下面是一个示例:
function One {
function Two {
Dir
}
Two
}
One
Two
假设您输入此密码到单个脚本文件并运行该脚本。 行七执行函数的一个,它启动一个行上。 行五执行函数名为两个,它在两行上启动。 因此,结果将是一个目录列表,这是上第三内部函数两行。
但是下, 一行,以执行将八个行,并且会导致错误。 该脚本不包含一个名为两个函数。 两个函数被埋在一个函数内。 结果是,存在一个作用域在函数中。 一个函数中的其他事项可以看到两个。 试图调用从随地其他两个将导致错误。
将参数添加到脚本
很难创建一个脚本,它具有用于执行完全相同的操作,每次运行时。 频繁地执行,您必须包含某种类型的变量数据或变量的行为的脚本。 您可以容纳带有参数的这些变化。
在脚本顶部的特殊方式定义参数。 您可以在前面使用注释,此定义,但它否则必须是第一个可执行的代码行的脚本中。 在参数定义区域中,每个参数与下一个以逗号分隔。 为了与巧妙的格式设置的概念,它可以帮助在其自己的行上放置每个参数。 这里是一个示例:
param (
[string]$computername,
[string]$logfile,
[int]$attemptcount = 5
)
此示例定义了三个参数。 中的脚本,这些只用像任何其他变量。 您会注意到行四、 指定默认值为 $attemptcount 参数。 默认值将覆盖任何输入参数,但如果指定该参数的情况下运行该脚本将使用。
下面是运行于其中的脚本可能,假定我将它保存为 Test.ps1 的几种方法:
./test -computername SERVER
./test -comp SERVER -log err.txt -attempt 2
./test SERVER err.txt 2
./test SERVER 2
./test -log err.txt -attempt 2 -comp SERVER
该脚本接受变得非常像任何 cmdlet 的参数。 变量的名称用作参数指定的名称,与之前在 Windows PowerShell 中的所有参数名称通常短划线。 下面是它的工作原理的细目分类:
上一个行,我仅指定的参数之一 — —$ 日志文件将因此为空,并且 $attemptcount 将包含 5,其默认值。
在两行中,我正在指定所有三个参数,虽然我正在做以便使用缩短参数名。 如同 cmdlet,只需键入足够多的 Windows PowerShell 知道哪一种,您正在谈论的参数名称。
三条我再次所有三个参数,虽然我会这样按位置,而不使用参数名。 只要我记住提供按正确的顺序在脚本中列出的参数的值,这将正常工作。
如果您不小心将会发生什么情况的行四个节目。 在这里,$ 计算机名中将包含服务器 并且 $ 日志文件将包含 2,而 $attemptcount 将包含 5。 这就是我可能不适用。 当您不使用参数名时,是更难灵活。 它也是更难他人对您含义,这使得他们能够解决任何问题更难进行解码。
行五是一个更好的示例。 在这里,我已指定参数的顺序,但这是正常,因为我使用的参数名称。 作为一般规则是,我总是使用参数名称的最大程度的灵活性。 我不需要记住的原来的顺序。
高级的脚本
Windows PowerShell 支持一种技术,用于指定有关参数的其他信息。 这样可以声明为强制性的参数接受管道输入,依此类推。 这一技术称为 Cmdlet 绑定。
它不会更改该脚本使用参数的方法。 它只是使外壳程序更多有关参数的信息。 您会发现在函数中,通常使用这种技术,但语法是有效以及一个脚本中。 下面是一个简单的示例:
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[string]$computername,
[Parameter(Mandatory=$True)]
[string]$logfile,
[int]$attemptcount = 5
)
我添加的只是代码的作为第一行可执行的脚本中的 [CmdletBinding()] 指令。 没关系,在此之前但没有其他意见的。 我还可以添加到我的参数中的两个 [Parameter()] 指令。 在该 [Paramater()] 指令,我已经指示这些参数是强制性。 现在,如果有人试图运行该脚本,而不指定这些参数,Windows PowerShell 将提示他们的信息。
请注意最后一个参数不具有任何特殊的指令,并且所有三个参数仍将出现在以逗号分隔的列表 (前两个参数都跟逗号的含义)。 还有您可以指定为参数,您可以阅读有关其他指令的 about_functions_advanced_parameters 帮助主题。
这是一些重要的 Windows PowerShell 脚本相关概念的迅猛审阅。 我希望您已经学习了一两。 能够生成参数化的脚本是特别有用,因为您可以进行的外观和行为 (如 Windows PowerShell 本机 cmdlet 的脚本。
是 Microsoft MVP 奖收件人和"了解 Windows PowerShell 中每月的食谱"(Manning 发布,2011年) 旨在帮助变得高效 Windows PowerShell 与任何管理员一本书的作者。 此外,Jones 还提供公开和现场 Windows PowerShell 培训。 与他联系通过他的网站 ConcentratedTech.com。
相关内容