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:

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


$nsg = 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}
Script 2 - Delete NSG security configuration rules via a CSV


$NSG = Get-AzNetworkSecurityGroup -Name <NetworkSecurityGroup> -ResourceGroupName <ResourceGroup>
foreach($rule in import-csv "<C:\CSVFILEHERE.csv>"){$NSG | Remove-AzNetworkSecurityRuleConfig -Name $}
$NSG | Set-AzNetworkSecurityGroup
Script 3 - Sound the alarm! Mayday! Put it all back

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


$NSG = Get-AzNetworkSecurityGroup -Name <NetworkSecurityGroup> -ResourceGroupName <ResourceGroup>
foreach($rule in import-csv "<C:\CSVFILEHERE.csv>"){
$NSG | Add-AzNetworkSecurityRuleConfig `
-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

Final words

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

PowerShell Microsoft Azure Network Security Group Azure Networking

Discussion 💬

Follow or start a discussion for this blog (Azure NSG security rule management like a boss) on Twitter. If you're after something more in depth, or want to ask me an expanded question: raise an issue in my open GitHub AMA repo.