![](/img/trans.png)
[英]Powershell: How do I install the Nuget provider for PowerShell on a unconnected machine so I can install a nuget package from the PS command line?
[英]How to install a nuget package such as it can be loaded from Powershell
我有使用 nuget 包 Vanara.PInvoke.Shell32 的 ac# 源。 正如預期的那樣,當我嘗試在 Powershell 中使用 Add-Type 使用此源時,但它在“使用 Vanara.Pinvoke”語句中窒息
我嘗試使用“Install-Package Vanara.PInvoke.Shell32”,但無法安裝
如何使這個模塊在 Powershell 核心中可用?
聽起來您已經下載了Vanara.PInvoke.Shell32
NuGet 包,並且知道包含感興趣的程序集的.dll
文件的完整路徑:
Install-Package
雖然原則上能夠下載 NuGet 包,但不會自動打包目標包所依賴的包); 該技術也用於下面的演示代碼。 使用PowerShell 代碼中的Vanara.PInvoke.*.dll
程序集- 通過使用Add-Type -LiteralPath
將它們加載到會話中,然后進行諸如[Vanara.PInvoke.User32]::GetForegroundWindow()
類的調用 -似乎無需額外的工作努力。
但是,您的用例需要使用臨時編譯的 C# 源代碼中傳遞給Add-Type
的-TypeDefinition
參數的程序集,並且正如您所發現的,這需要更多的努力,而不僅僅是將路徑傳遞給Vanara.PInvoke.*.dll
文件添加到-ReferencedAssemblies
參數中,至少從 PowerShell 7.1 開始:
令人費解的是,為了使以后的Add-Type -TypeDefinition
調用成功,NuGet 包中的程序集必須首先通過其完整路徑顯式加載到具有Add-Type -LiteralPath
的會話中 - 這聞起來像一個錯誤。
如果程序集是.NET 標准DLL,就像手頭的情況一樣,您還必須在調用Add-Type -TypeDefinition
-ReferencedAssemblies
將netstandard
程序集傳遞給 -ReferencedAssemblies。
例如,對於在兩個PowerShell 版本中運行的代碼,幫助程序 .NET SDK 項目(參見下面的代碼)應該以--framework netstandard2.0
為目標。
默認情況下,PowerShell 會話本身中默認可用的所有程序集(及其類型)也可以在傳遞給-TypeDefinition
的 C# 源代碼中引用:
-ReferencedAssemblies
的任何程序集都被添加到隱式可用類型。-ReferencedAssemblies
會排除通常隱式可用的程序集,因此必須顯式傳遞所有必需的程序集(例如, System.Console
以使用Console.WriteLine()
)。演示:
以下是一個獨立的、易於定制的示例,帶有詳細的注釋,可在Windows PowerShell和PowerShell (Core) 7+中使用,並執行以下操作:
*.dll
) 隨時可用。Add-Type -TypeDefinition
)。筆記:
必須安裝.NET SDK 。
忽略損壞的語法突出顯示。
$ErrorActionPreference = 'Stop'; Set-StrictMode -Off
# -- BEGIN: CUSTOMIZE THIS PART.
# Name of the NuGet package to download.
$pkgName = 'Vanara.PInvoke.Shell32'
# If the package assemblies are .NET Standard assemblies, the 'netstandard'
# assembly must also be referenced - comment out this statement if not needed.
# Note: .NET Standards are versioned, but seemingly just specifying 'netstandard'
# is enough, in both PowerShell editions. If needed, specify the fully qualified,
# version-appropriate assembly name explicitly; e.g., for .NET Standard 2.0:
# 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
# In *PowerShell (Core) 7+* only, a shortened version such as 'netstandard, Version=2.0' works too.
$netStandardAssemblyName = 'netstandard'
# The target .NET framework to compile the helper .NET SDK project for.
# Targeting a .NET Standard makes the code work in both .NET Framework and .NET (Core).
# If you uncomment this statement, the SDK's default is used, which is 'net5.0' as of this writing.
$targetFrameworkArgs = '--framework', 'netstandard2.0'
# Test command that uses the package from PowerShell.
$testCmdFromPs = { [Vanara.PInvoke.User32]::GetForegroundWindow().DangerousGetHandle() }
# C# source that uses the package, to be compiled ad-hoc.
# Note: Modify only the designated locations.
$csharpSourceCode = @'
using System;
// == Specify your `using`'s here.
using Vanara.PInvoke;
namespace demo {
public static class Foo {
// == Modify only this method; make sure it returns something, ideally the same thing as
// PowerShell test command.
public static IntPtr Bar() {
return User32.GetForegroundWindow().DangerousGetHandle();
}
}
}
'@
# -- END of customized part.
# Make sure the .NET SDK is installed.
$null = Get-command dotnet
# Helper function for invoking external programs.
function iu { $exe, $exeArgs = $args; & $exe $exeArgs; if ($LASTEXITCODE) { Throw "'$args' failed with exit code $LASTEXIDCODE." } }
# Create a 'NuGetFromPowerShellDemo' subdirectory in the TEMP directory and change to it.
Push-Location ($tmpDir = New-Item -Force -Type Directory ([IO.Path]::GetTempPath() + "/NuGetFromPowerShellDemo"))
try {
# Create an aux. class-lib project that downloads the NuGet package of interest.
if (Test-Path "bin\release\*\publish\$pkgName.dll") {
Write-Verbose -vb "Reusing previously created aux. .NET SDK project for package '$pkgName'"
}
else {
Write-Verbose -vb "Creating aux. .NET SDK project to download and unpack NuGet package '$pkgName'..."
iu dotnet new classlib --force @targetFrameworkArgs >$null
iu dotnet add package $pkgName >$null
iu dotnet publish -c release >$null
}
# Determine the full paths of all the assemblies that were published (excluding the helper-project assembly).
[array] $pkgAssemblyPaths = (Get-ChildItem bin\release\*\publish\*.dll -Exclude "$(Split-Path -Leaf $PWD).dll").FullName
# Load the package assemblies into the session.
# !! THIS IS NECESSARY EVEN IF YOU ONLY WANT TO REFERENCE THE PACKAGE
# !! ALL YOU WANT DO TO IS TO USE THE PACKAGE TO AD HOC-COMPILE C# SOURCE CODE.
# Write-Verbose -vb "Loading assembly file paths, from $($pkgAssemblyPaths[0] | Split-Path):`n$(($pkgAssemblyPaths | Split-Path -Leaf) -join "`n")"
Add-Type -LiteralPath $pkgAssemblyPaths
# Write-Verbose -vb 'Performing a test call FROM POWERSHELL...'
& $testCmdFromPs
# Determine the assemblies to pass to Add-Type -ReferencedAssemblies.
# The NuGet package's assemblies.
$requiredAssemblies = $pkgAssemblyPaths
# Additionally, the approriate .NET Standard assembly may need to be referenced.
if ($netStandardAssemblyName) { $requiredAssemblies += $netStandardAssemblyName }
# Note: In *PowerShell (Core) 7+*, using -ReferencedAssemblies implicitly
# excludes the assemblies that are otherwise available by default, so you
# may have to specify additional assemblies, such as 'System.Console'.
# Caveat: In .NET (Core), types are often forwarded to other assemblies,
# in which case you must use the forwarded-to assembly; e.g.
# 'System.Drawing.Primitives' rather than just 'System.Drawing' in
# order to use type System.Drawing.Point.
# What mitigates the problem is that failing to do so results in a
# an error message that mentions the required, forwarded-to assembly.
# E.g.:
# if ($IsCoreCLR) { $requiredAssemblies += 'System.Console' }
Write-Verbose -vb 'Ad-hoc compiling C# CODE that uses the package assemblies...'
Add-Type -ReferencedAssemblies $requiredAssemblies -TypeDefinition $csharpSourceCode
Write-Verbose -vb 'Performing a test call FROM AD HOC-COMPILED C# CODE...'
[demo.Foo]::Bar()
}
finally {
Pop-Location
Write-Verbose -vb "To clean up the temp. dir, exit this session and run the following in a new session:`n`n Remove-Item -LiteralPath '$tmpDir' -Recurse -Force"
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.