Hi, i'm Lucian and here I share my experiences, thoughts and opinions on life in the blue cloud. I'm a Cloud Solution Architect, specialising in Azure infrastructure, at Microsoft, in Sydney, Australia.

Azure NSG security rule management like a boss

Using PowerShell and CSVs

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, deprovision and manipulate NSGs at scale.

There’s certainly content on the line that outlines how to better implement NSGs leveraging PowerShell, which I did consult the oracle to work out part of the solution I share here. The road block’s I’ve run into mostly came about because I’ve stopped using the AzureRM PowerShell module(s) and moved to the 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 me 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 Az module


$nsgs = Get-AzNetworkSecurityGroup
$exportPath = '<C:\somewhere>'
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 <NetworkSecurityGroup> -ResourceGroupName <ResourceGroup>
foreach($rule in import-csv "<C:\CSVFILEHERE.csv>"){$NSG | Remove-AzNetworkSecurityRuleConfig -Name $rule.name}
$NSG | Set-AzNetworkSecurityGroup
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 was certainly a was weird one
  • A couple of the security rules exported fine, looked 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”
  • Basically, 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:

Example error output:

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 <NetworkSecurityGroup> -ResourceGroupName <ResourceGroup>
foreach($rule in import-csv "<C:\CSVFILEHERE.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