本文的內容分成兩個部分:一是延續上一篇討論變數的文章,補充說明 Windows PowerShell 的常數和陣列;另一個部分則是為下一篇正式討論指令碼程式編寫的文章預作熱身,先行討論編寫指令碼的前置準備。
常數 | |
唯讀的變數 | |
陣列 | |
關聯陣列 | |
Windows PowerShell 指令碼的副檔名 | |
執行 Windows PowerShell 指令碼程式 | |
結語 |
簡單來說,程式是演算法和資料的集合;程式是以演算法處理資料,資料可能儲存於程式之外 (例如任何類型的檔案或資料庫),但是當程式欲處理資料時,都會先將資料載入程式的變數、常數、陣列等資料儲存區域,再加以處理。現代程式語言大都設計了變數、常數或陣列來儲存資料,Windows PowerShell 亦然。我們已經在上一篇文章《Windows PowerShell講座(4)—變數》(http://www.5dmail.net/html/2008-2-26/2008226103718.htm) 說明了 Windows PowerShell 的變數,於此本文將補充 Windows PowerShell 儲存資料的其他方式,包括常數和陣列。
此外,本文的後半部將討論編寫指令碼的前置準備,包括如何開啟 Windows PowerShell 執行指令碼的能力、如何執行Windows PowerShell指令碼程式,以及 Windows PowerShell 主程式 powershell.exe 的啟動選項。
對 Windows PowerShell 來說,變數與常數的差別,是常數不允許移除、不允許更動其值。 Windows PowerShell 常數可以說是一種特殊的變數,其實 Windows PowerShell 變數有一個名為Options的屬性,如果變數的 Options 屬性值為 Constant,那麼這種變數即具備常數的特性 (不允許移除、清除、或更動其值),也因此就將這種變數視為常數。
我們可以利用 New-Variable (別名為 nv) 或 Set-Variable (別名為 set)、並加上特定的 Options 參數來建立常數,例如以下建立了名為 cPi、值為 3.14159 的常數;請注意,必須加上 -Option Constant 才能讓變數變成常數:
nv -Name cPi -Value 3.1415 -Option Constant
Windows PowerShell 常數的使用與變數相同,必須在名稱之前加上 $ 符號。由於 Windows PowerShell 常數不允許移除、清除或更改其值,因此若以 Remove-Variable、Clear-Variable 或 Set-Variable 試圖移除、清除或更改其值,都會出現錯誤 (如下圖)。此外要注意的是,不能將現有的變數轉成常數,例如以 Set-Variable 對現有變數加上 -Option Constant,會導致錯誤。再者,建立常數的同時別忘了指定其值,因為建立之後就無法更改 (即使建立時忘了指定亦然)。
如果您覺得 Windows PowerShel l常數 (也就是 Option 屬性值為 Constant 的變數)一經建立就不能更改其值不夠彈性,也可以利用上述的唯讀變數,也就是在建立時,將變數的 Option 屬性值設為 ReadOnly。例如以下的例子建立了一個名為 LastName 的唯讀變數,其初值為 Lai:
nv -Name LastName -Value Lai -Option ReadOnly
Windows PowerShell 的唯讀變數與常數的差別,是利用 -Force 參數就能更改其值 (常數是完全不能更改),但與常數相同的是,唯讀變數也不能移除、清除。例如以下的例子是將上例建立的 LastName 唯讀變數值改成 Lo:
set -Name LastName -Value Lo -Force
或可簡略寫成:
set LastName Lo -Force
如果嘗試要清除或移除唯讀變數,會出現與企圖清除、移除常數相同的錯誤。
陣列是一組資料的集合,而這些資料都編了索引值 (index),因此我們可以利用索引值來取得陣列裡的資料。若以 「維度」 來看陣列,最常用的是一維陣列,下圖是一維陣列的簡單示意圖。有些程式語言的陣列索引值是 1 起始,而 Windows PowerShell 的陣列值則是 0 起始,因此以下陣列七個元素的索引值是從 0 到 6。
索引值 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
陣列元素 | red | orange | yellow | green | blue | indigo | violet |
某些情況,我們必須以一組變數來儲存一群相關的資料,例如彩虹的七個顏色、伺服器裡的磁碟機等,在這類的情況,如果是以個別變數來儲存這些相關的資料,程式會很不好處理,例如:
$RainbowColor1 = "red"$RainbowColor2 = "orange"…$RainbowColor7 = "violet"
但如果改用陣列,就比較容易處理:
$RainbowColor = "red", "orange", "yellow", "green", "blue", "indigo", "violet"
以上會建立一個名為 RainbowColor 的陣列,而且這個陣列的內容 (稱為陣列元素) 分別是彩虹七種顏色的英文;因為每個陣列元素都是字串,因此必須以雙引號括住各個字串,並且以逗號隔開這七個陣列值 (以上只是 Windows PowerShell 建立一維陣列的作法,後續還會提及進一步存取陣列元素的方式,現在我們繼續說明建立陣列的作法)。
如果陣列元素為數值,就不需括註雙引號,否則數值會被視為字串,例如以下陣列 a 的內容是六個整數值:
$a = 1, 3, 17, 24, 8, 33
如果要建立內容為循序整數值的陣列,可以利用範圍運算子.. (兩個半形英文句點),例如以下陣列 b 的內容是 2 到 11 的整數值:
$b = 2..11
甚至,舉例來說,如果想要將 1、2 和 5 到 9 等七個數值指定到陣列,下列應該是最快的方式。又如果想要將 1 到 2、5 到 7、10 到 15 等 11 個數值指定到陣列,該怎麼做才最快呢?這個題目就留給你舉一反三。
$b = 1, 2 + 5 .. 9
透過上述的例子或許您發現陣列名稱和變數名稱的規則似乎類似。的確,您甚至可以將陣列視為一組變數的集合,而且陣列元素可以混合各種 Windows PowerShell 型別,例如以下陣列 c 混合了整數、字串、小數:
$c = 2, 3, "apple", 3.14, "banana"
如同 Windows PowerShell 變數可以宣告成特定的型別,陣列也可以,而且在作法上,變數與陣列有許多相同之處,因為陣列可以說是源自變數。首先,陣列與變數的型別相同,都是源自 .NET Framework 的型別。其次,陣列也是以類似的方式宣告型別,例如以下欲宣告整數型別的陣列,並指定內容 (也請留意與變數宣告型別的差異):
# 陣列宣告特定型別,並指定內容[int[]]$g = 15, 22, 33, 40# 變數宣告特定型別,並指定內容[int]$Age = 18
同樣的,指定過內容 (也就是非 Null 值) 的陣列 (或變數),都可以利用的 GetType 方法,或 Type 物件的 Name 屬性值,傳回變數的 Type 物件,或取得型別名稱;例如:
$g.GetType()$g.GetType().Name
在陣列建立並設定初值之後,我們仍可以指定個別的陣列元素值,在這個時候,您必須知道欲指定元素值的陣列索引值。例如以下第一個例子是將整數 10 指定成陣列 $a 的第二個元素值,而第二個例子則是將字串 Lai 指定成陣列 $ LastName 的最後一個元素值:
[int[]]$a = 1, 2, 3, 4$a[1] = 10[string[]]$LastName = "Lin", "Li", "Lo", "Hu"LastName[-1] = "Lai"
另一種指定個別的陣列元素值的作法,是利用SetValue方法;以下是上述兩個例子改以SetValue方法的作法:
$a.SetValue(10, 1)#SetValue方法不能使用負的索引值$LastName.SetValue("Lai", 3)
如果想新增陣列元素,可以利用遞增運算子 +=。繼續以上的兩個例子,以下第一個例子會在陣列 $a 末尾加入整數 101 為其新的元素,而第二個例子則會加入字串 Chen:
$a += 101$LastName += "Oh"
遞增運算子也可以用在陣列元素 (上述是作用在陣列),其結果是將元素遞增特定值。例如以下的例子:
# 將整數10與第一個元素相加$a[0] += 10# 將字串Yang與最後一個元素相加(連接)$LastName[-1] += "Yang"
Windows PowerShell 的陣列很容易合併,只要利用加號就可以;例如以下的例子:
$i = 1, 2$j = 3, 4$k = $i + $j# $k的內容為 1, 2, 3, 4$x = "Hello, "$y = "Windows PowerShell!"$z = $x + $y # $z 的內容為 Hello,Windows PowerShell!
同理,利用指定運算子 (=) 就能將整個陣列的內容,指定給另一個陣列,例如:
$n = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9$p = $n
此外,我們也可以利用範圍運算子將陣列的部分內容指定給另一個陣列。例如以下的例子會將陣列 $n 索引值的第 0、1 及 3 到 8 等八個元素的值指定給陣列 $m:
$m = $n[0, 1 + 3..8]
將資料存入變數之後,最重要的就是取出並進一步處理,陣列亦然,但因為陣列裡有一組元素,因此若要取得個別元素,就必須利用元素的索引值。以上述的彩虹陣列為例,如果要取得第一個元素,就要利用索引值 0,如果要取得最後一個元素,其索引值是 6;甚至可以用逗號隔開欲取得的元素索引值,例如:
$RainbowColor[0]$RainbowColor[6]$RainbowColor[0, 3]
而索引值也可以是負數:-1 代表陣列的最後一個元素、-2 代表陣列的倒數第二個元素、-3 代表陣列的倒數第三個元素,依此類推。
Windows PowerShell 的世界處處可以見到物件,就連陣列也是,而我們可以利用陣列物件的 Length 屬性,得知陣列的元素數量,例如:
$RainbowColor.Length$c.Length
上述前者會得到 7,後者則是 4;雖然我們可以利用下列的方式,取得陣列的最後一個元素,但總不比利用索引值 -1 來得更為方便:
$RainbowColor[$RainbowColor.Length - 1]$c[$c.Length - 1]
範圍運算子 (..) 也可以用在陣列元素的取得,甚至還可以搭配負的索引值,例如以下的例子:
# 取得 $RainbowColor 陣列的前四個元素$RainbowColor[0..3]# 取得 $RainbowColor 陣列的第一、第三以及第五到第七等五個元素$RainbowColor[0, 2 + 4..6]# 取得 $RainbowColor 陣列的最後及倒數第二個元素$RainbowColor[-1..-2]# 取得 $RainbowColor 陣列的第一、最後及倒數第二個元素(共三個)$RainbowColor[0..-2]
由於陣列的索引值是 0 起始的循序整數,而且陣列元素也都是循序排列,因此我們也經常利用 「迴圈」 來處理陣列。但關於細節,我們將留待後續說明迴圈的文章再討論。
刪除陣列的方式一如刪除變數,利用 Remove-Item 或 Remove-Variable 皆可,例如:
Remove-Item Variable:aRemove-Variable LastName
上述所討論的陣列,是以 「索引值」 作為存取、處理元素的基礎,每個索引值對應到特定的元素。這雖然已經很方便儲存一組資料,但是 Windows PowerShell 還提供了 「關聯陣列」 (associative array),能以另一種方式讓我們儲存一組相關的資料。
雖然概念類似一維陣列,但關聯陣列與陣列最大的差別,是前者採用 「索引鍵」 (key) 作為存取陣列內容的基礎;索引鍵是字串,每個索引鍵對應到特定的資料值 (value),因此索引鍵和資料值是互為。舉例來說,以下的員工分機表即可利用關聯陣列來儲存。
索引鍵(員工姓名) | 王小明 | 李大同 | 林中成 |
資料值(分機號碼) | 4122 | 4213 | 4421 |
以下是建立並指定關聯陣列內容的語法:
$<關聯陣列名稱> = @{<索引鍵1 = 資料值1="">; <索引鍵2 = 資料值2="">;...}
若是上述分機表,其關聯陣列的建立方式如下:
$phoneEx = @{王小明 = 4122; 李大同 = 4213; 林中成 = 4421}
請注意,如果索引鍵或資料值內含空白字元,或者資料值內含符號,就必須以單引號或雙引號括住索引鍵或資料值,例如:
$phoneTable = @{"Mike Wang" = "2845-4122"; "John Li" = "5211-4213"…}
上述的索引鍵是因為內含空白字元,所以必須加註引號,而資料值因為有橫線符號 (-),如果不加註引號,橫線符號會被視為減號,因此存入關聯陣列的值會是兩個整數的差。
關聯陣列的資料值可以混合各種資料型別,甚至可以是另一個關聯陣列,例如以下的例子:
$Mix = @{Key1 = 100; Key2 = Get-ChildItem; Key3 = "Hello!"; Key4 = $phoneEx}
點符號或陣列符號可以用來取得關聯陣列的資料值,例如:
$phoneTable.'Mike Wang'$phoneTable['John Li']
如果要更改關聯陣列資料值的方式,可以利用之前提及建立關聯陣列的方式,再重新指定新的資料值即可;或者也可以利用點符號或陣列符號,例如:
$phoneTable.'Mike Wang' = "8541-6258"$phoneTable['John Li'] = "8889-6841"
我們也可以利用關聯陣列的 Keys 和 Values 屬性,來取得關聯陣列的索引鍵和資料值,例如:
$phoneTable.Keys$phoneTable.Values$Mix.Keys$Mix.Values
關聯陣列也能利用迴圈,但細節也留待後續說明迴圈的文章再討論。
刪除關聯陣列的方式一如刪除陣列,利用 Remove-Item 或 Remove-Variable 皆可,例如:
Remove-Item Variable:aRemove-Variable LastName
Windows PowerShell 不只是功能完整的 shell 環境,也提供了指令碼 (script) 程式的直譯能力。有些系統管理者可能認為 「寫程式」 是一件艱深的苦差事,但其實未必,尤其指令碼的編寫又比其他類型程式的編寫更為容易,因此系統管理者除了應該熟悉 Windows PowerShell 的指令操作,更應該熟悉 Windows PowerShell 的指令碼編寫。
或許您會質疑:「Windows PowerShell 已經夠方便、實用了,為什麼還要編寫指令碼程式?」 如果您覺得 Windows PowerShell 方便、實用,那更應該熟悉 Windows PowerShell 指令碼程式的編寫,因為這會讓 Windows PowerShell 更加的方便、實用。
簡單來說,Windows PowerShell 指令碼程式就是 Windows PowerShell 指令的集合,如果您經常依賴某些指令來完成一件工作,那麼只要將這些指令分行依序集中在文字檔,除了給予文字檔主檔名,再給予 ps1 作為副檔名,這些指令就成為指令檔,而只要執行這個指令檔,Windows PowerShell 直譯環境就會依序執行指令檔裡的指令,因此您不需要每次都輸入相同的指令。
再者—這也是之所以應該熟悉指令碼程式編寫的重要原因,指令碼程式可以依照您的指定,自動重複執行某些指令 (例如重複處理 20 個資料夾的內容),或者根據不同的邏輯狀況而給予不同的處理 (例如處理所有副檔名為 .txt 的檔案)。
為了說明 Windows PowerShell 指令碼程式的編寫與執行,我們先寫個非常簡單的小程式,這個程式只有以下這行指令:
get-host
get-host 會顯示 Windows PowerShell 的版本及地域資訊。因為 Windows PowerShell 指令碼檔案是副檔名為 ps1 的純文字檔 (最後一個字元是數字 1),因此我們可以任何文字編輯器來編寫,但要注意的是,存檔時一定要將副檔名存成 ps1。目前有許多更便於編寫指令碼的編輯器,甚至也有編寫指令碼的整合開發環境,這類工具對指令碼開發很有幫助,若日後經常需要編寫大量的指令碼程式,不妨找一個好用的工具,但若還是初學者,建議先將焦點放在 Windows PowerShell 的學習。
我們將這個簡單的程式存成 test1.ps1,並且放在 c:\MyMSH 資料夾。Windows PowerShell 指令碼程式可以從文字模式 Windows PowerShell 執行,也可從 Windows GUI 執行,在說明執行方式之前,我們要先開啟 Windows PowerShell 執行指令碼的能力。
基於安全的考量,Windows PowerShell 預設關閉了指令檔的執行功能,若要開啟,我們需要 set-executionPolicy,不過您可以先利用 get-executionPolicy 來檢查系統目前的指令檔執行限制:
• | Restricted:預設值,關閉指令檔的執行功能。 |
• | AllSigned:只允許執行受信任發行者簽署過的指令檔。 |
• | RemoteSigned:從網際網路下載的指令檔必須經過受信任發行者的簽署才能執行。 |
• | Unrestricted:任何指令檔皆可執行,但是從網路網路下載的指令檔在執行之前會出現提示交談窗。 |
為了方便起見,我們將指令檔的執行限制改成RemoteSigned,也就是自己在本機建立的指令檔不受限制,但限制來自網際網路的指令檔 (但要提醒您的是,只要權限足夠的使用者,都有可能自行修改或建立危害系統的設定檔或指令檔);設定的方式如下:
set-executionPolicy RemoteSigned
如果想還原成限制所有指令檔執行的預設狀態,請如下操作:
set-executionPolicy Restricted
上述設定的影響範圍遍及整個 Windows 環境,而不只是設定時的 Windows PowerShell 環境。
如果要從 Windows PowerShell 文字模式環境執行 ps1 指令碼,除了要輸入完整的檔名 (包含副檔名 ps1),通常還要指定指令碼程式的完整路徑 (因為 Windows PowerShell 執行環境只會搜尋Path環境變數裡的資料夾),例如下圖裡的三種執行狀況,只有指定了指令碼程式路徑的第三種 (也就是.\test1.ps1),才能得到正確的結果;就算工作資料夾已經切換到指令碼程式所在的 c:\MyMSH,也要指定路徑。
指令路徑的方式有很多種,上述之所以使用 .\test1.ps1,是因為工作資料夾已經切換到了指令碼程式所在的 c:\MyMSH,因此能以 「單點」 表示目前的資料夾。除了相對路徑的表示方式,也可以利用絕對路徑表示方式 (不論工作資料夾為何,絕對路徑只要無誤,皆可找到檔案),此例的絕對路徑即為:
c:\MyMSH\test1.ps1
要提醒您的是,如果路徑或檔名裡有空白字元,例如 c:\My MSH 或 test 1.ps1,除了必須以單引號或雙引號括住徑名或檔名,還必須在最前面加上執行運算子&,例如:
# 絕對路徑PS C:\User> & "c:\My MSH\test 1.ps1"# 相對路徑(也可以用單引號括住)PS C:\User> & '..\My MSH\test 1.ps1'
預設無法直接從 Windows 執行 Windows PowerShell 指令碼程式,如果雙按檔案總管裡的 ps1 檔,只會以記事本開啟程式檔。雖然我們可以改用 『執行』 交談窗來執行,但必須將欲執行的指令碼程式當作 powershell.exe (Windows PowerShell 環境的主程式)的選項,並且要加上 -NoExit 選項,以免執行之後 Windows PowerShell 視窗馬上消失;例如:
如果徑名或檔名裡有空白字元,類似之前提及必須加上執行運算子&,但是只能以單引號括住完整徑名,例如:
powershell -NoExit & 'c:\My MSH\test 1.ps1
許多程式都可以在執行時加上啟動選項,Windows PowerShell 執行環境的 powershell.exe 也一樣,關於 powershell.exe 啟動選項的說明,只要在 『命令提示字元』 或 Windows PowerShell 環境執行以下指令:
powershell /?
就會列出 Windows PowerShell 的啟動參數,以及參數的使用說明:
powershell[.exe] [-PSConsoleFile <file> | -Version <version>] [-NoLogo] [-NoExit] [-NoProfile] [-NonInteractive] [-OutputFormat {Text | XML}] [-InputFormat {Text | XML}] [-Command { - | <script-block> [-args <arg-array>] | <string> [<CommandParameters>] } ]
以下的這些選項的說明。
• | -Help、/Help、-?、/?:顯示 Windows PowerShell 的啟動選項說明訊息。 |
• | -PSConsoleFile:載入指定的 Windows PowerShell 控制台檔案;Export-Console cmdlet 可以匯出 Windows PowerShell 環境的控制台檔案。例如: PowerShell -PSConsoleFile MyPSConsole.psc1 |
• | -Version:啟動特定版本的 Windows PowerShell (前提是系統裡已經安裝這些版本的 Windows PowerShell)。例如: PowerShell -Version 1或PowerShell -Version 1.0 |
• | -NoLogo:啟動時不顯示開頭的版權訊息。 |
• | -NoExit:執行完啟動所指定的指令後,不結束 Windows PowerShell。 |
• | -NoProfile:不載入使用者設定檔。 |
• | -Noninteractive:關閉互動模式;有些 cmdlet 若未指定必要參數,會以互動模式提示使用者輸入必要參數,這個選項會關閉互動模式,因此若未輸入必要參數,會直接顯示錯誤訊息。 |
• | -OutputFormat:指定 Windows PowerShell 的輸出格式,有效的值是 Text 和 XML (循序的 CLIXML 格式)。 |
• | -InputFormat:指定輸入到 Windows PowerShell 的格式,有效的值是 Text 和 XML (循序的 CLIXML 格式)。 |
• | -Command:指定給 Windows PowerShell 的執行命令 (及任何參數)、程式區塊 (用大括號括住程式碼),執行後 Windows PowerShell 隨即結束 (除非另指定 -NoExit 選項)。如果 -Command 的值是要執行的命令字串,要避免其他的 Windows PowerShell 選項被認為是命令字串的參數,例如以下的 -NoExit 選項會被認為是 dir 的參數: |
PowerShell -Command dir -NoExit
正確的寫法應該是:
PowerShell -NoExit -Command dir或PowerShell -Command "& {dir}" -NoExit
如果要執行的命令字串之後需要加上參數,可以寫成:
PowerShell -NoExit -Command dir -Name desktop或PowerShell -Command "& {dir -Name desktop}" -NoExit
Windows PowerShell 提供了相當實用的變數、常數、陣列機制,這些機制是程式處理資料的重要基礎,因此我們花了一篇半的文章篇幅來說明這些機制的基本用法。此外,Windows PowerShell 除了是功能優異的文字模式操作介面 (shell),本身也兼具指令碼直譯功能,因此指令碼程式更是 Windows PowerShell 管理系統的利器。
本文的後半部論及編寫指令碼的前置準備,包括如何開啟 Windows PowerShell 執行指令碼的能力、如何執行 Windows PowerShell 指令碼程式,以及 Windows PowerShell 主程式 powershell.exe 的啟動選項。
我們將在下一篇文章繼續討論 Windows PowerShell 指令碼程式的編寫細節,包括運算紫、運算式、迴圈、流程控制等主題,而這也等於正式進入 Windows PowerShell 指令碼程式編寫的範圍。
自由广告区 |
分类导航 |
邮件新闻资讯: IT业界 | 邮件服务器 | 邮件趣闻 | 移动电邮 电子邮箱 | 反垃圾邮件|邮件客户端|网络安全 行业数据 | 邮件人物 | 网站公告 | 行业法规 网络技术: 邮件原理 | 网络协议 | 网络管理 | 传输介质 线路接入 | 路由接口 | 邮件存储 | 华为3Com CISCO技术 | 网络与服务器硬件 操作系统: Windows 9X | Linux&Uinx | Windows NT Windows Vista | FreeBSD | 其它操作系统 邮件服务器: 程序与开发 | Exchange | Qmail | Postfix Sendmail | MDaemon | Domino | Foxmail KerioMail | JavaMail | Winwebmail |James Merak&VisNetic | CMailServer | WinMail 金笛邮件系统 | 其它 | 反垃圾邮件: 综述| 客户端反垃圾邮件|服务器端反垃圾邮件 邮件客户端软件: Outlook | Foxmail | DreamMail| KooMail The bat | 雷鸟 | Eudora |Becky! |Pegasus IncrediMail |其它 电子邮箱: 个人邮箱 | 企业邮箱 |Gmail 移动电子邮件:服务器 | 客户端 | 技术前沿 邮件网络安全: 软件漏洞 | 安全知识 | 病毒公告 |防火墙 攻防技术 | 病毒查杀| ISA | 数字签名 邮件营销: Email营销 | 网络营销 | 营销技巧 |营销案例 邮件人才:招聘 | 职场 | 培训 | 指南 | 职场 解决方案: 邮件系统|反垃圾邮件 |安全 |移动电邮 |招标 产品评测: 邮件系统 |反垃圾邮件 |邮箱 |安全 |客户端 |