I do not know what is exactly happening, when one uses either 'Input' or 'Host' as parameter name for advanced functions/cmdlets.
But from time to time I forget that it is dangerous to use those as parameter names and this then produces hours of debugging, because really weird things might happen (they do not necessarily happen all the time).
It would be good, if Powershell wouldn't allow those names as parameter names at an early stage, like e.g. when importing a module which contains advanced functions/cmdlets it could fail with an error message, that those names must not be uses as parameter name for a cmdlet.
I recently ran into this issue myself. I had to go really deep troubleshooting it to identify exactly what was happening. Once I was sure that I knew exactly the way was broken (Value getting into the parameter but empty in the default end block), only then did I remember $input is a magic variable. It is so rare for me to think about that one that it completely slipped my mind when I was fighting the problems it caused. I know I have had similar issues with $host in the past.
The variable names $input and $host are very generic and could commonly be used for parameters. The problems presented are different if the parameter is or is not mandatory adding to the confusion.
function test-input{
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
$Input
)
if(-not $Input) {
throw "This should never happen"
}
"No issues here [$Input]"
}
Test-Input -Input "Test Value" # exception
"also fails" | Test-Input -input "other" # also exception
If we remove the mandatory attribute, we get these results that are a more expected if you realize that $Input is a special variable:
PS> Test-Input -Input "Definitely not null or empty"
No issues here []
PS> "CrazyTown" | Test-Input -Input "Definitely not null or empty"
No issues here [CrazyTown]
We also need a Script Analyzer rule in the short term for this one.
Edit: There already are Script Analyzer rules for these. Not sure how I missed it in my case.
This time it was 'Host' which caused troubles for me.
Thing is:
A cmdlet named 'Invoke-SQLQuery' with this parameter name ($Host) is in a self written module and was used successfully some months by automated tests under Windows Powershell 5.1.
It also did not run into problems on a machine where we use Powershell Core 7.0.x for evaluating purposes (we want to switch to Core generally).
Then the test which uses this cmdlet was changed slightly (an command line utility now gets called some lines BEFORE the call to 'Invoke-SQLQuery' and from that time on it started to crash the test on the machine where Core is used, but still not on the other machines.
The test writers looked into the issue and at the end came to me, because they couldn't find out what was going on in this case.
My first thought was: Must be the newly added 2 lines of code where the command line utility gets called and its output processed.
I commented those lines out and voil谩 - everything worked again!!! (As said, those 2 lines are BEFORE the code where ''Invoke-SQLQuery' gets called!)
So for sure I wanted to check which of those two newly added lines caused the trouble.
I then re-enabled the line which would process the output (already initialized with a short string).
Still no crash - as expected, because this just did a replace in the string and I anyway thought it would be the call of the external command line tool.
Thus I did it the other way around:
I re-enabled the line with the call to the command-line tool and out-commented the string processing line and expected to get into troubles again.
But all went well!
Then enabled both lines again and the crash was back - it happened at some point where the module containing 'Invoke-SQLQuery' is in got loaded, but I was not really able to exactly determine the place/line where it occurred - but it was NOT at the beginning of 'Invoke-SQLQuery'.
The error message said something about 'reference to object' and each time I reached that point I had to close 'Visual Code', because stopping the debugger didn't work...
Hours later 'Host' as a parameter name to 'Invoke-SQLQuery' got my attention - I renamed it to 'HostName' and from that point everything was back to normal...
I am not able to recreate your issue with $host as a parameter. It would be helpful if you could provide a way to reproduce it.
In my local testing on both 7.0.1 and 5.1, I get this error when trying to $host as a parameter and passing in a value:
WriteError: Cannot overwrite variable Host because it is read-only or constant.
I can't even assign a value to it as a normal variable. PSScriptAnalyzer is also warning me not to use it.
I would be super lucky, if I could create such an example where it actually crashes, because - as I said - it didn't crash on 5.1 even with the 2 new lines added to the test script and it also doesn't crash on 7.1 when I out-comment those 2 added lines...
I will create an example though, which at least will give a rough picture of the call sequence, which is like:
Start-Test invoked on the command line will invoke that function from a module named 'Testing'.
This function then calls a test script from some drive location (in our case a network drive).
And that test script calls 'Invoke-SQLQuery' which is located in a module named 'SQL'.
I never saw this error so far - but this is maybe because of the - although unlikely - fact that I never called 'Invoke-SQLQuery' with parameter 'Host', as that parameter has a default value which is the one which we use during our testing.
Also, I usually still work with 5.1 ISE on Windows, because I do not yet have the best experience with debugging modules in Visual Code. And on 7.1 ISE I once had PSScriptAnalyzer in use, but somehow it got lost...
The example will take a little, since it is already quite late here and we have a long weekend (including Monday) and this issue is work related.
But I will immediately try out if I manage to get this WriteError in a very quick test...
Okay, that WriteError always appears for me, if I just write a regular function or cmdlet with a parameter called 'Host' in a script file - in each case, even if I call the function without this parameter (which is not mandatory) - That's good!
Seems like the behavior is different, if the cmdlet is defined in a module...
Yes, it is! As soon as the absolutely same function is a cmdlet in a module, then this error doesn't appear and the function performs, regardless if called with the 'bad' parameter name or without it.
But no crash - that would be too simple...
(Tested from within 5.1 ISE and 7.0.1 console.)
With 'bad' parameter 'Input' there is no error message at all, also not, if function is just only in a script file. But at least one might quickly detect an issue (although not easily to understand why it happens) when using the argument to 'Input' in the called function, because it will not be the value one would expect...
Here we go:
Example.zip
This is a rough schema regarding the call sequence, where we had the issue.
Unfortunately it didn't crash for me - as expected...
Just unzip to some PoSh module directory and call 'Invoke-Test' without parameters.
This will call 'test'-script 'Main.ps1' under folder 'HopeForCrash' under the module path for module called 'Testing'. The script itself will call 'Invoke-SQLQuery' which is defined in module 'SQL'.
Most helpful comment
I recently ran into this issue myself. I had to go really deep troubleshooting it to identify exactly what was happening. Once I was sure that I knew exactly the way was broken (Value getting into the parameter but empty in the default end block), only then did I remember
$inputis a magic variable. It is so rare for me to think about that one that it completely slipped my mind when I was fighting the problems it caused. I know I have had similar issues with$hostin the past.The variable names
$inputand$hostare very generic and could commonly be used for parameters. The problems presented are different if the parameter is or is not mandatory adding to the confusion.If we remove the mandatory attribute, we get these results that are a more expected if you realize that
$Inputis a special variable:We also need a Script Analyzer rule in the short term for this one.
Edit: There already are Script Analyzer rules for these. Not sure how I missed it in my case.