# 如何封裝 PowerShell 模組並且上架到 PowerShell Gallery 資源庫

昨天發行了一個 [linqpad-folders-powershell-module](https://www.powershellgallery.com/packages/linqpad-folders-powershell-module) 模組到 [PowerShell Gallery](https://www.powershellgallery.com/)，我打算特別用這篇文章記錄一下發行的過程與注意事項。

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/589d72d847ffee929024-eace0a03-7677-4de2-a60c-b64f3863562c.webp)

1.  登入 [PowerShell Gallery](https://www.powershellgallery.com/) 並取得一把 API Key
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/b2caf74edc4b1e3a6ad1-157544796-466d71f3-7941-4b15-be63-4aa09e9dbe41.png)
    
    建立的時候要設定以下欄位：
    
    -   Key Name: `PushPackages`
    -   Expires in: `365 days`
    -   Select Scopes: `Push` > `Push new packages and package versions`
    -   Glob Pattern: `*` (wildcard)
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/fd3b71d361f59db0bf40-157545985-a3eb4cf4-6ecb-4ebb-b4fa-51387ae3e720.png)
    
    建立完成後，要**立刻**按下 **Copy** 複製 API Key 下來，因為離開此頁面之後就再也無法取得了！
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/97472a878d675eeea833-157546277-7c9f293b-d898-442a-89c3-65a84673ef77.png)
    
2.  先建立 PowerShell Module 專案資料夾
    
    ```powershell
    mkdir linqpad-folders-powershell-module
    cd linqpad-folders-powershell-module
    ```
    
3.  建立 Module Manifest 檔 ( `*.psd1` )
    
    使用 `New-ModuleManifest` 快速建立一個模組宣告檔 (Module Manifest) 範本
    
    ```powershell
    New-ModuleManifest `
      -Path .\linqpad-folders-powershell-module.psd1 `
      -PassThru
    ```
    
    這個 `linqpad-folders-powershell-module.psd1` 檔案包含著所有該模組的完整定義，之後要上架的時候也會拿這裡的資訊產生相對應的 `linqpad-folders-powershell-module.nuspec` 封裝規格檔 (NuGet)，所以必須認真的填寫。
    
4.  加入 PowerShell Module 主程式 ( `*.psm1` )
    
    原始碼: [linqpad-folders-powershell-module.psm1](https://github.com/doggy8088/linqpad-folders-powershell-module/blob/main/linqpad-folders-powershell-module.psm1)
    
5.  設定模組宣告檔 (Module Manifest)
    
    這裡最重要的一個設定，就是「模組名稱」了，模組名稱預設會等於 `*.psd1` 的檔名，而且通常該檔案所在的「資料夾名稱」會等於「模組名稱」。
    
    其次就是必要的 `ModuleVersion` 模組版本設定，這裡必須設定為 `X.X.X.X` 這樣的格式，建議將預設的 `0.0.1` 修改為 `0.0.1.0` 這樣的格式。
    
    檔案中的 `RootModule` 用來指定主要的 PowerShell Module 檔案路徑 (`*.psm1`)，所有的 Functions 與 Cmdlets 都會擺在這個檔案內。
    
    還有像是 `Author`、`CompanyName`、`Copyright`、`Description` 就盡量寫清楚。
    
    上架模組最好可以宣稱哪些東西要匯出給使用者使用，所以 `FunctionsToExport`、`CmdletsToExport`、`VariablesToExport`、`AliasesToExport` 記得要依據實際狀況設定。
    
    然後還有個 `PrivateData` 要設定幾項重要的 Metadata，像是 `Tags`、`LicenseUri`、`ProjectUri`、`IconUri` 能設定就都設定上去。
    
    最後，你可以用 `Test-ModuleManifest` 測試模組宣告檔有沒有設定錯誤：
    
    ```powershell
    Test-ModuleManifest -Path .\linqpad-folders-powershell-module.psd1
    ```
    
6.  使用 [PSScriptAnalyzer](https://www.powershellgallery.com/packages/PSScriptAnalyzer) 分析 PowerShell Module (`*.psm1`) 是否有問題
    
    先安裝 PSScriptAnalyzer 模組
    
    ```powershell
    Install-Module -Name PSScriptAnalyzer
    ```
    
    用以下命令分析 `linqpad-folders-powershell-module.psm1` 程式碼是否有建議改善事項：
    
    ```powershell
    Invoke-ScriptAnalyzer -Path ./linqpad-folders-powershell-module.psm1
    ```
    
    由於我的 Function 名稱為 `Set-LINQPadFolder`，使用了 `Set-` 開頭的命名，因此被要求要設定支援 `ShouldProcess` 才行。
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/059fe0d0de5734ee4f9d-157555371-373471b3-4c93-4f91-84bc-26e284b213ba.png)
    
    我在參數宣告之前加入了以下 `[CmdletBinding(SupportsShouldProcess)]` 宣告：
    
    ```powershell
    function Set-LINQPadFolder {
    
        [CmdletBinding(SupportsShouldProcess)]
        param(
            [Parameter()]
            [string]
            $DefaultPath = '~/Documents',
    
            [Parameter()]
            [string]
            $TargetPath = '~/Dropbox/Tools/LINQPad'
        )
    ```
    
7.  加入 `LICENSE` 授權宣告檔
    
    我一般都加入 [MIT License](https://en.wikipedia.org/wiki/MIT_License) 授權的內容。
    
8.  測試發行到 PowerShell Gallery
    
    透過以下命令，就可以測試看看能否成功發佈模組上去，這裡的 `-WhatIf` 參數不會將你的模組直接發佈，而是測試看看發佈時會不會有甚麼問題。
    
    ```powershell
    Publish-Module `
        -Path "G:\Projects\linqpad-folders-powershell-module\" `
        -NuGetApiKey $env:PowerShellGalleryApiKey `
        -WhatIf `
        -Verbose
    ```
    
9.  正式發行到 PowerShell Gallery
    
    只要將 `-WhatIf` 參數移除，就可以執行正式的發行作業。
    
    ```powershell
    Publish-Module `
        -Path "G:\Projects\linqpad-folders-powershell-module\" `
        -NuGetApiKey $env:PowerShellGalleryApiKey `
        -Verbose
    ```
    
    最後如果出現以下訊息，就代表成功發佈了！
    
    ```
    VERBOSE: Successfully published module 'linqpad-folders-powershell-module' to the module publish location 'https://www.powershellgallery.com/api/v2/package/'. Please allow few minutes for 'linqpad-folders-powershell-module' to show up in the search results.
    ```
    

> 上述完整的原始碼放在這裡: [https://github.com/doggy8088/linqpad-folders-powershell-module](https://github.com/doggy8088/linqpad-folders-powershell-module)

以上就是發行 PowerShell 模組到 PowerShell Gallery 的完整過程，以下則是安裝與使用的方法：

1.  安裝模組
    
    ```powershell
    Install-Module linqpad-folders-powershell-module -Force
    ```
    
    若是要更新版本，可以使用以下命令：
    
    ```powershell
    Update-Module linqpad-folders-powershell-module -Force
    ```
    
2.  使用模組中的 Functions 或 Cmdlets
    
    ```powershell
    Set-LINQPadFolder -TargetPath '~/Dropbox/Tools/LINQPad'
    ```
    

### 相關連結

-   [PowerShell Gallery | linqpad-folders-powershell-module](https://www.powershellgallery.com/packages/linqpad-folders-powershell-module)
-   [Creating and publishing Packages](https://learn.microsoft.com/en-us/powershell/scripting/gallery/how-to/publishing-packages/publishing-a-package?view=powershell-7.2&WT.mc_id=DT-MVP-4015686)
-   [PowerShellGallery Publishing Guidelines and Best Practices](https://learn.microsoft.com/en-us/powershell/scripting/gallery/concepts/publishing-guidelines?view=powershell-7.2&WT.mc_id=DT-MVP-4015686)
-   [How to Publish Your First PowerShell Gallery Package](https://jeffbrown.tech/how-to-publish-your-first-powershell-gallery-package/)
    -   [2020 Q3 - Chicago PowerShell Conference - Jeff Brown - Publishing Your 1st Package to the PS Gallery - YouTube](https://www.youtube.com/watch?v=w-t7jBLD9LE)
-   [Approved Verbs for PowerShell Commands](https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands?view=powershell-7.2&WT.mc_id=DT-MVP-4015686)
-   [Stop or exit a PowerShell script when it errors | 4sysops](https://4sysops.com/archives/stop-or-exit-a-powershell-script-when-it-errors/)
