A while back I was helping a co-worker with a project where the customer needed
to automate a lot of minor Windows configuration steps on some Windows IoT
server appliances. One of the tasks was to make it possible to disable Windows
Firewall, because even an administrator was greeted with the message "For your
security, some settings are managed by your system administrator" and the option
to change firewall settings was disabled.
While I don't agree with disabling the firewall, they weren't my or my
organizations computers and the customer needed to be able to task their
distributor with pre-configuring hundreds or maybe thousands of systems
identically without Active Directory or Azure AD.
System administration or provisioning isn't my role but I'm familiar enough
with Windows to automate most thing that come up. I figured there would be
a cmdlet or command-line tool baked into the OS that would make quick work
of this, but as I dug into it, the only option seemed to be to apply a GPO
or use the interactive netsh prompt.
Maybe there's a better way, and you should really just keep the firewall
enabled with whatever rules you require, but I wrote this function to run
those interactive netsh commands in a way that could be automated.
functionSet-FirewallGpo{<#.SYNOPSIS Sets the Windows Firewall local security policy for one or more network profiles..DESCRIPTION If the Windows Firewall cannot be manually enabled, or disabled for one or more network profiles and you see a message similar to "For your security, some settings are managed by your system administrator", it means that the settings are managed either by group policy enforced by your organization, or the local security policy in the Windows host machine. The manual method to set this local security policy is to launch the "Local Security Policy" dialog (secpol.msc), and open the properties for "Security Settings > Windows Defender Firewall with Advanced Security - Local Group Policy Object" and modify the state for each of the three profiles - Domain, Private, and Public. Note that this should only be done if this setting is NOT managed by your organization, and you are entitled to modify the local security policy of the Windows machine in question. The command-line method is to use the netsh CLI. Unfortunately, it seems like even with the latest edition of Windows 11 and Server 2022, there is no native PowerShell cmdlet or one-line netsh command to modify the Windows Firewall local group policy object. The following netsh commands will get the job done. Be sure to replace "<hostname>" with the real machine hostname, "<ProfileName>"" with one of "allprofiles", "domainprofile", "privateprofile", or "publicprofile", and "<State>" with one of "On", "Off", or "NotConfigured". C:\> netsh netsh> advfirewall netsh advfirewall> set store gpo=<hostname> Ok. netsh advfirewall>set <ProfileName> state <State> Ok. To do this in one line, you can provide multiple "standard input" values to enter the advfirewall context in netsh like so: "advfirewall", "set store gpo=$(hostname)", "set AllProfiles state NotConfigured" | netsh Manually typing commands at the netsh CLI is not useful for automation, so this cmdlet launches the netsh CLI and types the commands for you. If the command fails with a non-zero exit code, the output from the CLI is provided in an error, or you can use -PassThru to receive the results from the process including the exit code, and standard output and standard error content..PARAMETER ProfileName Specifies the network profile to which to apply the policy change..PARAMETER State Specifies the new state for the Windows Firewall for the specified network profile(s)..PARAMETER PassThru Specifies that the raw exit code, stdout, and stderr should be returned to the caller..EXAMPLE Set-FirewallGpo -ProfileName AllProfiles -State NotConfigured Set-NetFirewallProfile -All -Enabled True Sets the firewall policy for all network profiles to "NotConfigured" which means that as a local Administrator you can enable or disable the Windows Firewall for any profile. Then enables the firewall for all profiles. #>[CmdletBinding(SupportsShouldProcess)]param([Parameter()][ValidateSet('AllProfiles','DomainProfile','PrivateProfile','PublicProfile')][string]$ProfileName='AllProfiles',[Parameter(Mandatory)][ValidateSet('On','Off','NotConfigured')][string]$State,[Parameter()][switch]$PassThru)process{if(-not$PSCmdlet.ShouldProcess((hostname),"Set Firewall local security policy for profile '$ProfileName' to '$State'")){return}try{$pinfo=[System.Diagnostics.ProcessStartInfo]@{FileName='netsh'Arguments=''WorkingDirectory=(Resolve-Path.\).PathUseShellExecute=$falseCreateNoWindow=$trueRedirectStandardOutput=$trueRedirectStandardError=$trueRedirectStandardInput=$true}$p=[System.Diagnostics.Process]::Start($pInfo)$p.StandardInput.WriteLine('advfirewall')$p.StandardInput.WriteLine("set store gpo=$(hostname)")$p.StandardInput.WriteLine("set $ProfileName state $State")$p.StandardInput.WriteLine('exit')$stringBuilder=[text.stringbuilder]::new()while($null-ne($line=$p.StandardOutput.ReadLine())){$null=$stringBuilder.AppendLine($line.Trim())}$stdout=$stringBuilder.ToString()$null=$stringBuilder.Clear()while($null-ne($line=$p.StandardError.ReadLine())){$null=$stringBuilder.AppendLine($line.Trim())}$stderr=$stringBuilder.ToString()Write-Verbose"Waiting for process $($p.Id) to exit"$p.WaitForExit()if($p.ExitCode-ne0){$message='{0} exited with exit code {1}. {2}'-f$pinfo.FileName,$p.ExitCode,($stdout+$stderr)Write-Error-Message$message}if($PassThru){[pscustomobject]@{Process=$pExitCode=$p.ExitCodeStandardOutput=$stdoutStandardError=$stderr}}}catch{Write-Error-ErrorRecord$_}}}