How to determine which version of PowerShell is installed on a PC - powershell

I am writing a script which check the version of PowerShell. If it's version 4 then proceed, otherwise stop the execution. What I am trying to achieve here is I have five scripts in a folder which are run in order. I would like to put a PowerShell script right at the top which checks the version.
Here is my code:
$psversion= $psversiontable
if($psversion -eq 4.0)
{
./01. Run All Script.ps1
}
"Run All Script" runs the rest of the scripts in order, so I would like to give PowerShell script as 02. check_psversion.ps1
requires -version 4
write-host "this is your version"

You don't need to write any if tests; use the requires directive in all of your scripts (never assume or depend upon execution order, be explicit in each script).
#requires -version 4
If you attempt to execute the script on version 3 or earlier, it will stop because of the requires directive.
Edit: To get the Powershell version number, use $psversiontable.psversion.major, unless you need finer resolution (exact build number).

Related

.Bat file unable to run powershell 7

I have set up a very simple .bat file to execute a couple of commands to save me typing them out every time, however the processes need to be run in powershell 7.
If i manually run powershell 7.0.3 and then run the commands everything work, however running the .bat script starting
powershell -Version 7.0.3 -Command {XXXXX};
presents me with a message "Cannot start Windows PowerShell version 7.0.3 because it is not installed."
If i try and run it without the version number then it runs in 5.1.x and this then fails as it requires 6+.
tl;dr
As Lee_Dailey notes, you must use pwsh.exe, not powershell.exe, to start a version of PowerShell [Core] v6+ and you must invoke the desired version's specific executable.
In the simplest case:
pwsh -Command "XXXXX"
Note that I've replaced {XXXXX} with "XXXXX", because you cannot directly execute script blocks ({...}) from outside PowerShell - just supply the commands as a string.
Given that - unlike with Windows PowerShell - you can install multiple PowerShell [Core] versions side by side:
Run pwsh -version (sic; see below) to report the version in your system's path (the instance that comes first among the directories listed in the PATH environment variable, $env:PATH).
If it is not the one you want to target, you'll have to invoke it via its full path:
If you want to rely on the standard installation location, you can use the following on Windows for version 7.0: "C:\Program Files\PowerShell\7\pwsh.exe"
To determine the target version's executable location reliably, open an interactive console for it and run (Get-Process -Id $PID).Path
The -Version parameter of powershell.exe, the Windows PowerShell CLI, does not allow you to start just any PowerShell version, only an older version of Windows PowerShell:
In fact, the only supported argument is -Version 2, and even that will only succeed if you have previously installed the required legacy versions of .NET Framework.
Caveat: While versions higher than v5.1 - the latest and last Windows PowerShell version - sensibly result in an error (the one you saw), unsupported lower versions are quietly ignored; in effect, -Version 1 and -Version 2 will both start version 2.0, whereas -Version 3, -Version 4 and -Version 5 are effectively ignored and run v5.1 - verify with $PSVersionTable.PSVersion
While a -Version parameter still exists in pwsh.exe, the PowerShell [Core] v6+ CLI, its meaning has changed:
It now simply reports a version number, namely the targeted executable's own (and therefore takes no argument).

How to force a Powershell Script to run a specific Version

I have both Powershell 5.1 and Powershell 7.0 on my computer and I'm try to run a script that has to be run in Powershell 7.0. How do I make the script run in a specific version.
If it's a script being invoked in a PS shell, you could relaunch it if it's not the correct version.
# At beginning of .ps1
if ($PSVersionTable.PSVersion -ne [Version]"5.1") {
# Re-launch as version 5 if we're not already
powershell -Version 5.1 -File $MyInvocation.MyCommand.Definition
exit
}
# Your script code
If the scripts are launched via Task Scheduler, you could just use the full path to the .exe in the "Actions -> Start a program" section, as they have separate install locations.
another option is to use #Requires statement
#Requires -Version 7.0
here is the reference from Microsoft support
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_requires

SCCM Powershell Script Package

I have created a package in SCCM 2012 that should deploy and run a powershell script. I have looked at a previous post on here Other Post but there wasn't any information.
In the Program Command Line, I have the following command:
powershell.exe -ExecutionPolicy Bypass -force -WindowStyle Hidden .\PowershellUpdateScript.ps1
I am targeting a test group and setting it to deploy immediately however when I check the deployment status, it shows as status "In Progress" and Description "Received". It has been that way for over 2 hours. I am not sure where the issue is.
I know that the Scripts feature is there and super convenient but the client powershell version needs to be a minimum version 3. The irony is that this package will update client powershell versions.
Any suggestions or advise would be greatly appreciated.
Since you are updating the powershell version, instead of using a powershell script you should download the MS update package for the version of powershell.
You can then use the wusa.exe command to deploy the update. Then use this ps command as a detection method
Get-WmiObject Win32_QuickFixEngineering -filter "HotFixID='KB#######'"

PowerShell code behaving differently under SCCM and MDT TaskSequences

I've got code that has been extensively tested across multiple PowerShell sessions, multiple machines, etc all doing exactly what I expect.
switch ($e.Data.Type) `
{
{$_ -in [Policy.Reg]::SZ, [Policy.Reg]::EXPAND_SZ} `
{
$e.Data[$e.Data.Type] = ([string]$e.Data[$e.Data.Type]) -replace "{PC}", "$PC"
}
{$_ -in [Policy.Reg]::MULTI_SZ} `
{
$e.Data[$e.Data.Type] = [string[]]($e.Data[$e.Data.Type] | % { $_ -replace "{PC}", "$PC" })
}
}
[Policy.Reg] is an Enum that $e.Data.Type is a variable of that enum
Running the code from the ISE or the Powershell command line code works every time.
When I add it as a RunPowerShell task sequence step (MDT 2012/2013 and SCCM 2012 all tried) the task sequence fails with
you must provide a value expression on the right-hand side of the '-' operator. [Policy.Reg]::SZ, [Policy.Reg]::EXPAND_SZ
I'm at a complete loss what is going on when a TaskSequence runs a Powershell script that makes it different than when I manually execute the some code.
So really quick it seems my issue was with MDT itself.
The standard wsf and vbs files that control PowerShell Execution check for the existence in the registry for the currently installed version and then runs one of two executables that sets up a unique PowerShell environment.
One of the Exes just runs the most recent version of powershell.
The other forces it to run in powershell 2.0 (for compatibility i'm guessing)
Here's the issue the LOGIC in the script file is all wrong
Instead of being something like
if (PSVersion >= 2.0) then
Run newest PowerShell
else
Run PowerShell 2.0
end if
It looks like
if (PSVersion = 3.0 then
Run newest Powershell
else
Run Powershell 2.0
end if
So since all my images have PowerShell 4.0 installed on them, well as LOGIC dictates 4.0 is NOT equal to 3.0 so off to PowerShell 2.0 we go and toss out ALL the things we have gotten used to having since we spent a LONG time ensuring every system in our environment is at least on PowerShell 4.0
So in the end a little code change to the code Launching the PowerShell Scripts fixed the issue.

PowerShell Version check prior to script execution

I'm just asking the communitty if they have come across a way to have the a script check what version of POSH is running prior to the execution of the script. Currently, my work around is the following code:
#region Final Checks
#//Check to make sure that version of PowerShell is at least 3.0 before preceding.
If($PSVersionTable.PSVersion.Major -le 2) {
Throw "This script has not been tested with version 2.0 or older of PowerShell. Please execute this script from a system that has PowerShell 3.0 or newer installed. Windows 8/Server 2012 and newer has it installed by default. Windows 7/Server 2008 R2 can be patched to have 3.0 installed."
}
#endregion Final Checks
I have this right after defining my parameters. However, for my own crazy sake, I want the script to preform this check automatically prior to getting into the meat and potato of the script. A good comparison is using Validate[X] for a parameter. If an operator tries to provide data that doesn't fit my user, an error is thrown prior to the execution of the script. Any ideas? I know that there is nothing in [CmdletBinding()] that does it. Thanks!
You can use #Requires at the top of your script as a way of telling PowerShell what your script needs to do it's thing.
In your specific case you would put
#Requires -Version 3
This will tell PowerShell that at least PowerShell Version 3 is needed, if someone tries to run the script with PowerShell Version 2 they will receive the following message:
The script 'version3.ps1' cannot be run because it contained a "#requires" statement at line 1 for Windows PowerShell version 3.0. The version required by the script does not match the currently running version of Windows PowerShell version 2
.0.
At line:1 char:2
+ & <<<< C:\Users\testuser\Desktop\version3.ps1
+ CategoryInfo : ResourceUnavailable: (version3.ps1:String) [], ScriptRequiresException
+ FullyQualifiedErrorId : ScriptRequiresUnmatchedPSVersion
In addition to Version you can require other things as well, all of which are listed in about_Requires on TechNet: https://technet.microsoft.com/en-us/library/hh847765.aspx
#Requires -Version 4
#Requires -Module MyCmdlets
Write-Host "If you see this, you are running Version 4 and have the MyCmdlets Module available"
#Requires was added in PowerShell 5 Will not work in earlier versions.