Network Security Groups (NSG) are pretty good. I don’t mind them that much as for what they are, they do a good job. Designing them can be a little tricky, having to know all the nuances of working with them. When it comes to implementing them, changing them at scale… well that’s where things can be a little tiresome. Well, I looked at it that way until recently when I had to really think about a better way to provision, de-provision and manipulate NSGs at scale.

There’s certainly other content available that outlines how to implement NSGs leveraging PowerShell which I consulted in order to assess the solution I have shared here. The roadblocks I’ve run into came from stopping use of the AzureRM PowerShell module(s) and moved to the Azure Az module(s) in mid-January. The general availability of the Az module is less than 6 months old (December 2018), from the time of writing this. That’s fairly new. So what better excuse, and the fact that I’ve temporarily parted ways with my old PowerShell script stash, to work on putting together a better means of NSG security rule management, more so because I need it urgently for some work at a customer.

What I needed

Here’s a list of things I needed to do efficiently, reliably and at scale:

  • Export all NSGs associated with a subscription
    • I suppose that could then be extended to cover all NSGs across all subscriptions for any given Enterprise Agreement
  • Delete a whole bunch of security configuration rules, so why not make it easy and use the CSV exports to do that
  • In case of an emergency, a good back out or contingency strategy would be good where I’d like to use that original CSV export to import the rules back in like nothing ever happened
    • I did run into a weird issue though, continue further down to learn more

Here’s the output from those requirements, a series of PowerShell scripts that I thought would be good to share. Enjoy!

Script 1 – Export all NSGs to a CSV file

  • This is pretty easy
  • This searches for all NSGs in a given subscription
  • Outputs all the security rule configuration into individual file outputs
  • This uses the Azure As module

$nsg = Get-AzNetworkSecurityGroup
$exportPath = ''
Foreach ($nsg in $nsgs){
New-Item -ItemType file -Path "$exportPath\$($nsg.Name).csv" -Force
$nsgRules = $nsg.SecurityRules
foreach ($nsgRule in $nsgRules){
$nsgRule | Select-Object Name,Description,Priority,Protocol,Access,Direction,@{Name=’SourceAddressPrefix’;Expression={[string]::join(“,”, ($_.SourceAddressPrefix))}},@{Name=’SourcePortRange’;Expression={[string]::join(“,”, ($_.SourcePortRange))}},@{Name=’DestinationAddressPrefix’;Expression={[string]::join(“,”, ($_.DestinationAddressPrefix))}},@{Name=’DestinationPortRange’;Expression={[string]::join(“,”, ($_.DestinationPortRange))}} `
| Export-Csv "$exportPath\$($nsg.Name).csv" -NoTypeInformation -Encoding ASCII -Append}

  • If you’d like grab that from GitHub, you can find that and fork it from here >

Script 2 – Delete NSG security configuration rules via a CSV

  • Next I needed to delete NSG security rules from an NSG before I replace them with a few others
  • This is pretty easy and the following script can do that
  • Note that it is a good idea to copy the original exported CSVs to another folder/repo/location to be used with Script 3 bellow
    • You don’t want to lose the originals as then there’s a more difficult road ahead

$NSG = Get-AzNetworkSecurityGroup -Name  -ResourceGroupName 
foreach($rule in import-csv ""){$NSG | Remove-AzNetworkSecurityRuleConfig -Name $rule.name}
$NSG | Set-AzNetworkSecurityGroup 

  • If you’d like grab that from GitHub, you can find that and fork it from here >

Script 3 – Sound the alarm! Mayday! Put it all back

This was probably the most difficult as I ran into a couple of problems/issues that needed troubleshooting.

Problem 1

  • The following attributes could and most likely have multiple values
  • SourcePortRange, DestinationPortRange ,SourceAddressPrefix and DestinationAddressPrefix
  • So splitting each cell by its delimiter ‘,’ needed to be done

Not that difficult, but at the same time, I ran into problem 2:

Problem 2

This certainly was a weird one;

  • A couple of the security rules exported fine and appeared normal
  • They had a sequence of multiple ports
  • I found the following Azure Feedback that stumped me
  • Entitled “Allow specification of multiple ports in a single NSG rule”
  • Multiple port assignment for NSG security rules was available via the Azure portal
  • It seemed that PowerShell and/or the Azure CLI was not supported
  • The request still hasn’t been closed or updated in a while
  • For a second there I thought I was toast

For reference, here’s the error I was getting:

Set-AzNetworkSecurityGroup: Security rule has invalid Port range. Value provided: 80 8080 8081 443 444. Value should be an integer OR integer range with '-' delimiter. Valid range 0-65535.
StatusCode: 400
ReasonPhrase: Bad Request
OperationID : 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
At line:14 char:8
+ $NSG | Set-AzNetworkSecurityGroup
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Set-AzNetworkSecurityGroup], NetworkCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Network.SetAzureNetworkSecurityGroupCommand 


In the end, I took a stab a removing the 2x rules that were playing up:

  • Mainly to see if it was the rules themselves vs the process that was causing failure;
  • After removing those 2 rules, my script below executed perfectly.

What’s weirder is that:

  • I added the 2 rules back into the NSG in the exact same way via the portal (not sure who or how it was added in the first place);
  • I exported with the export script;
  • I removed the rules manually via the portal;
  • Then executed the import script and it worked again flawlessly;
  • My conclusion is that there was a fault in the software defined networking configuration on the Azure side somewhere with the original rule.

$NSG = Get-AzNetworkSecurityGroup -Name  -ResourceGroupName 
foreach($rule in import-csv ""){
$NSG | Add-AzNetworkSecurityRuleConfig `
-Name $rule.name `
-Description $rule.Description `
-Priority $rule.Priority `
-Protocol $rule.Protocol `
-Access $rule.Access `
-Direction $rule.Direction `
-SourceAddressPrefix ($rule.SourceAddressPrefix -split ',') `
-SourcePortRange ($rule.SourcePortRange -split ',') `
-DestinationAddressPrefix ($rule.DestinationAddressPrefix -split ',') `
-DestinationPortRange ($rule.DestinationPortRange -split ',')
}
$NSG | Set-AzNetworkSecurityGroup 

  • If you’d like grab that from GitHub, you can find that and fork it from here >

Final words

PowerShell. Much heart, such useful. Enjoy! #PromptPowerShell