前篇文章提到 VSSetup PowerShell Module,在一般連網環境用 Install-Module 可自動下載安裝:

但如果主機處在連不到網際網路的網段,Install-Module 指令會冒出如下錯誤:

這篇就來介紹如何在離線環境安裝 PowerShell。參考:Manual Package Download

首先,PowerShell Gallery 網站的模組頁面有個 Manual Download 頁籤:

按 【Download the raw nupkg file】可下載 .nupkg 檔。

.nupkg 檔是個 ZIP 檔,用解壓縮工具檢視可在其中看到 Module 檔案摻雜 \rels、package 資料夾及 [content_type].xml、.nuspec 等 NuGet 專屬內容。下一步是將 NuGet 專屬內容以外的 Module 檔案複製到 PowerShell 模組目錄下,由 .nupkg 檔名取出模組名稱及版號,建立【模組名稱\版號】的資料夾結構。PowerShell 模組目錄的所在位置可透過 $Env:PSModulePath 取得,C:\Users\username\Documents\WindowsPowerShell\Module無權限需求最方便但只對單一使用者有效,伺服器環境建議用管理者權限裝到 C:\Program Files\WindowsPowerShell\Modules

若一切無誤,就可以開始使用模組了。(註:手動安裝的模組無法用 Uninstall-Module 移除,要靠人工刪檔移除,就想成綠色軟體唄)

手工操作有點複雜又容易失誤,不符合我推動 PowerShell 以求標準化自動化的初衷,所以我試寫了以下腳本將解壓縮及複製檔案一氣喝成:

Param (
    [Parameter(Mandatory=$true)]
    [string] $nupkgName
)
$ErrorActionPreference = "STOP"
if (!(Test-Path $nupkgName -PathType Leaf)) {
    throw "$nupkgName not found"
}
Add-Type -AssemblyName System.IO.Compression.FileSystem
$pureNupkgFileName = [System.IO.Path]::GetFileNameWithoutExtension($nupkgName)
#取得版號
$ver = [System.Text.RegularExpressions.Regex]::Match($pureNupkgFileName, "\.(?<v>\d+\.\d+\.\d+)").Groups["v"].Value
#取得模組名稱
$modName = $pureNupkgFileName.Replace($ver, "").TrimEnd(".")
#決定安裝目錄
$instPath = ($Env:PSModulePath.Split(';') | Where-Object { $_ -match "Documents" } | Select-Object -First 1)
$instPath = "$instPath\$modName\$ver"
if (Test-Path $instPath) {
    throw "$instPath already exists"
}
[System.IO.Directory]::CreateDirectory($instPath) | Out-Null
Write-Host "Installing module [$modName]..." -ForegroundColor Yellow
#解壓到暫存目錄
$tempPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), (Get-Date -Format "yyyyMMddHHmmss"))
[System.IO.Compression.ZipFile]::ExtractToDirectory($nupkgName, $tempPath) | Out-Null
#排除NuGet內容,將其餘內容複製過去
Get-ChildItem -Path $tempPath | ForEach-Object {
    $name = $_.Name
    if ($name -eq "_rels" -or $name -eq "[content_type].xml" -or $name -eq "package" -or $name -match "\.nuspec") {
        return
    }
    Write-Host "Copy $($_.Name)..."
    if ($_.PSIsContainer) {
        Copy-Item $_.FullName "$instPath\" -Recurse
    }
    else {
        Copy-Item $_.FullName "$instPath\"
    }
}
Write-Host "Module $($modName) installed" -ForegroundColor Green

來個實測,成功! (灑花)

Tutorial of how to install PowerShell module in offine environment.


Comments

# by Ho.Chun

請問黑大,我去看了 C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules 發現有些資料夾的結構是【模組名稱\版號】 (ex. HostComputeService) 但又有些資料夾的結構是【模組名稱】(ex. IISAdministration) 使用 Get-Module -ListAvailable HostComputeService, IISAdministration 確定都查的到資料 想請問有哪些 module 必須使用版號當資料夾結構 ?

# by Ho.Chun

補充 我將 IISAdministration 的資料夾結構 從【模組名稱】改成【模組名稱\版號】 ex. IISAdministration => IISAdministration\1.0.0.0 此時 Get-Module -ListAvailable IISAdministration 就查無資料惹

# by Jerry.T

請問你的powershell腳本目前安裝在C:\%UserProfile%\Documents\,要如何將他改到其他路徑呢?

# by Jeffrey

to Jerry.T,好奇要把它改掉的理由?

Post a comment