I'm running into the following error while trying to use System.Collections.Immutable reference package in PowerShell binary module.
Import-Module : Could not load file or assembly 'System.Collections.Immutable, Version=1.2.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
At line:1 char:1
+ Import-Module ./CmdletPacking.psd1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Import-Module], FileLoadException
+ FullyQualifiedErrorId : FormatXmlUpdateException,Microsoft.PowerShell.Commands.ImportModuleCommand
csproj contents:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>SampleCmdlet</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0-preview-06" />
<PackageReference Include="System.Collections.Immutable" Version="1.6.0"/>
</ItemGroup>
</Project>
psd1 file contents:
@{
# Script module or binary module file associated with this manifest.
RootModule = 'bin/CmdletPacking.dll'
RequiredAssemblies = 'bin/System.Collections.Immutable.dl'
}
bin contents:
CmdletPacking.deps.json CmdletPacking.pdb System.Collections.Immutable.dll System.Memory.dll System.Runtime.CompilerServices.Unsafe.dll
CmdletPacking.dll System.Buffers.dll System.Management.Automation.dll System.Numerics.Vectors.dll
Name Value
---- -----
PSVersion 6.2.4
PSEdition Core
GitCommitId 6.2.4
OS Darwin 18.7.0 Darwin Kernel Version 18.7.0: Tue Aug 20 16:57:14 PDT 2019; root:xnu-4903.271.2~2/RELEASE_X86_64
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
This happens with System.Collections.Immutable version > = 1.6.0.
It's likely that PowerShell can't load System.Collections.Immutable.dll because it already has that assembly loaded. You should see it in $PSHOME. Let us know what the output of the following is:
gci $PSHOME | ? { $_.Name -eq 'System.Collections.Immutable.dll' } | % { [System.Reflection.Assembly]::LoadFile($_.FullName).GetName() }
You won't be able to load your version and PowerShell's version at the same time, and since PowerShell uses its version very early on, it's always going to win. The best solution is probably to pin your version to the lowest version used by any of the PowerShell versions you want to support.
Also, if you're putting together a binary module (i.e. using the DLL dependency from C#/.NET rather than from PowerShell script), you probably don't want RequiredAssemblies but instead should put your DLL next to the RootModule and let PowerShell's assembly resolve event handler do the dependency resolution for you.
Finally, since in this case the DLL is present in PowerShell, you probably don't want to include it in your module at all. When you build your module, try just omitting it.
I'm actually about to publish a blog post relevant to this.
A few extra points:
$error[0] | fl * -force, in PS 7 it's as simple as Get-Error.@rjmholt thanks for the response. Yes, you're correct. Seems like PS has installed a version of System.Immutable.Collections.
gci $PSHOME | ? { $_.Name -eq 'System.Collections.Immutable.dll' } | % { [System.Reflection.Assembly]::LoadFile($_.FullName).GetName() }
Version Name
------- ----
1.2.3.0 System.Collections.Immutable
By removing the Required assemblies, I was able to import the module. However, when I try to execute the cmdlet the execution fails with the same error.
Cmdlet Code:
[Cmdlet(VerbsDiagnostic.Test,"SampleCmdlet")]
[OutputType(typeof(FavoriteStuff))]
public class TestSampleCmdletCommand : PSCmdlet
{
[Parameter(
Mandatory = true,
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
public int FavoriteNumber { get; set; }
public static readonly ImmutableList<string> BODY_HEADERS = new string[] { "string1", "string2" }.ToImmutableList();
....
Cmdlet invocation:
Import-Module ./CmdletPacking.psd1
Test-SampleCmdlet -FavoriteNumber 22 -Verbose
VERBOSE: Beginsss!
Test-SampleCmdlet : Could not load file or assembly 'System.Collections.Immutable, Version=1.2.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Could not find or load a specific file. (Exception from HRESULT: 0x80131621)
At line:1 char:1
+ Test-SampleCmdlet -FavoriteNumber 22 -Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Test-SampleCmdlet], FileLoadException
+ FullyQualifiedErrorId : System.IO.FileLoadException,CmdletPacking.TestSampleCmdletCommand
Complete Error message:
$error[0] | fl * -force
PSMessageDetails :
Exception : System.IO.FileLoadException: Could not load file or assembly 'System.Collections.Immutable, Version=1.2.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Could not find or l
oad a specific file. (Exception from HRESULT: 0x80131621)
File name: 'System.Collections.Immutable, Version=1.2.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' ---> System.IO.FileLoadException: Could not load file or assembly 'Sys
tem.Collections.Immutable, Version=1.2.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
at System.Reflection.Assembly.LoadFromResolveHandler(Object sender, ResolveEventArgs args)
at System.AppDomain.InvokeResolveEvent(ResolveEventHandler eventHandler, RuntimeAssembly assembly, String name)
at CmdletPacking.TestSampleCmdletCommand.ProcessRecord()
at System.Management.Automation.Cmdlet.DoProcessRecord()
at System.Management.Automation.CommandProcessor.ProcessRecord()
TargetObject :
CategoryInfo : NotSpecified: (:) [Test-SampleCmdlet], FileLoadException
FullyQualifiedErrorId : System.IO.FileLoadException,CmdletPacking.TestSampleCmdletCommand
ErrorDetails :
InvocationInfo : System.Management.Automation.InvocationInfo
ScriptStackTrace : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {}
We plan to support PowerShell modules for the Powershell >=6.0 version. Is there a way we could make this work with my current package configuration?
Is there a way we could make this work with my current package configuration?
There is, but the ease of it depends on the circumstances.
The easiest way to fix the issue is to downgrade your dependency versions to support System.Collections.Immutable v 1.2.3.
Otherwise, I'm planning to publish a blog post on the PowerShell Team blog in the next week that goes over a number of other ways to make this work. All the other techniques are more complicated though.
PS 6 is planned to go out of support in about 3 months (by 2020-06-01), so it might be worth evaluating whether implementing a more complex solution is worth it for that kind of support duration.
Worth taking a look at https://github.com/PowerShell/PowerShell/issues/12920.
I'll mark this as a duplicate of https://github.com/PowerShell/PowerShell/issues/2083.
@rjmholt
The best solution is probably to pin your version to the lowest version used by any of the PowerShell versions you want to support.
I tried testing System.Collection.Immutable 1.5.0 on PS 6 and PS 7 versions, Powershell is able to import the assembly in both the versions whereas if I upgrade the version to 1.7.0, the Import breaks on Powershell 6. Based on this can we safely assume that Powershell modules with System.Collection.Immutable dependent assembly works if System.Collections.Immutable version <= Powershell's System.Collection.Immutable version?
Could you please share your doc link here when you publish it? Thanks a lot for the quick response, very much appreciated :)
Another thing to try is building your module against the Microsoft.PowerShell.Sdk package -- the only problem is that that will mean you'll have to target netcoreapp3.1
Blog post has been published: https://devblogs.microsoft.com/powershell/resolving-powershell-module-assembly-dependency-conflicts/
PowerShell
When writing a PowerShell module, especially a binary module (i.e. one written in a language like C# and loaded into PowerShell as an assembly/DLL), it鈥檚 natural to take dependencies on other packages or libraries to provide functionality. Taking dependencies on other libraries is usually desirable for code reuse.