PowerShell 提供模組化使用方式,讓你可以將各種功能模組化後,根據需求匯入使用,通常我們會將 PowerShell 的模組安裝在固定的位置,你可以在 PowerShell 環境中執行 $Env:PSModulePath 來查看 PowerShell 會自動從那些地方載入模組,但有時候我們不想安裝在全域,只是想在我當前的 .ps1 檔中簡單的匯入使用,這時候你可以參考這篇的做法。
模組化架構
講架構感覺有點太高尚,其實也就是整理指令碼的管理方式,我這邊先建立了一個專案資料夾,並在裡面建立 modules 模組資料夾,然後在 modules 資料夾中建立兩個 PowerShell 模組指令檔 .psm1,指令碼內容如下:
1 | # ./modules/module1.psm1 |
1 | # ./modules/module2.psm1 |
注意!指令碼模組的附檔名一定要是
.psm1,若你使用.ps1則會造成指令第二次執行時發生找不到 cmdlet 的錯誤訊息。
接著在專案根目錄中建立一個 main.ps1 指令檔,在裡面匯入上面這兩個模組並執行他們,指令碼如下:
1 | Import-Module ".\modules\module1.psm1" |
你應該比較常看到 Import-Module SOME-MODULE 這樣的用法,這寫法是會去 $Env:PSModulePath 這裡有註冊的位置找模組來載入,其實是用 Import-Module 模組載入是可以直接使用路徑來指定模組位置的。
如此一來,我們就可以把 PowerShell 專案的資料夾結構規劃的漂亮些,甚至把功能切小,方便之後重複使用。
執行 main.ps1 的結果如下:

把 .ps1 指令檔當成模組匯入,會怎樣?
前面有提到 PowerShell 模組指令檔的附檔名是 .psm1,如果你使用 Import-Module 載入模組指令碼的時候,載入到 .ps1 的時候,會發生甚麼事呢?
我們來實驗一下,把 main.ps1 改成下面這樣:
1 | Import-Module ".\modules\module1.ps1" |
同時把模組檔的副檔名改成 .ps1,然後執行 main.ps1 看看,結果如下:

你會發現第一次執行 main.ps1 的時候是成功的,但第二次執行時卻抱錯,說找不到 Get-Something1 這個名稱的 cmdlet。
1 | The term 'Get-Something1' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. |
為什麼會有這種差別呢?這時候我們使用 Get-Module 查看已匯入至目前工作階段的模組看看。

圖中紅框的 module1 就是我們載入的模組,之所以是這個名稱,是 PowerShell 在匯入模組檔案時,會自動用檔案名稱作為模組名稱,這篇官方文件有提到這件事,PowerShell 對模組資料夾和名稱是有一定規範的。
這時候會覺得奇怪,Get-Module 裡面明明有顯示該模組,為什麼會找不到呢?
因為只有 .psm1 檔才能正確註冊進 PowerShell 模組中,而 Get-Module 所顯示的只是載入的模組檔案名稱而已。
那位甚麼第一次執行會成功呢?
第一次之所以會執行成功,是因為當前工作階段的 Get-Module 沒有 module1 這個模組,所以 Import-Module 會真的執行 module1.ps1 這個指令檔內的指令碼,這時候就讓 main.ps1 可以執行 Get-Something1 這個 cmdlet 了。
而第二次執行的時候,Get-Module 裡面已經有 module1 這個模組的設定,因此會去找 module1.psm1 來執行,但因為沒有這個檔案呀,所以當然找不到所需要的 cmdlet。
後記
這篇其實就兩個重點:
Import-Module可以使用路徑來載入模組指令碼- 撰寫模組指令碼請用
.psm1副檔名
參考資料: