有时在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”文件夹下的一个给定的软件包/版本,沿着它的任何依赖项。然而,它看起来像是下载了每个framework版本,没有明显的方法来告诉你在给定的环境下使用哪个版本。
否则,您可以循环遍历结果并调用Add-Type:
Get-ChildItem .\packages\ -Recurse -Filter "*.dll" | % {
try
{
Add-Type -Path $_.FullName
}
catch [System.Exception]
{
}
}
我试着用restore
命令和project.json
文件来控制框架版本,但没有成功,这对我来说太过笨拙了。
我将查看@crownedjitter关于使用PowerShell 5的建议。
更新
使用@crownedjitter的建议,我最终能够用NuGet注册PackageManagement模块(参见下面的注解)。使用下面的命令,我能够重现上面的Nuget.exe
命令所做的事情:
Install-Package Dapper -Destination packages
很明显,这要短得多。问题是它有同样的限制;它会关闭一个包的每个framework版本。如果这包括.NET core,它会关闭大量的.NET core framework!似乎没有一种方法可以指定一个目标framework(也就是.NET 4.5.1或更低版本)。
我想知道是否有一种方法可以根据PowerShell当前的$PSVersionTable.CLRVersion
字段确定从哪个NuGet包文件夹加载DLL。
2条答案
按热度按时间jgwigjjp1#
crownedjitter's helpful answer是一个很好的起点,Travis本人也在评论中提供了更多的提示,但让我尝试总结一下Windows PowerShell v5.1/PowerShell(核心)7.3.2:
Add-Type
的链接,但是它所展示的基于Install-Package
的方法最终福尔斯缺陷的,因为它**没有考虑到包的 * 依赖性 *,正如BACON所指出的:缺少的一个步骤(不那么简单)是加载任何可能已经安装的依赖项,因为the Dependencies property doesn't contain enough information,这似乎涉及到从Source目录的
.nupkg
文件中提取.nuspec
文件,阅读<group>
以获得适当的框架,并加载这些包的汇编。以下方法可解决此问题,但请注意,首先需要下载并安装.NET SDK及其
dotnet
CLI:Set-Location (New-Item -Type Directory assemblies)
dotnet new classlib
dotnet new classlib -f netstandard2.0
.csproj
并更新<TargetFramework>
元素;例如,为了以最新和最后版本4.8为目标,使用<TargetFramework>net48</TargetFramework>
;要将.NET 6.0与特定于Windows的API结合使用,请使用<TargetFramework>net6.0-windows</TargetFramework>
dotnet add package Dapper
-v <version>
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
子文件夹中创建辅助项目的脚本。注意事项:
dotnet publish
将其放置在发布文件夹的runtimes
子文件夹树中,位于特定于平台的子文件夹中,如runtimes\win-x64\native
。Add-Type -LiteralPath
(及其底层的.NET API方法[System.Reflection.Assembly]::LoadFrom()
)* 确实 * 找到了适合平台的本机库,但奇怪的是,它 * 不 * 在 PowerShell(Core)7.2.0-preview.9 中起作用-至少在Microsoft.Data.Sqlite
NuGet包的5.0.9版本中观察到了这一点。runtimes
子文件夹树中找到适合平台的本机库,然后将其 * 直接 * 复制到publish文件夹中。this answer中讨论的按需安装Add-NuGetType
helper函数自动化了这一过程。原始答案
PackageManagement
模块,它是一个 meta包管理器,通过 * 提供程序 * 提供对多个存储库的访问;这个模块的按需安装在v3和v4中 * 可能 * 是可能的(this download被标记为“March 2016 Preview”,这是我能找到的最新版本)。Find-PackageProvider
列出所有 * 可用 * 提供程序。Get-PackageProvider
列出 * 已安装 * 的。nuget
提供程序支持通过Install-Package
安装Nuget包,并且存在两个潜在障碍:nuget
提供程序。Find-Package
返回结果。测试是否安装了
nuget
提供程序:如果 * 已 * 安装:验证包源URI是否正确:
Get-PackageSource
:Nugettest
源代码,请将其删除:nuget.org
的Location
列显示https://api.nuget.org/v3/index.json
(或ttps://www.nuget.org/api/v2
以外的内容),请更新它:Set-PackageSource nuget.org -NewLocation https://www.nuget.org/api/v2 -Trusted
*警告:这可能会破坏在Visual Studio中浏览NuGet包的功能:参见https://github.com/PowerShell/PowerShellGet/issues/107
如果 * 未 * 安装:从头开始安装提供程序:
完成上述步骤后,NuGet软件包的发现(例如
Find-Package Dapper
)和安装(例如Install-Package Dapper
)应会成功。默认情况下,
Install-Package
安装在AllUsers
作用域中,这需要提升,但您可以选择仅使用-Scope CurrentUser
在当前用户的上下文中安装。*使用 * 下载的NuGet软件包:
注:请参阅GitHub issue #6724,它建议通过扩展
Add-Type
来简化在PowerShell中使用NuGet包,这将消除对所有后续步骤的需要,而这些步骤在PowerShell Core 7.3.2中仍然需要。Add-Type -Path <assembly-file-path>
将软件包的程序集手动加载到PowerShell会话中;但是,在.NET Core时代,软件包可能具有用于不同.NET环境的DLL,因此您不能总是盲目加载 * 软件包文件夹中的 * 所有 **.dll
文件:Get-Package
返回的相关对象的.Source
属性:Dapper
封装为例:2.0
:42fyovps2#
您是否正在使用Powershell 5?因为如果您正在使用,它有一个包管理模块:
它似乎是开源的:https://github.com/OneGet