PowerShell 模組的公司內部分發與更新 ── PSResourceGet 與內部儲存庫

· · PowerShell, 模組, 分發, 版本管理, 維運改善, 可維護性, 資訊系統, 自動化

「寫了個方便的腳本,就放到共用資料夾裡了」── 從那一刻起,維護債務就開始悄悄地累積。有人複製後在本機改造,原始檔案修好了也不會反映到那份複製上,沒有人掌握到底哪個版本正在哪裡運作。幾年後,共用資料夾裡就會並排著 彙總.ps1彙總_v2.ps1彙總_修正版_最新.ps1

這個問題的答案,在 PowerShell 的世界裡是明確的。做成模組、加上版本,再從儲存庫分發。光是這樣,就能回答「裝的是哪一版」「更新後是否會送達所有人」這兩個問題。而 PowerShell 7.4 之後,用來做這件事的機制(PSResourceGet)從一開始就內建其中。

本文將以不建置專用伺服器的務實架構,說明如何把公司內部共用的腳本模組化,並建立內部儲存庫來分發與更新。至於函式的模組化本身,建議先閱讀「PowerShell 腳本的參數設計與模組化」,會比較容易理解。

適用讀者・前提環境

項目 內容
適用讀者 目前把 .ps1 放在共用資料夾裡分發的資訊系統・維運負責人
適用版本 Windows PowerShell 5.1 與 PowerShell 7.x 兩者皆適用。不過 PSResourceGet 是從PowerShell 7.4 以後才內建,在 5.1 上,分發端與使用端都需要事先安裝(第 5 章)1
與既有環境並存 PSResourceGet 可以和傳統的 PowerShellGet 2.2.5 並存,不需要改寫既有腳本就能導入1
範例的驗證環境 文章末尾分發的範例程式碼是在 PowerShell 7.6 上執行驗證的
所需權限 建立與設定儲存庫用共用資料夾、以及以 -Scope AllUsers 安裝,都需要管理員權限

1. 先講結論

  • PSResourceGet(Microsoft.PowerShell.PSResourceGet)從 PowerShell 7.4 起就已內建。由於它與傳統的 PowerShellGet 2.2.5 並存,因此可以在不破壞既有腳本的情況下使用。Windows PowerShell 5.1 並未內建它,因此使用端與分發端都需要事先安裝(下一章)。1
  • 內部儲存庫可以用檔案共用來起步。只需在 Register-PSResourceRepository 中指定 UNC 路徑即可。不需要專用伺服器。2
  • 請把資訊清單(.psd1)視為必要。沒有版本編號,就無法更新,也無法排查問題。3
  • FunctionsToExport 不要用萬用字元,改用陣列明確列出。這樣能加快命令探索速度,也能防止內部函式被意外公開。3
  • 版本請採用語意化版本(Semantic Versioning)。若無法用主要版本號來表達破壞性變更,使用端就無法放心更新。4
  • 公開用 Publish-PSResource,取得用 Install-PSResource,更新用 Update-PSResource56
  • 模組的探索路徑在 5.1 與 7 之間並不相同。若不理解 $env:PSModulePath 的差異,就會發生「明明裝了卻找不到」的情況。7
  • 若執行原則為 AllSigned,就必須對每個腳本檔案進行 Authenticode 簽章。目錄簽章是用於驗證套件的完整性,並不能滿足執行原則的要求。8
  • 無人執行所依賴的模組,其自動更新請謹慎處理。先驗證再有計畫地升級,運作上比較安全。

本文要建立的機制,整體會呈現如下的形式。

Publish-PSResourceInstall-PSResourceInstall-PSResource -Scope AllUsers開發端資訊系統負責人撰寫模組測試與靜態分析Pester / PSScriptAnalyzer內部儲存庫檔案共用-UNC 路徑,或NuGet 相容 feed使用端 PCFind / Install / Update-PSResource使用端伺服器夜間批次等無人執行

圖中箭頭上的命令,就是本文處理的核心。儲存庫只需要分發端與使用端各自在一開始用 Register-PSResourceRepository 登錄一次(第 5 章),之後只靠公開、取得、更新這幾個命令就能運轉(第 6 章)。只有分發負責人擁有寫入權限,這是這張圖裡唯一的安全邊界。

2. 「共用資料夾裡的 ps1」所帶來的問題

首先,先釐清我們打算解決的是什麼問題。

症狀 根本原因
不知道現在運作的是哪一版 沒有版本編號這個概念
修好了也不會反映到所有人身上 每個人各自持有一份複製
不知道誰在使用 沒有取得的紀錄留下來(※如後述,唯獨這一點需要看分發方式的選擇)
只有部分環境會出問題 相依關係(所需模組・PS 版本)沒有宣告
想修但看不出影響範圍 沒有區分公開的函式與內部函式

模組化與儲存庫分發,對其中上面 4 項有直接的效果。不過唯獨「誰在使用」這一點,要看分發機制而定。下一章開始要介紹的檔案共用儲存庫雖然簡便,但不會留下誰在何時取得的紀錄(Get-InstalledPSResource 能得知的,只有執行該命令那台端點的狀態)。若想掌握使用狀況,請並用以下其中一種做法。

3. 模組的最小構成

可分發模組的最小形式,是資料夾、.psm1.psd1 這三項。

KsOps\
  KsOps.psd1     ← 資訊清單(版本・公開函式・相依關係)
  KsOps.psm1     ← 實作(或是從 Public/Private 資料夾以點來源載入)
  Public\
    Get-KsShareUsage.ps1
    Invoke-KsArchive.ps1
  Private\
    ConvertTo-KsSize.ps1

資訊清單可以用 New-ModuleManifest 建立雛形,再填入必要的項目。3

$manifest = @{
    Path              = '.\KsOps\KsOps.psd1'
    RootModule        = 'KsOps.psm1'
    ModuleVersion     = '1.0.0'
    GUID              = [guid]::NewGuid().Guid
    Author            = '資訊系統部'
    CompanyName       = '範例股份有限公司'
    Description       = '公司內部維運腳本共用模組(檔案伺服器盤點・封存)'
    PowerShellVersion = '5.1'
    CompatiblePSEditions = @('Desktop', 'Core')      # 用於同時給 5.1 與 7 使用的情況
    # 不要用萬用字元。只明確列出打算公開的內容
    FunctionsToExport = @('Get-KsShareUsage', 'Invoke-KsArchive')
    CmdletsToExport   = @()
    VariablesToExport = @()
    AliasesToExport   = @()
    RequiredModules   = @()                          # 若有相依項目,在此宣告
    Tags              = @('internal', 'operations')
    ProjectUri        = 'https://git.example.co.jp/it/ksops'
}
New-ModuleManifest @manifest

.psm1 可以用固定寫法來撰寫,讀入 Public/Private 的腳本後只匯出公開函式。

# KsOps.psm1
$public  = @(Get-ChildItem -Path "$PSScriptRoot\Public\*.ps1"  -ErrorAction SilentlyContinue)
$private = @(Get-ChildItem -Path "$PSScriptRoot\Private\*.ps1" -ErrorAction SilentlyContinue)

foreach ($file in @($public + $private)) {
    try   { . $file.FullName }
    catch { throw "模組載入失敗: $($file.FullName) ── $_" }
}

# 公開的只有 Public 目錄下的函式(要與資訊清單的宣告一致)
Export-ModuleMember -Function $public.BaseName

不把 FunctionsToExport 設為萬用字元的理由有兩個。一個是命令探索的效能,明確列出後,就能不解析模組本體,直接判斷「哪個命令位在哪裡」。另一個是設計上的理由,若內部輔助函式能從外部呼叫,它就會實質上變成公開 API,之後就無法再變更。3

上面的範例中,CompatiblePSEditions 同時宣告了 Desktop(Windows PowerShell 5.1)與 Core(PowerShell 7),但光是宣告,並不代表兩邊都真的能動。在 5.1 上要使用 PSResourceGet 本身所需的準備,整理在第 5 章;因 5.1 與 7 的模組探索路徑不同而發生的「明明裝了卻找不到」,則整理在第 7 章。若打算做雙版本相容的分發,請先讀過這兩章。

4. 版本編號的決定方式

使用端能否放心更新,取決於版本編號的訂定方式。請採用語意化版本(主要.次要.修訂),並務必用主要版本號表達破壞性變更4

變更內容 要提升的部分
變更參數名稱、刪除函式、變更回傳值的形式 主要版本(1.2.3 → 2.0.0)
新增函式或參數(既有的維持照常運作) 次要版本(1.2.3 → 1.3.0)
僅修復問題 修訂版本(1.2.3 → 1.2.4)

想要分發驗證用的版本時,可以使用預發布版(prerelease)。在資訊清單的 PrivateData.PSData.Prerelease 設定像 beta1 這樣的字串(與版本之間的連字號會自動加上,成為 1.3.0-beta1),一般的取得不會抓到它,只有明確指定 -Prerelease 時才會安裝。字串只能使用 ASCII 英數字與連字號,不能使用句點或 +4

關於破壞性變更的處理方式,介面設計的思路可以作為參考(參見「DLL・COM 介面的向後相容性」)。

5. 建立內部儲存庫 ── 用檔案共用就夠了

PSResourceGet 可以把檔案共用上的資料夾當成儲存庫來處理2 這是導入成本最低的架構。

首先確認前提。PowerShell 7.4 以後版本已內建,但 Windows PowerShell 5.1 並未內建。要在 5.1 上使用接下來的命令(Register-PSResourceRepository 等),請先安裝好模組。1

# 【僅限 Windows PowerShell 5.1】安裝 PSResourceGet。
# 5.1與7載入的模組路徑不同,請在實際使用的版式(edition)上執行
if (-not (Get-Module -ListAvailable -Name Microsoft.PowerShell.PSResourceGet)) {
    Install-Module -Name Microsoft.PowerShell.PSResourceGet -Scope AllUsers -Force
}
# 【分發端・使用端都只需執行一次】註冊內部儲存庫
# Trusted: 因為是公司內部分發物,視為信任 / Priority: 優先於 PSGallery 進行搜尋
$repo = @{
    Name     = 'KsInternal'
    Uri      = '\\fileserver\PSRepository'
    Trusted  = $true
    Priority = 10
}
Register-PSResourceRepository @repo

Get-PSResourceRepository | Format-Table Name, Uri, Trusted, Priority

共用資料夾的存取權限,請設為「只有分發負責人能寫入,使用者僅能讀取」。這裡若設得太寬鬆,就會變成任何人都能對全公司分發任意程式碼的途徑。共用存取權限與 NTFS 存取權限請兩者都設定(有效權限會取兩者中較嚴格的一方)。9

# 在檔案伺服器端執行(需要管理員權限)
$path = 'D:\PSRepository'
$null = New-Item -Path $path -ItemType Directory -Force

# 共用: 使用者僅能讀取,只有分發負責人能寫入
New-SmbShare -Name 'PSRepository' -Path $path `
    -ReadAccess 'EXAMPLE\Domain Users' -ChangeAccess 'EXAMPLE\模組分發負責人'

# NTFS: 不是「用加的」,而是「用許可清單整個換掉」。
# New-Item -Force 即使資料夾已存在也會成功,所以如果這個資料夾以前
# 曾以其他共用方式公開過、或曾暫時給過某人變更權限,只靠加上
# icacls /grant,那條寫入途徑就會殘留下來。由於這是所有端點都以 Trusted
# 方式註冊的儲存庫,殘留下來的那個人就能對全公司分發程式碼
$acl = Get-Acl -Path $path
$acl.SetAccessRuleProtection($true, $false)          # 切斷繼承,且不繼承既有的繼承ACE
foreach ($ace in @($acl.Access)) {                   # 也把直接授予的ACE移除
    [void]$acl.RemoveAccessRuleSpecific($ace)
}

# 只保留這裡列出的主體
$allow = @(
    @{ Id = 'EXAMPLE\模組分發負責人'; Rights = 'Modify' }              # 可以公開
    @{ Id = 'EXAMPLE\Domain Users';       Rights = 'ReadAndExecute' } # 僅能取得
    @{ Id = 'BUILTIN\Administrators';     Rights = 'FullControl' }
    @{ Id = 'NT AUTHORITY\SYSTEM';        Rights = 'FullControl' }
)
foreach ($a in $allow) {
    $acl.AddAccessRule([System.Security.AccessControl.FileSystemAccessRule]::new(
        $a.Id, $a.Rights, 'ContainerInherit, ObjectInherit', 'None', 'Allow'))
}
# 若把「清空」和「重新加入」分成兩次 Set-Acl,中間會出現誰都碰不到的瞬間。
# 要一次套用完成
Set-Acl -Path $path -AclObject $acl

icacls $path        # 確認設定結果。用肉眼檢查是否有非預期的主體列在其中

請不要只靠加上 icacls /grant 就了事。/grant 不會刪除既有的 ACE。就算還有其他人擁有可以寫入這個資料夾的途徑,也會原封不動地留下來。9 而且,這個儲存庫是以全端點都用 Trusted = $true 註冊為前提。放在信任儲存庫裡的模組,會在不經確認的情況下就被安裝。只要還殘留一個人,他就能對全公司的 PowerShell 執行環境分發任意程式碼,「只有分發負責人才能公開」這個前提,在那一刻就會崩潰。

光是切斷繼承(SetAccessRuleProtection($true, $false))也不夠。這個方法能處理的只有繼承 ACE,直接授予這個資料夾的 ACE 並不在範圍內9 因此要像上面那樣,先把直接授予的部分也移除,再重新加入許可清單中的主體。若是新建立的資料夾,結果雖然相同,但這是一種只有沿用既有資料夾時才會出問題的類型,所以把這個步驟寫進流程裡會比較保險。

「分發負責人」請設定為群組,而不是個人帳號。負責人異動導致模組無法更新的停擺情況,實際上會發生。若使用需要驗證的 NuGet 相容 feed,請發行僅具讀取權限的憑證給使用端,並與公開用的憑證(API 金鑰)分開。共用資料夾的權限設計本身,也可以參考「用 PowerShell 盤點檔案伺服器」。

若想更正式地運作,可以註冊 Azure Artifacts、GitHub Packages 這類 NuGet 相容 feed。需要驗證的儲存庫,可以設計成從 SecretManagement 的保管庫參照憑證(參見「PowerShell 中安全處理憑證的方法」)。2

6. 公開・取得・更新

# 【分發端】公開模組
Publish-PSResource -Path .\KsOps -Repository 'KsInternal'

# 【使用端】搜尋並安裝
Find-PSResource -Name 'KsOps' -Repository 'KsInternal'
Install-PSResource -Name 'KsOps' -Repository 'KsInternal' -Scope CurrentUser

# 固定版本後安裝(正式環境的伺服器建議這樣做)
Install-PSResource -Name 'KsOps' -Version '1.2.3' -Repository 'KsInternal' -Scope AllUsers

# 更新
Update-PSResource -Name 'KsOps' -Repository 'KsInternal'

# 確認裝了什麼(僅代表「這台端點」的狀態)
Get-InstalledPSResource -Name 'KsOps' | Format-Table Name, Version, Repository, InstalledDate

# 若想了解全公司的導入狀況,可以在各端點執行後彙整
Invoke-Command -ComputerName $servers -ScriptBlock {
    Get-InstalledPSResource -Name 'KsOps' -ErrorAction SilentlyContinue |
        Select-Object Name, Version
} | Sort-Object PSComputerName

-Scope 的區分使用很重要。工作排程器無人執行時所用的模組,必須裝在 AllUsers(或服務帳戶自身的環境)中。「明明在自己的環境能動,只有夜間批次以『無法辨識 Cmdlet』失敗」,其典型原因就是安裝在了 CurrentUser 範圍。67

另外,-Scope AllUsers 會寫入所有使用者共用的位置(Program Files 之下),因此若不是以系統管理員身分啟動的 PowerShell 就會失敗7 若第一次安裝時出現「存取被拒」,請先確認是否已提升權限。

7. 模組的探索路徑與 5.1/7 的差異

PowerShell 會從 $env:PSModulePath 中列舉的資料夾裡尋找模組。Windows PowerShell 5.1 與 PowerShell 7 的預設路徑並不相同7

版式(Edition) 使用者範圍的預設路徑
Windows PowerShell 5.1 %USERPROFILE%\Documents\WindowsPowerShell\Modules
PowerShell 7 %USERPROFILE%\Documents\PowerShell\Modules

要在兩邊都使用的模組,請在 CompatiblePSEditions 中同時宣告 DesktopCore,並在兩種環境都測試過後再分發。相容性驗證上,PSScriptAnalyzer 的 PSUseCompatibleSyntax 很有幫助(參見「用 PSScriptAnalyzer 守護 PowerShell 腳本品質」)。

發生問題時,請確認以下這 3 點。

$env:PSModulePath -split ';'                       # 探索路徑
Get-Module -Name KsOps -ListAvailable              # 是否找得到・是哪一版
(Get-Module KsOps -ListAvailable).ModuleBase       # 實際被讀取的位置

8. 簽章與執行原則

簽章有兩種目的不同的機制,若混淆兩者,就會發生「明明簽了章卻無法執行」的情況。8

機制 保障的內容 是否滿足執行原則 AllSigned
Authenticode 簽章(Set-AuthenticodeSignature) 個別腳本檔案的發行者與完整性 滿足(每個檔案都需要簽章)
目錄簽章(New-FileCatalog + 簽章) 整組模組(套件)的完整性 不滿足

執行原則驗證的,是打算載入的 .ps1 / .psm1 本身的 Authenticode 簽章。即使對目錄檔案(.cat)簽了章,裡面的腳本檔案依然是未簽章狀態,因此在 AllSigned 環境下,執行仍會被封鎖。因此,若正在運作 AllSigned,就必須對每個實際會被執行的檔案簽章

# (1) AllSigned環境下必須: 對每個實際會被執行的檔案進行 Authenticode 簽章
Get-ChildItem .\KsOps -Recurse -Include *.ps1, *.psm1, *.psd1 | ForEach-Object {
    Set-AuthenticodeSignature -FilePath $_.FullName -Certificate $cert `
        -TimestampServer 'http://timestamp.digicert.com'
}

# (2) 另外,併用目錄來偵測整個套件是否遭到竄改
New-FileCatalog -Path .\KsOps -CatalogFilePath .\KsOps\KsOps.cat -CatalogVersion 2
Set-AuthenticodeSignature -FilePath .\KsOps\KsOps.cat -Certificate $cert `
    -TimestampServer 'http://timestamp.digicert.com'

# 使用端的驗證(與執行原則無關,用來確認分發物是否完好)
Test-FileCatalog -Path .\KsOps -CatalogFilePath .\KsOps\KsOps.cat -Detailed

目錄的價值在於能確認「取得的整組模組是否與分發時相同」,PSResourceGet 端也有用來驗證簽章與目錄的 -AuthenticodeCheck6 請把角色分開理解:能否執行看 Authenticode 簽章,分發物的完整性看目錄

附加時間戳記後,即使簽章憑證的有效期限過了,簽章仍然會維持有效。執行原則與簽章運作的整體概觀,整理在「PowerShell 的執行原則與腳本簽章」。

9. 應當事先決定好的運作規則

比起技術,運作面更重要。請至少決定以下事項。

  • 誰能公開。擁有共用資料夾寫入權限的人=能對全公司分發程式碼的人
  • 變更歷程要寫在哪裡。ReleaseNotes(資訊清單的 PrivateData.PSData)或 CHANGELOG 中,明確記載破壞性變更
  • 正式環境的伺服器是否固定版本。無人執行所依賴的模組,固定版本並有計畫地更新會比較安全
  • 廢止的程序。要刪除函式時,請提升主要版本號,並事先公告廢止(deprecated)
  • 通過測試與 lint 後再公開。理想上公開作業應由 CI 執行(參見「用 Pester 整備 PowerShell 測試」)

10. 實務的定石(判斷表)

論點 選項 判斷依據
分發形式 共用資料夾的 .ps1 / 模組 + 儲存庫 能否管理版本與更新,是分歧點
模組管理 PowerShellGet 2.x / PSResourceGet 7.4 以後已內建。新專案用 PSResourceGet1
儲存庫 檔案共用 / NuGet 相容 feed 先從檔案共用開始。若需要驗證・稽核則改用 feed2
資訊清單 省略 / 必須 沒有版本,運作就無法成立3
公開函式 '*' / 用陣列明示 為了探索效能,以及讓內部函式不被公開3
安裝位置 CurrentUser / 無人執行用 AllUsers 基準在於服務帳戶是否看得到7
正式環境的更新 自動更新 / 固定版本 + 計畫性更新 防止夜間批次擅自改用新版本運作
簽章 無 / 每個檔案的 Authenticode 簽章(+目錄) AllSigned 環境下,逐檔案的簽章是必要條件。目錄用於完整性驗證8

11. 總結

  • 共用資料夾的 .ps1 分發,會讓版本、更新、相依關係、公開範圍全部變得無法管理。模組化與儲存庫分發可以解決這個問題。不過唯獨「誰在使用」是另一回事。由於檔案共用儲存庫不會留下取得的紀錄,請並用共用資料夾的讀取稽核、能取得下載統計的 feed,或是在各端點彙整 Get-InstalledPSResource 這幾種方式的其中之一。
  • 資訊清單是必要的。FunctionsToExport 請用陣列明確列出,不要公開內部函式。
  • 內部儲存庫只需要用 UNC 路徑註冊檔案共用即可起步。寫入權限的管理,是實質上的安全邊界。
  • 公開用 Publish-PSResource,取得用 Install-PSResource,更新用 Update-PSResource。無人執行所使用的模組,請裝在 AllUsers 範圍中。
  • 5.1 與 7 的探索路徑並不相同。若要做雙版本相容,請宣告 CompatiblePSEditions,並在兩邊都測試過。
  • AllSigned 環境下,每個腳本檔案都需要 Authenticode 簽章。目錄簽章是用於驗證分發物的完整性,與能否執行是兩回事。請務必附加時間戳記。

範例程式碼下載

本文所處理的程式碼,已整理成可以直接執行的形式提供下載。內含區分公開/非公開的整組模組,以及分發到內部儲存庫的步驟。

下載範例程式碼(zip)

本文的範例,已實際在 PowerShell 7.6 上執行驗證(Pester 16 項)。只要執行 zip 中所附的 Invoke-SampleTests.ps1,您也能在自己手邊重現相同的驗證。

# 語法解析 + 靜態分析 + Pester 測試
./Invoke-SampleTests.ps1

設定值(路徑、伺服器名稱、租用戶 ID 等)僅為範例。請勿直接在正式環境中執行,請依自家環境對應調整後再使用。

相關文章

相關諮詢領域

合同會社小村軟體承接公司內部腳本資產的模組化與分發基礎建設整備、屬人化運作的標準化,以及既有腳本可維護性改善等業務。

參考連結

  1. Microsoft Learn, Package management for PowerShell。關於 Microsoft.PowerShell.PSResourceGet 是取代 PowerShellGet 及 PackageManagement 的模組、PowerShell 7.4 內建並與傳統的 PowerShellGet 2.2.5 並存,以及 Windows PowerShell 5.1 也能從 PowerShell Gallery 安裝的說明。  2 3 4 5

  2. Microsoft Learn, Register-PSResourceRepository。關於可以在 -Uri 中指定本機資料夾、檔案共用(UNC 路徑)或 NuGet 相容 feed 的 URL 來註冊儲存庫、透過 -Trusted 設定信任狀態、透過 -Priority 設定搜尋順序,以及需要驗證的儲存庫如何指定憑證的說明。  2 3 4

  3. Microsoft Learn, How to write a PowerShell module manifest。關於用 New-ModuleManifest 建立資訊清單、RootModule・ModuleVersion・GUID・PowerShellVersion・CompatiblePSEditions・RequiredModules 等各個鍵值,以及 FunctionsToExport 等匯出指定不應使用萬用字元、而應明確列出的理由(命令探索的效能)的說明。  2 3 4 5 6

  4. Microsoft Learn, Prerelease module versions。關於基於語意化版本的編號方式、透過 PrivateData.PSData.Prerelease 指定預發布版,以及預發布版不會成為預設取得對象的說明。  2 3

  5. Microsoft Learn, Publish-PSResource。關於將 -Path 指定的模組資料夾公開到儲存庫、透過 -Repository 指定公開目的地,以及透過 -ApiKey 進行驗證的說明。 

  6. Microsoft Learn, Install-PSResource。關於透過 -Name / -Version / -Repository 進行安裝、透過 -Scope(CurrentUser / AllUsers)指定安裝位置,以及透過 -TrustRepository 省略確認的說明。另外也一併說明透過 Update-PSResource 進行更新的方式。  2 3

  7. Microsoft Learn, about_PSModulePath。關於 PowerShell 會從 $env:PSModulePath 中列舉的資料夾搜尋模組,以及 Windows PowerShell 與 PowerShell 7 在使用者範圍・全使用者範圍的預設路徑並不相同的說明。  2 3 4 5

  8. Microsoft Learn, New-FileCatalog。關於可以產生包含資料夾下各檔案雜湊值的目錄檔案(.cat)、可以用 Set-AuthenticodeSignature 對目錄簽章,以及可以用 Test-FileCatalog 比對目錄與檔案群以偵測竄改的說明。至於執行原則所驗證的是執行對象腳本檔案本身的 Authenticode 簽章這一點,請參閱 about_Execution_Policies(AllSigned 下只能執行由受信任發行者簽署的腳本)以及 Set-AuthenticodeSignature(對檔案賦予 Authenticode 簽章、透過 -TimestampServer 附加時間戳記)。  2 3

  9. Microsoft Learn, New-SmbShare。關於可以透過 -FullAccess / -ChangeAccess / -ReadAccess,針對各帳號分別指定共用層級存取權限的說明。NTFS 端的存取權限設定,請參閱 icacls(透過 /grant 授予權限、RX=讀取與執行、M=變更、F=完全存取等權限遮罩、(OI)=物件繼承・(CI)=容器繼承的指定)。/grant 的行為是「在已授予的明確許可上追加」,加上 :r/grant:r 則會替換該主體的明確許可(其他主體的 ACE 無論哪種都會保留)。切斷繼承請參閱 ObjectSecurity.SetAccessRuleProtection(第一個引數用於保護繼承,第二個引數指定是否要引繼已繼承的 ACE)。這個方法能指定的只有繼承 ACE 的處理方式,直接授予該物件的 ACE 並不在範圍內。要移除直接授予的部分,需要用 ObjectSecurity.RemoveAccessRuleSpecific 等方法逐一移除。  2 3

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

常見問題

整理諮詢這個主題時常見的問題。

PowerShellGet 和 PSResourceGet 有什麼不同?該用哪一個?
PSResourceGet(Microsoft.PowerShell.PSResourceGet)是取代傳統 PowerShellGet 與 PackageManagement 的新一代模組管理機制,PowerShell 7.4 一開始就內建了它。由於它可以和傳統的 PowerShellGet 2.2.5 並存,因此可以在不破壞既有腳本的情況下進行遷移。若是新寫的程式碼,建議使用命令名稱屬於 -PSResource 系列(Install-PSResource、Publish-PSResource 等)的 PSResourceGet。Windows PowerShell 5.1 也可以透過從 PowerShell Gallery 安裝來使用。
要建立內部儲存庫,需要專用的伺服器嗎?
不需要。最簡單的方式,是把檔案共用上的資料夾註冊為儲存庫,只要在 Register-PSResourceRepository 中指定 UNC 路徑即可運作。不需要專用伺服器,也不需要資料庫。若組織上需要存取控制或稽核,或是需要從公司外部取得,則可以使用 Azure Artifacts、GitHub Packages 這類相容於 NuGet 的 feed。務實的做法是先從檔案共用開始,等有需要時再遷移。
模組資訊清單(.psd1)一定需要嗎?
實務上請視為必要。雖然只靠 .psm1 也能作為模組讀入,但沒有資訊清單就無法擁有版本編號,會變得無法得知「裝的是哪一版」。沒有版本,就無法管理更新,發生問題時也無法排查。此外,資訊清單還能明確指定要匯出的函式、宣告相依模組,以及指定對應的 PowerShell 版本與版式(edition)。可以用 New-ModuleManifest 建立雛形,建立成本也很低。
在 FunctionsToExport 中寫 '*' 會有什麼問題?
命令的自動探索會變慢,也會連不打算公開的內部函式都一併公開出去。PowerShell 在載入模組之前,需要知道哪個命令位在哪個模組中,若使用萬用字元,就必須解析模組本體才能得知。若用陣列明確列出要公開的函式,就不需要這道解析。另外,若內部用的輔助函式能從外部呼叫,它就會實質上變成公開 API,之後就無法再變更了。
已分發的模組,可以讓使用端自動更新嗎?
雖然可以用 Update-PSResource 更新,但業務腳本所依賴的模組,其自動更新請務必謹慎設計。因為這會導致無人值守執行的夜間批次,在不知不覺中改用新版本執行。實務上,先在驗證環境確認新版本,再有計畫地對正式環境進行更新,會比較安全。若無論如何都要自動化,請設下防線,例如固定主要版本再更新(像 -Version '1.*' 這樣指定範圍)。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽