Same module different casing. Why? - powershell

There is a bit of a problem going on with minikube and docker-machine on windows, determining if hyper-v module is available. For more information:
https://github.com/kubernetes/minikube/issues/2634
https://github.com/docker/machine/issues/4424
but this is not essential.
What is, that on two Windows 10 machines, both up-to-date, both with WMF 5.1 (PSVersion 5.1.16299.251) When running Get-Command hyper-v\get-vm we get different results.
Let me demonstrate:
The difference is that the module name differs. It's "hyper-v" vs "Hyper-V".
I compared byte-for-byte files inside C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Hyper-V. They are the same, and the path name have the same casing.
So why is the difference?

This is likely caused by how the module is imported:
Import-Module Hyper-v
(Get-Command hyper-v\get-vm).Module.Name
The previous code will report the module as Hyper-v.
You can avoid this problem with performing the query as follows:
#(Get-Module -ListAvailable hyper-v).Name | Get-Unique
You will get the casing that is consistent between all version of PowerShell and Build versions of Windows.
Expected:
But this is sometimes seen:
Note: There are two libraries installed for the modules, which you can see with Get-Module -ListAvailable. Maybe these versions or the Windows build or release version differs? At least, this information is relevant since Windows 10, as they are not fixed anymore. They might help with pinpointing (added comment).

Related

WARNING: Multiple variants of AWS Tools for PowerShell are currently installed

When I run a powershell script, I get the following warning:
WARNING: Multiple variants of AWS Tools for PowerShell (AWSPowerShell,
AWSPowerShell.NetCore or AWS.Tools) are currently installed. Please
run 'Get-Module -Name
AWSPowerShell,AWSPowerShell.NetCore,AWS.Tools.Common -ListAvailable'
for details. To avoid problems with cmdlet auto-importing, it is
suggested to only install one variant. AWS.Tools is the new
modularized version of AWS Tools for PowerShell, compatible with
PowerShell Core 6+ and Windows Powershell 5.1+ (when .NET Framework
4.7.2+ is installed). AWSPowerShell.NetCore is the monolithic variant that supports all AWS services in a single large module, it is
compatible with PowerShell Core 6+ and Windows Powershell 3+ (when
.NET Framework 4.7.2+ is installed). AWSPowerShell is the legacy
module for older systems which are either running Windows PowerShell 2
or cannot be updated to .NET Framework 4.7.2 (or newer).
Screenshot:
How do I fix the warning? Do I uninstall one or 2 of these modules? Which ones?
Going purely by the error message:
How do I fix the warning?
You ensure that only one of the three listed module (groups) is installed:
Modern, modular group of related modules:
AWS.Tools.*, core module is AWS.Tools.Common, installation-helper module is AWS.Tools.Installer
Legacy modules (monolithic):
AWSPowerShell
AWSPowerShell.NetCore
Do I uninstall one or 2 of these modules? Which ones?
Yes. Which ones to uninstall and thereby implicitly which one to keep depends on your needs and which powershell version you have:
(a) If you're running Windows PowerShell 5.1 and have .NET Framework 4.7.2+ installed, or you're running PowerShell (Core), keep the AWS.Tools.* modules.
(b) If you're still running Windows PowerShell 3 or 4, and have .NET Framework 4.7.2+ or higher installed, keep the AWSPowerShell.NetCore module.
(c) If you're still running Windows PowerShell 2 or a higher version, but cannot install .NET Framework 4.7.2+, keep the legacy AWSPowerShell module.
For instance, to go with (a):
Note
To be safe, run with elevation (as admin), so that removal of modules that were installed in the AllUser scope can be removed.
Any non-installed modules among the specified ones are quietly ignored.
Start a new PowerShell session afterwards (modules already imported in the current session remain in memory, even after uninstallation; however, you can also remove them individually from memory with Remove-Module).
Get-Module -ListAvailable AWSPowerShell, AWSPowerShell.NetCore |
Uninstall-Module -Force

Install-Module not available - not recognized as a name of a cmdlet

I'm trying to take advantage of the PowerShell Gallery which requires Install-Module. For some reason I cannot get this to work on any computer I have access to:
Install-Module: The term 'Install-Module' is not recognized as a name of a cmdlet, function, script file, or executable program.
I tried this on a Windows 8.1, Windows 10 and even installed PowerShell 7.1 on the Windows 10 computer. I see that a lot of people have this issue, but other than installing WMF (which seems to already be included with Win10) I don't see any useful suggestions.
I don't have a lot of experience with PowerShell, and definitely not managing it, so I'm curious if anybody has an idea as to why this is not working.
Edit 1:
I seem to have the PowerShellGet module in the following directories:
C:\Program Files\WindowsPowerShell\Modules
C:\Program Files\PowerShell\7\Modules
and the $env:PSModulePath variables contains C:\Program Files\PowerShell\Modules;c:\program files\powershell\7\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
Edit 2:
This may be related to the __PSLockDownPolicy environment variable, that was set to 4 on all of the affected computers. I was able to figure this out by attempting to manually load the PowerShellGet module, which yielded an error that hinted at this.
After removing that environment variable, it seems to work.
As you've discovered yourself, it was the presence of machine-level environment variable __PSLockDownPolicy that prevented Install-Module from running (see below for general prerequisites).
This undocumented environment variable, effective on Windows only, is for security reasons only respected if defined at the machine level via the registry (rather than as a per-user or process-specific variable) and can be used to restrict what is allowed in a PowerShell session.
Values 4 through 7 result in PowerShell operating in constrained language mode, where only a handful of pre-approved .NET types may be used, which as a result prevents the PowerShellGet module that contains the Install-Module from loading - see the conceptual about_Language Modes help topic.
You can check what language mode is in effect in a given session by executing $ExecutionContext.SessionState.LanguageMode; in constrained mode, the result is ConstrainedLanguage; FullLanguage indicates that no language restrictions are in place.
Looking at PowerShell's source code, the fact that this variable is checked inside a method named GetDebugLockdownPolicy() suggests that it isn't officially supported.
For more information, see this archived blog post.
The simplest way to remove this restriction is to delete the environment variable, by running the following from an elevated PowerShell prompt:
Remove-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' __PSLockdownPolicy
One mystery remains:
As you state, importing the PowerShellGet module explicitly, with Import-Module PowerShellGet showed you that the real problem was not that the Install-Module command didn't exist, but that its enclosing module failed to load.
Doing so revealed that yet another module was the problem, namely the PackageManagement module that PowerShellGet depends on; Import-Module PackageManagement finally reveals: Cannot set property. Property setting is supported only on core types in this language mode, which implies that the (constrained) language mode was the problem.
The mystery is the error message reported in your question: Install-Module: The term 'Install-Module' is not recognized as a name of a cmdlet, function, script file, or executable program.
I see a different error message, both in Windows PowerShell 5.1 and PowerShell (Core) 7.1.2, when the constrained language mode is in effect, i.e. when $ExecutionContext.SessionState.LanguageMode reports ConstrainedLanguage:
Install-Module: The 'Install-Module' command was found in the module 'PowerShellGet', but the module could not be loaded. For more information, run 'Import-Module PowerShellGet'.
This error message makes it more obvious what the problem is, and would probably have led to a faster diagnosis.
The following contains general information that is unrelated to the above:
Installing / troubleshooting of the PowerShellGet module that provides the Install-Module command:
Install-Module is a (function-based) cmdlet that comes with Windows PowerShell 5.0 and 5.1 as well as all versions of PowerShell (Core) (v6+), as part of the PowerShellGet module.
If your computers do meet these criteria, the implication is that your PowerShell installation has been corrupted in one or both of the following ways:
The PowerShell get module was removed (or renamed) from its default location
(C:\Program Files\WindowsPowerShell\Modules\PowerShellGet in Windows PowerShell,
C:\Program Files\Powershell\7\Modules\PowerShellGet in PowerShell (Core) 7.x, on Windows).
Either reinstall PowerShell or try the manual installation instructions linked to below.
The $env:PSModulePath environment variable is missing an entry for the parent directory of the respective default location (that is,
C:\Program Files\WindowsPowerShell\Modules /
C:\Program Files\PowerShell\7\Modules). Without this entry, PowerShell cannot find the PowerShellGet module (by name only).
Manually update the machine-level definition of environment variable PSModulePath via sysdm.cpl, tab Advanced, button Environment Variables... to include the applicable directory.
If your computers do not meet these criteria, you have two choices:
If you can, upgrade the Windows PowerShell version to v5.1 or switch to PowerShell (Core).
Alternatively - if your Windows PowerShell version is 3 or 4 - install PowerShellGet manually, as per the official instructions.
Note: You may have to have access to at least one computer that already has a functioning copy of PowerShellGet to source the manual installation from.

PowerShell Core and AppX package management

I am using PowerShell 6.2 preview at the moment. In my script I am trying to do stuff with Windows 10 apps. To be able to use commands like Get-AppxPackage, I need to import Windows modules from previous PowerShell like so:
Import-Module C:\Windows\system32\WindowsPowerShell\v1.0\Modules\Appx\Appx.psd1 -SkipEditionCheck
Import-Module C:\Windows\system32\WindowsPowerShell\v1.0\Modules\dism\dism.psd1 -SkipEditionCheck
Does PowerShell core has its own modules to work with this? I found Get-Package for example, but that does not give me anything.
Since this is one of the top search results for PowerShell Core Get-AppxPackage, I'm going to take the information from the link provided in the comments and provide an answer, with example.
As LangsGalgEnRad pointed out in the comments, it's easiest just to do this from Windows PowerShell, but ultimately that's just-shy-of-deprecated at this point, with Microsoft stating that there are to be no more fixes or changes other than critical security issues. That said, it's still (afaik) universally available in Windows installations.
But for those of us who want to follow Microsoft's advice to use PowerShell Core, LangsGalgEnRad also points out in the comments the WindowsCompatibility module from Microsoft. Reading the blog post, this seems a bit safer than importing a Windows module (e.g. AppX) from PowerShell Core, since among other things ...
WindowsCompatibility is very careful to not overwrite native PowerShell core commands.
To install from PowerShell Gallery:
Install-Module WindowsCompatibility
Example usage for AppX:
Import-Module WindowsCompatibility
Import-WinModule AppX
Get-AppxPackage

Is there way to know cmdlet version in Powershell for backward compatibility?

Say you are scripting in Powershell 4.0 environment and you want to make sure the script works in Powershell 3.0. How do you ensure its backward compatible?.
Ok the question as phrased is a little more specific into what you are looking for. Sounds like you are asking for requires.
The#Requires statement prevents a script from running unless the Windows
PowerShell version, modules, snap-ins, and module and snap-in version
prerequisites are met. If the prerequisites are not met, Windows PowerShell
does not run the script.
That way, while you are scripting, you can enforce the functional version of your script.
#Requires -Version 3.0
So now while you are building and debugging your script you know that it will work on systems with at least 3.0. It recognizes minor builds as well if that matters.
I recently came across this requirement for my own needs and realize now that what I suggested up above will not get you the exact results I think you are looking for. What you should do instead is when you run your script call a new PowerShell session and use the -Version switch which Starts the specified version of Windows PowerShell(TechNet).
So when you are testing your script run it like this:
powershell -Version 2 -File myscript.ps1
Here an example to get the Version of "Get-ChildItem":
(Get-Command Get-ChildItem).Version
using get-module of the required Command, you can do it like:
(Get-Module (Get-Command Get-NetTCPConnection).Source).PowerShellVersion
For clarification:
(Get-command <your cmdlet>). Source gives you the installed location

What causes "powershell -version 2" to fail?

I have been running PowerShell v3 for some time on several different systems. On occasion I wish to check compatibility or other issues with v2 so I switch to v2 within an existing PowerShell with this:
PS> powershell -version 2
As a matter of course I then use either $hosts.Version or $PSVersionTable to do a sanity check. But on one machine when I did this they both reported I was still in a V3 shell. I tried again from scratch; same result. I also tried invoking it from a DOS shell instead of a PowerShell; again, same result. Then to check my own sanity(!) I went to another system, did the same sequence, and it worked as expected--I did indeed switch from a V3 to a V2 environment.
The only other observation I have is that on the system that worked, I got a 2009 copyright notice when it started up the inner shell; on the system that did not it showed 2012.
Final detail: of the two machines mentioned, it worked on Win8 and failed on Win7 enterprise but I really doubt that is a relevant factor here.
I would be really surprised if (a) this is a PS bug or (b) I am the only one seeing the issue, yet web searching has been fruitless for me thusfar. Any thoughts on why this might be happening?
One reason would be that .NET 2.0 is not installed on the failing system, I cant recall if it had to be already installed prior to v3 or you can install it after upgrading to v3.
Quick search turned up this, just an idea? Maybe V2 is not installed?
Is Version 2 installed?