Powershell – Copy a Windows Server Firewall address list from one rule to another using Powershell

powershellwindows-firewallwindows-server-2012

I'm a little stuck on the documentation for the Firewall cmdlets in Windows server. I am trying to copy the address lists for the remote and local ips from one rule to another. I can get the list using

Get-NetFirewallRule -DisplayName "MSSQL" | Get-NetFirewallAddressFilter

Now I was trying to set this for another rule like this:

Set-NetFirewallAddressFilter -DisplayName "FTP Server (FTP Traffic-In)" | Get-NetFirewallRule -DisplayName "MSSQL" | Get-NetFirewallAddressFilter

This is obviously wrong, as I immediately get an error saying that Set-NetFirewallAddressFilter does not have a parameter ´Displayname´

When I use Set-NetFirewallRule instead it does, but there I cannot use a complete object but only Local and Remote Addresses seperately.
Could you help, please?

Update

I have now tried running something like this:

Set-NetFirewallRule -DisplayName "Test" -RemoteAddress | 
    Get-NetFirewallRule -DisplayName "MSSQL" | Get-NetFirewallAddressFilter | ft Remote

That doesn't work: Set-NetFirewallRule : The address is invalid. Addresses may be specified as IP addresses, ranges, or subnets.

Stuck again…

Best Answer

What you need to do is:

  • Get the original rule by name
  • Get the address filter out of it
  • Get the new rule by name
  • Set the address filter in it

And yes, you can merge a lot of those into a one-liner, but for example I think this will do it:

$sourceRule = Get-NetFirewallRule -DisplayName "MSSQL"
$sourceIPs = $sourceRule | Get-NetFirewallAddressFilter

Set-NetFirewallRule -DisplayName "Test" -RemoteAddress $sourceIPs.RemoteAddress -LocalAddress $sourceIPs.LocalAddress

(and if you have the Windows Firewall with Advanced Security GUI open, refresh it).

but there I cannot use a complete object but only Local and Remote Addresses seperately

I can't see any way around that if it needs them separately. Splatting might make it possible, but that would be a lot more code for effectively the same result. If it really has to be one line (why?) you can do both together with something like:

Set-NetFirewallRule -DisplayName "Test" -RemoteAddress ($ip = Get-NetFirewallRule -DisplayName "MSSQL" | Get-NetFirewallAddressFilter).RemoteAddress -LocalAddress $ip.LocalAddress

Your two pipelines both have some really misunderstood bits in them. The first one:

Set-NetFirewallAddressFilter -DisplayName "FTP Server (FTP Traffic-In)" | 
Get-NetFirewallRule -DisplayName "MSSQL" | Get-NetFirewallAddressFilter
  • Tries to set an address filter by DisplayName - they don't have a display name, filters are tied to FirewallRules.
  • The Set- commandlets don't often return any output, but you pipe as if it would have
  • The piped imaginary output goes into Get-ing the original firewall rule, which is just going to do weird things. It might ignore any pipeline input, or might crash based on it. Either way...
  • The two Get- cmdlets would work together to get addresses, but they just output to the screen and would not change anything.

The second updated one:

Set-NetFirewallRule -DisplayName "Test" -RemoteAddress | 
    Get-NetFirewallRule -DisplayName "MSSQL" | Get-NetFirewallAddressFilter | ft Remote
  • Is a Set- at the start and gets as far as the RemoteAddres parameter, but then switches (ouch!) to a pipeline, to pipe what ?? into Get-NetFirewallRule (same caveat as before)
  • then gets the addressfilter for the rule, and pipes to Format-Table(!) which is a display cmdlet for interactive console use only.

It's allllmost right - at a glance it has the look of a PowerShell one-liner, but it's really really broken.

  • You don't tend to pipeline output from Set- cmdlets.
  • You can't connect a pipeline into the middle of writing a parameter value
  • You oughtn't send data through Format-List or Format-Table, and plan to use the output as input to another cmdlet - they will happily add spaces, tabs, display names, throw data away, and generally mash things up to make it look nice on screen
  • You chain Get-s together but don't use the output.

:flail:

But it's so close, it would look like:

Set-NetFirewallRule -DisplayName "Test" -RemoteAddress (Get-NetFirewallRule -DisplayName "MSSQL" | Get-NetFirewallAddressFilter).RemoteAddress

Encapsulating the Get- sub-pipeline in parens () so you can use the output of it, taking the .RemoteAddress property, and using that as the value for the -RemoteAddress parameter to Set-NetFirewallRule.