Windows PowerShell字串理論

Don Jones

目錄

真實案例
複雜的比對
真是個字串連連的世界

當我在像是 Tech•Ed 或 TechMentor 等研討會發表演說時,我總是習慣提出宣言 — 幫助使用者記住例如 Windows PowerShell 等重點的通則宣告。我最近的宣言是「如果您在 Windows PowerShell 中剖析字串,肯定是搞錯了」。

這是我就 Windows PowerShell™ 是物件導向殼層的觀點提出來的。如果您把服務清單傾印到文字檔,然後剖析該文字檔來查看啟動了哪些服務,或諸如此類的事,那也未免太辛苦了。這在以文字為基礎的 OS (如 UNIX) 中是個有效的方法,但 Windows PowerShell (還有 Windows® 本身) 可讓您以更有效的方式來使用物件。

即便是您自己的指令碼都應該產生物件而不是格式化文字,如此一來,就可以利用殼層的各種格式化、篩選、匯出和其他命令,從您的指令碼來操作輸出 (在我 2008 年 7 月號的《Windows PowerShell》專欄中,您可以進一步了解將物件自訂成指令碼輸出的概念)。

最近在佛羅里達州奧蘭多舉辦的 TechMentor 中,我有一名學生提醒我幾乎所有規則,特別是通則,都有例外。「那麼要在 IIS 記錄檔中搜尋呢?這種情況下,不是只能剖析文字嗎?」

呃,沒錯。好在像 Windows PowerShell 這麼適合使用物件,說到剖析文字字串,它也絕非等閒之輩。經您這麼一說,IIS 記錄檔、防火牆記錄檔和其他文字型的記錄檔都是絕佳的範例。

真實案例

我實際上曾為一家我服務的公司剖析過一組防火牆記錄檔。有名員工被抓到瀏覽一些不當的網站,為了進行後續調查,人事部需要一份他曾造訪過的完整網站清單。要調出一天的記錄檔就已經有點難了,HR 的同仁竟然想回溯好幾週的記錄 — 這樣的工作我一點也不想手動進行。

該公司的動態主機設定通訊協定 (DHCP) 伺服器指出,該名員工的電腦好幾個月以來一直都是使用相同的 IP 位址 (基於本例的目的,讓我們假設是 192.168.17.54)。這其實並不罕見,尤其這是一部桌上型電腦,而且很少關機。既然防火牆記錄檔有保留來源 IP 位址的記錄,我知道 Windows PowerShell 可以幫上忙。

秘密在於常常受到忽視的 Select-String 命令。另外,您也必須具備規則運算式的實務經驗 (我在 2007 年 11 月號的《Windows PowerShell》中曾討論過)。

Select-String 命令可以接受檔案路徑,充滿著文字檔、規則運算式或是簡單字串可供尋找。它接著會輸出每個記錄檔中與規則運算式或簡單的字串相符的每一行。為了開始工作,我想取得包含該名員工之桌上型電腦 IP 位址的每一行。每個記錄檔行都包含一個日期和一個時間戳記,這也正是人事部的同仁想要的。

以下就是這個命令:

select-string -path c:\logs\*.txt -pattern "192.168.17.54" 
-allmatches –simplematch

–simpleMatch 參數指出我提供的模式不過是一個簡單的字串,並非規則運算式。[圖 1] 顯示一些也可傳送到檔案的輸出。要特別注意的是,輸出同時包含了找到相符項目的檔名和行號,如果您事後想要回頭找更多資訊的話,這將非常管用。

本月指令程式:Start-Sleep

這個指令程式可以滿足您在一天漫長的工作後所想要的 — 小盹一會兒。Start-Sleep 提供片刻休息 — 當然是指 Windows PowerShell 指令碼啦。

指令碼中需要片刻暫停是很正常的。比方說,假設您需要啟動服務,等幾秒的時間好讓它啟動和運行,然後執行一些仰賴該服務的其他工作。Start-Sleep 正是這種行為所需的,譬如,執行 Start-Sleep 10 會使殼層暫停 10 秒的時間。如果您需要更準確的控制,比如說,您可執行 Start-Sleep -milli 100 來暫停 100 毫秒的時間。Start-Sleep 會在指定的時間內完全中止殼層,包括指令碼、管線和任何一切在內。現在要是有人寫我期待已久的那個 Start-Nap 指令程式的話就太好了。

fig01.gif

[圖 1] Select-String 命令的輸出 (按一下以放大影像)

複雜的比對

在我提供 HR 同仁他們想要的東西後,他們卻發現那其實不是他們要的。我的報告包含了對眾多 IP 位址的造訪,例如 207.68.172.246 (也就是 MSN® 網站)。調查人員的下一個請求是把我的報告精簡成只對特定 IP 位址的造訪,也就是他們識別出屬於前述的其中一個網站。在本專欄中,我將不會公開調查中出現的真正 IP 位址。針對此範例,我會改用 207.68.172.246 (雖然 MSN 網站一般不被認為是不當的網站)。

這項請求可能比較困難一點。在我處理的記錄檔中,來源和目標 IP 位址都是彼此相鄰,並且由一個逗號分隔。所以我只要把搜尋字串改成「192.168.17.54,207.68.172.246」,然後重複搜尋就行了。

然而,在比較複雜的記錄檔裡面,兩個 IP 位址之間可能存有變數,因此簡單的字串比對是行不通的。在這種情況下,您就得訴諸規則運算式,它也可以用在比較簡單的記錄格式中,這也正是我要在此處示範的。

在規則運算式中,句點字元是代表任何單一字元的萬用字元。而我可以使用子運算式 (.)* 來搜尋兩個 IP 位址之間的任何字元。不過,為了逸出出現在 IP 位址本身的文字句點,有必要使用反斜線。

所得的命令是:

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" –allmatches

因為我這次是使用規則運算式,所以我移除了 –simpleMatch 參數。所得到的輸出結果只會顯示從特定員工的電腦對被視為不當之特定網站的造訪。輸出也包括了調查人員想要的日期和時間戳記資訊。[圖 2] 顯示在執行這類命令時可能會得到的部分輸出。

fig02.gif

[圖 2] 縮小範圍的搜尋結果,只顯示對特定網站的造訪 (按一下以放大影像)

但是我可以更進一步把輸出代入 Format-Table,並利用它的功能來顯示計算欄。我可以讓表格包含記錄檔的檔名和找到相符項目的行號,我甚至還可以顯示相符行本身。不過,我可以讓殼層以空白字串來取代規則運算式相符項目,而只顯示該行其餘的部分 — 在我的例子中即日期和時間戳記。這是進階技巧,但它更進一步示範了 Windows PowerShell 如何操作字串資料,並產生高度自訂的輸出,全都在單一命令列中完成:

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" -allmatches | 
ft  filename,linenumber,@{"Label"="Time";
"Expression"={$_.line.replace
($_.matches[0],"")}} –auto

[圖 3] 顯示我的最終結果可能的樣子。

fig03.gif

[圖 3] Select-String 命令的格式化輸出 (按一下以放大影像)

真是個字串連連的世界

我宣布 Windows PowerShell 的物件導向本質是它最大的優勢,話說得有點太快。但是,儘管如此,還是有不能用物件的時候。

Windows PowerShell 可能活在物件導向的世界,所幸,Windows PowerShell 小組覺察到您的世界常常在格式化的字串裡包含外部資料,因此他們加進了 Select-String 命令。有了 Select-String 加上對規則運算式的熟悉度,您可以使用 Windows PowerShell 來編寫單行的命令剖析最複雜的字串。

Don Jones 是《Windows PowerShell:TFM》的作者之一,也著有其他十幾本 IT 書籍。請透過他的部落格與他連絡,網址是 www.concentratedtech.com