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

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).

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.

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

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

Get-Module -ListAvailable doesn't display my module

I've created a module manifest .psd1 file and I've used Test-ModuleManifest on it which returns nicely and shows the two CmdLets in the binary C# .dll.
The manifest file is in a folder under c:\Program Files\WindowsPowerShell\Modules but when I run Get-Module -ListAvailable it is not showing.
If I run Get-Module it is not showing.
If I run one of the CmdLets then the module is automatically imported and shows when I next run Get-Module.
What am I misunderstanding?? Why doesn't it show as available?
Update
Just done this again with a script module, psm1 and psd1 on a different machine, and same problem. It doesn't show as available and yet posh-git which seems to be setup in a similar way, does.
Okay, the script module does now show up after I fixed a version inconsistency between the version in the manifest and the subfolder name I'd placed it in.
Came in handy:
Test-ModuleManifest

Register Powershell SnapIn to specific version of Powershell

I am trying to run an Exchange Management Shell script via managed code.
Our PowerShell version is version 4.
I am trying to use the runspaceConfiguration.AddPSSnapin() method to add the exchange SnapIn Microsoft.Exchange.Management.Powershell.E2010, however this line fails, giving :
no snapins have been registered for Powershell version 4.
A quick Get-PSSnapIn -registered shows the SnapIn is installed but registered to PS version 1.
In regEdit, I have found the registry key for the snapIn for PowerShell v1, used the export function to script the key, changed the target version to 4 and ran the export command, which has created the new key '4' under PowerShell as expected, with the snapin details copied across. However I still get the 'no snapins have been registered for Powershell version 4.', even though the key is there in the registry.
Is there something else I should be doing to register the snapin to PowerShell version 4?
Thank you for your time.
You are correct in that this is a 32/64 bit build issue. After I set the target build to x64 in VS and redeployed, all magically seemed to work fine.
The error message regarding Powershell versions is a massive Red Herring in this case.

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.