首页 | 邮件资讯 | 技术教程 | 解决方案 | 产品评测 | 邮件人才 | 邮件博客 | 邮件系统论坛 | 软件下载 | 邮件周刊 | 热点专题 | 工具
网络技术 | 操作系统 | 邮件系统 | 客户端 | 电子邮箱 | 反垃圾邮件 | 邮件安全 | 邮件营销 | 移动电邮 | 邮件软件下载 | 电子书下载

操作系统

Windows 9X | Linux&Uinx | Windows Server | 其它操作系统 | Vista | FreeBSD | Windows 7 |
首页 > 操作系统 > Windows Server > Windows PowerShell 講座 (8)—迴圈與流程控制 > 正文

Windows PowerShell 講座 (8)—迴圈與流程控制

出处:www.goodman-lai.idv.tw 作者:賴榮樞 时间:2008-6-7 14:19:40

任何程式語言都有迴圈及流程控制的概念或功能,Windows PowerShell 亦然。本文將以實例說明 Windows PowerShell 所提供的迴圈及流程控制。

本頁內容
IfIf
SwitchSwitch
ForEach(Foreach-Object)ForEach(Foreach-Object)
ForFor
WhileWhile
巢狀迴圈巢狀迴圈
BreakBreak
ContinueContinue
Break、Continue 及迴圈標籤Break、Continue 及迴圈標籤
結語結語

Windows PowerShell 提供豐富的流程控制及迴圈功能,包括 If、Switch、ForEach、For、While,以及終止或繼續迴圈的 Break 和 Continue;此外,Windows PowerShell 還提供了迴圈標籤的功能,能讓我們明確指出要終止或繼續的迴圈。

我們經常需要在程式裡持續執行某一段程式碼,直到某種情況成立(或不成立)才停止重複執行,像這種情形就需要用到迴圈。迴圈用在某種情況之下需要重複執行的某一段程式碼,如果某種情況不存在,迴圈就停止。因此迴圈的使用必須注意終止條件是否存在,如果終止條件始終不存在而讓迴圈陷入「無窮迴圈」,可能導致程式無法繼續執行而形同當掉。雖然有時候我們會以無窮迴圈的形式來使用迴圈,但這種情況都會加入流程控制來作為迴圈的終止條件。

流程控制能用來控制程式進行的岔路方向。程式可能會設計成「如果某種情況成立就跳到某一個程式碼區塊繼續執行」,這就需要利用流程控制所提供的功能:判斷條件式,並且根據判斷結果引導程式執行的路徑。本文就從 Windows PowerShell 提供的流程控制功能開始。

If

If 是經常用到的流程控制指令,任何程式語言都有 If,而且用法也都幾乎相同。If 的語法如下所示:

If (<條件式1>) {	<程式碼區塊1>}Elseif (<條件式2>) {	<程式碼區塊2>	…}Else {	<程式碼區塊n>}           

您可以依照程式分岔的情況設定 If 的條件式和程式碼區塊數量,但是通常遇到太多的條件式,我們就會改用稍後即將說明的 Switch,因為過多的條件式會讓 If 不易編寫、維護。如下僅有一個條件式是最單純的 If:

$wmi = Get-WmiObject win32_processorif ($wmi.Architecture -eq 0) {	"您的電腦是 x86 CPU"}            

上述第一行利用了 WMI 取得電腦的處理器資訊,並將處理器資訊置入 $wmi 變數。所取得資訊裡的 Architecture 包含了處理器架構資訊,如果該值為 0,其處理器架構為 x86,而其他的值所代表的架構如下表:

處理器架構

0

x86

1

MIPS

2

Alpha

3

PowerPC

6

Itanium

9

x64

因此這個例子接著再以 If 且輔以條件式來檢查所取得的 Architecture,而判斷電腦是哪一種處理器。不過上述的例子雖然可以執行,但並不完整,如果電腦不是 x86,就不會有任何結果。這並不理想,因此我們加上 Else 來處理「不是 x86」的情況。

$wmi = Get-WmiObject win32_processorif ($wmi.Architecture -eq 0) {	# 處理器屬於 x86	"您的電腦是 x86 CPU"}Else {	# 處理器非屬 x86	"不清楚 WMI Architecture 值為 " + $wmi.Architecture + " 是哪一種處理器"}            

上述程式雖然能處理 x86 和「非 x86」兩種情況,但還是不完整,因此我們要根據上述表格,將 6 種情況的檢查判斷都加入。

$wmi = Get-WmiObject win32_processorIf ($wmi.Architecture -eq 0) {	"您的電腦是 x86 CPU"}Elseif ($wmi.architecture -eq 1) {	"您的電腦是 MIPS CPU"}Elseif ($wmi.architecture -eq 2) {	"您的電腦是 Alapha CPU"}Elseif ($wmi.architecture -eq 3) {	"您的電腦是 PowerPC CPU"}Elseif ($wmi.architecture -eq 6) {	"您的電腦是 Itanium CPU"}Elseif ($wmi.architecture -eq 9) {	"您的電腦是 x64 CPU"}Else {	# 以上皆非	"不清楚 WMI Architecture 值為 " + $wmi.Architecture + " 是哪一種處理器"}Write-Host "以上資訊係根據 WMI 所得"            

最單純的 If 陳述式只有一個 If,如果還有其他的情況要判斷,就要如上述範例再加入其他的 Elseif。但不論單純或複雜,當 If 的任一個條件式成立時,就會執行條件式所屬的程式碼區塊,之後就會跳離整個 If。若以此例來說,如果 wmi.Architecture 的值為 0,在第一個條件式判斷即成立,因此會顯示 x86 CPU,並在顯示之後隨即跳離整個 If;如果 wmi.Architecture 的值為 9,就會歷經 6 次的條件式判斷,且在第 6 次判斷才讓條件式成立執行;如果 6 次的條件式判斷都不成立,就是執行 Else 所屬的程式碼區塊。

此外要提醒您的是,此例的程式碼區塊都只有簡單的一行程式,但實際上程式碼區塊允許多行程式,而如果有多行程式,每一行程式都必須放在大括號裡面,例如:

…Else {	程式行 1	程式行 2	程式行 3	程式行 4}…            
 

Switch

如果要判斷的條件式較多,可以改用 Switch,其語法如下所示:

Switch [-regex|-wildcard|-exact][-casesensitive] -file <檔名> (<欲判斷的變數>) {	<比對條件1> {		程式碼區塊 1	}	<比對條件2> {		程式碼區塊 2	}	<比對條件3> {		程式碼區塊 3	}…	Default {		程式碼區塊 n	}}            

若將之前的 CPU 範例改寫成 Switch 則如下所示:

$wmi = Get-WmiObject win32_processorSwitch ($wmi.Architecture) {	0 {		"您的電腦是 x86 CPU"	}	1 {		"您的電腦是 MIPS CPU"	}	2 {		"您的電腦是 Alapha CPU"	}	3 {		"您的電腦是 PowerPC CPU"	}	6 {		"您的電腦是 Itanium CPU"	}	9 {		"您的電腦是 x64 CPU"	}	Default {		"WMI Architecture = " + $wmi.Architecture + ",不清楚是哪一種處理器"	}}Write-Host "以上資訊係根據 WMI (switch) 所得"            

Switch 的比對條件也可以是字串,而且 Switch 在比對時也支援正規運算式、萬用字元、精確比對、字母大小寫有別,或者從檔案輸入。例如以下是字母大小寫有別的比對實例:

$var = "Windows PowerShell"Switch -casesensitive ($var) {	"windows" {		"windows"	}	"windows powershell" {		"windows powershell"	}	"Windows PowerShell" {		"Windows PowerShell (case sensitive)"	}}            

要提醒您的是,Switch 和 If 最大的不同,是 If 只要有條件式成立,並執行了條件式所屬的程式區塊之後,就會跳離整個 If,但是 Switch 若有條件式成立,並執行過條件式所屬的程式區塊之後,仍會往下繼續比對。因此在設計 Switch 的比對時,應先考量會不會發生多重結果的情況、多重結果是不是您要的;如果不想得到多重結果,可以在每個程式碼區塊的最後加入稍後隨即說明的 Break 或 Continue。

 

ForEach(Foreach-Object)

由於 Windows PowerShell 隨處可見物件,因此也就經常需要處理物件,尤其當我們需要依序處理集合物件裡的每一個物件時,ForEach 更是最方便的處理方式。VBScript 也有功能相同的 For…Each…Next,但是 Windows PowerShell 的方式更為簡便:Windows PowerShell 的作法簡化成一個 ForEach,因此再也不用擔心會忘了結尾的 Next。ForEach 的用法如下所示:

ForEach ($<個別的項目或物件> in $<集合物件>) {	<指令區塊>}            

舉凡迴圈都應該要有終止條件,不然若變成無窮迴圈,會讓程式卡在迴圈而無法繼續執行,形同程式當掉。ForEach 執行時會依序並一一取得集合物件裡的物件,而且每次取得個別物件時,就執行一次 <指令區塊> 裡的程式碼。這意味著 ForEach 的終止條件就是處理完集合物件裡的每一個物件,如果集合物件裡有十個物件,ForEach 就會執行十次。

我們先以簡單的例子來說明 ForEach,以下的例子會先建立陣列,然後利用 ForEach 一一取得陣列元素,最後再以指令區塊裡的 $item 顯示元素值。

PS > $array=@(1..5)PS > ForEach ($item in $array) {$item}12345            

稍後提及 If 時,我們將舉出綜合 ForEach 和 If 的實例,但現在我們要強調 ForEach 的另一種用法。實際上,Windows PowerShell 的 ForEach 其實是 Foreach-Object 的別名,而 Foreach-Object 是 Windows PowerShell 內建的 cmdlet。因此 ForEach 的另一種用法就是以管線符合結合其他的 cmdlet,其語法如下所示:

<命令> | ForEach -process {指令區塊} [-begin {指令區塊}] [-end {指令區塊}]            

例如以下兩個例子,第一個先以 dir 列出目前磁碟目錄底下所有的檔案和目錄,然後將結果透過管線送到 ForEach,而 ForEach 會以 {指令區塊} 處理每一筆檔案和目錄;也就是將每個檔案或目錄的長度除以 1024,並加以顯示(以 KB 顯示檔案長度)。要注意的是,其中的 $_ 變數代表的是傳入 ForEach 的物件:

PS > dir | ForEach -process { $_.length / 1024}            

第二個例子先以 Get-Eventlog 取得最新的一千個「系統」事件,並置入 $Events 變數。接著透過管線將 $Events 傳給 ForEach,而 ForEach 首先以 -begin 顯示目前的日期和時間,再以 -process 裡的 Out-File 建立名為 event.txt 的文字檔,並且將每個事件的訊息屬性存入這個檔案,最後再以 -end 在所有的處理都完成之後,再次顯示目前的日期和時間。

PS > $Events = Get-Eventlog -logname system -newest 1000PS > $Events | ForEach -begin {get-date} -process {out-file -filepath events.txt -append -inputobject $_.message} -end {get-date}            
 

For

For 類似 ForEach,但不同的是 ForEach 便於處理集合物件裡的每個物件,For 比較適合用在以固定次數作為終止條件的迴圈。以下是 For 迴圈的語法:

For (<計數器啟始>; <條件式>; <計數器增量>) {	<程式碼區塊>}            

For 迴圈之所以適合用在固定次數的迴圈,是因為在其語法就配備了迴圈執行次數的計數器啟始及增量,而其執行的基本邏輯步驟是:1. 計數器啟始 2. 判斷條件式 3. 若條件式成立則執行程式碼區塊(若條件式不成立就結束迴圈,後續步驟 4 也不會執行)4. 計數器增量,接著跳到步驟 2 判斷條件式。以下的例子是以 WMI 搭配 For 迴圈來 ping 127.0.0.1 到 127.0.0.10 這一段循序範圍的 IP 位址。

[int]$intIPRange = 10[string]$intIP = "127.0.0."# 此 For 迴圈的計數器啟始值為1,條件式為$i < $intIPRange# 也就是會 ping 127.0.0.1 到 127.0.0.10 等 10 個 IP 位址For ($i=1; $i -le $intIPRange; $i++){	# 要 ping 的 IP 位址是由 $intIP 和 $i 所結合	$strQuery = "select * from win32_pingstatus where address = '" + $intIP + $i + "'"	# 利用 Get-WmiObject 送出 ping 的查詢	$wmi = Get-WmiObject -query $strQuery	"Pinging $intIP$i ... "	If ($wmi.statuscode -eq 0) {		"成功"	}	Else {		"錯誤,狀態碼: " + $wmi.statuscode	}}           

For 的寫法還有一些變化,例如故意省略條件式,讓 For 迴圈變成無窮迴圈,但另在 For 迴圈的程式碼區塊利用 If 達到條件式跳出迴圈的目的。例如以下兩種變化,可以讓 For 適用於迴圈次數不固定的情況。

# 變化一:無窮迴圈For (;;) {	<程式碼>	If (<條件式>) {		Break	}}# 變化二:無窮迴圈,但保持計數器啟始和增量For ($i = 1; ;$i++) {	<程式碼>	If (<條件式>) {		Break	}}           
 

While

For 適合用在次數固定的迴圈,如果迴圈執行次數不固定或未知,除了如上將 For 寫成外加條件式的無窮迴圈,也可以改用 While 迴圈。While 迴圈可重複執行若干次數,並且可在重複執行之前依照其所附屬的條件式來決定繼續重複與否。根據先執行或先判斷條件式,以及條件式的判斷方式,While 迴圈有三種變化,以下分別討論。

‧While

While 迴圈的使用語法如下:

While (<條件式>) {	<程式碼區塊>}			

While 迴圈會先檢查 <條件式>,如果條件式成立才會執行附屬的程式碼區塊,因此如果條件式一開始就不成立,程式碼區塊就一次都不會執行。例如以下顯示 1 到 10 的簡單例子,如果將 -le 改成 -ge,就完全不會顯示任何數值:

$i = 1While ($i -le 10) {	"While loop: " + $i	$i ++}"程式結束"			

‧Do While

Do While 迴圈的使用語法如下:

Do {	<程式碼區塊>} While (<條件式>)			

Do While 和 While 迴圈幾乎相同,差別只在 Do While 會先執行所屬的程式碼區塊,再檢查 <條件式>,若條件式成立會再次執行所屬的程式碼區塊,然後再檢查條件式,並以此重複。這意味著 Do While 所屬的程式碼區塊至少會執行一次。

‧Do Until

Do Until 迴圈的使用語法如下:

Do {	<程式碼區塊>} Until (<條件式>)			

Do Until 和 Do While 也很類似,兩者都是先執行所屬的程式碼區塊,再檢查 <條件式>。但兩者的差別在於:Do While 是條件式成立就再次執行所屬的程式碼區塊,而 Do Until 則是條件式成立就結束迴圈(也就是若條件式不成立就再次執行所屬的程式碼區塊)。

 

巢狀迴圈

迴圈也可以巢狀,也就是迴圈裡還有迴圈;例如以下的雙層巢狀迴圈:

While (<條件式>) {	…	While (<條件式>) {		…	}}			

如果巢狀的是兩個 For 迴圈,那麼總執行次數將是兩個 For 迴圈執行次數的乘積;例如外層執行 3 次,內層執行 5 次,總共會執行 15 次。

 

Break

Break 除了可以用來終止所屬的迴圈(包括 ForEach、For、While、Do While、Do Until),而且也能用來結束整個 Switch 陳述式。例如以下兩個範例的第一個範例比對到 windows powershell 就會結束,因為此例不是字母大小寫相異的比對,更重要的是受到 Break 的作用。

$var = "Windows PowerShell"Switch ($var) {	"windows" {		"windows"		Break	}	"windows powershell" {		"windows powershell (case insensitive)"		Break		# 由於不是字母大小寫相異的比對,而且還有 Break,		# 所以此例執行至此便告終止。	}	"Windows PowerShell" {		"Windows PowerShell (case sensitive)"		Break	}}			

另一個範例則是受到 If 的影響,當 $i 遞增到 5 的時候,使得 If 的條件式成立而執行了 Break,因而終止了 For 迴圈。

For ($i = 1; $i -le 10; $i++) {	Write-Host $i	If ($i -eq 5) {		Write-Host "BREAK!!"		Break	}}			
 

Continue

和 Break 相同的是 Continue 也能作用在 ForEach、For、While、Do While、Do Until 等迴圈以及 Switch 流程控制,但更重要的差別是 Break 會終止這些陳述式,而 Continue 會跳回這些陳述式開頭的地方,「繼續」執行迴圈或 Switch 的下一個動作。例如以下的範例,只有 $i 是奇數時,條件式 $i % 2 才會成立,也才會執行If程式碼區塊裡的 Continue,而這會跳過下一行的 $i、跳回 ForEach 迴圈繼續下一個數值,因此這個範例只會顯示 1 到 10 裡的偶數。

ForEach ($i in 1..10) {	If ($i % 2) {		Continue	}	$i}			
 

Break、Continue 及迴圈標籤

Break 和 Continue 可以指定要作用的迴圈,通常在巢狀迴圈時,為了清楚 Break 或 Continue 所作用的迴圈為何,就會在 Break 或 Continue 指定之後迴圈名稱。但是在這之前,必須先替迴圈命名,也就是替迴圈加上標籤,位置是在迴圈關鍵字之前,並且還要在最前面加上冒號,例如以下的例子,在 While 之前的 :OutHere 即為 While 迴圈的標籤,而內層 While 迴圈裡的 Break OutHere 則明確指定了要結束的是外層 While 迴圈(這當然會連同內層的迴圈都一併結束)。

…:OutHere While (1) {	While (1) {		If ($var -le 1024) {			Break OutHere		}	}}…			

我們甚至可以如下使用迴圈標籤:

:OutHere While (1) {	While (1) {		If ($var -le 1024) {			Break $target		}	}}…			
 

結語

迴圈和流程控制能讓程式變得靈活、彈性,讓程式不只是循序的執行一次,更能依照我們所設定的條件,重複執行程式裡的某些程式碼,或者跳過某些程式碼不執行。

使用迴圈或條件控制時,除了要瞭解語法,更重要的是條件式,包括要避免無窮迴圈,以及必須確定所設定的條件必須真的符合現況,而不只是語法正確,否則很可能會得到沒有錯誤訊息但錯誤的執行結果(如果還把錯誤結果當真,就更麻煩了)。

相关文章 热门文章
  • 微软宣布已售出4亿份Windows 7许可
  • 文件共享的12条军规——多一点规划可以使你的共享文件夹环境更合理
  • Powercfg 从命令行控制系统的电源管理
  • windows NT 4.0 Domain升级到windows server 2008 R2需要注意的几个问题
  • windows 7使用GPO统一桌面黑屏
  • Windows 2003域更名工具(Domain Rename Tool)
  • PowerShell命令解释器技巧
  • PowerShell脚本优化技巧
  • 创建Windows 7部署介质
  • 轻松传送——Windows Easy Transfer
  • 使用MDT 2010执行Windows 7裸机安装
  • Windows Server 2008 R2和Windows 7的组策略
  • “http 500内部服务器错误”的解决方法
  • 利用Windows 2000 Server的RRAS实现VPN服务器
  • 用凤凰万能启动盘解决本地/域管理员密码丢失
  • Win2003 Server企业版安装配置
  • Active directory 灾难恢复
  • Windows 2000/03域和活动目录
  • 如何在vmware4上创建windows 2003群集
  • MSI文件制作全过程
  • Win2000命令全集(一)
  • Windows 2000/AD技巧
  • 此系统的本地策略不允许您采用交互式登录解决方法
  • Win2000路由的安装与设置实现不同网段互通
  • 自由广告区
     
    最新软件下载
  • SharePoint Server 2010 部署文档
  • Exchange 2010 RTM升级至SP1 教程
  • Exchange 2010 OWA下RBAC实现的组功能...
  • Lync Server 2010 Standard Edition 标..
  • Lync Server 2010 Enterprise Edition...
  • Forefront Endpoint Protection 2010 ...
  • Lync Server 2010 Edge 服务器部署文档
  • 《Exchange 2003专家指南》
  • Mastering Hyper-V Deployment
  • Windows Server 2008 R2 Hyper-V
  • Microsoft Lync Server 2010 Unleashed
  • Windows Server 2008 R2 Unleashed
  • 今日邮件技术文章
  • 腾讯,在创新中演绎互联网“进化论”
  • 华科人 张小龙 (中国第二代程序员 QQ...
  • 微软推出新功能 提高Hotmail密码安全性
  • 快压技巧分享:秒传邮件超大附件
  • 不容忽视的邮件营销数据分析过程中的算..
  • 国内手机邮箱的现状与未来发展——访尚..
  • 易观数据:2011Q2中国手机邮箱市场收入..
  • 穿越时空的爱恋 QQ邮箱音视频及贺卡邮件
  • Hotmail新功能:“我的朋友可能被黑了”
  • 入侵邻居网络发骚扰邮件 美国男子被重..
  • 网易邮箱莫子睿:《非你莫属》招聘多过..
  • 中国电信推广189邮箱绿色账单
  • 最新专题
  • 鸟哥的Linux私房菜之Mail服务器
  • Exchange Server 2010技术专题
  • Windows 7 技术专题
  • Sendmail 邮件系统配置
  • 组建Exchange 2003邮件系统
  • Windows Server 2008 专题
  • ORF 反垃圾邮件系统
  • Exchange Server 2007 专题
  • ISA Server 2006 教程专题
  • Windows Vista 技术专题
  • “黑莓”(BlackBerry)专题
  • Apache James 专题
  • 分类导航
    邮件新闻资讯:
    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营销 | 网络营销 | 营销技巧 |营销案例
    邮件人才:招聘 | 职场 | 培训 | 指南 | 职场
    解决方案:
    邮件系统|反垃圾邮件 |安全 |移动电邮 |招标
    产品评测:
    邮件系统 |反垃圾邮件 |邮箱 |安全 |客户端
    广告联系 | 合作联系 | 关于我们 | 联系我们 | 繁體中文
    版权所有:邮件技术资讯网©2003-2010 www.5dmail.net, All Rights Reserved
    www.5Dmail.net Web Team   粤ICP备05009143号