What is the purpose of ImportSystemModules? - powershell

What is the purpose of ImportSystemModules? Using help ImportSystemModules -Full produces an empty shell description.
PS 09:12 C:\src
>get-command *module*
CommandType Name Version Source
----------- ---- ------- ------
Function Find-Module 2.2.1 PowerShellGet
Function Get-InstalledModule 2.2.1 PowerShellGet
Function **ImportSystemModules**
Function InModuleScope 3.4.0 Pester
Function Install-Module 2.2.1 PowerShellGet
...

From Roger Lipscombe's blog, it used to do the following:
This runs Powershell.exe -ImportSystemModules, which, in turn, runs the ImportSystemModules command. You can call this command as part of your profile, if you want these modules loaded each time you run PowerShell.
Various places on the Internet state that it loads the available modules from C:\Windows\System32\WindowsPowerShell\v1.0\Modules. Among these are modules for managing IIS, Hyper-V, etc.
It turns out that it also loads snap-ins from C:\Users\rogerl\Documents\WindowsPowerShell\Snapins
However, according to another SO answer:
The -ImportSystemModules switch has no impact in v3, looks like it is going away.
And the Powershell changelog states for v6 beta 9 states the argument has been removed entirely:
Remove parameters -importsystemmodules and -psconsoleFile from powershell.exe. (#4995)
And indeed, running Get-Command ImportSystemModules on Powershell Core v6 cannot find the command anymore:
> Get-Command ImportSystemModules
Get-Command : The term 'ImportSystemModules' is not recognized as the name of a cmdlet, function, script file, or operable program.
As to why it's still there and defined in v5.1 and earlier? Perhaps it's for backwards compatibility, v2 compatibility was guaranteed for a long time.

Related

Powershell 7 import-module does not persist across sessions

If I open a new Powershell 7 session and run get-command Get-Website
the response I get is
Get-Command: The term 'Get-Website' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
If I then run import-Module WebAdministration and again run get-command Get-Website, this time I get the expectefd output of
CommandType Name Version Source
----------- ---- ------- ------
Function Get-Website 1.0 WebAdministration
If I close the Powershell 7 session, open a new one and run get-command Get-Website, the new session does not recognise the command.
If I run a session of Windows Powershell, I do not have to import the module, the command is already there.
Anyone able to explain what is going on?
Thanks
You are not the only person having this problem. Unfortunately, I can't speak to whether any of the solutions there work, as neither the asker or anyone else has confirmed them.
Note: I had originally suspected this might be a problem with automatic importing through the WindowsCompatibility module, but it appears that it does not interfere with auto-importing of modules. In addition, as of PowerShell 7 the WindowsCompatibility module features are baked into PowerShell itself.
For whatever reason, WebAdministration may not be able to be automatically imported in PowerShell Core. There are a few reasons for this but they are mostly on the module side, and you can't change the behavior without modifying the module.
You can try setting $PSModuleAutoLoadingPreference = 'All' in your current PowerShell session, but generally that doesn't need to be changed from the default value of ModuleQualified. More information on $PSModuleAutoLoadingPreference can be found here.
If that doesn't work, you'll have to manually import the module in every session.
Fortunately, manually importing modules isn't required for the vast majority of them. For the ones which can't be automatically imported, you must use Import-Module MODULENAME in each new session. You can simplify this by adding the Import-Module cmdlet to one of the following profile locations:
$profile.CurrentUserCurrentHost
$profile.CurrentUserAllHosts
$profile.AllUsersCurrentHost
$profile.AllUsersAllHosts
For scripts, Import-Module should generally be done inside the script to prevent needing profiles in scenarios where profile loading is desired to be disabled such as when PowerShell is invoked in the following way: powershell.exe -NoProfile ....
In your case, it would like like so:
Import-Module WebAdministration
Here is some additional information about the $profile variable.

NetTCPIP missing from Get-Modules for one minute

Why does Get-Module not show all the installed Modules?
Some PCs don't have the NetTCPIP module installed. Mine does, but when I open a new PowerShell ISE window
Get-Module | Where-Object Name -eq 'NetTCPIP' | Format-Table
Returns blank.
After one minute it returns:
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 1.0.0.0 NetTCPIP {Find-NetRoute, ...}
The strange thing is:
Get-Command -Name Test-NetConnection
Always shows that the command exists in the Source: NetTCPIP.
Now the even strange thing is that on a Server OS running the same version of PowerShell, never shows the NetTCPIP module but does have the command Test-NetConnection.
Why does Get-Module not show all the installed Modules?
Get-Module by default lists only the modules which are currently imported. If you want to see all the modules, you can use Get-Module -ListAvailable.
Starting with PowerShell 3.0, modules are dynamically imported first time you use the cmdlet from that module. So if you test the cmdlet to see if it exists (or you use Get-Command Test-NetConnection), PowerShell silently imports the module and it's displayed next time you use Get-Module.

Get-RDUsersession is not recognized as the name of a cmdlet

I have problems running a script with Powershell in Windows 7.
The script just retrieves a list of all connected user in terminal server in order to connect to them via "mstsc.exe". The problem is that when I run cmdlet "Get-RDUsersession" it returns that it is not recognized as the name of a cmdlet.
I already knew that it could be an error because before running this cmdlet, I had to install the RSAT administrative tools for windows in order to have all of the modules dedicated to "remotedesktop" and "active directory".
In fact, I've done both Windows 7 and Windows 10, but in Windows 10 it works just fine, while Windows 7 that error came up.
Moreover, I saw that in the path C:\Windows\system32\WindowPowerShell\v1.0\Modules there is no remote desktop module, while there is in Windows 10.
Is it normal? How can I run that cmdlet in Windows 7?
I've not had Win7 in my environment for years now, so, no way for me to sanitly check directly. However, if you are saying you downloaded and installed the Win7 version of RSAT (there are different installer for WinOS Clinet versions), and RSAT is not in any of the module paths, there are several module paths, then something went wrong with your RSAT install.
Also, of note, PowerShell cmdlets availability differs on WinClient versions, even if you have installed the latest builds. Some cmdlets are only available to the OS version that they were designed for.
If all else fails, you can use Implicit PS Remoting to a new machine and proxy the cmdlets from that machine and use them. In implicit sessions, the cmdlets are actually ran on the remote host, not your local station that you are using them from.
So, if you do the below on your WIn7 and Win10 systems, what are the results?
Get-Command -Name Get-RDUsersession
CommandType Name Version Source
----------- ---- ------- ------
Function Get-RDUserSession 2.0.0.0 RemoteDesktop
Get-Module -Name RemoteDesktop
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 2.0.0.0 RemoteDesktop {Add-RDServer, Add-RDSessionHost,...
Import-Module -Name RemoteDesktop -Verbose

Powershell running a cmdlet from a called script

I have a script that calls another script (with arguments). The called script contains the Install-WindowsFeature cmdlet. When I run the script, the called script runs, but returns the following error:
Install-WindowsFeature : The term 'Install-WindowsFeature' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path
Of course, I can run the cmdlet just fine from a PowerShell console. I can also run the called script from a PowerShell console and Install-WindowsFeature works fine. So, is it something to do with calling a script from a script that runs a cmdlet? Here is my calling code:
$script = "C:\Path\script.ps1"
$argumentList = #()
$argumentlist += ("-Arg1", "value")
$argumentlist += ("-Arg2", "value")
$argumentlist += ("-Arg3", "value")
Invoke-Expression "$script $argumentList"
In the called script, I called Install-WindowsFeature as below:
if ($someValue) { Invoke-Command -ScriptBlock {Install-WindowsFeature -Name RSAT-AD-Tools} }
I've also tried it as below:
if ($someValue) { Install-WindowsFeature -Name RSAT-AD-Tools }
12/16/16 EDIT: This script is running in a GUI built with Sapien PowerShell Studio. When I change the build type to "Native" it works. I have to reset my lab to check, but I suspect it will also run if I just run it in the x64 context. This article explains why I think this matters.
Running on Windows Server 2012 R2
Unless you've got a compelling reason for it, let's see if we can clean up your calling pattern a bit - and hopefully make your other issues go away by avoiding the contortionism.
Rather than creating your parameter list as a string, take advantage of parameter splatting. It's good to get out of the habit of treating PowerShell like other scripting languages that don't work with objects.
$splat = #{
Arg1 = "value1";
Arg2 = "value2";
Arg3 = "value3"
}
& c:\path\script.ps1 #splat
Using that on a script.ps1 something like this:
param(
$Arg1,
$Arg2,
$Arg3
)
Write-Host "Arg1 = $Arg1, Arg2 = $Arg2, Arg3 = $Arg3
You'll get an expected output of:
Arg1 = value1, Arg2 = value2, Arg3 = value3
Once you've got that, there's probably no reason to use Invoke-Command on the call to Install-WindowsFeature, unless you're leaving out details like invoking remotely to a server. Invoke-Command { Install-WindowsFeature } still works fine for me on Server 2012R2 with PowerShell 5, and there's no reason it shouldn't.
This assumes you're running this script on a Server that support Install-WindowsFeature, as the other comments point out. Client Windows doesn't support Install-WindowsFeature, and the RSAT tools are installed via a stand-alone RSAT .MSU package, which you manage differently.
Install-WindowsFeature is natively provided with Server Manager on Server 2012R2 - there's no need to Import-Module... unless you've done something to your profile or fouled up your modules folders. One of the earlier versions of Windows Server needed it - but that was a couple versions back. Likewise, Add-WindowsFeature was the old name - and it's still available as an alias for Install-WindowsFeature.
I'm assuming you've tried Install-WindowsFeature directly from the command line to ensure it's in working order, and Get-Module Install-WindowsFeature looks reasonable.
PS C:\Windows\system32> get-module ServerManager
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 2.0.0.0 ServerManager {Get-WindowsFeature, Install-WindowsFeature, Uninstall-Win...
While we're on the topic, there's very little reason to drop to DISM on Server that supports Install-WindowsFeature, and a number of reasons not to.
Server Manager and several other tools (including Win32_ServerFeature) rely on the feature states parsed and understood by the WMI provider used by Install-WindowsFeature. It's possible to enable the right set of features using DISM, but needs attention and detail. Enabling only "part" of a role and feature may get the functionality you want for specific cases, but the role or feature may not show up as installed in Get-WindowsFeature, may not be uninstallable via Remove-WindowsFeature, and may not offer relevant UI features in Server Manager like monitoring health of the role, viewing relevant events, or offering tools for administering it.
Install-WindowsFeature integrates with additional code from the role & features you're installing, and may run additional health and pre-requisite checks to ensure your correctly configured.
DISM featurenames tend to change more often than the role & feature name of Server Manager, so your script portability will be better.
There are other points, but I won't go into them since DISM was primarily a comment fork.
You are probably right, it seems like the script gets executed with x86 PowerShell. I want to share a snippet with you which I use for scripts that needs to run in a specific environment (e. g. x64 PowerShell).
The script restarts itself in a x64 PowerShell if its started as x86 process. Just put this at the top of your script:
# Reinvoke the script as x64 if its called from a x86 process.
if ($env:Processor_Architecture -eq "x86")
{
&"$env:windir\sysnative\WindowsPowerShell\v1.0\powershell.exe" -noprofile -file $myinvocation.Mycommand.path -executionpolicy bypass
exit
}
Also note that the Install-WindowsFeature cmdlet doesn't work on all windows versions so consider to use dism instead:
$featuresToInstall = #('RSAT-AD-Tools')
$dismParameter = #('/online', '/Enable-Feature', ($featuresToInstall | % { '/FeatureName:{0}' -f $_ }), '/NoRestart')
dism #dismParameter
The running environment determines what modules you have access to. When I created this project in PowerShell Studio, it took the default of x86 (a 32 bit environment). This worked but because I was running it on Windows Server 2012 R2 (a 64-bit environment) I did not have access to the powershell modules such as Import-Module and Install-WindowsFeature. Changing this to a x64 project resolved my issue.
In order to avoid this scenario, it is important to make sure you run PowerShell scripts and modules in the architecture that is native to the OS. You can do this by setting the project correctly (if using a tool like PowerShell Studio) or by verifying that you are running in the native mode for that OS with the code Martin Brandl provided.

Is module auto-loading meant to be reliable?

Environment
I have the following folder structure where I keep powershell modules:
C:
PsModules
...
util
util.psm1 (this contains implementation of 'Test-Function')
util.test.ps1
ftp
ftp.psm1
http.test.ps1
...
There are about 50 folders and modules in c:\PsModules.
I have set environment variable PSModulePath to include c:\PsModules. This seems to meet the conditions for "well-formed modules" described in Microsoft's documentation and this answer.
Symptoms
Sometimes Test-Function is not found automatically when calling it from ISE. In fact, on any given fresh launch of ISE, there are always some (seemlingly unpredictable) modules that are not found automatically. The failure to automatically find Test-Function, for example, looks like this:
PS C:\> Test-Function
Test-Function : The term 'Test-Function' is not recognized as the name
of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is
correct and try again.
...
+ FullyQualifiedErrorId : CommandNotFoundException
At first glance, this seems to indicate that util.psm1 is not "well-formed". If it were not "well-formed", then ListAvailable shouldn't work. But it does work:
c:\> get-module -ListAvailable util
Directory: c:\PsModules\util
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 util
PS C:\> Test-Function
...
+ FullyQualifiedErrorId : CommandNotFoundException
Furthermore, after calling Get-Command for the module, the commands in the module are available for general use:
c:\> Get-Command -Module util
CommandType Name ModuleName
----------- ---- ----------
Function Test-Function util
c:\> Test-Function
Call to Test-Function succeeded!
Questions
Is automatic discovery and module auto-loading supposed to be reliable and predictable?
How do I troubleshoot why powershell is sometimes doesn't find a command until a call to Get-Command -module?
Is it bad practice to rely on powershell to automatically load modules? If so, what is the good practice for automatically loading modules?
I can't speak to whether module auto-loading is intended to be reliable, but I personally do not rely on it in finished code.
If I'm writing a script or module, I always use Import-Module TheModule -ErrorAction Stop, and often use #Requires -Module AciveDirectory,TheModule,SQLPs to ensure that the modules are available.
For interactive use in the PowerShell console or ISE, I do generally rely on auto-loading, but if it fails I just Import-Module manually for the session.
In situations where I always want a specific module loaded for an interactive session, I load it in a profile. To see the various profiles run this (from both ISE and Console):
$profile | Get-Member -MemberType NoteProperty
You can decide where you want to place the code for importing the module based on which user(s) and in which host(s) you want the module to be available.
So far I only do this for posh-git, but it seems like it would fit your use case well.
In case this is helpful to anyone else, I think this may be a problem exclusive to ISE. I could not repro but recently went around with MS on inconsistent ISE workflow behavior and after some effort the issue was closed without a solution, with the official answer being to not use ISE which is not approved for production and instead use the native shell. It was a realistic answer for us, never saw the issues in native shell. I wonder if it's the same on this symptom?
I have found that the FunctionsToExport section in the module manifest cannot be set to *
THIS IS BAD:
# Functions to export from this module, for best performance, do not use
# wildcards and do not delete the entry, use an empty array if there are no
# functions to export.
FunctionsToExport = '*'
THIS IS GOOD:
# Functions to export from this module...
FunctionsToExport = 'Test-Function, Test-Function2'