Skip to content

Instantly share code, notes, and snippets.

@dnewsholme
Last active March 20, 2023 16:44
Show Gist options
  • Save dnewsholme/88c3ea1efc9d25ea8a8d9108e97e5e86 to your computer and use it in GitHub Desktop.
Save dnewsholme/88c3ea1efc9d25ea8a8d9108e97e5e86 to your computer and use it in GitHub Desktop.
Export-NSG.ps1
[CmdletBinding()]
PARAM()
<# CONSTANTS
$AzureDefaultRuleNames contains the names of the defaule rules in an Azure Network Security Group.
These names can be updated if Microsoft introduce new default rules in to Azure Network Security Groups.
#>
$AzureDefaultRuleNames = @("ALLOW VNET INBOUND", "ALLOW AZURE LOAD BALANCER INBOUND", "DENY ALL INBOUND", "ALLOW VNET OUTBOUND", "ALLOW INTERNET OUTBOUND", "DENY ALL OUTBOUND")
$AzureDefaultRmRuleNames = @("AllowVnetInBound", "AllowAzureLoadBalancerInBound", "DenyAllInBound", "AllowVnetOutBound", "AllowInternetOutBound", "DenyAllOutBound")
#region Azure Network Security Group Validation Rules
<#
.Synopsis
Validates a port range for use with an Azure Network Security Group
.DESCRIPTION
This ensures that the requested port range is valid for Azure Network Security Groups
.PARAMETER PortRange
This is the port range to be validated. It could a single integer between 0 and 65537, a range between 0 and 65537 or an * to denote all ports
.EXMAPLE
Test-AzurePortRange -PortRange 0-1000
.EXAMPLE
Test-AzurePortRange -PortRange 100
.EXAMPLE
Test-AzurePortRange -PortRange *
#>
function Test-AzurePortRange() {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateNotNullOrEmpty()]
$PortRange
)
#New Code
if ($PortRange.ToString() -match "\*") {
return $true
}
elseif ($PortRange.ToString() -match ",") {
$PortRangeNumbers = $PortRange -split ","
if ($PortRangeNumbers -match "-") {
$PortRangeNumbers = $PortRangeNumbers -split "-"
}
$result = @()
$PortRangeNumbers | foreach-object {
if (-not($_ -in 0..65537)) {
$result += $false
}
else {
$result += $true
}
}
if ($result -contains $false) {
return $false
}
else {
return $true
}
}
elseif ($PortRange.ToString() -match "-") {
$PortRangeNumbers = $PortRange -split "-"
if (-not($PortRangeNumbers[0] -in 0..65537)) {
return $false
}
if (-not($PortRangeNumbers[1] -in 0..65537)) {
return $false
}
return $true
}
elseif ($PortRange -in 0..65537) {
#number
return $true
}
else {
return $false
}
}
<#
.Synopsis
Validates an Azure Network Security Group Rule action
.DESCRIPTION
Validates that the required action is permitted
.PARAMETER Action
This is either Allow or Deny
.EXAMPLE
Test-AzureNetworkSecurityRuleAction -Action Allow
.EXAMPLE
Test-AzureNetworkSecurityRuleAction -Action Deny
#>
function Test-AzureNetworkSecurityRuleAction() {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
$Action
)
return ($Action -match "^(Allow|Deny)$")
}
<#
.Synopsis
Validates an Azure Network Destination Address Prefix will be permitted
.DESCRIPTION
Validates that the passed value is one of the following:
1. VIRTUAL_NETWORK
2. INTERNET
3. AZURE_LOADBALANCER
4. IP in CIDR form (examples are 10.0.0.0/24 or 10.0.0.5/32)
5. * (which denotes any)
.PARAMETER AddressPrefix
This is the value to validate
.EXAMPLE
Test-AzureNetworkSecurityAddressPrefix -AddressPrefix 10.0.0.0/25
.EXAMPLE
Test-AzureNetworkSecurityAddressPrefix -AddressPrefix VIRTUAL_NETWORK
#>
function Test-AzureNetworkSecurityAddressPrefix() {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,
Position = 1)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
$AddressPrefix,
[Parameter(Mandatory = $false,
Position = 2)]
[switch]$IsARM = $false
)
if (-not($IsARM)) {
return ($AddressPrefix -match "^(VIRTUAL_NETWORK|AZURE_LOADBALANCER|INTERNET|(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(/([1-9]|1[0-9]|2[0-9]|3[0-2]))|\*)$")
}
else {
return ($AddressPrefix -match "(VirtualNetwork|AzureLoadBalancer|INTERNET|[A-z]+|((([0-9]{0,3}\.){3,}([0-9]{0,3}))(\/([0-9]){1,2})?),?|\*)")
}
}
<#
.Synopsis
Validates an Azure Network Security Group, or Rule, Name
.DESCRIPTION
Validates that the name doesn't contain a $ or `
.PARAMETER Name
This is the value to validate
.EXAMPLE
Test-AzureNetworkSecurityName -Name RDP$
This test would fail
.EXAMPLE
Test-AzureNetworkSecurityName -Name RDP
#>
function Test-AzureNetworkSecurityName() {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
$Name,
[Parameter(Mandatory = $false,
Position = 2)]
[switch]$IsARM = $false
)
if (-not($IsArm)) {
if (($Name -match "\`$") -or ($Name -match "``") -or ($AzureDefaultRuleNames -contains $Name) ) {
return $false
}
}
else {
if ($AzureDefaultRmRuleNames -contains $Name) {
return $false
}
return $Name -match "^(?=[\S\s]{1,80}$)([a-zA-Z0-9]{1}[a-zA-Z0-9_.-]{1,78}[a-zA-Z0-9_])$"
}
return $true
}
<#
.Synopsis
Validates an Azure Network Security Rule Priority
.DESCRIPTION
Validates that the priority is in a valid range
.PARAMETER Priority
This is the value to validate
.EXAMPLE
Test-AzureNetworkSecurityRulePriority -Priority 100
.EXAMPLE
Test-AzureNetworkSecurityRulePriority -Priority 5000
This test would fail
#>
function Test-AzureNetworkSecurityRulePriority() {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
$Priority
)
return ($Priority -in 100..4096)
}
<#
.Synopsis
Validates an Azure Network Security Group Rule Protocol
.DESCRIPTION
Validates that the required Protocol is permitted by Azure NSG Rules
.PARAMETER Protocol
This is either TCP, UDP or *
.EXAMPLE
Test-AzureNetworkSecurityRuleProtocol -Protocol TCP
.EXAMPLE
Test-AzureNetworkSecurityRuleProtocol -Protocol UDP
#>
function Test-AzureNetworkSecurityRuleProtocol() {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
$Protocol
)
return ($Protocol -match "^(TCP|UDP|\*)$")
}
<#
.Synopsis
Validates an Azure Network Security Group Rule Type
.DESCRIPTION
Validates that the required type is permitted by Azure NSG Rules
.PARAMETER Type
This is either inbound or outbound
.EXAMPLE
Test-AzureNetworkSecurityRuleType -Type Inbound
.EXAMPLE
Test-AzureNetworkSecurityRuleType -Type Outbound
#>
function Test-AzureNetworkSecurityRuleType() {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
$Type
)
return ($Type -match "^(inbound|outbound)$")
}
<#
.Synopsis
Validates a list of Azure Network Security Group Rules
.DESCRIPTION
Validates that the list of rules defined in a CSV.
.PARAMETER NetworkSecurityRules
This is usually the content of the CSV file
.EXAMPLE
Test-AzureNetworkSecurityGroupRules -NetworkSecurityRules (import-csv <path>)
.EXAMPLE
$NSGRules = import-csv <path>
Test-AzureNetworkSecurityGroupRules -NetworkSecurityRules $NSG
#>
function Test-AzureNetworkSecurityGroupRules() {
[CmdletBinding()]
Param
(
#Rule List
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateNotNullOrEmpty()]
$NetworkSecurityRules,
[Parameter(Mandatory = $false,
Position = 1)]
[switch]$IsARM = $false
)
#Rule numbers
$i = 1
Write-Verbose "Testing in ARM Mode: $IsArm"
#This contains the failed rules to be thrown at the user
$FailedRules = @()
#Validate each rule
ForEach ($NSR in $NetworkSecurityRules) {
Write-Verbose "Validating Rule $i"
#Validate Action is Allow or Deny
Write-Verbose "Validating Action..."
if (-not($IsARM)) {
if (-not(Test-AzureNetworkSecurityRuleAction -Action $NSR.Action)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.Action) is not a valid NSG Action"
}
}
else {
if (-not(Test-AzureNetworkSecurityRuleAction -Action $NSR.Access)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.Access) is not a valid NSG Access"
}
}
#Validate the Source Prefix address is valid and is one of VIRTUAL_NETWORK, INTERNET, AZURE_LOADBALANCER, an IP CIDR or *
Write-Verbose "Validating Destination Address Prefix..."
if (-not(Test-AzureNetworkSecurityAddressPrefix -AddressPrefix $NSR.DestinationAddressPrefix -IsARM:$IsARM)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.DestinationAddressPrefix) is not a valid Destination Address Prefix in an Azure NSG"
}
#Validate the it is a number, range or *
Write-Verbose "Validating Destination Port Range..."
if (-not(Test-AzurePortRange -PortRange $NSR.DestinationPortRange)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.DestinationPortRange) is not a valid Destination Port Range"
}
#Validate the name doesn't contain a $ or ` symbol
Write-Verbose "Validating Name..."
if (-not(Test-AzureNetworkSecurityName -Name $NSR.Name -IsARM:$IsARM)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.Name) is not valid for a NSG rule name"
}
else {
#Check the rule name is unique
if ($RuleNames -contains $NSR.Name) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "The rule name $($NSR.Name) is not unique within the NSG"
}
else {
$RuleNames += $NSR.Name
}
}
#Validate the priority is a number in range
Write-Verbose "Validating Priority..."
if (-not(Test-AzureNetworkSecurityRulePriority -Priority $NSR.Priority)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.Priority) is not a valid Priority number in an Azure NSG"
}
#Validate the protocol is either TCP, UDP or * (for either)
Write-Verbose "Validating Protocol..."
if (-not(Test-AzureNetworkSecurityRuleProtocol -Protocol $NSR.Protocol)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.Protocol) is not a valid Protocol in an Azure NSG"
}
#Validate the Source Prefix address is valid and is one of VIRTUAL_NETWORK, INTERNET, AZURE_LOADBALANCER, an IP CIDR or *
Write-Verbose "Validating Source Address Prefix..."
if (-not(Test-AzureNetworkSecurityAddressPrefix -AddressPrefix $NSR.SourceAddressPrefix -IsARM:$IsARM)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.SourceAddressPrefix) is not a valid Source Address Prefix in an Azure NSG"
}
#Validate the it is a number, range or *
Write-Verbose "Validating Source Port Range..."
if (-not(Test-AzurePortRange -PortRange $NSR.SourcePortRange)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.Source) is not a valid Source Port Range"
}
#Validate the it is a number, range or *
Write-Verbose "Validating Description..."
if (!($NSR.description)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "Description is null and not valid"
}
#Validate Type is either Inbound or Outbound
Write-Verbose "Validating Type..."
if (-not($IsARM)) {
if (-not(Test-AzureNetworkSecurityRuleType -Type $NSR.Type)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.Type) is not a valid Type in an Azure NSG Rule."
}
}
else {
if (-not(Test-AzureNetworkSecurityRuleType -Type $NSR.Direction)) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "$($NSR.Direction) is not a valid Type in an Azure NSG Rule."
}
}
#Validate there is no other rule of the same type that has the same priority
Write-Verbose "Validating the Priority Number"
if (($NetworkSecurityRules | ? {(($_.Priority -eq $NSR.Priority) -and ($_.Type -eq $NSR.Type) -and ($_.Name -ne $NSR.Name))}).Count -gt 0) {
$FailedRules += New-FailedAzureNetworkGroupRule -RuleNumber $i -Message "The Priority number $($NSR.Priority) is duplicated for the direction $($NSR.Type)"
}
#Increment Rule Number
$i++
}
#Return the FailedRules (if any)
$FailedRules
}
<#
.Synopsis
Creates an object that contains the rule number and reason why it failed
.DESCRIPTION
Creates an object that contains the rule number and reason why it failed. Custom PowerShell object
.PARAMETER RuleNumber
This is the rule number is the CSV file
.PARAMETER Message
This is the reason why the rule failed validation
.EXAMPLE
New-FailedAzureNetworkGroupRule -RuleNumber 1 -Message "The type declared in this rule is not permitted"
#>
function New-FailedAzureNetworkGroupRule() {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true)]
[int]$RuleNumber,
[Parameter(Mandatory = $true)]
[string]$Message
)
#Build and return the object
New-Object –TypeName PSObject -Property @{RuleNumber = $RuleNumber; Message = $Message}
}
<#
.Synopsis
Creates an object that contains the rule number, the reason why it failed and the direction the rule applies in
.DESCRIPTION
Creates an object that contains the rule number, the reason why it failed and the direction the rule applies in. Custom PowerShell object
.PARAMETER RuleNumber
This is the rule number is the CSV file
.PARAMETER Message
This is the reason why the rule failed validation
.EXAMPLE
New-FailedUpdateAzureNetworkGroupRule -RuleNumber 1 -Message "The type declared in this rule is not permitted" -Direction
#>
function New-FailedUpdateAzureNetworkGroupRule() {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true)]
[int]$RuleNumber,
[Parameter(Mandatory = $true)]
[string]$Message,
[Parameter(Mandatory = $true)]
[string]$Direction
)
#Build and return the object
New-Object –TypeName PSObject -Property @{RuleNumber = $RuleNumber; Message = $Message; Direction = $Direction}
}
#endregion
#region Azure Resource Manager Network Security Group
<#
.Synopsis
Creates an Azure Network Security Group based on the CSV file that is passed
.DESCRIPTION
This script accepts a path to a CSV file where the rule definitions are listed.
It iterates through each rule in the CSV adding to the required Azure NSG.
.PARAMETER CSVPath
The location of the CSV that contains the rules to apply
.PARAMETER AzureLocation
A valid Azure Location, for example "North Europe"
.PARAMETER ResourceGroupName
The name of the Resource Group where the Network Security Group is to be created
.PARAMETER NetworkSecurityGroupName
The name of the Azure Network Security Group to create
.PARAMETER Tags
The Azure tags to apply. This can be a hashtable or an array of hastables
.EXAMPLE
New-AzureRmCustomNetworkSecurityGroup -CSVPath .\Rules.csv -AzureLocation "North Europe" -ResourceGroupName TEST-RG -NetworkSecurityGroupName NSG-DMZ-1 -Tags @{Name="State";Value="Production"}
#>
function New-AzureRmCustomNetworkSecurityGroup() {
[CmdletBinding()]
Param
(
# CSVPath is the path to the CSV containin the rules
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateScript( {
Test-Path -Path $_ -PathType Leaf
})]
[string] $CSVPath,
# Which Azure Location will this NSG reside in
[Parameter(Mandatory = $true,
Position = 1)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[ValidateScript( {
$DesiredLocation = $_
if (-not(Get-AzLocation | ? {$_.Name -eq $DesiredLocation})) {
Throw "The location you requested ""$DesiredLocation"" is not a valid Azure location"
}
$true
})]
[string]$AzureLocation,
# Resource Group Name
[Parameter(Mandatory = $true,
Position = 2)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[string] $ResourceGroupName,
# Network Security Group Name
[Parameter(Mandatory = $true,
Position = 3)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[ValidateScript( {
$RequiredNSGName = Get-AzSecurityGroup -ResourceGroupName $ResourceGroupName | Where-Object -Property Name -EQ -Value $_
if ($RequiredNSGName) {
Throw "The Network Security Group Name ""$_"" is already in use. Consider using Update-AzureRmCustomNetworkSecurityGroup"
}
$true
})]
[string] $NetworkSecurityGroupName,
#Azure Tags
[Parameter(Mandatory = $false,
Position = 4)]
$Tags,
[Parameter(Mandatory = $false,
Position = 5)]
[switch]$PassThru = $false
)
#Import the CSV file
Write-Verbose "Importing CSV from: $CSVPath"
$NetworkSecurityRules = Import-Csv -Path $CSVPath
#Confirm there are rules in the CSV
if (-not($NetworkSecurityRules)) {
Throw "There are no Azure Network Security Rules defined in the CSV ($CSVPath)"
}
#Test the rules to see if they'll be accepted by Azure
$FailedRules = Test-AzureNetworkSecurityGroupRules -NetworkSecurityRules $NetworkSecurityRules -IsARM
#If there are failed rules then stop
if ($FailedRules) {
$FailedRules | % {
Write-Error "Rule: $($_.RuleNumber) FAILED because $($_.Message)"
}
Throw ($FailedRules)
}
#ARM
#Create rules then create group
$newRule = "New-AzNetworkSecurityRuleConfig -Name '{0}' -Access {1} -Description '{2}' -DestinationAddressPrefix {3} -DestinationPortRange {4} -Direction {5} -Priority {6} -Protocol {7} -SourceAddressPrefix {8} -SourcePortRange {9} -Debug:`$false"
$newRules = @()
ForEach ($NSR in $NetworkSecurityRules) {
Write-Verbose "Creating rule name $($NSR.Name)"
#Use PowerShell formating to substitute the parameters in the $SetRule
$RuleToCreate = $newRule -f $NSR.Name, $NSR.Access, $NSR.Description, $NSR.DestinationAddressPrefix, $NSR.DestinationPortRange, $NSR.Direction, $NSR.Priority, $NSR.Protocol, $NSR.SourceAddressPrefix, $NSR.SourcePortRange
$newRules += (Invoke-Expression $RuleToCreate)
}
if (-not($Tags)) {
$Tags = @{}
}
#$newRules
Write-Verbose "Creating NSG: $NetworkSecurityGroupName"
$CreatedNSG = New-AzNetworkSecurityGroup -Location $AzureLocation -Name $NetworkSecurityGroupName -ResourceGroupName $ResourceGroupName -SecurityRules $newRules -Tag $Tags
#Does the user want the NSG back?
if ($PassThru) {
$CreatedNSG
}
}
<#
.Synopsis
Updates an Azure Network Security Group based on the CSV file that is passed and ensures that the NSG in Azure matches the CSV file
.DESCRIPTION
This script accepts a path to a CSV file where the rule definitions are listed.
Removes all the rules from the existing NSG and replaces them with the updated rules. Azure is only updated with the updated rules. This is different from Classic Azure
.PARAMETER CSVPath
The location of the CSV that contains the rules to apply
.PARAMETER ResourceGroupName
The name of the Resource Group where the Network Security Group resides
.PARAMETER NetworkSecurityGroupName
The name of the Azure Network Security Group to update
.EXAMPLE
Update-AzureRmCustomNetworkSecurityGroup -CSVPath C:\AzureNetworkSecuriyGroupRules\RulesARM.csv -ResourceGroupName TEST-RG -NetworkSecurityGroupName NSG-DMZ-1
#>
function Update-AzureRmCustomNetworkSecurityGroup {
[CmdletBinding()]
param(
# CSVPath is the path to the CSV where the rules are stored
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateScript( {
#Ensure the CSV file exists
Test-Path -Path $_ -PathType Leaf
})]
[string] $CSVPath,
# Resource Group Name
[Parameter(Mandatory = $true,
Position = 1)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[string] $ResourceGroupName,
# Network Security Group Name
[Parameter(Mandatory = $true,
Position = 2)]
[ValidateNotNullOrEmpty()]
[ValidateScript( {
$RequiredNSGName = Get-AzNetworkSecurityGroup | Where-Object -Property Name -EQ -Value $_
if (-not($RequiredNSGName)) {
Throw "The Network Security Group Name ""$_"" does not exist. Consider using New-AzureRmCustomNetworkSecurityGroup"
}
$true
})]
[string] $NetworkSecurityGroupName,
#Azure Tags
[Parameter(Mandatory = $false,
Position = 3)]
$Tags,
[Parameter(Mandatory = $false,
Position = 4)]
[switch]$PassThru = $false
)
#Import the CSV file
Write-Verbose "Importing CSV from: $CSVPath"
$NetworkSecurityRules = Import-Csv -Path $CSVPath
#Confirm there are rules in the CSV
if ($NetworkSecurityRules.Name.Count -lt 1) {
Throw "There are no Azure Network Security Rules defined in the CSV ($CSVPath). If you want to remove the NSG then use Remove-AzureRmNetworkSecurityGroup -Name ""$NetworkSecurityGroupName"" -ResourceGroupName ""$"""
}
Write-Verbose "Validating all rules, inbound and outbound"
#Test the rules to see if they'll be accepted by Azure
# Commenting Out the rule checks as we are using pester to check them instead.
#$FailedRules = Test-AzureNetworkSecurityGroupRules -NetworkSecurityRules $NetworkSecurityRules -IsARM
Write-Verbose "Rule Validation Complete"
#If there are failed rules then stop
if ($FailedRules) {
Write-Warning "Some rules have failed to process:"
$FailedRules | % {
Write-Warning "Rule: $($_.RuleNumber) FAILED because $($_.Message)"
}
Throw ($FailedRules)
}
#Get the Existing NSG from Azure Rm
$ExistingNSG = Get-AzNetworkSecurityGroup -Name $NetworkSecurityGroupName -ResourceGroupName $ResourceGroupName
#Get the rules from Azure Rm NSG
$ExistingNSGRules = Get-AzNetworkSecurityRuleConfig -NetworkSecurityGroup $ExistingNSG
#Remove all existing rules - WILL NOT UPDATE AZURE
ForEach ($ExistingNSGRule in $ExistingNSGRules) {
$ExistingNSG | Remove-AzNetworkSecurityRuleConfig -Name $ExistingNSGRule.Name | Out-Null
}
#Create the new rules and add them to the NSG,
$newRule = "`$ExistingNSG | Add-AzNetworkSecurityRuleConfig -Name '{0}' -Access {1} -Description '{2}' -DestinationAddressPrefix {3} -DestinationPortRange {4} -Direction {5} -Priority {6} -Protocol {7} -SourceAddressPrefix {8} -SourcePortRange {9} -Debug:`$false"
$newRules = @()
ForEach ($NSR in $NetworkSecurityRules) {
Write-Verbose "Creating updated rule name $($NSR.Name)"
#Use PowerShell formating to substitute the parameters in the $SetRule
$RuleToCreate = $newRule -f $NSR.Name, $NSR.Access, $NSR.Description, $NSR.DestinationAddressPrefix, $NSR.DestinationPortRange, $NSR.Direction, $NSR.Priority, $NSR.Protocol, $NSR.SourceAddressPrefix, $NSR.SourcePortRange
Invoke-Expression $RuleToCreate | Out-Null
}
if ($Tags) {
$ExistingNSG.Tag = $Tags
}
Write-Verbose "Updating NSG: $($ExistingNSG.Name)"
$ExistingNSG = $ExistingNSG | Set-AzNetworkSecurityGroup
if ($PassThru) {
$ExistingNSG
}
}
<#
.Synopsis
Exports an existing Azure Network Security Group to a CSV file.
.DESCRIPTION
This script will export all the rules from an existing Network Security Group to a CSV file, this CSV can then be used with Update-AzureRmCustomNetworkSecurityGroup or New-AzureRmCustomNetworkSecurityGroup
.PARAMETER CSVPath
The location of the CSV to export the rules to
.PARAMETER ResourceGroupName
The name of the Resource Group where the Network Security Group resides
.PARAMETER NetworkSecurityGroupName
The name of the Azure Network Security Group to export
.EXAMPLE
Export-AzureRmCustomNetworkSecurityGroup -CSVPath .\Rules.csv -ResourceGroupName TEST-RG -NetworkSecurityGroupName NSG-DMZ-1
#>
function Export-AzureRmNetworkSecurityGroup {
param(
# CSVPath is the path to the CSV where the rules are stored
[Parameter(Mandatory = $true,
Position = 0)]
[string] $CSVPath,
# Resource Group Name
[Parameter(Mandatory = $true,
Position = 1)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[string] $ResourceGroupName,
# Network Security Group Name
[Parameter(Mandatory = $true,
Position = 2)]
[ValidateNotNullOrEmpty()]
[ValidateScript( {
$RequiredNSGName = Get-AzNetworkSecurityGroup | Where-Object -Property Name -EQ -Value $_
if (-not($RequiredNSGName)) {
Throw "The Network Security Group Name ""$_"" does not exist. Cannot export and non-existent Network Security Group."
}
$true
})]
[string] $NetworkSecurityGroupName
)
Write-Verbose "Getting the NSG from Azure RM"
#Get the Existing NSG from Azure Rm
$ExistingNSG = Get-AzNetworkSecurityGroup -Name $NetworkSecurityGroupName -ResourceGroupName $ResourceGroupName
Write-Verbose "Extracting the Security Rules"
#Get the rules from Azure Rm NSG
$ExistingNSGRules = Get-AzNetworkSecurityRuleConfig -NetworkSecurityGroup $ExistingNSG
Function Convert-ArrayToString {
param(
[parameter(ValueFromPipeline)]$array
)
$str = $null
$array | foreach-object {$str += "$($_),"}
$str = $str.Trim(',')
return $str
}
#If existing rule then export them
if ($ExistingNSGRules) {
Write-Verbose "Exporting rules to $CSVPath"
$Rules = @()
foreach ($line in $ExistingNSGRules) {
$Rules += New-Object -TypeName PSObject -Property @{
Name = Convert-ArrayToString -array $line.Name
Priority = Convert-ArrayToString -array $line.Priority
Access = Convert-ArrayToString -array $line.Access
SourceAddressPrefix = Convert-ArrayToString -array $line.SourceAddressPrefix
SourcePortRange = Convert-ArrayToString -array $line.SourcePortRange
DestinationAddressPrefix = Convert-ArrayToString -array $line.DestinationAddressPrefix
DestinationPortRange = Convert-ArrayToString -array $line.DestinationPortRange
Protocol = Convert-ArrayToString -array $line.Protocol
Direction = Convert-ArrayToString -array $line.Direction
Description = Convert-ArrayToString -array $line.Description
}
}
$Rules | sort Priority | Export-Csv -Path $CSVPath -NoTypeInformation -Force
#Sort-Object Direction,Priority | Select Name,Priority,Access,SourceAddressPrefix,SourcePortRange,DestinationAddressPrefix,DestinationPortRange,Protocol,Direction,Description | Export-CSV -Path $CSVPath -NoTypeInformation -Force
}
else {
Write-Error "No rules in the NSG to export"
}
}
#endregion
#region Azure Classic Network Security Group
<#
.Synopsis
Creates an Azure Network Security Group based on the CSV file that is passed
.DESCRIPTION
This script accepts a path to a CSV file where the rule definitions are listed.
It iterates through each rule in the CSV adding to the required Azure NSG.
.PARAMETER CSVPath
The location of the CSV that contains the rules to apply
.PARAMETER NetworkSecurityGroupName
The name of the Azure Network Security Group to create
.PARAMETER AzureLocation
A valid Azure Location, for example "North Europe"
.PARAMETER NetworkSecurityGroupLabel
The description to apply to the NSG in Azure
.EXAMPLE
New-AzureCustomNetworkSecurityGroup -CSVPath .\Rules.csv -NetworkSecurityGroupName NSG-DMZ-1 -AzureLocation "North Europe" -NetworkSecurityGroupLabel "Default NSG for VNet Dub-Prod, VSubnet DMZ"
#>
function New-AzureCustomNetworkSecurityGroup() {
[CmdletBinding()]
Param
(
# CSVPath is the path to the CSV containin the rules
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateScript( {
Test-Path -Path $_ -PathType Leaf
})]
[string] $CSVPath,
# Network Security Group Name
[Parameter(Mandatory = $true,
Position = 1)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[ValidateScript( {
$RequiredNSGName = Get-AzNetworkSecurityGroup -Name $_ -ErrorAction SilentlyContinue
if ($RequiredNSGName) {
Throw "The Network Security Group Name ""$_"" is already in use. Consider using Update-AzureCustomNetworkSecurityGroup"
}
$true
})]
[string] $NetworkSecurityGroupName,
# Which Azure Location will this NSG reside in
[Parameter(Mandatory = $true,
Position = 2)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[ValidateScript( {
$DesiredLocation = $_
if (-not(Get-AzLocation | ? {$_.Name -eq $DesiredLocation})) {
Throw "The location you requested ""$DesiredLocation"" is not a valid Azure location"
}
$true
})]
[string]$AzureLocation,
# Network Security Group Label in Azure - i.e. the description for the NSG
[Parameter(Mandatory = $true,
Position = 3)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[string]$NetworkSecurityGroupLabel
)
#Import the CSV file
Write-Verbose "Importing CSV from: $CSVPath"
$NetworkSecurityRules = Import-Csv -Path $CSVPath
#Confirm there are rules in the CSV
if ($NetworkSecurityRules.Count -lt 1) {
Throw "There are no Azure Network Security Rules defined in the CSV ($CSVPath)"
}
#Test the rules to see if they'll be accepted by Azure
$FailedRules = Test-AzureNetworkSecurityGroupRules -NetworkSecurityRules $NetworkSecurityRules
#If there are failed rules then stop
if ($FailedRules) {
$FailedRules | % {
Write-Error "Rule: $($_.RuleNumber) FAILED because $($_.Message)"
}
Throw ($FailedRules)
}
#Creating Azure Network Security Group
Write-Verbose "Creating Azure Network Security Group $NetworkSecurityGroupName"
$NSG = New-AzNetworkSecurityGroup -Name $NetworkSecurityGroupName -Location $AzureLocation -Label $NetworkSecurityGroupLabel
#Base Rule - used to format the rule and passed to Invoke-Expression
$SetRule = "Set-AzureNetworkSecurityRule -Action {0} -DestinationAddressPrefix {1} -DestinationPortRange {2} -Name ""{3}"" -NetworkSecurityGroup `$NSG -Priority {4} -Protocol {5} -SourceAddressPrefix {6} -SourcePortRange {7} -Type {8}"
Write-Verbose "Creating Azure Network Security Group Rules in Azure Network Security Group $NetworkSecurityGroupName"
#As rules have passed validation create them in the NSG
ForEach ($NSR in $NetworkSecurityRules) {
Write-Verbose "Creating rule name $($NSR.Name)"
#Use PowerShell formating to substitute the parameters in the $SetRule
$RuleToCreate = $SetRule -f $NSR.Action, $NSR.DestinationAddressPrefix, $NSR.DestinationPortRange, $NSR.Name, $NSR.Priority, $NSR.Protocol, $NSR.SourceAddressPrefix, $NSR.SourcePortRange, $NSR.Type
Invoke-Expression $RuleToCreate | Out-Null
}
Write-Verbose "Created the Azure Network Security Group $NetworkSecurityGroupName"
#return the detailed NSG
Get-AzNetworkSecurityGroup -Name $NetworkSecurityGroupName -Detailed
}
<#
.Synopsis
Updates an Azure Network Security Group based on the CSV file that is passed and ensures that the NSG in Azure matches the CSV file
.DESCRIPTION
This script accepts a path to a CSV file where the rule definitions are listed.
It iterates through each rule in the CSV adding it to, or updating, the required Azure Network Security Group.
If the Azure Network Security Group contains rules no longer the CSV it will remove the rule in NSG.
This does not make any alterations to the default Azure Network Security Group rules as this is not permitted.
.PARAMETER CSVPath
The location of the CSV that contains the rules to apply
.PARAMETER NetworkSecurityGroupName
The name of the Azure Network Security Group to update
.EXAMPLE
Update-AzureCustomNetworkSecurityGroup -CSVPath .\Rules.csv -NetworkSecurityGroupName NSG-DMZ-1
#>
function Update-AzureCustomNetworkSecurityGroup {
[CmdletBinding()]
param(
# CSVPath is the path to the CSV where the rules are stored
[Parameter(Mandatory = $true,
Position = 0)]
[ValidateScript( {
#Ensure the CSV file exists
Test-Path -Path $_ -PathType Leaf
})]
[string] $CSVPath,
# Network Security Group Name
[Parameter(Mandatory = $true,
Position = 1)]
[ValidateNotNullOrEmpty()]
[ValidateScript( {
$RequiredNSGName = Get-AzureNetworkSecurityGroup -Name $_ -ErrorAction SilentlyContinue
if (-not($RequiredNSGName)) {
Throw "The Network Security Group Name ""$_"" does not exist. Consider using New-AzureCustomNetworkSecurityGroup"
}
$true
})]
[string] $NetworkSecurityGroupName
)
#Import the CSV file
Write-Verbose "Importing CSV from: $CSVPath"
$NetworkSecurityRules = Import-Csv -Path $CSVPath
#Confirm there are rules in the CSV
if ($NetworkSecurityRules.Count -lt 1) {
Throw "There are no Azure Network Security Rules defined in the CSV ($CSVPath). If you want to remove the NSG then use Remove-AzureNetworkSecurityGroup -Name ""$NetworkSecurityGroupName"""
}
Write-Verbose "Validating all rules, inbound and outbound"
#Test the rules to see if they'll be accepted by Azure
$FailedRules = Test-AzureNetworkSecurityGroupRules -NetworkSecurityRules $NetworkSecurityRules
Write-Verbose "Rule Validation Complete"
#If there are failed rules then stop
if ($FailedRules) {
Write-Warning "Some rules have failed to process:"
$FailedRules | % {
Write-Warning "Rule: $($_.RuleNumber) FAILED because $($_.Message)"
}
Throw ($FailedRules)
}
###################################################################################
#region Inbound Rules
###################################################################################
Write-Verbose "Updating the inbound rules"
#Get the current rules in the NSG
$CurrentRules = (Get-AzureNetworkSecurityGroup -Name $NetworkSecurityGroupName -Detailed).Rules
$CurrentInboundRules = $CurrentRules | ? {($_.Type -eq "Inbound") -and ($AzureDefaultRuleNames -notcontains $_.Name)}
#Breakdown the rules defined in the CSV
$NetworkSecurityRulesInbound = $NetworkSecurityRules | ? {$_.Type -eq "inbound"} | Sort-Object Priority
$NSG = Get-AzureNetworkSecurityGroup -Name $NetworkSecurityGroupName
#Base Rule - used to format the rule and passed to Invoke-Expression
$SetRule = "Set-AzureNetworkSecurityRule -Action {0} -DestinationAddressPrefix {1} -DestinationPortRange {2} -Name ""{3}"" -NetworkSecurityGroup `$NSG -Priority {4} -Protocol {5} -SourceAddressPrefix {6} -SourcePortRange {7} -Type {8}"
#Holds objects to help set the priority numbers correct
$RequestPriorityNumbers = @()
#This holds rules that have failed for some reason. A failed run will not fail the function at this time
$FailedRules = @()
#Process the rules in the CSV file, updating or creating.
ForEach ($NSR in $NetworkSecurityRulesInbound) {
#See if the rule exists in the current set of NSG rules
$CurrentRule = $CurrentInboundRules | ? {$_.Name -eq $NSR.Name}
#Found?
if ($CurrentRule) {
#Build the currrent rule set statement
$CurrentSetRule = $SetRule -f $CurrentRule.Action, $CurrentRule.DestinationAddressPrefix, $CurrentRule.DestinationPortRange, $CurrentRule.Name, $CurrentRule.Priority, $CurrentRule.Protocol, $CurrentRule.SourceAddressPrefix, $CurrentRule.SourcePortRange, $CurrentRule.Type
#Build the new rule set statement
$NewSetRule = $SetRule -f $NSR.Action, $NSR.DestinationAddressPrefix, $NSR.DestinationPortRange, $NSR.Name, $NSR.Priority, $NSR.Protocol, $NSR.SourceAddressPrefix, $NSR.SourcePortRange, $NSR.Type
#Are the set statements the same? if so then the rules are the same
if ($CurrentSetRule -ne $NewSetRule) {
#Rules are different, has the Priority Changed?
If ($CurrentRule.Priority -ne $NSR.Priority) {
if ($CurrentInboundRules | ? {$_.Priority -eq $NSR.Priority}) {
#Found a rule with the same priority as the new updated rule
#Keep iterating reducing the priority by one each time until we've foun a free number and use that otherwise fail the rule.
[int]$i = $NSR.Priority
while ($i -ge 100) {
if (-not($CurrentInboundRules | ? {$_.Priority -eq $i})) {
#Not rule in the current Active NSG that has the same priority, use that temporarily (will be changed later)
$RequestPriorityNumbers += (New-Object –TypeName PSObject -Property @{Name = $NSR.Name; RequestedPriority = $NSR.Priority; TemporaryPriority = $i})
$NSR.Priority = $i
break
}
if ($i -eq 100) {
#can't create the rule
$FailedRules += New-FailedUpdateAzureNetworkGroupRule -RuleNumber $($NetworkSecurityRulesInbound.IndexOf($NSR + 1)) -Message "The rule failed as there are no temporary priorty numbers left between the requested number and 100" -Direction "Inbound"
}
$i--
} # End of while loop
#Update the set rule with the new temporary priority
$NewSetRule = $SetRule -f $NSR.Action, $NSR.DestinationAddressPrefix, $NSR.DestinationPortRange, $NSR.Name, $NSR.Priority, $NSR.Protocol, $NSR.SourceAddressPrefix, $NSR.SourcePortRange, $NSR.Type
}
}
#Update the rule
Invoke-Expression $NewSetRule
}
}
else {
#New rule. Create the rule
#Check the Priority is available
if ($CurrentInboundRules | ? {$_.Priority -eq $NSR.Priority}) {
#Found a rule with the same priority as the new updated rule
#Keep iterating reducing the priority by one each time
[int]$i = $NSR.Priority
while ($i -ge 100) {
if (-not($CurrentInboundRules | ? {$_.Priority -eq $i})) {
#No rule in the current Active NSG has the same priority as $i, use that temporarily (will be changed to what it should be later)
$RequestPriorityNumbers += (New-Object –TypeName PSObject -Property @{Name = $NSR.Name; RequestedPriority = $NSR.Priority; TemporaryPriority = $i})
$NSR.Priority = $i
break
}
if ($i -eq 100) {
#Reached the bottom number of the permitted priority rules. Fail the rule
$FailedRules += New-FailedUpdateAzureNetworkGroupRule -RuleNumber $($NetworkSecurityRulesInbound.IndexOf($NSR + 1)) -Message "The rule failed as there are no temporary priorty numbers left between the requested number and 100" -Direction "Inbound"
}
$i--
}
}
#Build the new rule set statement
$SetRule2 = "`$NSG | Set-AzureNetworkSecurityRule -Action {0} -DestinationAddressPrefix {1} -DestinationPortRange {2} -Name ""{3}"" -Priority {4} -Protocol {5} -SourceAddressPrefix {6} -SourcePortRange {7} -Type {8}"
$NewSetRule = $SetRule2 -f $NSR.Action, $NSR.DestinationAddressPrefix, $NSR.DestinationPortRange, $NSR.Name, $NSR.Priority, $NSR.Protocol, $NSR.SourceAddressPrefix, $NSR.SourcePortRange, $NSR.Type
Write-Verbose "Updating the Rule using this PowerShell: $NewSetRule"
#Update the rule
Invoke-Expression $NewSetRule
}
}
#See if any rules have failed
if ($FailedRules) {
Write-Warning "Some rules have failed to process:"
$FailedRules | % {
Write-Warning "Rule: $($_.RuleNumber) FAILED because $($_.Message)"
}
}
#Get the updated NSG
$NSG = Get-AzureNetworkSecurityGroup -Name $NetworkSecurityGroupName -Detailed
#Get the current rules in the NSG
$CurrentRules = $NSG.Rules
$CurrentInboundRules = $CurrentRules | ? {($_.Type -eq "Inbound") -and ($AzureDefaultRuleNames -notcontains $_.Name)}
#Process the rules in the current NSG that no longer appear in the CSV file
ForEach ($CurrentRule in $CurrentInboundRules) {
#See if the rule exists
$Found = $NetworkSecurityRulesInbound | ? {($_.Name -eq $CurrentRule.Name)}
if (-not($Found)) {
#The rule doesn't exist in the CSV remove from the NSG
Write-Verbose "Removing the NSG rule name $($CurrentRule.Name)"
Remove-AzureNetworkSecurityRule -Name $CurrentRule.Name -NetworkSecurityGroup $NSG -Force
}
}
#Update the rules so they have the correct priorities now that the NSG should match the CSV
ForEach ($RequestPriorityNumber in $RequestPriorityNumbers) {
#Get the rule from the NSG
#Create a new set rule for the rule
$RuleToUpdate = $CurrentInboundRules | ? {$_.Name -eq $RequestPriorityNumber.Name}
#Found a rule to update
if ($RuleToUpdate) {
#rule found
$NewRule = $SetRule -f $RuleToUpdate.Action, $RuleToUpdate.DestinationAddressPrefix, $RuleToUpdate.DestinationPortRange, $RuleToUpdate.Name, $RequestPriorityNumber.RequestedPriority, $RuleToUpdate.Protocol, $RuleToUpdate.SourceAddressPrefix, $ruletoupdate.SourcePortRange, $RuleToUpdate.Type
Invoke-expression $NewRule
}
}
Write-Verbose "Completed inbound rules"
###################################################################################
#endregion #Inbound Rules
###################################################################################
###################################################################################
#region Outbound Rules
###################################################################################
Write-Verbose "Updating the outbound rules"
#Get the current rules in the NSG
$CurrentRules = (Get-AzureNetworkSecurityGroup -Name $NetworkSecurityGroupName -Detailed).Rules
$CurrentOutboundRules = $CurrentRules | ? {($_.Type -eq "Outbound") -and ($AzureDefaultRuleNames -notcontains $_.Name)}
#Breakdown the rules defined in the CSV
$NetworkSecurityRulesOutbound = $NetworkSecurityRules | ? {$_.Type -eq "Outbound"} | Sort-Object Priority
$NSG = Get-AzureNetworkSecurityGroup -Name $NetworkSecurityGroupName
#Base Rule - used to format the rule and passed to Invoke-Expression
$SetRule = "Set-AzureNetworkSecurityRule -Action {0} -DestinationAddressPrefix {1} -DestinationPortRange {2} -Name ""{3}"" -NetworkSecurityGroup `$NSG -Priority {4} -Protocol {5} -SourceAddressPrefix {6} -SourcePortRange {7} -Type {8}"
#Holds objects to help set the priority numbers correct
$RequestPriorityNumbers = @()
#This holds rules that have failed for some reason. A failed run will not fail the function at this time
$FailedRules = @()
#Process the rules in the CSV file, updating or creating.
ForEach ($NSR in $NetworkSecurityRulesOutbound) {
#See if the rule exists in the current set of NSG rules
$CurrentRule = $CurrentOutboundRules | ? {$_.Name -eq $NSR.Name}
#Found?
if ($CurrentRule) {
#Build the currrent rule set statement
$CurrentSetRule = $SetRule -f $CurrentRule.Action, $CurrentRule.DestinationAddressPrefix, $CurrentRule.DestinationPortRange, $CurrentRule.Name, $CurrentRule.Priority, $CurrentRule.Protocol, $CurrentRule.SourceAddressPrefix, $CurrentRule.SourcePortRange, $CurrentRule.Type
#Build the new rule set statement
$NewSetRule = $SetRule -f $NSR.Action, $NSR.DestinationAddressPrefix, $NSR.DestinationPortRange, $NSR.Name, $NSR.Priority, $NSR.Protocol, $NSR.SourceAddressPrefix, $NSR.SourcePortRange, $NSR.Type
#Are the set statements the same? if so then the rules are the same
if ($CurrentSetRule -ne $NewSetRule) {
#Rules are different, has the Priority Changed?
If ($CurrentRule.Priority -ne $NSR.Priority) {
if ($CurrentOutboundRules | ? {$_.Priority -eq $NSR.Priority}) {
#Found a rule with the same priority as the new updated rule
#Keep iterating reducing the priority by one each time until we've foun a free number and use that otherwise fail the rule.
[int]$i = $NSR.Priority
while ($i -ge 100) {
if (-not($CurrentOutboundRules | ? {$_.Priority -eq $i})) {
#Not rule in the current Active NSG that has the same priority, use that temporarily (will be changed later)
$RequestPriorityNumbers += (New-Object –TypeName PSObject -Property @{Name = $NSR.Name; RequestedPriority = $NSR.Priority; TemporaryPriority = $i})
$NSR.Priority = $i
break
}
if ($i -eq 100) {
#can't create the rule
$FailedRules += New-FailedUpdateAzureNetworkGroupRule -RuleNumber $($NetworkSecurityRulesOutbound.IndexOf($NSR + 1)) -Message "The rule failed as there are no temporary priorty numbers left between the requested number and 100" -Direction "Outbound"
}
$i--
} # End of while loop
#Update the set rule with the new temporary priority
$NewSetRule = $SetRule -f $NSR.Action, $NSR.DestinationAddressPrefix, $NSR.DestinationPortRange, $NSR.Name, $NSR.Priority, $NSR.Protocol, $NSR.SourceAddressPrefix, $NSR.SourcePortRange, $NSR.Type
}
}
#Update the rule
Invoke-Expression $NewSetRule
}
}
else {
#New rule. Create the rule
#Check the Priority is available
if ($CurrentOutboundRules | ? {$_.Priority -eq $NSR.Priority}) {
#Found a rule with the same priority as the new updated rule
#Keep iterating reducing the priority by one each time
[int]$i = $NSR.Priority
while ($i -ge 100) {
if (-not($CurrentOutboundRules | ? {$_.Priority -eq $i})) {
#No rule in the current Active NSG has the same priority as $i, use that temporarily (will be changed to what it should be later)
$RequestPriorityNumbers += (New-Object –TypeName PSObject -Property @{Name = $NSR.Name; RequestedPriority = $NSR.Priority; TemporaryPriority = $i})
$NSR.Priority = $i
break
}
if ($i -eq 100) {
#Reached the bottom number of the permitted priority rules. Fail the rule
$FailedRules += New-FailedUpdateAzureNetworkGroupRule -RuleNumber $($NetworkSecurityRulesOutbound.IndexOf($NSR + 1)) -Message "The rule failed as there are no temporary priorty numbers left between the requested number and 100" -Direction "Outbound"
}
$i--
}
}
#Build the new rule set statement
$SetRule2 = "`$NSG | Set-AzureNetworkSecurityRule -Action {0} -DestinationAddressPrefix {1} -DestinationPortRange {2} -Name ""{3}"" -Priority {4} -Protocol {5} -SourceAddressPrefix {6} -SourcePortRange {7} -Type {8}"
$NewSetRule = $SetRule2 -f $NSR.Action, $NSR.DestinationAddressPrefix, $NSR.DestinationPortRange, $NSR.Name, $NSR.Priority, $NSR.Protocol, $NSR.SourceAddressPrefix, $NSR.SourcePortRange, $NSR.Type
Write-Verbose "Updating the Rule using this PowerShell: $NewSetRule"
#Update the rule
Invoke-Expression $NewSetRule
}
}
#See if any rules have failed
if ($FailedRules) {
Write-Warning "Some rules have failed to process:"
$FailedRules | % {
Write-Warning "Rule: $($_.RuleNumber) FAILED because $($_.Message)"
}
}
#Get the updated NSG
$NSG = Get-AzureNetworkSecurityGroup -Name $NetworkSecurityGroupName -Detailed
#Get the current rules in the NSG
$CurrentRules = $NSG.Rules
$CurrentOutboundRules = $CurrentRules | ? {($_.Type -eq "Outbound") -and ($AzureDefaultRuleNames -notcontains $_.Name)}
#Process the rules in the current NSG that no longer appear in the CSV file
ForEach ($CurrentRule in $CurrentOutboundRules) {
#See if the rule exists
$Found = $NetworkSecurityRulesOutbound | ? {($_.Name -eq $CurrentRule.Name)}
if (-not($Found)) {
#The rule doesn't exist in the CSV remove from the NSG
Write-Verbose "Removing the NSG rule name $($CurrentRule.Name)"
Remove-AzureNetworkSecurityRule -Name $CurrentRule.Name -NetworkSecurityGroup $NSG -Force
}
}
#Update the rules so they have the correct priorities now that the NSG should match the CSV
ForEach ($RequestPriorityNumber in $RequestPriorityNumbers) {
#Get the rule from the NSG
#Create a new set rule for the rule
$RuleToUpdate = $CurrentOutboundRules | ? {$_.Name -eq $RequestPriorityNumber.Name}
#Found a rule to update
if ($RuleToUpdate) {
#rule found
$NewRule = $SetRule -f $RuleToUpdate.Action, $RuleToUpdate.DestinationAddressPrefix, $RuleToUpdate.DestinationPortRange, $RuleToUpdate.Name, $RequestPriorityNumber.RequestedPriority, $RuleToUpdate.Protocol, $RuleToUpdate.SourceAddressPrefix, $ruletoupdate.SourcePortRange, $RuleToUpdate.Type
Invoke-expression $NewRule
}
}
Write-Verbose "Completed inbound rules"
###################################################################################
#endregion
###################################################################################
#return the detailed NSG
Get-AzureNetworkSecurityGroup -Name $NetworkSecurityGroupName -Detailed
}
#endregion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment