The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何對 PowerShell 腳本檔案進行數位簽章

我個人寫過的 PowerShell 腳本可能有數百到上千支,數不清了,由於大部分的腳本都是自己個人使用為主,所以大多都不會特別對這些腳本進行數位簽章。但是對於金融業這種高度管制的企業或組織來說,其實 PowerShell 腳本是被嚴格禁止的,此時對你的 PowerShell 腳本進行數位簽章就顯的十分重要。除此之外,若你要發佈腳本給其他人使用,對腳本進行數位簽章也是一個很好的選擇,不但可以增加可信度,也可以確保腳本的完整性,不會被惡意竄改後重新散佈有問題的版本。這篇文章我將介紹如何對 PowerShell 腳本檔案進行數位簽章。

the idea of digitally signing PowerShell scripts

每次在 PowerShell 使用 GitHub Copilot CLI 的時候,他都經常會回我 bash 底下才有的命令,所以我最近設計了一支 ghcs.ps1 腳本,讓我在尋求 AI 建議時可以盡可能的以 PowerShell 為主,比較不會亂回答,實用性很高!👍

今天我就拿這個腳本來做數位簽章的示範!

新電腦使用 PowerShell 的起手式

這裡我以 Windows Sandbox 為例,快速打造一個全新的 Windows 環境,並且安裝好 PowerShell 7.x 版本。

# 安裝 Chocolatey
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

# 安裝 PowerShell 7.x, Windows Terminal, Git, GitHub CLI
choco install -y powershell-core microsoft-windows-terminal git gh

# 安裝 GitHub Copilot CLI
gh extension install github/gh-copilot

# 如果已經安裝過也可以用以下命令升級
gh extension upgrade gh-copilot

# 登入 GitHub 帳戶
gh auth login --web -h github.com

接著請下載 ghcs.ps1 腳本,並且放到你的 $HOME\Documents\PowerShell\Scripts 目錄下,若是全新的電腦,該目錄可能不存在,需要事先建立:

mkdir $HOME\Documents\PowerShell\Scripts

注意: 這裡的 $HOME 是 PowerShell 的環境變數,代表你的家目錄,通常是 C:\Users\你的使用者名稱

除此之外,你還可能需要設定一次 PATH 環境變數,讓你可以直接在 PowerShell 中執行 ghcs 這個指令:

理解 PowerShell 的執行原則

接著我們就可以開始執行 ghcs.ps1 這個腳本了,例如:

ghcs How to list all files?

不過,我們若在 Windows 10 或 Windows 11 第一次執行 PowerShell,通常都會遇到以下錯誤:

因為這個系統上已停用指令碼執行,所以無法載入 C:\Users\XXX\Documents\PowerShell\Scripts\ghcs.ps1 檔案。如需詳細資訊,請參閱 about_Execution_Policies,網址為 https://go.microsoft.com/fwlink/?LinkID=135170。

我在授課 Angular 前端開發課程時,也常常有許多學員遇到這個問題,這是因為 Windows Client 預設的執行原則是 Restricted,也就是不允許執行任何 PowerShell 腳本,如下圖示:

ng new

可以透過以下命令查看不同 Scope 底下的執行原則為何:

Get-ExecutionPolicy -List

事實上,在不同的 Windows 版本中,執行原則有不同的預設值設定:

  • Windows Client: Restricted (允許執行個別命令,但不允許執行腳本)
  • Windows Server: RemoteSigned (允許執行本機編寫的腳本,但從遠端下載的腳本必須經過數位簽章)
  • Windows Sandbox: Undefined (當所有 Scope 都是 Undefined 時,預設會是 Restricted 限制執行)

只要你是透過 TeamsOutlook 下載的 PowerShell 腳本,該檔案在儲存到 NTFS 檔案系統時,就會自動幫你加上一些隱形標記。若要移除這些標記,可以透過 Windows 內建的 Unblock-File Cmdlet 來解除封鎖。

由於 Restricted 直接從本機電腦的層級禁止了所有腳本執行,但你依然可以在 CurrentUser 這個各明確的 Scope 層級,將執行原則改成 RemoteSigned,這樣就可以執行自己寫的腳本了:

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

因此,你若是寫了一支 PowerShell 腳本,不但想要在自己的電腦上執行,也希望可以讓更多人使用的話,當使用者將執行原則設定為 RemoteSigned 時,你的 PowerShell 腳本要是沒簽章,同時使用者又是從網路上下載你的腳本,那麼他們即便下載也會無法執行的。

注意: 建議不要鼓勵使用者調低 PowerShell 的執行原則,設定為 Bypass 的安全風險極高,因為這樣會讓所有的腳本都可以執行,包括從網路上下載的惡意腳本。

對 PowerShell 腳本檔案進行數位簽章

由於我公司每年都會購買 GlobalSign 的 EV Code Signing 憑證,所以我這裡就以 GlobalSign 為例,示範如何對 PowerShell 腳本檔案進行數位簽章。

  1. 首先,你需要先安裝 GlobalSign 的驅動程式

    因為 GlobalSign 的 EV Code Signing 憑證是透過 USB Token 來進行簽章的,所以你需要先安裝 GlobalSign 的 Safenet Drivers 驅動程式,讓你的電腦可以讀取 USB Token。

    注意: 第一次拿到 USB Token 時,你需要先將 USB 進行初始化的操作,每個 USB Token 只需要設定一遍!

  2. 接著,取得 GlobalSign 的 EV Code Signing 憑證

    因為 GlobalSign 的 EV Code Signing 憑證是透過 USB Token 來進行簽章的,你不能將憑證的金鑰匯出,所以你每次要進行簽章時,都需要將 USB Token 插在電腦上。然而,你必須先安裝好 Safenet Drivers 驅動程式,然後 USB 要插在電腦上,讓你的電腦可以讀取 USB Token 的資訊,並執行以下 PowerShell 命令:

    $cert = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert |
    Where-Object { $_.Thumbprint -like "*28A7F86E813C879989426E401947473D7FDB911E*" } |
    Select-Object -First 1
    
  3. 簽署指定 PowerShell 腳本檔案

    Set-AuthenticodeSignature -FilePath "$HOME\Documents\PowerShell\Scripts\ghcs.ps1" -Certificate $cert -TimestampServer "http://timestamp.globalsign.com/tsa/r6advanced1"
    

    簽署完畢後,會在檔案最下方出現一大堆像亂碼的簽章內容,這表示你的 PowerShell 腳本已經被數位簽章了。

  4. 驗證簽章是否有效

    Get-AuthenticodeSignature "$HOME\Documents\PowerShell\Scripts\ghcs.ps1"
    

如此一來,我們的 PowerShell 腳本就已經被數位簽章了,這樣就可以讓其他人在下載執行時,就可以用來確認你這個腳本是由你所簽署的,並且沒有被竄改過。

相關連結

留言評論