PowerShell

PowerShell 初學者快速入門教學

適合初學者閱讀的 Windows PowerShell 指令工具教學文件,介紹基本概念與操作方法。

PowerShell 簡介

PowerShell 是由微軟所發展的任務自動化與組態管理框架,它的角色類似於 UNIX/Linux 系統上的殼層(shell),透過腳本語言以及各種輔助工具,讓系統管理者可以將各種工作自動化。

起初 PowerShell 僅支援 Windows 系統,後來於 2016 年以開放原始碼(MIT 授權)的方式釋出後,發展成為跨平台的管理工具,目前它已經支援各種主流的 Linux 發行版以及 Mac OS 系統,其安裝檔案與原始碼都可以從 GibHub 網站上直接下載,而 Windows 7 以後的系統都已經有內建 PowerShell 了,所以不需要安裝即可使用。

互動式殼層(Shell)

若要開啟 Windows 的 PowerShell,可從開始選單中尋找「Windows PowerShell」,點選後就可以打開 PowerShell 的執行環境。

Windows 開始選單

PowerShell 的操作介面跟傳統的命令提示字元(cmd.exe)類似,打開之後就會看到類似這樣的 PowerShell 命列列視窗,在這個視窗之中,我們可以輸入各種 PowerShell 的指令,以互動式的方式處理各種工作。

Windows PowerShell 視窗

Cmdlets 與別名

在 PowerShell 指令視窗中,除了可以執行傳統的 Windows 指令、執行檔之外,PowerShell 本身也提供了一種特殊的 cmdlet(發音為 command-let)結構式指令,所有的 cmdlet 指令名稱都是以 動詞-名詞 的方式來命名,例如 Get-ProcessGet-ContentStop-Process 等。

以下這個例子是使用 Get-Process 這個 cmdlet 指令,查詢 Greenshot 這個應用程式的行程資訊:

Get-Process -Name Greenshot
Get-Process 查詢行程資訊

大部分的 cmdlet 指令名稱都很長,打字麻煩、也容易不小心打錯字,遇到這種情況時,可以先打指令的前幾個字母,接著按下 Tab 鍵,這樣 PowerShell 就會自動想辦法補其後續的字母。

以輸入 Get-Process 這行指令來說,我們就可以在輸入 Get-Pr 這幾個字之後,按下 Tab 來補齊後續的指令名稱,如果以這幾個字母開頭的指令有很多個的話,則會依序顯示每一個可能的組合,我們可以多按幾下 Tab 鍵來尋找自己想要輸入的指令。

雖然 Tab 鍵可以讓我們少打一些字,但是管理者在平常互動式的操作中,使用太長的指令還是不方便,為了讓互動式操作更順手,PowerShell 為所有的 cmdlet 都定義了簡短的別名(aliases),並且允許使用者再輸入參數名稱時,只要輸入足夠辨識的字母即可,另外 PowerShell 的指令是不分大小寫的,所以可以全部都以小寫輸入。

Get-Process 這行指令預設的別名是 gps,所以我們也可以這樣執行上面的指令:

gps -n Greenshot
使用 cmdlet 別名

cmdlet 指令的參數除了以參數名稱來指定之外,也可以透過參數的位置順序來判斷(這樣就不需要打參數名稱)。以 Get-Process 來說,若不加參數名稱,其第一個參數就是行程名稱(也就是 -Name),而這個行程名稱參數也允許使用萬用字元,所以我們可以使用這樣的指令找出名稱是 G 開頭、t 結尾的行程:

gps G*t
依據位置判斷參數

物件

PowerShell 將許多的資料都當成物件來處理,這樣可以讓許多的工作指令搞撰寫起來更方便。

舉例來說,以下這行指令會產生一個簡單的字串:

"Hello, World."
Hello, World.

事實上這行字串就是一個 .NET 框架的物件,我們可以透過它的 Length 屬性,得知此字串的長度:

"Hello, World.".Length
13

所有會產生輸出的 cmdlet 指令,也可以傳回資料物件,例如 Get-Process 就會傳回 System.Diagnostics.Process 這種物件,我們可以把指令傳回的物件儲存在變數中,方便後續的指令稿使用。

在 PowerShell 中,變數名稱都是以錢字號($)開頭,若要把 Get-Process 指令的查詢結果儲存下來,可以這樣寫:

$process = Get-Process -Name Greenshot

由於這個儲存下來的 $process 是一個完整的 Process 物件,所以我們可以使用其中的各種屬性或函數來控制該行程。例如取得行程的 CPU 使用率:

$green.CPU

或強制關閉這個應用程式:

$green.Kill()
這裡的範例只是讓大家了解我們可以透過物件進行各種操作,在 PowerShell 若要讓特定的程式終止執行,最直接的做法是使用 Stop-Process 這個 cmdlet 指令。

管理者需求導向

PowerShell 本身在設計時就考慮了許多系統管理者的需求,除了可使用 .NET 框架的物件之外,還有其他很多方便的小功能,像在電腦上常用的 KB、MB、GB 等單位,也可以在 PowerShell 中直接使用,例如計算 2TB 的資料以每秒 3.5 MB 的速度備份,需要幾個小時:

2TB / 3.5MB / 3600
166.440634920635

另一項常用的功能就是日期與時間的處理,以下這一行指令是計算從現在的時間到晚上 21:45 還有多久:

[DateTime] "21:45" - [DateTime]::Now
Days              : 0
Hours             : 11
Minutes           : 22
Seconds           : 44
Milliseconds      : 956
Ticks             : 409649565189
TotalDays         : 0.474131441190972
TotalHours        : 11.3791545885833
TotalMinutes      : 682.749275315
TotalSeconds      : 40964.9565189
TotalMilliseconds : 40964956.5189

這裡用中括號包起來的 [DateTime] 代表 System.DateTime 這個類別,[DateTime] "21:45" 的作用是將 "21:45" 這個字串轉換為 System.DateTime 的物件。

後面的 [DateTime]::Now 代表呼叫 System.DateTime 類別內的 Now 靜態函數,傳回現在的時間,與前面的時間相減之後,就得到間隔的時間了。

如果只想取出結果中的 Hours 欄位,可以這樣寫:

$result = [DateTime] "21:45" - [DateTime]::Now
$result.Hours
11

若要計算兩個日期之間的天數,可以這樣寫:

$result = [DateTime] "2018/10/23" - [DateTime]::Now
$result.TotalDays
160.565214351617

組合多項指令

有時候我們在處理資料時,會經過好幾道程序,前一個指令的輸出會作為下一個指令的輸入,在這種狀況下就可以使用 PowerShell 的管線(pipe)功能,串接多個指令。

PowerShell 的管線符號為 |,只要上一個指令所產生的物件類型可以被下一個指令接受,就可以用管線符號直接串接起來使用。例如我們可以使用 Get-Process 指令找出 Edge 瀏覽器的行程,然後將結果直接導給 Stop-Process,關閉 Edge 瀏覽器:

Get-Process -Name MicrosoftEdge | Stop-Process

另一個例子是使用 Get-ItemFolderA 目錄下的的所有檔案列出來,導給 Move-Item 指令,將這些檔案搬移至 FolderB 目錄中:

Get-Item FolderA* | Move-Item -Destination FolderB

我們也可以使用 PowerShell 的管線串接多個指令,以下是將 Get-Process 的輸出用 Where-Object 篩選出 Handles 大於或等於 1000 的項目,經過 Sort-Object 排序後,再由 Format-Table 輸出指定的欄位:

Get-Process |
  Where-Object { $_.Handles -ge 1000 } |
  Sort-Object Handles |
  Format-Table Handles,Name,Description -Auto
複雜的管線

保護機制

PowerShell 提供系統管理者非常強大又方便的功能,不過有了快速方便的管理工具,在使用上也必須謹慎小心,避免下錯指令搞壞系統。

為了讓管理者可以方便確認要執行的實際動作,PowerShell 在許多的指令中都提供了 -WhatIf-Confirm 的功能,可讓管理者在執行重要指令之前,可以先確認一下。

例如我們如果想要把所有系統上 Edge 相關的程式都關閉,可以搜尋所有名稱含有 Edge 的行程,再交給 Stop-Process 關閉程式,如果不確定自己的指令是否會把不該關閉的程式都關閉,可以在 Stop-Process 指令後方加上 -WhatIf,這樣 Stop-Process 就只會列出要執行的動作有哪些,但是不會真正去執行:

Get-Process -Name *Edge* | Stop-Process -WhatIf
使用 -WhatIf 參數

在我們確認所有的動作都沒問題之後,再將 -WhatIf 參數拿掉,實際這些動作,就可以確保不會下錯指令。

另外一種方式是使用 -Confirm 參數,它會讓指令在執行每一項動作時,都讓使用者確認一次,這樣也可以確保執行的動作是正確的:

Get-Process -Name *Edge* | Stop-Process -Confirm
使用 -Confirm 參數

查詢指令與物件用法

PowerShell 中可用的 cmdlet 指令數量相當多,我們不太可能記得所有的指令名稱與用法,實務上的做法通常都是遇到問題時,再去查詢有哪些相關的指令可以使用。

若想要以關鍵字來尋找相關的 cmdlet 指令,可以使用 Get-Command 配合萬用字元(*)來搜尋,例如搜尋含有 process 關鍵字的指令就可以執行:

Get-Command *process*
Get-Command 搜尋指令

Get-Command 會列出所有符合搜尋條件的指令,若想要查詢某個指令的詳細用法,可以使用 Get-Help 加上指令名稱來查詢,例如查詢 Stop-Process 的用法就可以執行:

Get-Help Stop-Process
查詢 Stop-Process 的用法

在 PowerShell 中除了 cmdlet 指令很多讓人記不起來之外,.NET 框架的物件種類也不少,再加上每一種物件的用法都不同,所以在使用物件時,我們也時常會需要查詢各種物件可用的屬性與方法。

若要查詢一個物件有哪些屬性與方法,可以將物件透過管線的方式導給 Get-Member,例如查詢 "Hello" 這個字串物件的屬性與方法:

"Hello" | Get-Member
查詢字串物件的屬性與方法

我們也可以將其他 cmdlet 指令輸出的物件直接導給 Get-Member,查看該指令輸出的物件有哪些屬性與方法可用,這樣查詢方式是最常用的:

Get-Process | Get-Member

或是將儲存在變數中的物件導給 Get-Member 也可以:

$result = Get-Process
$result | Get-Member

指令稿

PowerShell 跟一般的指令稿語言(script language)一樣,可以直接在互動式的視窗中執行,若程式碼比較長的話,也可以把指令寫在指令稿檔案(script file)當中,一次執行檔案內所有的指令。

假設我們有以下的幾行下載網頁的 PowerShell 指令稿:

$webClient = New-Object System.Net.WebClient
$url = "https://www.google.com/"
$content = $webClient.DownloadString($url)
$content > google.html

若要以指令稿檔案的方式執行這段程式碼,首先要把它們儲存成 PowerShell 的指令搞檔案(副檔名為 .ps1),假設我們將其儲存在 C:OfficeGuidescript.ps1,則可在 PowerShell 命令列中直接執行這個檔案,即可讓 PowerShell 執行其中的內容:

C:OfficeGuidescript.ps1

若執行時出現了「系統上已停用指令碼執行」的錯誤訊息,請參考 PowerShell 更改執行原則的教學來解決。

歷史指令

若要查詢過去執行過的指令,可以使用 Get-History 指令:

Get-History

在執行一系列的指令之後,若想要將執行過的動作儲存成整份的指令稿,可以使用 Get-History 取得歷史指令之後,用 Foreach-Object 抽出實際的指令內容,然後再導入檔案中儲存起來:

Get-History | Foreach-Object { $_.CommandLine } > C:OfficeGuidescript2.ps1

接著可以啟動記事本編輯一下這些執行過的指令:

notepad C:OfficeGuidescript2.ps1

編輯好之後,就可以直接執行這份指令稿了:

C:OfficeGuidescript2.ps1

註解

在撰寫指令稿的時候,為了讓程式碼更容易閱讀,建議可以加上適當的註解,在 PowerShell 中單行的註解可用井字號(#)開頭:

# 列出 chrome 的行程
Get-Process -Name chrome

在程式碼中,所有 # 之後的內容都會被視為註解,我們也可以將單行註解放在指令的結尾:

Get-Process -Name chrome # 列出 chrome 的行程

如果要放置多行的註解,可以將註解使用 <##> 包起來,放在其中的任何文字也都會被視為註解:

<#
這是多行的註解,適合用於詳細的敘述,
或是把整段暫時沒用的程式碼註解起來。
#>

這種多行的註解適合用於詳細的敘述,或是把整段暫時沒用的程式碼註解起來。

瀏覽種類型資料

PowerShell 的 provider 架構允許程式開發者以類似檔案系統的操作方式,瀏覽與操作各類型的資料庫。

以最普通的檔案系統來說,我們可以使用以下指令列出 C: 槽底下的檔案:

Set-Location C:
Get-ChildItem
瀏覽檔案

而在熟悉這套操作模式之後,就可以用相同的方法瀏覽 Windows 的登錄機碼:

Set-Location HKCU:SoftwareMicrosoftWindows
Get-ChildItem
瀏覽 Windows 登錄機碼

相同的操作方法也可以套用在憑證的瀏覽上:

Set-Location cert:CurrentUserRoot
Get-ChildItem
瀏覽憑證

參考資料:iT邦幫忙TechNet Taiwan 官方部落格

Share
Published by
Office Guide

Recent Posts

Python 使用 PyAutoGUI 自動操作滑鼠與鍵盤

本篇介紹如何在 Python ...

1 年 ago

Ubuntu Linux 以 WireGuard 架設 VPN 伺服器教學與範例

本篇介紹如何在 Ubuntu ...

1 年 ago

Linux 網路設定 ip 指令用法教學與範例

本篇介紹如何在 Linux 系...

1 年 ago

Linux 以 Cryptsetup、LUKS 加密 USB 隨身碟教學與範例

介紹如何在 Linux 系統中...

1 年 ago