Windows PowerShell每周提示(29):向Windows PowerShell脚本内添加一个简单的菜单
在上周的提示中我们提到了对于一个面向图形界面的程序而言,一个表面上的优势是能很容易暂停脚本直到用户选择继续。(具体说来?一种方法是弹出一个消息框并保留它直到用户单击确定,只有这样程序才能继续运行。)当然,在说明了这是面向图形界面程序的一个优势后,我们随后向你展示了如何在基于控制台的Windows PowerShell脚本中实现同样的事。
脚本专家倾向于做这样的事。
事实上,本周我们打算做类似的事。面向图形界面程序的另一个优势是它能够简单地驱使用户在有限的集合中做出选择:比如你显示一个只包含是和否按钮的消息框,此时,对于用户而言也很难做出是和否之外的选择。当然,这对于基于控制台而言的Windows PowerShell脚本而言比较困难,是么?
让我们看看:
| $title = "Delete Files" $message = "Do you want to delete the remaining files in the folder?" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` "Deletes all the files in the folder." $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", ` "Retains all the files in the folder." $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $result = $host.ui.PromptForChoice($title, $message, $options, 0) switch ($result) { 0 {"You selected Yes."} 1 {"You selected No."} } |
那么我们在这里做了什么?我们在这里所做的是添加了一个基于控制台的简单菜单,类似于传统的放弃,重试,失败:
| Delete Files Do you want to delete the remaining files in the folder? [ Y ] Yes [ N ] No [?] Help (default is "Y"): |
我们如何创建这个菜单,这个菜单事实上如何工作?你这样问很有趣……
如果你看一眼脚本代码,你将会看到我们从向一对变量赋值开始 :
l $title是菜单的标题,在本例中,我们将菜单命名为Delete Files
l $message是我们向用户显示的信息。这里我们只是向用户询问他或她是否要删除文件夹中的剩余文件。
接下来我们定义我们菜单的选项。对于这个菜单我们只给用户两个选择:是,我想要删除剩余文件,或则,否,我不要删除剩余文件。让我们看一下建立Yes选项的语法:
| $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` "Deletes all the files in the folder." |
如你所见,我们在这所做的是将一个值赋给名为$yes的变量。注意你可以将变量命名为你想要的任何名称。没有任何强制性要求变量名必须和选项相同。即使我们建立的是关于Yes的选项,但是如果我们想要做话,我们仍能将变量命名为$watermelon。我们只是不想这样做而已。
| 注意:为什么不这样做呢?好的,如果你的变量名和选项关联的话,你的排错将变得轻松。它也使得你的脚本对其他人而言变得更易读和理解。 |
那么我们将什么样的值赋值给了变量$yes?为了创建该值,我们使用了New-Object cmdlet来创建System.Management.Automation.Host.ChoiceDescription类的实例。ChoiceDescription类恰好是一个你能为基于控制台的菜单系统定义选项的.NET Framework类。当你创建该类的实例时,我们需要传递两个参数:
l &Yes.这是将会在菜单中显示的标签。在一个Yes/No系统中理所当然的会有一个选项将被标记为Yes。连字符(&)被用来指出此选项的“快捷键”在字母Y之前放置连字符使得我们给了用户两种方式选择此选项:输入Yes然后按回车;或者输入Y然后按回车。如果我们想要给用户一个机会输入S然后按回车?那样的话,将连字符放置在s前,像这样:Ye&s。看上去古怪,但是的确可行。
l "Deletes all the files in the folder."这是关于这个选项所要实现的功能的一个(通常是一行)描述。如果用户在菜单提示出现时输入“?”作为应答,那么该提示就会出现在屏幕上。(别急,我们待会就给你展示一下。)
当配置完第一个选项后我们为菜单中的其它项目重复这个过程。在本例中我们仅有一个额外的选项(No)但是我们可以添加我们需要的任意多的选项。想要给用户一个机会来选择Maybe?那么使用类似以下的代码:
| $maybe = New-Object System.Management.Automation.Host.ChoiceDescription "&Maybe", ` "Pauses for 60 seconds and then asks again about deleting the files." |
在我们定义好这些选项后我们把这些选项添加到菜单中,这是由以下代码完成的:
| $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) |
如你所见,我们在这里所做的是创建名为$options的数组并向数组内添加相关选项($yes及$no)这件并不复杂的事。如果我们想要向菜单中添加第三个选项($maybe)?那么我们只需在将选项添加到菜单时包含第三个选项即可:
| $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $maybe) |
确实很容易,当你知道怎么做的时候。
此时我们已经准备好显示菜单:
| $result = $host.ui.PromptForChoice($title, $message, $options, 0) |
这里我们只是调用PromptForChoice方法(属于$host对象的UI属性)。当我们调用PromptForChoice时我们需要按顺序传递四个参数:
l $title,菜单的标题。
l $message,向用户显示的消息。
l $options,菜单的选项。
l 0,表示默认选项的索引号。在本例中,我们想要Yes成为默认选项,所以我们传递给PromptForChoice值0;这是因为Yes是我们菜单选项数组中的第一项。(数组中第一项的索引号总是0。)如果我们想要No成为默认选项?没问题,这种情况下我们传递1作为替代。(作为数组中的第二项,No的索引号为1。)
哦,问得好:什么是默认选项?好的,当用户按回车时这是被默认选择的选项。在我们的例子中,如果用户只按回车,那么这和输入Yes后再按回车是一样的。
当我们调用PromptForChoice方法时,我们的菜单出现在屏幕上并且脚本等待用户选择某一项并按回车。当用户输入回车后,用户的选择将被储存在名为$result的变量中。(事实上,储存的是被选择项的索引号。在本例中,$result将会等于0如果用户选择Yes,而用户选择No时将等于1。)
接下来,我们可以检验$result的值,并采取相应的措施,通过使用简单的switch语句块:
| switch ($result) { 0 {"You selected Yes."} 1 {"You selected No."} } |
在我们的示例脚本中我们只是回显用户的选择。在真实的脚本中,我们需要包含相应的删除文件的代码如果用户选择Yes以及选择No时的相应代码。
这就是所有我们需要做的。像我们所说的,很简单,不是么?
当然,你也许会更认同我们,当我们确切知道菜单系统是如何工作。好的,下面就是菜单第一次出现在屏幕上时的样子:
| Delete Files Do you want to delete the remaining files in the folder? [ Y ] Yes [ N ] No [?] Help (default is "Y"): |
注意到“?”选项了么?下面是当用户输入问号并按回车后所发生的:
| Delete Files Do you want to delete the remaining files in the folder? [ Y] Yes [ N ] No [?] Help (default is "Y"): ? Y - Deletes all the files in the folder. N - Retains all the files in the folder. [ Y ] Yes [ N ] No [?] Help (default is "Y"): |
瞧见没?我们所添加的所有帮助描述被自动显示。现在,如果用户输入一个不存在的选项,例如,当用户X并按回车将会发生什么?让我们自己试试:
| Delete Files Do you want to delete the remaining files in the folder? [ Y ] Yes [ N ] No [?] Help (default is "Y"): X [ Y ] Yes [ N ] No [?] Help (default is "Y"): |
结果是什么都没有发生。因为X不是一个合法选项,菜单只是提示用户再试一次。你能输入你想要的所有不合法选项,菜单将永远不会接受他们。
但是如果你输入一个合法选项?在这种情况下,选择是被接受的,我们使用switch语句来分析$result的值,然后我们运行合适的代码块。在屏幕上,看起来像这样:
| Delete Files Do you want to delete the remaining files in the folder? [ Y ] Yes [ N ] No [?] Help (default is "Y"): Y You selected Yes. |
不错,很不错吧。
下面是另外一个简单的例子,该例子向你展示你如何使用菜单系统重复提示用户采取某一行为。脚本将向屏幕输出1至10,然后询问用户他或她是否愿意退出。如果用户选择Yes那么脚本将会结束。如果用户选择No那么下面10个数字将会显示在屏幕上。它也算不上是有实际意义的脚本,但是他给你提供了一个基础来构建更有用的脚本:
| $x = 0 $title = "Endless Loop" $message = "Do you want to quit?" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` "Exits the loop." $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", ` "Displays the next 10 numbers onscreen." $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) :OuterLoop do { for ($i = 1; $i -le 10; $i++) {$x = $x + 1; $x} $result = $host.ui.PromptForChoice($title, $message, $options, 0) switch ($result) { 0 {break OuterLoop} } } while ($y -ne 100) |
这就是我们今天所要谈论的内容。下周见。
PS,为了避免Blog系统的表情自动转换功能,“[ ? ]”中“?”两侧的空格实际上是不存在的
英文原文
http://www.microsoft.com/technet/scriptcenter/resources/pstips/jan08/pstip0125.mspx