I wrote a simple PowerShell module. I need to keep more versions of the module. All paths to versions are added to $env:PSModulePath. I'm facing strange problem when importing the module to my session.
This fails:
Import-Module Contoso.PowerShell -RequiredVersion "0.0.2"
Import-Module : The specified module 'Contoso.PowerShell' with version '0.0.2'
was not loaded because no valid module file was found in any module directory.
At line:1 char:1
+ Import-Module Contoso.PowerShell -RequiredVersion "0.0.2"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (Contoso.PowerShell:String) [Import-Module], FileNotFoundException
+ FullyQualifiedErrorId : Modules_ModuleWithVersionNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand
And now the strange thing - the module with the "0.0.2" version exists. I can successfully list it (with Get-Module -ListAvailable). I can even import it and work with it, but the only way how to do it is this:
Get-Module Contoso.PowerShell -ListAvailable |
? { $_.Version -eq "0.0.2" } |
Import-Module
Everything works like a charm then. The question is: WHY? I'd like to be able to import the module with the first simple command.
EDIT:
Here is how I store the versions of the module:
Get-Module Contoso.PowerShell -ListAvailable
Directory: C:\Program Files\WindowsPowerShell\Modules\Contoso.PowerShell\Contoso.PowerShell.0.0.1
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0.1 Contoso.PowerShell
Directory: C:\Program Files\WindowsPowerShell\Modules\Contoso.PowerShell\Contoso.PowerShell.0.0.2
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0.2 Contoso.PowerShell
And sorry for confusion - I do NOT have paths to each version in the PSModulePath environment variable.
The reason Import-Module works is because it uses a different parameter set; one where it accepts one or more [PSModuleInfo] objects, which are what Get-Module returns.
Likely, it uses the work already done by Get-Module to determine which file to load.
The next question then is "why doesn't Import-Module find the version the same way Get-Module does?" and the answer to that is "I don't know."
While they should be consistent in any case, a possible cause for trouble is your directly structure. How are you storing multiple versions?
It looks to me like your module paths are incorrect.
Your structure should be:
Contoso.PowerShell\0.0.2
Contoso.PowerShell\0.0.3
etc.
The module files go directly in the version number folder, and it shouldn't additionally have the name inside it.
You can see this structure by using Install-Module to install one from a repository and taking a look at how it handles it.
Related
I'm trying to create a powershell script to clear a redis cache, it's in Azure but I don't think that's relevant. I've seen 2 examples which I'm trying to copy where people have loaded StackExchange.Redis.dll into their script: https://www.powershellgallery.com/packages/Saritasa.Redis/1.2.0/Content/Saritasa.Redis.psm1 and Clearing Azure Redis Cache using PowerShell during deployment.
I've downloaded the current StackExchange.Redis.dll from nuget.org. I've tried to load it on 2 servers, one with .Net 4.61 installed, the other with .Net 4.8. I get the same problem on both.
If I try to use [System.Reflection.Assembly]::LoadFrom I get as below:
PS E:\redis\stackexchange.redis.2.2.88\lib\net461> dir
Directory: E:\redis\stackexchange.redis.2.2.88\lib\net461
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 05/11/2021 00:42 637440 StackExchange.Redis.dll
-a--- 05/11/2021 00:42 705989 StackExchange.Redis.xml
PS E:\redis\stackexchange.redis.2.2.88\lib\net461> [System.Reflection.Assembly]::LoadFrom("E:\redis\stackexchange.redis.
2.2.88\lib\net461\StackExchange.Redis.dll")
GAC Version Location
--- ------- --------
False v4.0.30319 E:\redis\stackexchange.redis.2.2.88\lib\net461\StackExchange.Redis.dll
PS E:\redis\stackexchange.redis.2.2.88\lib\net461> [StackExchange.Redis.ConnectionMultiplexer]::Connect($myConnectionStr
ing)
Unable to find type [StackExchange.Redis.ConnectionMultiplexer]: make sure that the assembly containing this type is
loaded.
At line:1 char:1
+ [StackExchange.Redis.ConnectionMultiplexer]::Connect($myConnectionString)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (StackExchange.R...tionMultiplexer:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
PS E:\redis\stackexchange.redis.2.2.88\lib\net461>
If I try to use Add-Type I get:
PS E:\redis\stackexchange.redis.2.2.88\lib\net461> Add-Type -AssemblyName .\StackExchange.Redis.dll
Add-Type : Could not load file or assembly '.\\StackExchange.Redis.dll' or one of its dependencies. The given assembly
name or codebase was invalid. (Exception from HRESULT: 0x80131047)
At line:1 char:1
+ Add-Type -AssemblyName .\StackExchange.Redis.dll
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Add-Type], FileLoadException
+ FullyQualifiedErrorId : System.IO.FileLoadException,Microsoft.PowerShell.Commands.AddTypeCommand
PS E:\redis\stackexchange.redis.2.2.88\lib\net461>
I've looked through the dependencies in nuget.org, I saw one non-Microsoft one called Pipelines.Sockets.Unofficial which I also downloaded and got the same thing. There's a whole hierarchy of other dependencies which I think are all part of .Net, surely I haven't got to download them all if .Net is installed on the server? Thanks for any help, I've been trying all day!
I'll put some things I learned above my code in case someone as inexperienced as me reads this. These points aren't in any order:
To download a nuget package for use by powershell, the easiest way is to use the Install-Package cmdlet, for example:
Install-Package -Name System.IO.Pipelines -ProviderName NuGet -SkipDependencies -Destination C:\Stackexchange.Redis-packages -RequiredVersion 5.0.1
Note that -SkipDependencies is needed because without it Install-Package gave me an error message about a circular dependency, described in https://endjin.com/blog/2020/12/how-to-consume-a-nuget-package-in-powershell. You have to download the dependencies yourself!
The alternative is: in nuget.org click the download link to download the .nupkg file, rename it to .zip, extract the files, then in File Explorer right-click the dll file, click Properties, Unblock.
I thought this app was great for showing the DLL dependencies of a DLL, it shows the whole heirarchy of dependencies and if they're found or not https://github.com/lucasg/Dependencies
To get the assembly versions of dll files in powershell:
Get-ChildItem -Filter *.dll -Recurse | Select-Object Name,#{n='FileVersion';e={$_.VersionInfo.FileVersion}},#{n='AssemblyVersion';e={[Reflection.AssemblyName]::GetAssemblyName($_.FullName).Version}}
from Get file version and assembly version of DLL files in the current directory and all sub directories
When loading DLLs, Add-Type behaves differently from [System.Reflection.Assembly]::LoadFrom(). Add-Type seems to load dependencies which can be useful. If Add-Type -Literalpath <dllFileName> fails with an error message “Add-Type : Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more
information” you can get the DLL it was looking for with $error[0].Exception.GetBaseException().LoaderExceptions https://www.reddit.com/r/PowerShell/comments/7a4vw6/addtype_how_do_i_retrieve_the_loaderexceptions/
To get round the situation where DLLs in the heirarchy have a dependency on different versions of the same DLL (which seems to be very common) this guy's solution is simply fantastic. I couldn't find any alternative and it seems to work perfectly https://www.azurefromthetrenches.com/powershell-binding-redirects-and-visual-studio-team-services/
The DLLs I used
I ended up with these DLL files in a folder:
Name FileVersion AssemblyVersion
---- ----------- ---------------
Microsoft.Bcl.AsyncInterfaces.dll 6.0.21.52210 6.0.0.0
Pipelines.Sockets.Unofficial.dll 2.2.0.45337 1.0.0.0
StackExchange.Redis.dll 2.2.88.56325 2.0.0.0
System.Buffers.dll 4.6.28619.01 4.0.3.0
System.IO.Pipelines.dll 5.0.120.57516 5.0.0.1
System.Memory.dll 4.6.28619.01 4.0.1.1
System.Numerics.Vectors.dll 4.6.26515.06 4.1.4.0
System.Runtime.CompilerServices.Unsafe.dll 6.0.21.52210 6.0.0.0
System.Threading.Channels.dll 6.0.21.52210 6.0.0.0
System.Threading.Tasks.Extensions.dll 4.6.28619.01 4.2.0.1
The code It's not finished, but shows the Stackexhange.Redis DLL loaded and used.
# Code to load the DLLs needed for Stackexchange.Redis.dll and clear the cache
# Basically copied from https://www.azurefromthetrenches.com/powershell-binding-redirects-and-visual-studio-team-services/
$DllPath = 'C:\Stackexchange.Redis-packages\combined DLLS'
$redisHostName = '<my cache name here>.redis.cache.windows.net'
$redisConnectionString = '<my cache name here>.redis.cache.windows.net:6380,password=<my cache password here>,ssl=True,abortConnect=False'
# Load DLL assemblies into memory, required by the event handler below
$SystemBuffersDll = [System.Reflection.Assembly]::LoadFrom("$DllPath\System.Buffers.dll")
$SystemRuntimeCompilerServicesUnsafeDll = [System.Reflection.Assembly]::LoadFrom("$DllPath\System.Runtime.CompilerServices.Unsafe.dll")
$SystemMemoryDll = [System.Reflection.Assembly]::LoadFrom("$DllPath\System.Memory.dll")
$SystemSystemThreadingTasksExtensionsDll = [System.Reflection.Assembly]::LoadFrom("$DllPath\System.Threading.Tasks.Extensions.dll")
$SystemIoPipelinesDll = [System.Reflection.Assembly]::LoadFrom("$DllPath\System.IO.Pipelines.dll")
$MicrosoftBclAsyncInterfacesDll = [System.Reflection.Assembly]::LoadFrom("$DllPath\Microsoft.Bcl.AsyncInterfaces.dll")
$PipelinesSocketsUnofficialDll = [System.Reflection.Assembly]::LoadFrom("$DllPath\Pipelines.Sockets.Unofficial.dll")
$SystemThreadingChannelsDll = [System.Reflection.Assembly]::LoadFrom("$DllPath\System.Threading.Channels.dll")
# Event handler to be run when the AssemblyResolve event occurs
$onAssemblyResolveEventHandler = [System.ResolveEventHandler] {
param($sender, $e)
Write-Verbose "Assembly resolve event for $($e.Name)"
$dllName = $e.Name.Split(',')[0]
switch ($dllName) {
'System.Buffers' {return $SystemBuffersDll}
'System.Runtime.CompilerServices.Unsafe' {return $SystemRuntimeCompilerServicesUnsafeDll}
'System.Memory' {return $SystemMemoryDll}
'System.Threading.Tasks.Extensions' {return $SystemSystemThreadingTasksExtensionsDll}
'Microsoft.Bcl.AsyncInterfaces' {return $MicrosoftBclAsyncInterfacesDll}
'Pipelines.Sockets.Unofficial' {return $PipelinesSocketsUnofficialDll}
'System.Threading.Channels' {return $SystemThreadingChannelsDll}
'System.Numerics.Vectors' {return $SystemNumericsVectorsDll}
'System.IO.Pipelines' {return $SystemIoPipelinesDll}
}
foreach($assembly in [System.AppDomain]::CurrentDomain.GetAssemblies()) {
if ($assembly.FullName -eq $e.Name) {
return $assembly
}
}
return $null
}
# Set up the handler above to be triggered when the AssemblyResolve event occurs
[System.AppDomain]::CurrentDomain.add_AssemblyResolve($onAssemblyResolveEventHandler)
# Load StackExchange.Redis.dll, prefer Add-Type because it seems to include dependencies, LoadFrom doesn't so might get an error later
Add-Type -LiteralPath "$DllPath\StackExchange.Redis.dll"
$redis = [StackExchange.Redis.ConnectionMultiplexer]::Connect("$redisConnectionString, allowAdmin=true")
$redisServer = $redis.GetServer($redisHostName, 6380)
# $rs.FlushAllDatabases(async=true)
$redisServer.FlushAllDatabases()
# Detach the event handler (not detaching can lead to stack overflow issues when closing PS)
[System.AppDomain]::CurrentDomain.remove_AssemblyResolve($onAssemblyResolveEventHandler)
I am trying to install the sysinternals package with powershell, but is instead greeted with tons of warnings. It should be noted that I am following a set of instructions and don't know a lot about this subject yet. Here are the warnings when attempting to run the install-package command:
Install-Package sysinternals
WARNING: NuGet: System.InvalidOperationException: Unable to find version '1.3.5.1' of package 'chocolatey-core.extension'.
WARNING: NuGet: at NuGet.PackageRepositoryHelper.ResolvePackage(IPackageRepository sourceRepository, IPackageRepository
localRepository, IPackageConstraintProvider constraintProvider, String packageId, SemanticVersion version, Boolean
allowPrereleaseVersions)
WARNING: NuGet: at NuGet.PackageManager.InstallPackage(String packageId, SemanticVersion version, Boolean ignoreDependencies,
Boolean allowPrereleaseVersions)
WARNING: NuGet: at NuGet.Commands.InstallCommand.InstallPackage(IFileSystem fileSystem, String packageId, SemanticVersion version)
WARNING: NuGet: at NuGet.Program.Main(String[] args)
WARNING: NuGet: System.InvalidOperationException: Unable to find version '2019.12.19' of package 'sysinternals'.
As for what I've done before this, I've only installed the Chocolatey package provider and updated windows, but maybe I did something wrong? Here are the steps leading up to this:
Set-ExecutionPolicy RemoteSigned
Install-PackageProvider Chocolatey
Install-Module -Name PSWindowsUpdate
Get-WUInstall -Verbose
Get-WUInstall -Install
Any help is much appreciated.
Though you can use Chocolatey and NuGet, PowerShell's package manager is PowerShellGet (well, that uses NuGet by design). So, Choco is not really needed, yet, many still install and use it for the other sources.
If you use PowerShellGet directly, you'll see the same errors.
Find-Module -Name 'SysInternals' -AllVersions |
Format-Table -AutoSize
<#
# Results
PackageManagement\Find-Package : No match was found for the specified search criteria and module name 'SysInternals'. Try Get-PSRepository to see all available registered module
repositories.
At C:\Users\Daniel\Documents\WindowsPowerShell\Modules\PowerShellGet\2.2.3\PSModule.psm1:8873 char:9
+ PackageManagement\Find-Package #PSBoundParameters | Microsoft ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Microsoft.Power...ets.FindPackage:FindPackage) [Find-Package], Exception
+ FullyQualifiedErrorId : NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.FindPackage
#>
Find-Package -Name 'SysInternals' -AllVersions |
Format-Table -AutoSize
<#
# Results
Find-Package : No match was found for the specified search criteria and package name 'SysInternals'. Try Get-PackageSource to see all available registered package sources.
At line:1 char:1
+ Find-Package -Name 'SysInternals' -AllVersions |
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Microsoft.Power...ets.FindPackage:FindPackage) [Find-Package], Exception
+ FullyQualifiedErrorId : NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.FindPackage
#>
Yet, if you do a wildcard search...
Find-Module -Name '*Internals*' |
Format-Table -AutoSize
<#
# Results
Version Name Repository Description
------- ---- ---------- -----------
1.0.34 PoshInternals PSGallery Collection of system internals tools for PowerShell.
4.3 DSInternals PSGallery The DSInternals PowerShell Module exposes several internal features of Active Directory and Azure Active Directory. These include FIDO2 and NGC key aud...
0.2.8 AADInternals PSGallery The AADInternals PowerShell Module utilises several internal features of Azure Active Directory, Office 365, and related admin tools. DISCLAIMER: Funct...
0.1 LCMInternals PSGallery Demo scripts explaining the internals of LCM
#>
Find-Package -Name '*Internals*' |
Format-Table -AutoSize
<#
# Results
Name Version Source Summary
---- ------- ------ -------
PoshInternals 1.0.34 PSGallery Collection of system internals tools for PowerShell.
DSInternals 4.3 PSGallery The DSInternals PowerShell Module exposes several internal features of Active Directory and Azure Active Directory. These incl...
AADInternals 0.2.8 PSGallery The AADInternals PowerShell Module utilises several internal features of Azure Active Directory, Office 365, and related admin...
LCMInternals 0.1 PSGallery Demo scripts explaining the internals of LCM
SilverlightToolkit-Internals-Unofficial 1.0.0 nuget.org The missing part of Microsoft Silverlight Toolkit. The internals DLL. 'System.Windows.Controls.Toolkit.Internals'
AppInternals.Agent.Cloud.Support 10.10.0 nuget.org Configure an Azure Cloud Service solution for AppInternals application performance monitoring.
InternalsVisibleTo.MSBuild 1.0.3 nuget.org Enables declaring 'InternalsVisibleTo' items in a .NET project file, rather than declaring them to an AssemblyInfo.cs file.
Akrual.DDD.Utils.Internals 1.0.8 nuget.org Useful Classes yo use everywhere
Meziantou.MSBuild.InternalsVisibleTo 1.0.1 nuget.org Allow to declare 'InternalsVisibleTo' in the csproj file, rather than declaring them to an AssemblyInfo.cs file.
microServiceBus.InternalService 1.0.0 nuget.org This package creates a stub from which you can create an Internal Service for microServiceBus.com
#>
So, as you can see, there is no such module/package called SysInternals to install.
What you do is just download the zip file from here and unpack and use it as normal.
Sysinternals Suite
https://learn.microsoft.com/en-us/sysinternals/downloads/sysinternals-suite
I was having the same issue and found the answer here helpful. It seems like something about TLS 1.3 is causing the issue, and the second part of the answer—changing the .Net Framework default TLS version—allowed me to finish my sysinternals install via PowerShell. Then I just deleted the new reg key I had created. I guess I'll just have to wait and see if this is something that comes up again as I continue to learn more and work more with package management in PS.
I have a scheduled task which runs an exported function from my PowerShell module which is hosted at powershellgallery.com. The function performs a check against the built-in PSGallery repository to see if a newer version is available and if so, update it.
I've noticed my module is not being updated as it should and to troubleshoot the issue I've redirected the output from two separate commands. First, to make sure the repository is 'visible' to the SYSTEM account running the task I run:
Get-PSRepository *>> c:\repo.log
This yields the following output:
Name InstallationPolicy SourceLocation
---- ------------------ --------------
PSGallery Untrusted https://www.powershellgallery.com/api/v2
So the SYSTEM account running the function as a scheduled task can 'see' the repo; no problem. Next, the function runs the Update-Module command as such:
Update-Module -Name $ProductName -Confirm:$false -Force -Verbose *>> c:\update.log
This yields the following output:
Checking for updates for module '[removed by me]'.
PackageManagement\Install-Package : Unable to find repository 'https://www.powershellgallery.com/api/v2/'. Use
Get-PSRepository to see all available repositories.
At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\2.0.4\PSModule.psm1:12546 char:20
+ ... $sid = PackageManagement\Install-Package #PSBoundParameters
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Microsoft.Power....InstallPackage:InstallPackage) [Install-Package], Ex
ception
+ FullyQualifiedErrorId : SourceNotFound,Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackage
Lastly, I checked the module to make sure it is indeed associated with PSGallery by running:
Get-InstalledModule -Name $ProductName | fl
The output shows:
RepositorySourceLocation : https://www.powershellgallery.com/api/v2/
Repository : PSGallery
UPDATE: I decided to use the Install-Module with the -Force switch to 'update' the module instead as I couldn't get the other command to work. Oddly though, when I do a Get-InstalledModule -AllVersions I can clearly see a difference between a module installed interactively and one installed under the SYSTEM account (running as a scheduled task). Pay attention to the Repository column:
If I run the function interactively it works without issue.
If I run Find-Module -Name $ProductName from within the function it finds the module without issue.
Tried both solutions from other question to no avail...
Any idea why the Update-Module command can't find the repo??
I believe you are seeing the bug described in https://github.com/PowerShell/PowerShellGet/issues/349 . It's not really related to SYSTEM account. Simplest workaround until fixed version is released is to uninstall the module then reinstall it again. You should only have to do that once, and update-module should work thereafter.
UPDATE: This is resolved in newer builds of PowerShellGet.
I am trying to get queue depth for remote IBM MQ using PowerShell script/commands. Seems it is not working correctly, please help.
{
$myremoteconns = New-WMQQmgrConnDef -Name T.test.TEST.QM1 -Hostname abcd_testhost01 -Port 1111 -Channel T.test.MQMQ.TESTCHN
$qm = Get-WMQQueueManager -Connections $myremoteconns | where {$_.Name -like 'T.test.TEST.QM1'}
Error New-WMQQmgrConnDef the term 'New-WMQQmgrConnDef' is not recognized
Already installed WebSphere MQ - Windows PowerShell Library from below.
http://www-01.ibm.com/support/docview.wss?uid=swg24017698
Thanks
This error means that PowerShell cannot find this cmdlet. You need to check if the module you installed is properly found by PowerShell. Check this first:
Get-Module -ListAvailable
The result will be like:
PS C:\Users\username\PowerShell> get-module -ListAvailable
Directory: C:\Program Files\WindowsPowerShell\Modules
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 3.0.1 ImportExcel {Import-Html, ConvertFrom-ExcelSheet, PieChart, Import-UPS...}
If you don't find the module on the list you can import it manually using:
Import-Module -Name 'C:\path\to\module.psm1'
In PowerShell (starting at V3) modules should be imported automatically if they are inside on of the path specified in environment variable PSModulePath. You can check its value by using:
$env:PSModulePath
Once you know which folders are included in this variable you can either move the module there or just add another path using
$env:PSModulePath = $env:PSModulePath + ";c:\path\to\module"
This will work for current session. If you want to modify it for all session you can add the line below to PowerShell profile.
More info:
Importing a module
Modifying PSModulePath
PowerShell profiles
I'm trying to setup a NuGet Feed here, and that worked ok. I installed a module from my feed via
Install-Module -Name MyCmdlets -Repository $RepoName -Scope CurrentUser -Force
Import-Module -Name MyCmdlets
However when I run Get-Module, I get no functions and it's a manifest?
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 1.0 MyCmdlets
If I manually go to the installed location and import manually
Import-Module <my-path>\1.0\MyCmdlets.psm1
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 MyCmdlets {Create-Project, Get-AuditLogs, Get-..
My manifest file does have these lines so I don't understand why Import-Module isn't working correctly.
FunctionsToExport = '*'
CmdletsToExport = '*'
I guess you haven't set the root module in your .psd1 like so
#
# Module manifest for module 'YourModule'
#
#{
# Script module or binary module file associated with this manifest
RootModule = 'YourModule.psm1'
# Version number of this module.
ModuleVersion = '1.0.0'
...
This is necessary so that when you import your manifest module it also loads the script module
For anyone coming across this looking for why their module wont import check that RootModule = 'YourModule.psm1' isn't commented out.
By default when creating a new manifest using New-ModuleManifest it throws a hash in front of this line..
ugh I feel so stupid.