Background: The "1" in ".ps1" stands for PowerShell 1.0. But as 2.0 is compatible with 1.0, the script file kept using the .ps1 extension without starting .ps2.
Today PowerShell is being brought to Linux and macOS. There will be more and more breaking changes in PowerShell 6.0 and later. (One possible example is removing UNIX alias.) I think it's time to create a mechanism to avoid breaking legacy code when making "breaking changes". One way is to re-enable the version number in the .ps1 extension.
Assume we have PowerShell 6.0 installed. When invoking a script ends with .ps6, enable all new "breaking changes". But if it's .ps1, keep the behavior as the old version (best effort).
We can avoid breaking changes and keep backwards compatibility for the moment, but we can't do it forever. We should have some mechanisms to keep backwards compatibility when introducing "breaking changes" to the new version, so that we will not fear making "breaking changes".
Of course file name extension is not the only way to mark the version of a script. We can pick up another way if it's better.
Just kidding: Soon you will suffer from 8.3 (short) name compatibility issues. 😂
@GeeLaw That will be one breaking change in PowerShell 10.0 😆 (Just kidding)
Is this required? Powershell already supports the #Requires -version X directive in scripts to set minimum compatible version. MSDN about_requires
@ebelew Indeed this has been available since v3 and is already a well known feature that doesn't require additional work or hassle for users/administrators
@ebelew @kilasuit Thank you. But is there a way to set a known maximum compatible version?
nope - it is minimum version version only
Could you expand on the reason for needing to set a maximum version?
@kilasuit Assume we wrote a script today which uses UNIX alias such as wget for Invoke-WebRequest, and in some later PowerShell versions, that alias is removed. It will stop working.
If PowerShell engine can know which version the script is wrtten for, it may be able to provide compatibility mode for legacy scripts.
Thats simple = dont ever use Aliases in scripts! We even have a rule in the Static analysis engine PSScriptAnalyzer https://github.com/PowerShell/PSScriptAnalyzer warning about this.
PowerShell engine will not run a script in downlevel versions if you were to put in
#Requires -version 6.0
Aliases are only really intended for interactive use so using them in scripts is really an anti-practice and something that I would seriously recommend against using
@kilasuit I agree with you, but the alias issue is just an example.
If we can let PowerShell know the version a script is created for, we will be able to introduce "breaking changes" to PowerShell itself in the future by providing compatibility mode for legacy scripts (if we don't want to break them).
We already have this with the requires statement which to fit your suggestion would be better if that was expanded to include a -maxversion arguement.
changing the ps1 to ps6 isnt really a suitable idea for this as this will increment through the versions and I'm not sure that there is much benefit in enforcing that going forward.
I would either change the issue title to expand #Requires should have a -MaxVersion arguement or raise a new issue on this.
However even then that would be a breaking change (as not down compat) so would require an RFC
@kilasuit I would prefer changing the title to something like "let PowerShell know the version a script is written for".
Add -MaxVersion to #Requires is a breaking change, but use ".ps6" is not. While I agree with you that it will increment through versions, which is not good.
I would suggest using "#Prefers -Version 5.0" rather than "#Requires -MaxVersion 5.0". Because:
BTW. If we don't plan to use version number in file name extension (.ps1, .psm1) any more, we should consider setting the default extension to .ps, .psm.
Thanks
Except that .ps is postscript, and has been for decades.
I would prefer we used the #! syntax, which would allow old versions to ignore it, and fail on unsupported features, but still allow the script author to say something like #!powershell -version 6. This mechanism would also allow a script to request -noprofile and other useful flags for non-interactive.
@kilasuit This won't, by adding some extra logic for compatibility. If a script requires MinVersion ≥ 6.0, or sets a MaxVersionTested, we'll know that the script is new and will use the new logic. If it sets MinVersion < 6.0 and does not set MaxVersionTested, do the things like it was invoked by 5.0.
The argument is that, Microsoft already does this for Windows applications (applications need a manifest to declare their support for systems with GUIDs or by default get some compat shims, like VersionLie, after 8.1, and UWPs have manifests with MaxVersionTested). This seems to be a good compat practice and it worth considering.
And I suggest we has better not drop the “1” out of the extensions.
@GeeLaw Thank you for the explanation.
For dropping "1" out of the extensions, can we support both (with "1" and without "1")? We can start from some version (e.g. 6.0) so we can get rid of the "1" gradually in the future.
I don´t see it as '.ps1' ever have been about PowerShell Version 1.
it dictate the structure and content of the file.
Lets say Microsoft wanted support binary compiled script files.
This would not work with a '.ps1' file, but it could be supported with a '.ps2' file.
So as I see it, the idea is that if Microsoft for some reason needed to change the structure of a script file, they could do it by bumping the number in the extension.
Jeffrey Snover explained why the .ps1 file extension was retaIned In subsequent PowerShell releases a while back. The '1' denotes the current side by side version rather than the current language version. Link and excerpt follow.
https://blogs.msdn.microsoft.com/powershell/2007/11/02/ctp-versioning/
PowerShell Scripts continue to use “.PS1”.
We will continue to pursue this approach until there is a major change in the CLR or .NET frameworks which force us to go side-by-side. It is at that point that we’ll go from .PS1 to .PS2 . Until then we will stay with .PS1 and everything that runs today will continue to run in new releases.
You might write a .PS1 script which takes advantage of a cmdlet/feature that is only available in V2. If you send this to someone that has PS V1, it will fail “in some way and at some time”. If it uses some new syntax, it will fail at parse time (with a PARSER error) but if it uses a new command line switch – it won’t fail until it tries to run that command. This is what #REQUIRES is all about. You start your script with
And we will check version #’s and produce a precise error message
If you have a #REQUIRES –VERSION 1 in your script, it will continue to run just find on PowerShell (V2) CTP because it is compatible with V1.
Thank you, @belstarr. I'm closing this issue.
Most helpful comment
I don´t see it as '.ps1' ever have been about PowerShell Version 1.
it dictate the structure and content of the file.
Lets say Microsoft wanted support binary compiled script files.
This would not work with a '.ps1' file, but it could be supported with a '.ps2' file.
So as I see it, the idea is that if Microsoft for some reason needed to change the structure of a script file, they could do it by bumping the number in the extension.