PowerShell Module cannot be loaded when running Pester test in Visual Studio - powershell

I have created a PowerShell test script, Common.tests.ps1, using Pester against some functions in a PowerShell script, Common.ps1, in the same directory.
There is a TestInitializer.ps1 script, also in the same directory, which uses the Microsoft.Xrm.Data.PowerShell module to create and get records in a Dynamics CRM instance.
When running the PowerShell test script from Visual Studio, the test fails in the Test Explorer with a message:
CommandNotFoundException: The module 'Microsoft.Xrm.Data.PowerShell' could not be loaded. For more information, run 'Import-Module Microsoft.Xrm.Data.PowerShell'.
The same test when run from the PowerShell ISE, however, runs without issue. This would seem to be as if the module is not installed for the instance as run by Visual Studio (I confirmed this when running Get-Module -ListAvailable and seeing that the output did not include the Microsoft.Xrm.Data.PowerShell module for the Visual Studio test), though even explicit calls like Import-Module Microsoft.Xrm.Data.PowerShell -Global -Force don't seem to load the module during the script execution with Visual Studio.
Here's Common.test.ps1:
$here = (Split-Path -Parent $MyInvocation.MyCommand.Path)
. $here\Common.ps1
. $here\TestInitializer.ps1
Describe "SelectionToSingleCharString" {
Context "StringTransforms" {
It "Retrieves a CRM record and uses the optionset value to retrieve a single character" {
SelectionToSingleCharString($crmRecord.new_type) | Should Be "I"
}
}
}
Snippet from TestInitializer.ps1:
# Whether or not this is uncommented does not matter
#Import-Module "$env:SystemRoot\System32\WindowsPowerShell\v1.0\Modules\Microsoft.Xrm.Data.PowerShell\Microsoft.Xrm.Data.PowerShell.psd1" -Global -Force
#$modules = Get-Module -ListAvailable
#Write-Host $modules
# Failing here
Microsoft.Xrm.Data.PowerShell\Connect-CrmOnPremDiscovery -ServerUrl $loginServerUrl -OrganizationName $loginOrgName -Credential $cred
I may instead design the test to use Mock instead of actually attempting to create/read records, though not being able to load external modules and run in Visual Studio would be limiting.

Regarding module install directories (skip this if you are interested in the actual problem):
First you should never install modules to $PSHome\Modules (%Windir%\System32\WindowsPowerShell\v1.0\Modules). This folder is reserved for modules shipped with Windows only.
You should always install your modules used only by your user under the following path:
$Home\Documents\WindowsPowerShell\Modules
And for a system-wide installation under:
$Env:ProgramFiles\WindowsPowerShell\Modules
Further reading regarding installing modules in PowerShell can be found on MSDN.
Regarding your actual problem:
What Visual Studio Version are you using? I have Visual Studio 2017 Community edition installed and can not reproduce your error. My PowerShell is also running as a 64-bit process. Your PowerShell could be running as a 32-bit process. For the 32-bit PowerShell the module directories are different. This would explain why the module you installed isn't showing up in Visual Studio.
You can verify if your PowerShell is running in a 64-bit process with the following command:
PS> [Environment]::Is64BitProcess
True
To make your modules accessible for the 32-bit PowerShell you need to install them under the following path as well:
{$Env:ProgramFiles(x86)}\WindowsPowerShell\Modules

Related

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.

TFS vNext Powershell build step is using older version of Powershell module

a build with Powershell++ (it comes from Extension Utilities Pack) step keeps failing when I try to run task containing following code Copy-Item -FromSession $cs to copy items from different machine. The error message is
A parameter cannot be found that matches parameter name 'FromSession'.
However, the code does not fail when run from PS console when I'm logged to that machine.
Then I included
(get-command copy-item).Version.ToString()
(get-command copy-item).ModuleName.ToString()
And got version 3.1.0.0 and module Microsoft.PowerShell.Management in PS console and 3.0.0.0 in TFS build step output (module is the same). The version of Powershell is identical in both - 5.0.10586.117.
Looks like the Powershell that is running inside TFS is using different modules.
Can anybody help? Thanks.
Shame on me for not knowing enough about Powershell providers. When wildcard was included in the source path I got this error, without the wildcard it worked fine.
The FromSession parameter is available in PS v5 and not limited to Microsoft.PowerShell.Management 3.0.0.0 (but that is still a mystery to me).

Create pure powershell Nuget module for PowerShellGet

What I want
I want to publish number of PowerShell scripts as Nuget package to be used on build systems.
I want to use PowerShellGet to do installation work for me and version management.
I don't want those scripts to be part of any Visual Studio solution, but as standalone scripts.
Usage scenario
On any system, with configured Nuget provider user executes:
Install-Module MyModule
From that moment all exports from that module permanently available for this user.
Also user can call that command again to update version of those scripts.
What I've done
You can find current state of package here: GitHub
I've added and configured Nuget provider to our local Nuget server
To do this call Get-PackageProvider -Name NuGet -ForceBootstrap and Set-PSRepository -Name My_Nuget_Repo -SourceLocation http://my-nuget/api -InstallationPolicy Trusted
Created proper module, which can be imported locally by Import-Module
Created and published Nuget package with that module
Problem
I can install that package by Install-Module cmdlet and I can see it later in Get-InstalledModule list.
But, no functions are available.
Also, no matter what, but Install-Module not calling any of scripts from my package:
Not calling ScriptsToProcess from MyModule.psd1
Not calling Install.ps1 from tools folder
Not calling Init.ps1 from tools folder
Cmdlets exported by module not available and module can't be imported by Import-Module
(Same package works properly when installed from Visual Studios Install-Package MyModule, scripts are called, PowerShell module is imported).
Investigation
Since PowerShellGet is based on OneGet it seems that problem is in Install-Package cmdlet (which is called inside Install-Module cmdlet).
When I'm executing Install-Package MyModule from Visual Studio Install.ps1 and Init.ps1 are called. But same command from pure PowerShell doing nothing.
After long reverse engineering I've found the root cause
Technical reason
Magical tag PSModule has to be added to <Tags> in nuspec file.
Real reason
You shouldn't create nuspec file and pack nuget package manually at all. Use Publish-Module cmdlet instead.
How to do it properly
I've updated powershellget-module GitHub with:
Example of minimal module which can be published
A way how to use local folder as Nuget feed
Publishing, installation and usage of that module
Reference script with no dependencies which does it all locally, so you can study it
Check it out.

WebAdministration module not found

I have installed a WebServer 2008 R2 Core version and I'm trying to configure it to be remotely managed from another server in the domain I need to import the WebAdministration module According to the steps exposed in this article
http://www.iis.net/learn/install/installing-iis-7/install-and-configure-iis-on-server-core
using the Import-module WebAdministration it gives me the specified module 'WebAdministration' was not loaded because no valid module file was found in any module directoryAt line1 char 14. I executed the command Get-Module -ListAvailable and returned 4 module types
BestPractices, BitsTrabsfer, PSDiagnostics and ServeManager
I read the other threads about the issue none of them is consistent and proposes a good solution to that. BTW is there a way to let the server download the requested modules form microsoft repository if not found. Any consistent proposal to solve this will be appreciated
Is the IIS PowerShell Snap-In installed? If not, you can download the 32-Bit version or the 64-Bit version. After you run the MSI (using msiexec /i, since this is core), the snap-in should be registered and can be invoked via import-module or
& "$env:programfiles\IIS\PowerShellSnapin\iisConsole.psc1"
On Windows 7 I installed Web Platform Installer from
https://www.microsoft.com/web/downloads/
On the start menu search for "web" to make the app visible.
Then using Web Platform Installer ... Install IIS: Management Scripts and Tools
Make sure that the IIS is installed and configured properly

TFS post build powershell script not seeing commands from imported module

We have a TFS build process using a custom template. The build works fine with the crm solution files successfully being created. We are then attempting to run a powershell script on the post build. This script imports a module. But the commands in the module are not being exposed. Whenever we attempt to invoke a command, we get an error. Along the lines of
The term 'Get-XrmSolution' is not recognized as the name of a cmdlet,
function, script file, or operable program.
It doesn't matter which command we use in that module, we get the same kind of error.
To troubleshoot, we have logged onto the build server under the identity of the build account and can successfully run the script we are attempting to run.
Putting some more output into the script to troubleshoot...
Get-Module lists Xrm.Framework.CI.PowerShell. - Good.
Get-Command -Module "Xrm.Framework.CI.PowerShell" returns nothing. From the console, a number of commands are listed.
Is there something we need to do with the running of powershell post build scripts to enable the contents of an imported module to be seen?
Watch out for the bitness of PowerShell invoked by MSBuild and likewise, the bitness of MSBuild launched by Visual Studio. Certain modules only run in either 32-bit or 64-bit PowerShell and not both. You want to make sure the correct version of PowerShell is getting launched.
IIRC you have to explicitly import the module with no assumption of being loaded on user profile, nor on the script path.
Suppose Module1.psm1 is in the same folder as your script, use something like
Import-Module (Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Definition) 'Module1.psm1')
I had the same problem.
The module was loaded in the 'C:\Program Files\WindowsPowerShell\Modules' folder (64 bits).
It all seemed fine when I logged on as the user, but it failed during TFS build.
Solution: I had to uninstall the module in PowerShell 64 bit and re-install in PowerShell 32 bit.
The module was then installed in 'C:\Program Files (x86)\WindowsPowerShell\Modules' folder.