Create NSG ARM Template from CSV via Azure PowerShell

246 views Asked by At

I am trying to automate my NSG creation, as well as NSG remediation for Azure via DevOps pipelines. Therefore, I wrote a PowerShell script that creates an ARM Template, which is deployable in Azure, from a CSV with the specified NSG ruleset. The script runs smoothly, but only when I am leaving out some quotes.

I am able to create this template:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "NSG_Name": {
            "defaultValue": "XXXXXX0000-nsg",
            "type": "String"
        },
        "Tag_SystemOwner": {
            "defaultValue": "systemowner",
            "type": "String"
        },
        "Tag_BusinessProcess": {
            "defaultValue": "Network",
            "type": "String"
        },
        "Tag_CostCenter": {
            "defaultValue": "Group-IT",
            "type": "String"
        },
        "Tag_MHP-ID": {
            "defaultValue": "EUWAZP-XXXXX0000",
            "type": "String"
        }
    },
    "variables": {},
    "resources": [ 
        {
            "type": "Microsoft.Network/networkSecurityGroups",
            "apiVersion": "2020-11-01",
            "name": "[parameters(NSG_Name)]",
            "location": "westeurope",
            "tags": {
                "SystemOwner": "[parameters(Tag_SystemOwner)]",
                "CostCenter": "[parameters(Tag_CostCenter)]",
                "MHP-ID": "[parameters(Tag_MHP-ID)]",
                "BusinessProcess": "[parameters(Tag_BusinessProcess)]",
                "NSG-Template-Build": "WillBeReplacedToBuildNumber"
            },
            "properties": {
                "securityRules": [    
                    {
                    ...
                    }
                ]
            }
        }
    ]
}

But I need to get this code with the correct quotes, e.g. around the NSG_Name parameter:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "NSG_Name": {
            "defaultValue": "XXXXXX0000-nsg",
            "type": "String"
        },
        "Tag_SystemOwner": {
            "defaultValue": "systemowner",
            "type": "String"
        },
        "Tag_BusinessProcess": {
            "defaultValue": "Network",
            "type": "String"
        },
        "Tag_CostCenter": {
            "defaultValue": "Group-IT",
            "type": "String"
        },
        "Tag_MHP-ID": {
            "defaultValue": "EUWAZP-XXXXX0000",
            "type": "String"
        }
    },
    "variables": {},
    "resources": [
        {
            "type": "Microsoft.Network/networkSecurityGroups",
            "apiVersion": "2020-11-01",
            "name": "[parameters('NSG_Name')]",
            "location": "westeurope",
            "tags": {
                "SystemOwner": "[parameters('Tag_SystemOwner')]",
                "CostCenter": "[parameters('Tag_CostCenter')]",
                "MHP-ID": "[parameters('Tag_MHP-ID')]",
                "BusinessProcess": "[parameters('Tag_BusinessProcess')]",
                "NSG-Template-Build": "WillBeReplacedToBuildNumber"
            },
            "properties": {
                "securityRules": [
                    {
                    ...
                    }
                ]
            }
        }
    ]
}

However, when adding the single quote around the 'NSG_Name' the PowerShell script outputs the following error:

param(
    [Parameter(Mandatory=$true)]
    [String]$filename
  )

    $arm = '{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "NSG_Name": {
            "defaultValue": "XXXXXX0000-nsg",
            "type": "String"
        },
        "Tag_SystemOwner": {
            "defaultValue": "systemowner",
            "type": "String"
        },
        "Tag_BusinessProcess": {
            "defaultValue": "Network",
            "type": "String"
        },
        "Tag_CostCenter": {
            "defaultValue": "Group-IT",
            "type": "String"
        },
        "Tag_MHP-ID": {
            "defaultValue": "EUWAZP-XXXXX0000",
            "type": "String"
        }
    },
    "variables": {},
    "resources": [ 
        {
            "type": "Microsoft.Network/networkSecurityGroups",
            "apiVersion": "2020-11-01",
            "name": "[parameters('NSG_Name')]",
            "location": "westeurope",
            "tags": {
                "SystemOwner": "[parameters(Tag_SystemOwner)]",
                "CostCenter": "[parameters(Tag_CostCenter)]",
                "MHP-ID": "[parameters(Tag_MHP-ID)]",
                "BusinessProcess": "[parameters(Tag_BusinessProcess)]",
                "NSG-Template-Build": "WillBeReplacedToBuildNumber"
            },
            "properties": {
                "securityRules": [    
                    '
                Import-Csv -Path $env:SYSTEM_DEFAULTWORKINGDIRECTORY\$filename -Delimiter ";" | ForEach {

                    if($_.SourcePortRange -Match "," ) {
                        $SPRS = $_.SourcePortRange
                        $SPR = """*"""
                    } else {
                        $SPRS = $NULL
                        $SPR = $_.SourcePortRange
                    }

                    if($_.DestinationPortRange -Match "," ) {
                        $DPRS = $_.DestinationPortRange
                        $DPR = """*"""
                    } else {
                        $DPRS = $NULL
                        $DPR = $_.DestinationPortRange
                    }

                    if($_.SourceAddressPrefix -Match "," ) {
                        $SAPS = $_.SourceAddressPrefix
                        $SAP = """*"""
                    } else {
                        $SAPS = $NULL
                        $SAP = $_.SourceAddressPrefix
                    }

                    if($_.DestinationAddressPrefix -Match "," ) {
                        $DAPS = $_.DestinationAddressPrefix
                        $DAP = """*"""
                    } else {
                        $DAPS = $NULL
                        $DAP = $_.DestinationAddressPrefix
                    }

                    Write-Host "RuleName:" $_.RuleName
                    Write-Host "SourcePortRanges:" $SPRS
                    Write-Host "SourcePortRange:" $SPR
                    Write-Host "DestinationPortRanges:" $DPRS
                    Write-Host "DestinationPortRange:" $DPR
                    Write-Host "SourceAddressPrefixes:" $SAPS
                    Write-Host "SourceAddressPrefix:" $SAP
                    Write-Host "DestinationAddressPrefixes:" $DAPS
                    Write-Host "DestinationAddressPrefix:" $DAP

                    $jsonrule =  "{
                        ""name"": ""$($_.RuleName)"",
                        ""properties"": {
                            ""description"": ""$($_.Description)"",
                            ""protocol"": ""$($_.Protocol)"",
                            ""sourcePortRange"": $SPR,
                            ""destinationPortRange"": $DPR,
                            ""sourceAddressPrefix"": $SAP,
                            ""destinationAddressPrefix"": $DAP,
                            ""access"": ""Allow"",
                            ""priority"": ""$($_.Priority)"",
                            ""direction"": ""$($_.Direction)"",
                            ""sourcePortRanges"": [$SPRS],
                            ""destinationPortRanges"": [$DPRS],
                            ""sourceAddressPrefixes"": [$SAPS],
                            ""destinationAddressPrefixes"": [$DAPS]
                        }
                    },"
                    $arm+=$jsonrule
                }
                $arm = $arm.Substring(0,$arm.Length-1)
                $arm+=' 
                ]
            }
        }       
    ]
}'

$filename = "$env:SYSTEM_DEFAULTWORKINGDIRECTORY" + "\ARM-Templates\NSG-Governance\template.json"
$arm | out-file $filename
+             "name": "[parameters('NSG_Name')]",
+                                   ~~~~~~~~~~~~~
Unexpected token 'NSG_Name')]",
            "location": "westeurope",
            "tags": {
                "SystemOwner": "[parameters(Tag_SystemOwner)]",
                "CostCenter": "[parameters(Tag_CostCenter)]",
                "MHP-ID": "[parameters(Tag_MHP-ID)]",
                "BusinessProcess": "[parameters(Tag_BusinessProcess)]",
                "NSG-Template-Build": "WillBeReplacedToBuildNumber"
            },
            "properties": {
                "securityRules": [    
                    '' in expression or statement.
##[error]PowerShell exited with code '1'.

Has someone any solution for this problem? Any help would be much appreciated! Unfortunately, Microsoft Doc about quoting rules does not help me.

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7.2

Thank you!

Kind regards, Moritz.

1

There are 1 answers

0
Pramod Palukuru On

You can add both single and double quotes to a variable using ` along with double quotes. Below is an example, hope it helps.

$ex = "Using 'Single' quotes with `"Double 

quotes`"

"

$ex will have the value as:

Using 'Single' quotes with "Double 

quotes"

Let me know if this is not what you are looking for.