NetFirewallProfile "Enabled" arg not auto variable?

I was trying to teach my troops to use PS instead of the Windows Server GUI. My goal for the series of lessons was to show them how to find their way without memorizing a hundred modules’ cmdlets, which is how I’ve largely done it, and because our job is to raise the network from the ground up. While standing up a fresh WS2012R2 server, I mentioned automatic variables, especially Boolean values, and proceeded to run through an example (turning off IPv6 using Set-NetAdapterBinding) and, of course, its exception (disabling Windows Firewall). What I don’t understand is, ‘why’ doesn’t Set-NetFirewallProfile take a Boolean automatic variable as an argument for the -Enabled parameter, but most other cmdlets do? Please point me in some direction?

PS C:\> Set-NetFirewallProfile * -Enabled $False
Set-NetFirewallProfile : Cannot process argument transformation on parameter 'Enabled'. Cannot convert value "False" to
type "Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetSecurity.GpoBoolean". Error: "Invalid cast from
'System.Boolean' to 'Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetSecurity.GpoBoolean'."
At line:1 char:35
+ Set-NetFirewallProfile * -Enabled $False
+                                   ~~~~~~
    + CategoryInfo          : InvalidData: (:) [Set-NetFirewallProfile], ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Set-NetFirewallProfile

PS C:\> Set-NetFirewallProfile * -Enabled False
PS C:\>PS C:\> Stop-Transcript
Windows PowerShell transcript end
End time: 20180218110109

Also, why is the $false argument case sensitive?

PS C:\> PS C:\> Set-NetAdapterBinding -ifAlias eth* -ComponentID ms_tcpip6 -Enabled $False
Get-Process : A positional parameter cannot be found that accepts argument 'Set-NetAdapterBinding'.
At line:1 char:1
+ PS C:\> Set-NetAdapterBinding -ifAlias eth* -ComponentID ms_tcpip6 -E ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-Process], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.GetProcessCommand

PS C:\> Set-NetAdapterBinding -ifAlias 'eth*' -ComponentID ms_tcpip6 -Enabled $false
PS C:\> PS C:\> Set-NetAdapterBinding -ifAlias 'eth*' -ComponentID ms_tcpip6 -Enabled $False
Get-Process : A positional parameter cannot be found that accepts argument 'Set-NetAdapterBinding'.
At line:1 char:1
+ PS C:\> Set-NetAdapterBinding -ifAlias 'eth*' -ComponentID ms_tcpip6  ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-Process], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.GetProcessCommand


It has always been said that Windows is not case sensitive as *NIX is.

Well, that has never really been true. I have been in IT for 4+ decades (an educator for half that time) and counting, and using MS stack since DOSv2/Win1x (ITPro, Dev, etc). As they moved forward with there wares, I have encountered more than my share of case sensitive items, especially as .Net hit the world. With all the cross platform stuff MS is now doing, the adage needs to be changed to:

Windows is not case sensitive, except for where it is.

In your $true / $false thing. If you type any built-in variable, or any cmdlet in a different case than is expected, sometimes PoSH will coerce it, but not always. At least that been my observation. If you want to be sure you are doing the right thing with a variable, function, cmdlet or alias naming construct. Type it, click anywhere in that variable, function, cmdlet, or alias string and tap the tab key. It will covert that string to the expected case / style.

So, you are going to see this more, IMHO, because of their cross platform direction.

As for the built-in variables, argument naming. You have to used them as they are defined. Don’t get creative. Thye are desinged the way they are designed. YOu may not care for that design decision, but it is what it is.

All things are explained in the help file of each of the cmdlets relative to you query and in teaching, it’s an absolute must that you hammer in the use of the help files. Showing that help for X & Y at every turn vs just showing the cmdlet in use.

As an educator for many years, I learned this lesson early on, and in every session I deliver, the first topic covered is how to find built-in help and help yourself. Starting with keeping this in front of students for the entire class.

    # Get parameters, examples, full and Online help for a cmdlet or function

    (Get-Command -Name Set-NetFirewallProfile).Parameters
    Get-help -Name Set-NetFirewallProfile -Examples
    Get-help -Name Set-NetFirewallProfile -Full
    Get-help -Name Set-NetFirewallProfile -Online

    Set-NetFirewallProfile | Get-Member

    Get-Help about_*

    # All Help topics locations
    explorer "$pshome\$($Host.CurrentCulture.Name)"

    Get-NetFirewallProfile -Name Domain | Get-Member

If they have a question, and they have not looked at the above info, I direct them there. If they don’t find what they need to satisfy their query there, then we dig further. Education, is not just delivering, How To’s, it is also about How Come and why.

Living with the philosophy, that, relative to IT, there is most likely not a single question which can be asked, in recent years; which has not already been asked and answered in one form or the other; via a book, article, class, friend, co-worker, well, internet-wide. Now, there may never be in a single source / location, so, you have to keep digging, the greater portion of the time to get all the pieces to put together. Avoid guessing/speculation/assumptions/should do thoughts, until you have absolutely exhausted all possible knowledge avenues. Any product is a philosophy of ‘Supposed to do’, that is, what it is documented to do, vs ‘Should do / What one thinks it should do.’ That should do stuff, is based what they may have learned before, other experiences, etc. Yet, that does not matter. Learn and use the ‘Supposed to do’, then mess with the ‘let’s see if I can make it do X or Y, because I think it should do it they way I think it should.’
The latter will most likely fail, in many cases, since you may have not had little to no involvement, thus no direct influence on the ‘Supposed to do’ strategy / features.

Now, about boolean, switch, arugment, query.

Going back to my help commnet above and looking at the two cmdlets in question, it will be obvious what they difference in the boolean expectation is. Again, one may not like it, but, you have to use it the way it is defined.

This is a true string property use case and not a built-in variable.

Set-NetFirewallProfile [-Name] [-PolicyStore ] [-GPOSession ]
   *** [-Enabled ] ***


Set-NetFirewallProfile -Profile Domain,Public,Private <strong>-Enabled True<strong>

This is a binary 1 or 0 surfaced via the variable name. Notice the type difference for that boolean, vs the later.

Set-NetAdapterBinding [-Name] [-ComponentID ] [-DisplayName ] [-IncludeHidden] [-AllBindings]
   *** [-Enabled ] ***


Set-NetAdapterBinding -Name "MyAdapter" -DisplayName "Internet Protocol Version 4 (TCP/IPv4)" <strong>-Enabled $True</strong>

Noted from the web…

Finding Built-In Variables

This features a piece of undocumented code that works in PowerShell v3 to list all built-in variables.

[psobject].Assembly.GetType('System.Management.Automation.SpecialVariables').GetFields('NonPublic,Static') &#8175;
| Where-Object FieldType -eq ([string]) &#8175;
| ForEach-Object GetValue $null

function Get-MyVariable
    $builtin = [psobject].Assembly.GetType('System.Management.Automation.SpecialVariables').GetFields('NonPublic,Static') &#8175;
    | Where-Object FieldType -eq ([string]) &#8175;
    ForEach-Object GetValue $null

    $builtin += 'MaximumAliasCount','MaximumDriveCount','MaximumErrorCount', 
    'MaximumFunctionCount', 'MaximumFormatCount', 'MaximumVariableCount', 
    'FormatEnumerationLimit', 'PSSessionOption', 

    Get-Variable &#8175;
    | Where-Object { $builtin -NotContains $_.Name } &#8175;
    | Select-Object -Property Name, Value, Description

This works in PoSHv2

[powershell]::create().addcommand('Get-Variable').invoke() &#8175;
| Select-Object -ExpandProperty Name

function Get-MyVariable
    $builtin = [powershell]::create().addcommand('Get-Variable').invoke() | Select-Object -ExpandProperty Name
    $builtin += 'args','MyInvocation','profile', 'PSBoundParameters', 
    'PSCommandPath', 'psISE', 'PSScriptRoot', 'psUnsupportedConsoleApplications'

    Get-Variable |
      Where-Object { $builtin -NotContains $_.Name } &#8175;
      | Select-Object -Property Name, Value, Description

Then there is this series as well

Finding PowerShell Default Variables


Understanding Booleans in PowerShell

PowerShell supports a data type Boolean, with two values possible $true, and $false. In general, $false evaluates to 0 (zero), and $true evaluates to 1. And (usually) any non-zero integer evaluates as $true. But PowerShell does automatic data type-casting, based on the left side of the equation, leading to some interesting (and correct) behaviour.