![](/img/trans.png)
[英]Artifactory restore nuget packages with authentication from powershell
[英]Loading Assemblies from NuGet Packages
有時在我的 PowerShell 腳本中,我需要使用Add-Type -AssemblyName
訪問特定的 DLL。 但是,我需要的 DLL 並不總是在機器上或 GAC 中。 例如,我可能想要一個使用 Dapper 查詢數據庫的快速腳本。 在這些情況下,我一直在復制 DLL 和ps1
文件。 我想知道這是否常見/一個好主意,以及是否有一個現有的擴展可以加載 NuGet 包,然后將其存儲在全局或本地文件夾中並自動調用Add-Type -AssemblyName
。
這很像分別在 Node.js 或 Python 中使用npm
或pip
。
我做了一些研究,發現舊版本的 PowerShell 沒有內置任何內容。 我在嘗試使用nuget.exe
從頭開始編寫一個時取得了一些進展
&"$(Get-Location)/nuget.exe" install $packageName -Version $version -OutputDirectory "$(Get-Location)/packages" -NoCache -NoInteractive
這將下載當前文件夾中“packages”文件夾下的給定包/版本,以及它的任何依賴項。 但是,看起來它會下載每個框架版本,但沒有明顯的方法來告訴您在給定環境中使用哪個版本。
否則,您可以循環遍歷結果並調用 Add-Type:
Get-ChildItem .\packages\ -Recurse -Filter "*.dll" | % {
try
{
Add-Type -Path $_.FullName
}
catch [System.Exception]
{
}
}
我嘗試通過project.json
文件使用restore
命令來查看是否可以在沒有運氣的情況下控制框架版本。 這對我來說太hacky了。
我將查看@crownjitter 關於使用 PowerShell 5 的建議。
使用@crownjitter 的建議,我最終能夠使用 NuGet 注冊 PackageManagement 模塊(請參閱下面的評論)。 使用以下命令,我能夠重現上面的Nuget.exe
命令正在執行的操作:
Install-Package Dapper -Destination packages
顯然,這要短得多。 問題是它有同樣的限制; 它降低了包的每個框架版本。 如果這包括 .NET 核心,它會降低很多 .NET 核心框架! 似乎沒有辦法指定目標框架(也就是 .NET 4.5.1 或更低版本)。
我想知道是否有辦法根據 PowerShell 當前的$PSVersionTable.CLRVersion
字段確定從哪個 NuGet 包文件夾加載 DLL。
Crownedjitter 的有用答案是一個很好的起點,Travis 本人在評論中提供了額外的指示,但讓我嘗試從 Windows PowerShell v5.1 / PowerShell [Core] 7.1開始總結:
更新:下面的原始答案包含一些有用的一般指針,以及指向GitHub 上功能建議的鏈接,以將 NuGet 包與Add-Type
集成,但它顯示的基於Install-Package
的方法最終達不到要求,因為它沒有考慮包的依賴關系,正如BACON指出的那樣:
缺少的一個(非常重要的)步驟是加載任何可能已安裝的依賴項。 由於Dependencies 屬性不包含足夠的信息,似乎需要從 Source 目錄中的
.nupkg
文件中提取.nuspec
文件,讀取相應框架的<group>
並加載這些包的程序集。
以下方法可解決此問題,但請注意,它首先需要使用dotnet
CLI 下載和安裝.NET SDK :
為要添加包的輔助項目創建一個文件夾並更改為該文件夾; 例如:
Set-Location (New-Item -Type Directory assemblies)
在該文件夾中,創建一個虛擬庫項目:
dotnet new classlib
添加對感興趣的包的引用; 例如:
dotnet add package Dapper
要引用特定版本,請添加-v <version>
發布虛擬項目,它將所有需要的 DLL(包括依賴項)復制到發布文件夾中:
dotnet publish -c Release
-c
參數的確切大小寫(小寫與大寫)決定了相應輸出文件夾的確切大小寫; 為確保您的代碼也適用於區分大小寫的文件系統,尤其是在 Linux 上,請確保在引用輸出二進制文件的文件路徑中使用完全相同的大小寫。測試包的主程序集是否可以加載; 例如:
Add-Type -Path bin/Release/*/publish/Dapper.dll
驗證包的類型是否可以使用; 例如: [Dapper.DbString]::new()
現在,您可以直接從輔助項目中引用主 DLL,也可以將所有bin/Release/*/publish/*.dll
文件復制到您選擇的文件夾並從那里引用。
以下示例腳本顯示了一個腳本,該腳本根據需要下載Terminal.Gui包,並在相對於腳本位置的assemblies
集子文件夾中創建輔助項目。
$packageName = 'Terminal.Gui'
$assembly = "$packageName.dll"
# Set to @() to get the latest stable version.
$packageVersionArgs = '-v', '1.0.0-pre.4'
$projectFolder = 'assemblies' # Subfolder for the aux. project
$assemblyPath = "$PSScriptRoot/$projectFolder/bin/Release/*/publish/$assembly"
$literalAssemblyPath = Convert-Path -ErrorAction Ignore $assemblyPath
if ($literalAssemblyPath) {
Write-Verbose -vb "Package '$packageName' already installed. Loading main assembly: $literalAssemblyPath"
Add-Type -ErrorAction Stop -LiteralPath $literalAssemblyPath
}
else {
Write-Verbose -vb "Installing package '$packageName'..."
$null = Get-Command -ErrorAction Stop -CommandType Application dotnet
Push-Location (New-Item -ErrorAction Stop -Type Directory "$PSScriptRoot/$projectFolder")
$null = dotnet new classlib
$null = dotnet add package $packageName @packageVersionArgs
$null = dotnet publish -c Release
Pop-Location
Write-Verbose -vb "Loading main assembly: $assemblyPath"
Add-Type -ErrorAction Stop -Path $assemblyPath
}
# Instantiate a type from the package to verify that it was loaded.
"Listing property names of a [Terminal.Gui.Button] instance:"
[Terminal.Gui.Button]::new().psobject.Properties.Name
警告:
某些包依賴於本機庫, dotnet publish
這些庫放在發布文件夾的runtimes
子文件夾樹中,在特定於平台的子文件夾中,例如runtimes\\win-x64\\native
。
在Windows PowerShell中, Add-Type -LiteralPath
(及其底層的.NET API方法, [System.Reflection.Assembly]::LoadFrom()
並找到適合平台的本地庫,但是,奇怪的是,這是行不通的作為PowerShell (Core) 7.2.0-preview.9 - 至少在Microsoft.Data.Sqlite
NuGet 包的 5.0.9 版中觀察到。
解決方法是在runtimes
子文件夾樹中找到適合平台的本機庫,並將其直接復制到發布文件夾中。 本答案中討論的按需安裝Add-NuGetType
幫助程序功能可自動執行此過程。
如前所述,PowerShell v5+ - 包括 PowerShell Core - 帶有PackageManagement
模塊,它是一個元包管理器,通過提供者提供對多個存儲庫的訪問; 在 v3 和 v4 中可能可以按需安裝此模塊( 此下載標記為“2016 年 3 月預覽版”,這是我能找到的最新版本)。
Find-PackageProvider
列出所有可用的提供程序。Get-PackageProvider
列出已安裝的。 nuget
提供程序允許通過Install-Package
安裝 Nuget 包,但有兩個潛在的障礙:
可能未安裝nuget
提供程序。
它可能安裝了不正確的 API URL,從而阻止Find-Package
返回結果。
測試是否安裝了nuget
提供程序:
# If this fails, the provider isn't installed
Get-PackageProvider nuget
如果已安裝:驗證包源 URI 是否正確:
Get-PackageSource
:
Nugettest
源,請將其刪除:
Unregister-PackageSource Nugettest
nuget.org
的Location
列顯示https://api.nuget.org/v3/index.json
(或ttps://www.nuget.org/api/v2
以外的其他ttps://www.nuget.org/api/v2
),請更新它:Set-PackageSource nuget.org -NewLocation https://www.nuget.org/api/v2 -Trusted
如果未安裝:從頭開始安裝提供程序:
打開提升的PowerShell 會話。
運行以下命令:
Install-PackageProvider nuget Register-PackageSource -ProviderName nuget -name nuget.org -Location https://www.nuget.org/api/v2 -Trusted
完成上述步驟后,NuGet 包的發現(例如Find-Package Dapper
)和安裝(例如Install-Package Dapper
)應該會成功。
默認情況下, Install-Package
安裝在AllUsers
范圍內,這需要提升,但您可以選擇僅使用-Scope CurrentUser
在當前用戶的上下文中安裝。
使用下載的 NuGet 包:
注意:請參閱GitHub 上的此建議,通過擴展Add-Type
在 PowerShell 中更輕松地使用 NuGet 包,這將消除所有后續步驟的需要,從 PowerShell Core 6.2.0 開始仍然需要這些步驟。
如問題所示,您需要使用Add-Type -Path <assembly-file-path>
手動將包的程序集加載到 PowerShell 會話中; 但是,在.NET Core時代,包可能有針對不同.NET環境的DLL,所以你不能總是盲目地加載包文件夾中的所有*.dll
文件:
為了發現下載包的文件系統位置,查詢Get-Package
返回的相關對象的.Source
屬性:
(Get-Package Dapper).Source
要查看包內所有 DLL 的完整路徑,請運行以下命令:
(Get-ChildItem -Filter *.dll -Recurse (Split-Path (Get-Package Dapper).Source)).FullName
查看完整的 DLL 路徑應該會告訴您哪些 DLL 適合為您的環境加載; 使用Dapper
包的示例:
C:\\Program Files\\PackageManagement\\NuGet\\Packages\\Dapper.1.50.4\\lib\\net451\\Dapper.dll C:\\Program Files\\PackageManagement\\NuGet\\Packages\\Dapper.1.50.4\\lib\\netstandard1.3\\Dapper.dll C:\\Program Files\\PackageManagement\\NuGet\\Packages\\Dapper.1.50.4\\lib\\netstandard2.0\\Dapper.dll
但是,鑒於.NET Standard DLL 可在所有.NET 平台上運行,您可以通過編程方式查找(最新的)此類 DLL 並加載它們:
(Get-Item (Join-Path (Split-Path (Get-Package Dapper).Source) lib/netstandard*) | Sort-Object { [version] ($_.Name -replace '^netstandard') })[-1] | Get-ChildItem -Filter *.dll -Recurse | ForEach-Object { Add-Type -LiteralPath $_.FullName }
以上尋找最高可用的.NET Standard 版本 DLL; 如果你想針對特定版本,命令會變得更容易; 例如,對於 .NET Standard 2.0
:
Get-ChildItem -Recurse -Filter *.dll -LiteralPath (Join-Path (Split-Path (Get-Package Dapper).Source) lib/netstandard2.0) | ForEach-Object { Add-Type -LiteralPath $_.FullName }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.