本週 Windows PowerShell 秘訣

Office Space

這是使用 Windows PowerShell 的快速秘訣。只要有新的秘訣,我們每週就會在這裡發佈。如果您想要分享任何秘訣,或有任何疑問,請讓我們知道

您可以在本週 Windows PowerShell 秘訣封存找到更多秘訣。

將簡單功能表新增至 Windows PowerShell 指令碼

我們在上一週的秘訣中提到,運用圖形化導向應用程式最主要的好處是可以輕鬆地暫停指令碼,直到使用者選擇繼續指令碼為止(要怎麼做呢?其中一個方式為跳出訊息方塊,並保留該訊息方塊直到使用者按一下 [確定] 為止,而這時應用程式才會繼續)。當然,在表明這是圖形化導向應用程式最大的優勢後,我們接著要坦白跟你說使用主控台 Windows PowerShell 指令碼也可以做出相同的結果。

我們 Scripting Guys 就是喜歡來這招。

事實上,本週我們要做的事和上週非常類似。圖形化導向應用程式的主要好處就是可以輕鬆地限制使用者可選擇的選項:如果只顯示包含 [是] 和 [否] 按鈕的訊息方塊,那麼這時使用者就不可能選擇 [是] 或 [否] 以外的項目。當然啦 (眨眼)…運用主控台 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"):
    

如何建立這個功能表呢,而這個功能表實際上如何運作呢?我就知道你會問…

稍微看一下這個指令碼,你會發現首先我們先把值指派給一對變數:

  • $title 是這個簡單小功能表的標題。在這個例子中,我們將功能表命名為「Delete Files」。

  • $message 是顯示給使用者的訊息。這邊我們簡單地詢問使用者是否要刪除資料夾中其餘的檔案。

接下來,我們定義功能表的選項。在這個簡單的功能表中,我們只提供使用者兩個選擇:Yes,我要刪除其餘的檔案,或 No,我不要刪除其餘的檔案。我們來看一下設定 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 類別。當我們建立 ChoiceDescription 類別的例項時,我們需要傳遞兩個參數:

  • &Yes 。這個標籤將會顯示在功能表。在 Yes/No 系統中,我們可以輕易理解其中一個選項要標示為 Yes。而 符號是用來表示這個選項的「快速鍵」。當我們在 Y 前面放置 & 符號時,使用者有兩種方式可以選取這個選項:鍵入 Yes 並按下 ENTER 鍵;或者鍵入 Y 並按下 ENTER 鍵。那如果我們希望提供使用者按下字母 S 並按下 ENTER 鍵的選項呢?在這種情況下,你只要在 s 之前放置 & 符號即可,如下所示:Ye&s。看起來有點怪,但這真的行得通。

  • "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 時,我們需要依序傳遞四個參數:

  • $title ,功能表的標題。

  • $message ,顯示給使用者的訊息。

  • $options ,功能表選項。

  • 0 ,表示預設選項的索引編號。在這個例子中,我們希望將 Yes 設定為為預設選項,因為 Yes 是功能表選項陣列中的第一個項目,所以我們將值 0 傳遞給 PromptForChoice(陣列中第一個項目的索引編號永遠是 0)。如果我們希望把 No 設定為預設選項呢?沒問題,只要傳遞值 1 即可(No 位於陣列的第二個項目,其索引編號為 1)。

嗯,這個問題好:什麼是預設選項呢?預設選項就是使用者直接按下 ENTER 鍵時會選取的選項。在我們的例子中,如果使用者按下 ENTER 鍵,結果會與鍵入 Yes 並按下 ENTER 鍵相同。

我們呼叫 PromptForChoice 方法時,功能表會出現在畫面上,而指令碼會等待使用者選取選項並按下 ENTER 鍵。使用者按下 ENTER 鍵時,他的選擇會儲存在名稱為 $result 的變數中(實際儲存的是選取選項的索引編號。在這個例子中,若使用者選擇 Yes,則 $result 會等於 0,如果選擇 No 則會等於 1)。

接著我們可以使用簡單的 switch 區塊來檢驗 $result 的值,並採取適當的動作:

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"):
    

注意到 [?] 選項了嗎?下列顯示使用者鍵入問號並按下 ENTER 鍵時的畫面:

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 並按下 ENTER 鍵。我們來實際操作看看:

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)
    

這就是我們今天要介紹的所有內容。大伙兒下週見。