Strict Mode #169
Replies: 13 comments
-
I use it religiously in modules and consider it a mandatory best practice for any PowerShell scripts/modules that you share with others. For any module I create, in the manifest I invoke Set-StrictMode -Version Latest at the top, unless the module uses WMI (in which case there can be many errors with "Latest", so I limit it to -Version 2). The value for me is huge. PowerShell watches my back and raises errors that I may otherwise not have noticed, and by using it in my module I ensure that no matter where my module is imported, whether strict mode is being used or not, the module will work as it was intended. I also use it religiously in standalone scripts I share, for the same reason. Without it, if you share code with others you may have someone complain about errors that show up because the module/script was loaded somewhere that strict mode is enabled. An alternative approach would be to explicitly turn strict mode off in your script module or shared standalone scripts if you don't want what it gives you and if you want to make sure that your content works if it is loaded somewhere else where strict mode is enabled, but I would only recommend doing that if strict mode actually generated incorrect errors that couldn't be worked around with proper coding (i.e. bugs in strict mode itself like the WMI issue, but in that case using version 2 works around the problem). I have yet to find anything other than the WMI issue with strict mode though, so I don't expect turning it off completely would be necessary. Day to day though, I don't use script mode in ad-hoc command invocation in a PowerShell host because I have no need for it there. It's really only beneficial when you move into programming with PowerShell. |
Beta Was this translation helpful? Give feedback.
-
This is interesting. Do you remember an example of the issue?
Here is what I recorded:
The last issue is probably just a defect which eventually may be fixed. But the |
Beta Was this translation helpful? Give feedback.
-
Here's the WMI issue I was talking about with the "Latest" version of StrictMode (which really means anything higher than 2 as long as this issue exists):
That last line will cause a terminating error to be raised, but only when using a strict mode that is greater than 2. If you change the -Version value from "Latest" to "2" on the first line, then the last line simply doesn't return anything, and no error is generated. It is confirmed to be a bug by Microsoft, and they have logged it internally, but it still exists in 5.0.10586. You can reproduce this by accessing other parts of WMI as well (e.g. $c.PSBase.Properties['DoesNotExist'] will give you the same behaviour), so it's not strictly related to retrieving amended data from WMI. Also, since these collections don't have a Contains or ContainsKey method (they aren't like hashtables or other dictionaries), there is no way to test for the presence of an index other than to attempt to retrieve it, so there isn't a valid workaround. For surrogate properties failing, that is a feature of -Version 2 of StrictMode. Those properties only exist because of some syntactic magic that was added to fix bugs that would show up when people weren't writing proper code. Even with that syntactic magic added, I still advocate for wrapping anything you expect to be an array in array enclosures, because then it will always be an array, even if it only contains one item. All to say, from my perspective, it isn't safe to use surrogate Count and Length properties without explicitly tuning down your strict mode level, and if you're like me thinking that's not a compromise that you're willing to make with your code as a whole, then you'll opt for array enclosures instead because it's a whole lot less work to use them than it is to turn down strict mode just for a little bit of lazy programming. For the Out-String issue, that's not a bug in Out-String. It's a bug in the format code for ErrorRecord objects defined in PowerShellCore.format.ps1xml. That logic is assuming too much information about $host, which is why the error occurs when StrictMode is version 2 or later. That code should coditionally check $host to ensure that it has a the properties it is looking for and if not, it should assume a default value for width. Right now it's just lucky logic because a $null value for $host.UI.RawUI.BufferSize.Width results in a negative value for the $width variable, and when you split on a negative length the string just doesn't split. It's buggy code regardless of the StrictMode value though because it isn't calculating the indent properly even when $host.UI.RawUI.BufferSize.Width is available, as can be seen by running this in the native PowerShell console:
That formatting bug is only really visible when you have an error message that would span multiple lines. Notice how the line wrapping of that message is somewhat arbitrary, and the indent fades away as more lines are added. The logic in that format file should set strict mode to version 1 when trying to get the buffer width (like it does just about everywhere else -- this code isn't written very well), and then if the buffer width comes up as null it should assume a default width or explicitly not split the message (and not just by chance like it does right now). That code should also have the indentation logic fixed, but that's completely independent of strict mode impacts. |
Beta Was this translation helpful? Give feedback.
-
@KirkMunro, thank you for interesting details and thoughts. As for the the script analyzer, I am not sure. I use strict mode in my internal scripts and I test my public scripts with the strict mode enabled. But I normally do not publish code with the strict mode enabled. So I would prefer if the analyzer does not force me to use this mode. |
Beta Was this translation helpful? Give feedback.
-
I agree that it shouldn't be forced by script analyzer. I wasn't proposing that, or anything related to script analyzer yet because these are my views and there is need for community consensus here. If anything is done in script analyzer with respect to strict mode, I would list it as recommended for modules (which are not dot sourced, and therefore current scope is not impacted), and I wouldn't do anything for scripts because script analyzer cannot identify whether the script will be dot sourced or not, and dot sourcing would impact strict mode in the current scope. Functionality that should be run with script mode enabled is primarily modules, in my opinion, because those are more of a programming entity. It can't be forced at all though because PowerShell is a scripting language first, and while I prefer using it as a programming language, the majority of the PowerShell community are simply not there and don't think that way. |
Beta Was this translation helpful? Give feedback.
-
My bad, I mentioned the script analyzer but was rather thinking of recommendations and gudelines. The recommendation for enabling strict mode in modules makes sense and looks good. |
Beta Was this translation helpful? Give feedback.
-
I strongly dislike strict mode, and wouldn't ever recommend people use it. writing things like: if(Test-Path variable:local:Foo) { ... }
if($HashTable.ContainsKey("Property") -and $HashTable.Property) { ... } Instead of if($local:foo) { ... }
if($HashTable.Property) { ... } drives me crazy, and makes code less readable. I know that I'm in the minority among former static language users, but I feel like strict mode is like coding with gloves on. Having said that, I would not go so far as to recommend against using it within a module (I would recommend against using it at the console), but because it affects child-scopes, you should be cautious when using it, as it can affect other people's code if you're using it and importing other modules. |
Beta Was this translation helpful? Give feedback.
-
The real question is, should we even care?The style guide rules focus on readability, to which StrictMode is tangential at best, detrimental at worst. The best practices focus on readable code, faster code, and coding practices that help you avoid shooting yourself in the foot... In my personal opinion, a language StrictMode should be about helping you to develop good habits. It's important to realize that PowerShell's strictmode is not a parsing mode, it's a runtime mode. Instead of forcing you to initialize variables, it causes you to test for them in strange ways. Additionally, rather than forcing you to test for things (like uninitialized variables), it allows you to rely on strict mode to cause an error (which you can "handle"). In other words, rather than forcing best practices, it forces you to write less readable code, and can even become a crutch where you skip testing for empty/unintialized variables (because you assume they'll blow up if they're empty). This impedes readability (the implied test is invisible) rather than improving it, and doesn't actually improve the quality of your scripts. Personally, I'd prefer static analysis to point out the problems which StrictMode attempts to address. Further -- there doesn't seem to be any documentation of changes to StrictMode post |
Beta Was this translation helpful? Give feedback.
-
FWIW, I can't think of any situation where I've needed to test for a variable's existence, rather than its value. Strict mode can help with identifying bugs that come from typos in your variable names (though I rarely have that problem since I compulsively tab-complete everything. :) ) |
Beta Was this translation helpful? Give feedback.
-
@dlwyatt Your lack of imagination is not my problem ;-) There are plenty of commands like Another case is when you're using preference variables like $OFS which by default are not set. |
Beta Was this translation helpful? Give feedback.
-
@Jaykul I strongly disagree with your assertion that:
While that is a valid opinion, and I agree with much of what you say from a convenience point of view, that doesn't strike me as a true summation of the purpose of this guide. From this repo's Readme:
Set-StrictMode absolutely makes it "harder to get into trouble". Readability for me also includes having to read code during code-reviews; especially where not everyone contributing to the script has as much PS experience as some others. Was this a deliberate use of "funky feature" or was it a mistake? Were all possible cases considered etc.; at it's simplest this means always ensuring what you request is actually there. |
Beta Was this translation helpful? Give feedback.
-
@MartinSGill you've missed half of my quote there. This is a two-part project: Style Guide and Best Practices. I did say that "The style guide rules focus on readability" -- I also said that the "best practices focus on readable code, faster code, and coding practices that help you avoid shooting yourself in the foot." However, I will repeat myself, and give an example. A static analyzer is better at catching most of these things, and StrictMode causes as many problems as it fixes. Since we haven't had any examples yet, consider this typo that StrictMode would detect: function Test-Code {
[CmdletBinding()]param()
Set-StrictMode -Version Latest
$MassiveList = Get-ChildItem # Imagine I'm doing some filtering for .ps1 or .psm1 files
<# Imagine code here to configure a complicated code linter #>
try {
# Now Imagine that ACL stands for AdvancedCodeLinting ;-)
$MassveList | Get-ACL
} catch {
Write-Warning "Unable to process all files, please try again."
}
}
Strict mode would instead like to cause an exception at runtime:
But because of the exception handling, the exception is caught and hidden. Of course, if we called the code with In this case, the exception handling is clearly bad -- but it could have been much better and still unknowingly suppressed that error. Worse: the exception handling could have been in a function that called mine, or just in your environment (ErrorActionPreference, WarningActionPreference). Worse still, the "help" that StrictMode provides is not provided at an appropriate time. It happens at run time -- not (only) when I am developing the script, but (also) when someone else is running it! There's no use in causing exceptions there. If you think the exception is fine, that I'll catch this in my testing:
In my opinion, test time is the only time when it's reasonable to use strict mode. I might even be willing to recommend using it there, although to be honest, I still dislike it (as mentioned earlier, it prohibits code that is perfectly safe and valid, forcing slower tests). |
Beta Was this translation helpful? Give feedback.
-
That's a valid point and I'd not considered the timing implications. I'm showing my background from compiled languages. I think the timing argument is probably your strongest point, from my perspective at least. The advantage StrictMode has over a tool like PSSA, though, is that it's part of the language and doesn't require additional things to be installed. For novice users working on shared scripts, that maybe don't realise they need to install/run PSSA, or use an editor that supports it instead of just syntax highlighting, it will at least find the worst offences when they try to run the script. Maybe I just have a prejudice against uninitialised variables, given how much time I've had to spend fixing issues in my c/c++ days related to them. |
Beta Was this translation helpful? Give feedback.
-
What's the community's view on Strict Mode? Is there one? Should there be one?
Beta Was this translation helpful? Give feedback.
All reactions