###### tags: `PowerShell` # PowerShell 學習筆記 ## 說明文件 查看本機的說明文件前, 請先更新說明文件: ```ps Update-Help ``` 接著就可以用 `get-help` 觀看本機版的說明文件: ```ps Get-Help get-item ``` 以上看到的是簡易版本的說明, 如果要觀看完整的說明文件, 必須加上 `-Full` 參數: ```ps Get-Help get-item -Full ``` 你也可以查看線上版本的說明文件: ```ps Get-Help get-item -Online ``` ### 指令語法 說明文件中的語法表示方式: ``` SYNTAX Move-Item [[-Destination] <System.String>] [-Credential <Sys tem.Management.Automation.PSCredential>] [-Exclude <System.S tring[]>] [-Filter <System.String>] [-Force] [-Include <Syst em.String[]>] -LiteralPath <System.String[]> [-PassThru] [-C onfirm] [-WhatIf] [<CommonParameters>] Move-Item [-Path] <System.String[]> [[-Destination] <System. String>] [-Credential <System.Management.Automation.PSCreden tial>] [-Exclude <System.String[]>] [-Filter <System.String> ] [-Force] [-Include <System.String[]>] [-PassThru] [-Confir m] [-WhatIf] [<CommonParameters>]``` ``` 1. 你可以看到顯示的語法有兩組, 這表示有兩組參數集, 彼此不能隨意混用。舉例來說, 如果使用了上方參數集獨有的 `-LiteralPath` 參數, 就不能同時使用下方參數集才有的 `-Path` 參數。 3. 每個參數都是 `-參數名稱 參數值` 的形式 4. 沒有被中括號括住的參數就是強制參數, 一定要有, 例如: ``` [-Path] <String[]> ``` 這個 `Path` 參數就是強制參數, 不過參數名稱有用中括號括起來, 表示指定此參數時, 可以不用加上 `-Path` 指定參數名稱。 1. 有用中括號括起來的參數就是可選用的參數, 例如: ``` [-Filter <String>] ``` 就表示 `Filter` 參數並不一定要有, 需要時才指定。 1. 選用參數的參數名稱若有再使用中括號括起來, 稱為**位置**參數, 表示指定該參數時, 並不一定要指定參數名稱, 但若是指令可接受多個位置參數時, 必須依照其在語法說明中的順序出現, 例如: ``` [[-Destination] <String>] ``` 也就是說, 下指令時, 若有多個不具名參數, 就會依照順序一一對應到語法中的個別位置參數。若該指令有強制參數, 那麼第 1 個不具名參數就會對應到強制參數。 1. 參數值具有型別, 若型別後面還跟著一對中括號, 表示該參數值可以接受單一資料或是資料清單 (陣列), 例如: ``` [-Path] <String[]> ``` 若是資料清單, 清單中的個別項目以逗號相隔, 單一資料內含空白時, 必須以 "" 括起來, 例如: ``` Move-Item a.txt,"new file.txt" .. ``` 1. 有些參數只有名稱沒有值, 稱為**開關 (switch)** 參數, 代表 `True` 或是 `False` 的值, 例如: ``` [-Confirm] ``` 如果查看完整的說明文件, 可以看到這個參數的進一步說明: ``` -Confirm [<SwitchParameter>] Prompts you for confirmation before running the cmdlet. Required? false Position? named Default value False Accept pipeline input? False Accept wildcard characters? false ``` 就可以知道這個參數不指定的話預設值為 `False`, 指定時代表 `True`。 ### 指令範例 以下可取得特定指令的範例: ``` get-help Get-Event -Examples ``` ## PowerShell 用詞 ### command command 代表各種可以執行的事物, 包括以下幾種: 1. cmdlet:PowerShell (以 .net 撰寫) 原生的指令, 除少數例外, 名稱都是 `動詞-名詞` 的格式, 像是 `Get-Help`。 2. function:用 PowerShell 語言撰寫的指令。 3. application:可執行的應用程式 ## 語法基礎 ### 語法注意要點: 1. PowerShell 並不區分大小寫。 2. 參數名稱最少字母原則, 只要能區分參數名稱, 可以不用打完整的名稱, 例如以下兩者功能相同: ```ps > Get-Date -DisplayHint time 下午 05:10:18 > Get-Date -Disp time 下午 05:10:27 ``` 由於沒有其他參數的名稱是 `Disp` 開頭, 因此打 `-Disp` 就可以代表 `-DisplayHint` 參數。 3. 如果指令太長, 可以用[反引號 (backtick, <code>`</code> 符號)](https://devblogs.microsoft.com/scripting/powertip-line-continuation-in-powershell/) 接續下一行, 例如: ```ps # echo ` hello hello ``` ### 在指令行中代入指令執行結果 用小括號可以在指令內代入其他指令的執行結果: ```ps > Write-Host hello (Get-Date) hello 2020/12/16 下午 04:20:17 ``` ### 在字串中代入指令執行結果 利用英文雙引號可以在字串中用 `$` 符號代入變數值, 或者用 `$()` 代入指令執行結果: ```ps ❯ echo "time: $(get-date)" time: 08/13/2021 17:38:22 ❯ $name = "John" ❯ echo "hello, $name" hello, John ``` 如果要在字串中表示 `$` 符號, 可以加上 `` ` `` 字元讓 `$` 跳脫置換功能變成一般文字, 或是改用英文單引號來表示字串, 就不會有置換功能了。 ## 字串處理 ### 規則表達式 PowerSehll 提供有 [`-match`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators?view=powershell-7.1#-match-and--notmatch) 及 [`-replace`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators?view=powershell-7.1#replacement-with-regular-expressions) 運算器, 可以依據[規則表達式](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_regular_expressions?view=powershell-7.1)比對或是取代字串, 例如: ```ps ❯ "john_at_gmail.com" -match "((.+)@(.+))" False ``` 如果比對成功, 它會自動產生一個雜湊陣列 `$Matches`, 包含比對相符的內容: ```ps ❯ "john@gmail.com" -match "((.+)@(.+))" True ❯ $Matches Name Value ---- ----- 3 gmail.com 2 john 1 john@gmail.com 0 john@gmail.com ``` 索引鍵 '0' 為相符的子字串內容, 索引鍵 '1' 開始是從最外層依序到最裡層的群組相符的子字串內容。 `-nomatch` 則是和 `-match` 相反的運算器。 你也可以處理字串替換, 例如: ```ps ❯ "john@gmail.com" -replace "((.+)@(.+))",'$2_at_$3' john_at_gmail.com ``` 注意在 PowerShell 中英文雙引號的字串會進行變數置換, 所以在使用規則表達式取代字串時, 最好用英文單引號, 避免以 `$` 字元標示的群組編號被當成變數。 ## Provider PowerShell 使用 Provider 抽象化系統內儲存的資料, 例如檔案系統、登錄檔、甚至環境變數等等。 以下指令可以得知目前系統上有哪些 Provider: ```ps > Get-PSProvider Name Capabilities Drives ---- ------------ ------ Registry ShouldProcess {HKLM, HKCU} Alias ShouldProcess {Alias} Environment ShouldProcess {Env} FileSystem Filter, ShouldProcess, Credentials {C, D, Temp, E…} Function ShouldProcess {Function} Variable ShouldProcess {Variable} ``` ### 列出抽象的磁碟 以下指令則可以知道系統上有哪些 (含抽象的) 磁碟機: ``` > Get-PSDrive Name Used (GB) Free (GB) Provider Root CurrentLocation ---- --------- --------- -------- ---- --------------- Alias Alias C 85.68 8.88 FileSystem C:\ Users\ShinWei Cert Certificate \ D 95.20 32.66 FileSystem D:\ temp E 3.98 0.00 FileSystem E:\ Env Environment F FileSystem F:\ Function Function HKCU Registry HKEY_CURRENT_USER HKLM Registry HKEY_LOCAL_MACHINE M 258.26 596.53 FileSystem \\192.168.0.244\maker_disk Temp 85.68 8.88 FileSystem C:\Users\ShinWei\AppData\Local\Tem… Variable Variable WSMan WSMan ``` ### 存取環境變數 你可以像是操作檔案系統的方式操作這些資料, 例如檢視環境變數: ```ps > cd Env: > Get-Item temp Name Value ---- ----- TEMP C:\Users\ShinWei\AppData\Local\Temp > Get-Content temp C:\Users\ShinWei\AppData\Local\Temp ``` ### 存取登錄檔 也可以這樣操作登錄檔: ```ps > cd HKLM: > Set-Location .\SOFTWARE\ > cd .\Windows\ > ls Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Windows Name Property ---- -------- CurrentVersion ``` ## 所有資料都是物件 取得集合中物件的屬性清單: ```ps >Get-Date 2023年6月23日 下午 03:01:37 >Get-Date | Get-Member TypeName: System.DateTime Name MemberType Definition ---- ---------- ---------- Add Method datetime Add(timespan value) AddDays Method datetime ... Year Property int Year {get;} DateTime ScriptProperty System.Object DateTime {get=… ``` 使用 `year` 取得年份: ```ps > (get-date).year 2023 ``` 所有的指令都是針對物件在操作: ```ps > Get-Item *.html Directory: D:\temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2020/12/15 下午 06:23 1010 index.html -a--- 2020/12/17 上午 09:49 24109 opencv.html ``` 我們可以針對兩個檔案物件排序: ```ps > (Get-Item *.html) | Sort-Object -Property Length -Descending Directory: D:\temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2020/12/17 上午 09:49 24109 opencv.html -a--- 2020/12/15 下午 06:23 1010 index.html ``` 取得物件的屬性: ```ps > get-process | Get-Member TypeName: System.Diagnostics.Process Name MemberType Definition ---- ---------- ---------- Handles AliasProperty Handles = Handlecount Name AliasProperty Name = ProcessName NPM AliasProperty NPM = NonpagedSystemMemorySize64 ... ``` 篩選物件的屬性, 只留下指定的屬性 (移除未指定屬性): ``` > get-process | Select-Object -Property Name | Get-Member TypeName: Selected.System.Diagnostics.Process Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() Name NoteProperty string Name=ACMON ``` 用指定的屬性替代原始的物件: ``` > get-process | Select-Object -ExpandProperty Name | Get-Member TypeName: System.String Name MemberType Definition ---- ---------- ---------- Clone Method System.Object Clone(), System.Object ICloneable.Clone() ... ``` 若該屬性是陣列, 就會展開陣列的內容, 例如: ``` > get-process -Name explorer | Select-Object -ExpandProperty Modules | Select-Object -Property ModuleName ModuleName ---------- Explorer.EXE ntdll.dll ... EFSUTIL.dll DSROLE.dll Windows.Internal.System.UserProfile.dll CloudExperienceHostBroker.dll ``` 這一堆 .dll 就是 Modules 屬性展開後的每一個 Module。 ## 物件預設的顯示格式 請參考[這裡](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_format.ps1xml?view=powershell-7.1) ## PowerShell 的系統變數 ### $PROFILE $PROFILE 變數會記錄目前使用的 PowerSehll 設定檔路徑: ``` ❯ $PROFILE C:\Users\ShinWei\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 ``` ### $PSVersionTable $PSVersionTable 可以取得 PowerShell 版本資訊: ``` ❯ $PSVersionTable Name Value ---- ----- PSVersion 7.1.3 PSEdition Core GitCommitId 7.1.3 OS Microsoft Windows 10.0.22000 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0 ``` ## 腳本區塊 (Script Block) [腳本區塊](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_script_blocks?view=powershell-7.1)是一種功能類似匿名函式的物件, 定義的方式就是用大括號將要執行的內容包起來, 例如: ```ps ❯ $s = { echo "hello" } ``` 要叫用定義好的腳本區塊, 必須使用 [`&`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_operators?view=powershell-7.1#call-operator-) 運算器: ```ps ❯ & $s hello ``` 你也可以幫腳本區塊定義引數, 例如: ```ps ❯ $s = { >> param( >> [String]$name >> ) >> echo "hello, $name" >> } ``` 叫用時可以利用位置傳遞傳數: ```ps ❯ & $s "John" hello, John ``` 也可以指名方式傳遞參數: ```ps ❯ & $s -name "John" hello, John ``` ### 從字串建立並執行腳本區塊 如果要從字串中記錄的敘述建立並執行腳本區塊, 可以搭配 [`Invoke-Expression`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-expression?view=powershell-7.1), 例如若我們讀取一個腳本檔案, 並將內容記錄在變數中: ```ps ❯ $s param([String]$name) echo "hello, $name" ``` 如果想使用 `$s` 的內容建構成腳本執行, 你可能會想這樣做: ```ps ❯ $err = { $s } ``` 但這樣建構出來的腳本區塊在叫用時, 是執行 `$s`, 所以只會顯示字串的內容: ```ps ❯ & $err -name Mary param([String]$name) echo "hello, $name" ``` 正確的作法是先透過字串置換, 然後再使用 `Invoke-Expression` 來執行叫用腳本區塊: ```ps ❯ $correct = "& { $s } -name 'Mary'" ❯ Invoke-Expression $correct hello, Mary ``` 你也可以省略中間置換字串的變數, 直接寫成一列: ```ps ❯ Invoke-Expression "& { $s } -name 'Mary'" hello, Mary ``` 在底下的[更新 PowerShell Core 到最新版](#%E6%9B%B4%E6%96%B0-PowerShell-Core-%E5%88%B0%E6%9C%80%E6%96%B0%E7%89%88)中, 就有實際運用的範例, 會從網路下載的腳本檔建立腳本區塊執行。 ## 重新導向與管線 ### 用 ForEach-Object 一行一行取得程式輸出做處理 單純用管線取得程式輸出的話, 會等到程式結束才傳回所有的輸出內容, 如果希望一行一行取得輸出結果處理, 不用等到程式結束, 可以使用 [`ForEach-Object`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/foreach-object?view=powershell-7.1): ``` ❯ ping -t 8.8.8.8 | ForEach-Object -process { $_ -replace '時間', 'time' } Ping 8.8.8.8 (使用 32 位元組的資料): 回覆自 8.8.8.8: 位元組=32 time=6ms TTL=115 回覆自 8.8.8.8: 位元組=32 time=7ms TTL=115 回覆自 8.8.8.8: 位元組=32 time=5ms TTL=115 回覆自 8.8.8.8: 位元組=32 time=5ms TTL=115 ``` 其中 `-process` 是預設參數, 所以可以省略不寫: ``` ❯ ping -t 8.8.8.8 | ForEach-Object { $_ -replace '時間', 'time' } Ping 8.8.8.8 (使用 32 位元組的資料): 回覆自 8.8.8.8: 位元組=32 time=11ms TTL=115 回覆自 8.8.8.8: 位元組=32 time=8ms TTL=115 回覆自 8.8.8.8: 位元組=32 time=9ms TTL=115``` ``` 另外, `%` 與 `foreach` 是 `ForEach-Object` 的別名, 可以縮短指令行: ``` ❯ ping -t 8.8.8.8 | % { $_ -replace '時間', 'time' } Ping 8.8.8.8 (使用 32 位元組的資料): 回覆自 8.8.8.8: 位元組=32 time=7ms TTL=115 回覆自 8.8.8.8: 位元組=32 time=4ms TTL=115 回覆自 8.8.8.8: 位元組=32 time=8ms TTL=115 ``` :::danger 如果 foreach 出現在一列的開頭, 會變成 [`foreach`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_foreach?view=powershell-7.1&source=docs) 敘述, 雖然和上面談的 `ForEach-Object` 內建指令相似, 但它無法一行一行取得程式輸出, 只能接收完整的集合資料後才一行行處理。例如: ``` ❯ foreach($i in (ping 8.8.8.8)) {get-date -disp time; echo $i} 下午 01:33:44 下午 01:33:44 Ping 8.8.8.8 (使用 32 位元組的資料): 下午 01:33:44 回覆自 8.8.8.8: 位元組=32 時間=5ms TTL=115 下午 01:33:44 回覆自 8.8.8.8: 位元組=32 時間=4ms TTL=115 下午 01:33:44 回覆自 8.8.8.8: 位元組=32 時間=8ms TTL=115 下午 01:33:44 回覆自 8.8.8.8: 位元組=32 時間=4ms TTL=115 下午 01:33:44 下午 01:33:44 8.8.8.8 的 Ping 統計資料: 下午 01:33:44 封包: 已傳送 = 4,已收到 = 4, 已遺失 = 0 (0% 遺失), 下午 01:33:44 大約的來回時間 (毫秒): 下午 01:33:44 最小值 = 4ms,最大值 = 8ms,平均 = 5ms ``` 可以看到時間都在同一秒, 但若是改用 `ForEach-Object`: ``` ❯ ping 8.8.8.8 | % { Get-Date -disp time; echo $_ } 下午 01:37:18 下午 01:37:18 Ping 8.8.8.8 (使用 32 位元組的資料): 下午 01:37:18 回覆自 8.8.8.8: 位元組=32 時間=7ms TTL=115 下午 01:37:19 回覆自 8.8.8.8: 位元組=32 時間=11ms TTL=115 下午 01:37:20 回覆自 8.8.8.8: 位元組=32 時間=10ms TTL=115 下午 01:37:21 回覆自 8.8.8.8: 位元組=32 時間=9ms TTL=115 下午 01:37:21 下午 01:37:21 8.8.8.8 的 Ping 統計資料: 下午 01:37:21 封包: 已傳送 = 4,已收到 = 4, 已遺失 = 0 (0% 遺失), 下午 01:37:21 大約的來回時間 (毫秒): 下午 01:37:21 最小值 = 7ms,最大值 = 11ms,平均 = 9ms ``` 就會看到 `ping` 每一秒動作一次產生輸出後, 就會立刻經由 `ForEach-Object` 的腳本區塊處理, 所以中間的幾行訊息時間間隔都是 1 秒鐘。 兩者的差異可以參考[這一篇文章](https://devblogs.microsoft.com/scripting/getting-to-know-foreach-and-foreach-object/)。 ::: ## PowerShell 範例 以下蒐集一些小範例供參考使用。 ### 以管理員權限執行指令 若要像是 Linux 下以 sudo 指令提升成管理員權限執行指令, 可以使用 `Start-Process` 搭配 `-verb runas` 參數執行指令, 例如: ``` ❯ start-process netsh -verb runas ``` 就會以管理員權限執行 netsh 指令, 過程中還是會詢問是否允許: ![](https://i.imgur.com/Awq45U1.png) 只要按**是**即可。 :::info 也可以使用 runas 指令, 例如: ``` ❯ runas /user:mee\shinwei netsh 輸入 mee\shinwei 的密碼: 嘗試以使用者 "mee\shinwei" 的身分啟動 netsh ... ``` ::: ### 計算執行時間 PowerShell 本身沒有計時的 cmdlet, 不過可以利用 .net 的 StopWatch 物件來計時, 首先產生物件: ``` ❯ $sw = New-Object -TypeName System.Diagnostics.Stopwatch ``` 接著即可使用 Start()、Stop()、Reset() 方法操控計時器, 並使用 Elapsed 屬性取得目前累計的計時時間。例如: ``` ❯ $sw.Reset();$sw.Start();sleep 3;$sw.Stop() ❯ $sw.Elapsed Days : 0 Hours : 0 Minutes : 0 Seconds : 3 Milliseconds : 13 Ticks : 30138681 TotalDays : 3.48827326388889E-05 TotalHours : 0.000837185583333333 TotalMinutes : 0.050231135 TotalSeconds : 3.0138681 TotalMilliseconds : 3013.8681 ``` ### 搜尋字串 #### `Select-String` 要篩選輸出內容, 可以使用 [`Select-String`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-string?view=powershell-7.3) 搜尋文字或是規則表達式, 例如有一個這樣的文字檔: ```ps ❯ type .\test.txt hello this is a book ``` 以下的指令就可以篩選出有 "this" 的那一行: ```ps # cat test.txt | Select-String 'this' this ``` 要注意的是, `Select-String` 是針對文字物件搜尋, 如果是要篩選 cmdlet 輸出的物件, 必須先用 [`Out-string`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-string?view=powershell-7.3) 轉成文字物件再篩選: ```ps # alias | Out-String -stream | Select-String 'Get-Content' Alias cat -> Get-Content Alias gc -> Get-Content Alias type -> Get-Content ``` 要特別留意 `Out-String` 的 `-stream` 參數, 如果沒有加上此參數, 就會轉換成一個包含多行文字的字串物件, 這樣搜尋到字串時, 顯示的是多行的文字。加上 `-stream` 選項會轉換成多個單行文字的字串物件, 就只會顯示搜尋到文字的那一行。 #### `find.exe` 在 PowerShell 中如果要使用 find 搜尋檔案中的字串, 會因為 PowerShell 把雙引號括起來的內容當成字串物件, 使得實際傳送給 find 的參數內容沒有雙引號而出錯 使用 find 會出錯: ```ps ❯ find "this" test.txt FIND: 參數格式不正確 ``` 必須用單引號把雙引號包起來, 改用 '"要搜尋的文字"' 才能將含有雙引號的文字當成參數傳給 find: ``` ❯ find '"this"' test.txt ---------- TEST.TXT this ``` #### `findstr.exe` 如果覺得太麻煩, 也可以改用 findstr 指令, 不需要引號: ``` ❯ findstr this test.txt this ``` #### 找尋 gcc 特定表頭檔內的定義內容 以下是找尋 `time.h` 檔案中名稱含有 "time" 的自訂資料型別: ``` echo "" | gcc -E -xc -include 'time.h' - | Select-String -Pattern "typedef" | Select-String -Pattern "time" ``` 有關 gcc 選項說明如下: 1. `-E` 會在前置處理完就停止。 2. 最後指定 `-` 當檔名表示不是從檔案讀取原始碼, 而是從標準輸入讀取, 這裡因為有資料通道的轉向, 原始碼就是前面的 `echo` 送出的空字串。 3. `-x` 是指定要編譯哪一種程式語言, 此處 `-xc` 表示是 C 語言。由於是從標準輸入讀取原始碼, 所以 gcc 無法依據副檔名判斷程式語言種類, 這裡一定要指定程式語言才能正常運作。 4. `-include` 可以指定要匯入的表頭檔, 這裡就是將 `time.h` 匯入。 以上的 gcc 指令實際結果就是讓前置處理器把 `time.h` 讀入與空的原始碼合併後輸出, 也就可以看到 `time.h` 檔案的內容。 後面透過資料通道串接的 `Select-String` 可以搜尋文字。 :::info 這個方式找不到像是 `#define` 定義的項目, 因為在前置處理器處理後, 這些項目都已經被取代掉了。 ::: ### 計算資料夾大小 ``` # Get-ChildItem .\get-pip.py | Measure-Object -Property Length -sum Count : 1 Average : Sum : 2658865 Maximum : Minimum : StandardDeviation : Property : Length ``` ### 更新 PowerShell Core 到最新版 要在 PowerShell 內更新 PowerShell, 可以使用以下[指令](https://github.com/PowerShell/PowerShell/blob/master/tools/install-powershell.ps1-README.md): ```bash iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI" ``` - irm 是 [Invoke-RestMethod](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-7.1) 這個 cmdlet 的別名, 可以送出 http 請求, 用來取得結構性的資料。本例就是用它來下載 [PowerShell 的安裝腳本](https://aka.ms/install-powershell.ps1)。 - [-UseMSI](https://github.com/PowerShell/PowerShell/blob/1ec61d955c5f7e1e62a83d6a0d1dab3882bd73c9/tools/install-powershell.ps1#L42) 是安裝腳本的選項, 表示下載 MSI 格式的安裝檔執行安裝程序。 - iex 是 [Invode-Expression](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-expression?view=powershell-7.1) 這個 cmdlet 的別名, 可以執行字串參數內的指令。本例就是執行後面參數字串中叫用[腳本區塊](#%E8%85%B3%E6%9C%AC%E5%8D%80%E5%A1%8A-Script-Block)的動作。 ## Module 以下指令可以得知模組的安裝位置: ``` > Get-Content Env:\PSModulePath C:\Users\ShinWei\Documents\PowerShell\Modules;C:\Program Files\PowerShell\Modules;c:\program files\powershell\7\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules ``` 以下指令可以列出已載入的模組: ``` > Get-Module ModuleType Version PreRelease Name ---------- ------- ---------- ---- Manifest 1.0.0.0 DnsClient Manifest 7.0.0.0 Microsoft.PowerShell.Management Manifest 7.0.0.0 Microsoft.PowerShell.Security Manifest 7.0.0.0 Microsoft.PowerShell.Utility Manifest 7.0.0.0 Microsoft.WSMan.Management Script 2.0.399 oh-my-posh Script 1.0.0 beta4 posh-git Script 2.1.0 PSReadLine ``` 搜尋網路上可安裝的模組: ``` > Find-Module posh-git Version Name Reposito ry ------- ---- -------- 0.7.3 posh-git PSGalle… ``` 若要包含未正式發佈的版本: ``` > Find-Module posh-git -AllowPrerelease Version Name Reposito ry ------- ---- -------- 1.0.0-beta4 posh-git PSGalle… ``` 已安裝的模組會在執行到其中的指令時自動載入, 例如若先卸載已載入的模組, 然後執行 oh-my-posh 模組的 Set-Theme 指令, 就會自動載入 oh-my-posh 模組: ``` > Get-Module | Remove-Module > Get-Module ModuleType Version PreRelease Name ---------- ------- ---------- ---- Manifest 7.0.0.0 Microsoft.PowerShell.Management Manifest 7.0.0.0 Microsoft.PowerShell.Utility Script 1.4.7 PackageManagement > Set-Theme Agnoster > Get-Module ModuleType Version PreRelease Name ---------- ------- ---------- ---- Manifest 7.0.0.0 Microsoft.PowerShell.Management Manifest 7.0.0.0 Microsoft.PowerShell.Utility Script 2.0.399 oh-my-posh Script 1.4.7 PackageManagement Script 1.0.0 beta4 posh-git ```