diff --git a/Control coverage/Feature/ApplicationGateway.md b/Control coverage/Feature/ApplicationGateway.md
new file mode 100644
index 00000000..d614a096
--- /dev/null
+++ b/Control coverage/Feature/ApplicationGateway.md
@@ -0,0 +1,108 @@
+# ApplicationGateway
+
+**Resource Type:** Microsoft.Network/applicationGateways
+
+
+
+- [Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial](#azure_applicationgateway_netsec_enable_waf_configuration_trial)
+
+
+
+
+___
+
+## Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial
+
+### Display Name
+[Trial] Application Gateway should have Web Application Firewall configured
+
+### Rationale
+Web application firewall configuration protects Application Gateway from internet based vulnerabilities and attacks without modification to back-end code.
+
+### Control Spec
+
+> **Passed:**
+> Web Application Firewall has been configured on Application Gateway.
+> Configured WAF Policy mode must be Prevention only.
+> DDoS is enabled on the Virtual Network assoicated with the Application Gateway.
+> Network Security Group is configured on the subnet assoicated with the Application Gateway.
+>
+> **Failed:**
+> WAF is not configured on Application Gateway.
+> Configured WAF Policy mode is not Prevention.
+> DDoS is not enabled on the Virtual Network assoicated with the Application Gateway.
+> Network Security Group is not configured on the subnet assoicated with the Application Gateway.
+>
+> **Error:**
+> There was an error fetching WAF Configuration details of Application Gateway.
+>
+### Recommendation
+
+- **Azure Portal**
+
+ Use the Azure portal to configure WAF on the Application Gateway.
+
+- **PowerShell**
+
+ ```powershell
+
+ # Below commands will be useful to Configure WAF on Application Gateway
+ Connect-AzAccount
+ Set-AzContext -SubscriptionId ""`
+ #Get Application Gateway and existing policy object
+ $appgw = Get-AzApplicationGateway -Name "applicationgatewayName" -ResourceGroupName "RgName"
+ $policy = Get-AzApplicationGatewayFirewallPolicy -Name "WAFPolicyName" -ResourceGroupName "RgName"
+
+ #Attach the policy to an Application Gateway
+ $appgw.FirewallPolicy = $policy
+ #Save the Application Gateway
+ Set-AzApplicationGateway -ApplicationGateway $appgw
+
+ #Below commands will be useful to configure the WAF at the listener level in the Application Gateway:
+ Connect-AzAccount
+ Set-AzContext -SubscriptionId ""`
+ #Get Application Gateway, Listener and existing policy object
+ $appgw = Get-AzApplicationGateway -Name "applicationgatewayName" -ResourceGroupName "RgName"
+ $policy = Get-AzApplicationGatewayFirewallPolicy -Name "WAFPolicyName" -ResourceGroupName "RgName"
+ $listener = Get-AzApplicationGatewayHttpListener -Name "L1" -ApplicationGateway $appgw
+ #Attach the policy to an Application Gateway Listener
+ $listener.FirewallPolicy = $policy
+
+ #Save the Application Gateway Listener
+ Set-AzApplicationGatewayHttpListener -FirewallPolicy $policy -ApplicationGateway $appgw
+
+ Below commands could be run to change the Policy Mode to Prevention mode:
+ Connect-AzAccount
+ Set-AzContext -SubscriptionId ""`
+ #Get Application Gateway Firewall policy
+ $policy = Get-azapplicationGatewayFirewallPolicy -Name "WAFPolicyName" -ResourceGroupName "RGName"
+ #Get the Policy Settings and Set the Mode to prevention
+ $Policysettings = $policy.PolicySettings
+ $Policysettings.Mode = "Prevention"
+ #Save the WAF Policy
+ Set-AzApplicationGatewayFirewallPolicy -PolicySetting $Policysettings -InputObject $policy
+
+ Run command
+ Retrieve-ApplicationGatewayVirtualNetworkDDoSNotConfigured - to retrieve the list of Application Gateway virtual network where DDoS is not enabled.
+ Run Enable-DDoSProtectionPlanOnVirtualNetwork to remediate the Virtual Network(s) retrieved from above command.
+
+ Run command Retrieve-ApplicationGatewaySubnetNSGNotConfigured to retrieve the list of Application Gateway subnet where NSG is not configured.
+ Run Add-NSGConfigurationOnSubnet to remediate the Subnet(s) retrieved from above command.
+
+ # For more help run:
+ Get-Help Retrieve-ApplicationGatewayVirtualNetworkDDoSNotConfigured -Detailed
+ Get-Help Enable-DDoSProtectionPlanOnVirtualNetwork -Detailed
+ Get-Help Retrieve-ApplicationGatewaySubnetNSGNotConfigured -Detailed
+ Get-Help Add-NSGConfigurationOnSubnet -Detailed
+ ```
+
+### Azure Policy or ARM API used for evaluation
+
+- ARM API to list all Application Gateway: /subscriptions/{0}/providers/Microsoft.Network/applicationGateways?api-version=2022-01-01
+**Properties:** properties.rights
+
+
+
+
+___
+
diff --git a/Scripts/RemediationScripts/Remediate-ConfigureNSGOnVirtualNetworkSubnet.ps1 b/Scripts/RemediationScripts/Remediate-ConfigureNSGOnVirtualNetworkSubnet.ps1
new file mode 100644
index 00000000..d6fd5dfc
--- /dev/null
+++ b/Scripts/RemediationScripts/Remediate-ConfigureNSGOnVirtualNetworkSubnet.ps1
@@ -0,0 +1,762 @@
+<###
+# Overview:
+ This script is used to configure the NSG on subnet of virtual network available in the App Gateway in a Subscription.
+
+# Control ID:
+ Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial
+
+# Display Name:
+ NGS must be configured on the Subnet.
+
+# Prerequisites:
+ Owner or higher priviliged role on the Virtual Network(s) is required for remediation.
+
+# Steps performed by the script:
+ To remediate:
+ 1. Validating and installing the modules required to run the script and validating the user.
+ 2. Get the list of Subnet(s) in a Subscription that have NSG is not configured.
+ 3. Back up details of Subnet(s) that are to be remediated.
+ 4. Configure the NSG on the Subnet(s) of Virtual Network in the Subscription.
+
+ To roll back:
+ 1. Validate and install the modules required to run the script and validating the user.
+ 2. Get the list of Subnet(s) in a Subscription, the changes made to which previously, are to be rolled back.
+ 3. Remove the NSG configuration from the Subnet(s) in the Subscription.
+
+# Instructions to execute the script:
+ To remediate:
+ 1. Download the script.
+ 2. Load the script in a PowerShell session. Refer https://aka.ms/AzTS-docs/RemediationscriptExcSteps to know more about loading the script.
+ 3. Execute the script to configure NSG on the Subnet(s) in the Subscription. Refer `Examples`, below.
+
+ To roll back:
+ 1. Download the script.
+ 2. Load the script in a PowerShell session. Refer https://aka.ms/AzTS-docs/RemediationscriptExcSteps to know more about loading the script.
+ 3. Execute the script to Remove the NSG configuration on the Subnet(s) in the Subscription. Refer `Examples`, below.
+
+# Examples:
+ To remediate:
+ 1. To review the Subnet(s) in a Subscription that will be remediated:
+
+ File has already been generated using the previous script.
+
+ 2. Configure the NSG on the Subnet(s)(s) in the Subscription:
+
+ Add-NSGConfigurationOnSubnet -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck
+
+ 3. Configure the NSG on the Subnet(s) in the Subscription, from a previously taken snapshot:
+
+ Add-NSGConfigurationOnSubnet -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -FilePath C:\AzTS\Subscriptions\00000000-xxxx-0000-xxxx-000000000000\202109131040\ConfigureNSG\SubnetDetailsBackUp.csv
+
+ To know more about the options supported by the remediation command, execute:
+
+ Get-Help Add-NSGConfigurationOnSubnet -Detailed
+
+ To roll back:
+ 1. Remove the NSG configuration on the Subnet(s) in the Subscription, from a previously taken snapshot:
+ Remove-NSGConfigurationOnSubnet -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -FilePath C:\AzTS\Subscriptions\00000000-xxxx-0000-xxxx-000000000000\202109131040\DisableDDoSProtectionPlan\RemediatedSubnetDetails.csv
+
+ To know more about the options supported by the roll back command, execute:
+
+ Get-Help Remove-NSGConfigurationOnSubnet -Detailed
+###>
+
+
+function Setup-Prerequisites
+{
+ <#
+ .SYNOPSIS
+ Checks if the prerequisites are met, else, sets them up.
+
+ .DESCRIPTION
+ Checks if the prerequisites are met, else, sets them up.
+ Includes installing any required Azure modules.
+
+ .INPUTS
+ None. You cannot pipe objects to Setup-Prerequisites.
+
+ .OUTPUTS
+ None. Setup-Prerequisites does not return anything that can be piped and used as an input to another command.
+
+ .EXAMPLE
+ PS> Setup-Prerequisites
+
+ .LINK
+ None
+ #>
+
+ # List of required modules
+ $requiredModules = @("Az.Accounts", "Az.Network")
+
+ Write-Host "Required modules: $($requiredModules -join ', ')"
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Checking if the required modules are present..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+
+ $availableModules = $(Get-Module -ListAvailable $requiredModules -ErrorAction Stop)
+
+ # Check if the required modules are installed.
+ $requiredModules | ForEach-Object {
+ if ($availableModules.Name -notcontains $_)
+ {
+ Write-Host "$($_) module is not present." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host "Installing [$($_)] module..." -ForegroundColor $([Constants]::MessageType.Info)
+ Install-Module -Name $_ -Scope CurrentUser -Repository 'PSGallery' -ErrorAction Stop
+ Write-Host "[$($_)] module installed." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ else
+ {
+ Write-Host "[$($_)] module is present." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ }
+ Write-Host "$($_) module is not present." -ForegroundColor $([Constants]::MessageType.Warning)
+}
+
+
+function Add-NSGConfigurationOnSubnet
+{
+ <#
+ .SYNOPSIS
+ Remediates 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+
+ .DESCRIPTION
+ Remediates 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+ Add the NSG configuration on the Subnet(s) in the Subscription.
+
+ .PARAMETER SubscriptionId
+ Specifies the ID of the Subscription to be remediated.
+
+ .PARAMETER Force
+ Specifies a forceful remediation without any prompts.
+
+ .Parameter PerformPreReqCheck
+ Specifies validation of prerequisites for the command.
+
+ .PARAMETER FilePath
+ Specifies the path to the file to be used as input for the remediation.
+
+ .INPUTS
+ None. You cannot pipe objects to Add-NSGConfigurationOnSubnet.
+
+ .OUTPUTS
+ None. Add-NSGConfigurationOnSubnet does not return anything that can be piped and used as an input to another command.
+
+ .EXAMPLE
+ PS> Add-NSGConfigurationOnSubnet -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck
+
+ .EXAMPLE
+ PS> Add-NSGConfigurationOnSubnet -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -FilePath C:\AzTS\Subscriptions\00000000-xxxx-0000-xxxx-000000000000\202109131040\ConfigureNSG\SubnetDetailsBackUp.csv
+
+ .LINK
+ None
+ #>
+
+ param (
+ [String]
+ [Parameter(ParameterSetName = "WetRun", Mandatory = $true, HelpMessage="Specifies the ID of the Subscription to be remediated")]
+ $SubscriptionId,
+
+ [Switch]
+ [Parameter(ParameterSetName = "WetRun", HelpMessage="Specifies validation of prerequisites for the command")]
+ $PerformPreReqCheck,
+
+ [String]
+ [Parameter(ParameterSetName = "WetRun", HelpMessage="Specifies the path to the file to be used as input for the remediation")]
+ $FilePath
+ )
+
+ Write-Host $([Constants]::DoubleDashLine)
+
+ if ($PerformPreReqCheck)
+ {
+ try
+ {
+ Write-Host "[Step 1 of 4] Validate and install the modules required to run the script and validate the user..."
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Setting up prerequisites..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Setup-Prerequisites
+ Write-Host "Completed setting up prerequisites." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ catch
+ {
+ Write-Host "Error occurred while setting up prerequisites. Error: $($_)" -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ }
+ else
+ {
+ Write-Host "[Step 1 of 4] Validate the user... "
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ # Connect to Azure account
+ $context = Get-AzContext
+
+ if ([String]::IsNullOrWhiteSpace($context))
+ {
+ Write-Host "Connecting to Azure account..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Connect-AzAccount -Subscription $SubscriptionId -ErrorAction Stop | Out-Null
+ Write-Host "Connected to Azure account." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ # Setting up context for the current Subscription.
+ $context = Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop
+
+
+ if(-not($AutoRemediation))
+ {
+ Write-Host "Subscription Name: [$($context.Subscription.Name)]"
+ Write-Host "Subscription ID: [$($context.Subscription.SubscriptionId)]"
+ Write-Host "Account Name: [$($context.Account.Id)]"
+ Write-Host "Account Type: [$($context.Account.Type)]"
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ Write-Host " To configure the NSG on the Subnet in a Subscription, Contributor or higher privileged role assignment on the Virtual Network(s) is required." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+
+ Write-Host "[Step 2 of 4] Fetch all Subnets(s)"
+ Write-Host $([Constants]::SingleDashLine)
+
+ # list to store Container details.
+ $SubnetDetails = @()
+
+ # To keep track of remediated and skipped resources
+ $logRemediatedResources = @()
+ $logSkippedResources=@()
+
+ # Control Id
+ $controlIds = "Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial"
+
+
+
+ if (-not (Test-Path -Path $FilePath))
+ {
+ Write-Host "ERROR: Input file: [$($FilePath)] not found. Exiting..." -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Fetch all Subnet(s) from [$($FilePath)]..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ $SubnetResources = Import-Csv -LiteralPath $FilePath
+
+ $validSubnetResources = $SubnetResources| Where-Object { ![String]::IsNullOrWhiteSpace($_.ResourceId) }
+
+ $validSubnetResources| ForEach-Object {
+ $resourceId = $_.ResourceId
+
+ try
+ {
+ $VNetResource = Get-AzVirtualNetwork -ResourceGroupName $_.ResourceVirtualNetworkRGName -Name $_.ResourceVirtualNetworkName -ErrorAction SilentlyContinue
+ $SubnetResource = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $VNetResource -Name $_.ResourceSubNetName
+ $SubnetDetails += $SubnetResource | Select-Object @{N='ResourceId';E={$_.Id}},
+ @{N='ResourceGroupName';E={$_.Id.Split("/")[4]}},
+ @{N='ResourceName';E={$_.Name}},
+ @{N='ResourceVirtualNetworkName';E={$_.Id.Split("/")[8]}},
+ @{N='IsNSGConfigured';E={
+ if($_.NetworkSecurityGroup -eq $null)
+ {
+ $false
+ }
+ else
+ {
+ $true
+ }
+ }}
+
+
+ }
+ catch
+ {
+ Write-Host "Error fetching subnet of Virtual Network(s) resource: Resource ID: [$($ResourceVNetName)]. Error: $($_)" -ForegroundColor $([Constants]::MessageType.Error)
+ }
+
+ }
+
+
+
+ $totalSubnet = ($SubnetDetails| Measure-Object).Count
+
+ if ($totalSubnet -eq 0)
+ {
+ Write-Host "No Subnet(s) found. Exiting..." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$($totalSubnet)] Subnet(s)." -ForegroundColor $([Constants]::MessageType.Update)
+
+ Write-Host $([Constants]::SingleDashLine)
+
+ # list for storing Subnet(s) for which NSG is not configured.
+ $SubnetWithoutNSGConfigured = @()
+
+ Write-Host "Separating Subnet(s) for which NSG is not configured..." -ForegroundColor $([Constants]::MessageType.Info)
+
+ $SubnetDetails | ForEach-Object {
+ $Subnet = $_
+ if($_.IsNSGConfigured -eq $false)
+ {
+ $SubnetWithoutNSGConfigured += $Subnet
+ }
+ }
+
+ $totalSubnetWithoutNSGConfigured = ($SubnetWithoutNSGConfigured | Measure-Object).Count
+
+ if ($totalSubnetWithoutNSGConfigured -eq 0)
+ {
+ Write-Host "No Subnet(s) found with where NSG is not configured.. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$($totalSubnetWithoutNSGConfigured)] Subnet(s) for which NSG is not configured ." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+
+ $colsProperty = @{Expression={$_.ResourceName};Label="ResourceName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceGroupName};Label="ResourceGroupName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceId};Label="ResourceId";Width=100;Alignment="left"},
+ @{Expression={$_.VirtualNetworkName};Label="VirtualNetworkName";Width=100;Alignment="left"}
+ @{Expression={$_.IsNSGConfigured};Label="IsNSGConfigured";Width=100;Alignment="left"}
+
+ if(-not $AutoRemediation)
+ {
+ Write-Host "Subnet(s) without NSG configuration are as follows:"
+ $SubnetWithoutNSGConfigured | Format-Table -Property $colsProperty -Wrap
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+
+ # Back up snapshots to `%LocalApplicationData%'.
+ $backupFolderPath = "$([Environment]::GetFolderPath('LocalApplicationData'))\AzTS\Remediation\Subscriptions\$($context.Subscription.SubscriptionId.replace('-','_'))\$($(Get-Date).ToString('yyyyMMddhhmm'))\ConfiguredNSGOnSubnet"
+
+ if (-not (Test-Path -Path $backupFolderPath))
+ {
+ New-Item -ItemType Directory -Path $backupFolderPath | Out-Null
+ }
+
+ Write-Host "[Step 3 of 4] Back up Subnet(s) details..."
+ Write-Host $([Constants]::SingleDashLine)
+
+ if ([String]::IsNullOrWhiteSpace($FilePath))
+ {
+ # Backing up Subnet(s) details.
+ $backupFile = "$($backupFolderPath)\SubnetDetailsBackUp.csv"
+ $SubnetWithoutNSGConfigured | Export-CSV -Path $backupFile -NoTypeInformation
+ Write-Host "Subnet(s) details have been backed up to [$($backupFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ else
+ {
+ Write-Host "Skipped as -FilePath is provided" -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ if (-not $DryRun)
+ {
+ Write-Host $([Constants]::DoubleDashLine)
+ Write-Host "[Step 4 of 4] Enable the DDoS Protection Plan on Subnet(s) in the Subscription..."
+ Write-Host $([Constants]::SingleDashLine)
+
+
+ if (-not $Force)
+ {
+ Write-Host "Do you want to configure NSG on the Subnet(s) in the Subscription? " -ForegroundColor $([Constants]::MessageType.Warning)
+
+ $userInput = Read-Host -Prompt "(Y|N)"
+
+ if($userInput -ne "Y")
+ {
+ Write-Host "we are starting the procedure to configure the NSG on the Subnet(s) in the Subscription. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ }
+
+
+ # List for storing remediated Subnet(s)
+ $SubnetRemediated = @()
+
+ # List for storing skipped Subnet(s)
+ $SubnetSkipped = @()
+
+ Write-Host "Enabling the NSG on Subnet(s)..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+
+ # Loop through the list of Subnet(s) which needs to be remediated.
+ $SubnetWithoutNSGConfigured | ForEach-Object {
+ $subnet = $_
+ try
+ {
+
+ Write-Host "To Start configuring the NSG on the Subnet(s), Please enter the Network Security Group Name..." -ForegroundColor $([Constants]::MessageType.Info)
+ $NSGName = Read-Host -Prompt "Please enter name of Network Security Group"
+ $NSGRGName = Read-Host -Prompt "Please enter Resource Group of Network Security Group"
+ if($NSGName -ne $null -and $NSGRGName -ne $null)
+ {
+ $nsg = Get-AzNetworkSecurityGroup -ResourceGroupName $NSGRGName -Name $NSGName
+ if($NSGName -ne $null)
+ {
+
+ $vnet = Get-AzVirtualNetwork -Name $_.ResourceVirtualNetworkName -ResourceGroupName $_.ResourceGroupName
+ $vNetSubnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $Vnet -Name $_.ResourceName
+ $vNetSubnet.NetworkSecurityGroup = $nsg
+ # $remediatedVNet = Set-AzVirtualNetwork -VirtualNetwork $vnet
+ $remediatedVnet = $vnet | Set-AzVirtualNetwork
+ $remediatedSubnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $remediatedVnet -Name $_.ResourceName
+
+ if($remediatedSubnet.NetworkSecurityGroup -ne $null)
+ {
+ $subnet.IsNSGConfigured = $true
+ $SubnetRemediated += $subnet
+ $logResource = @{}
+ $logResource.Add("ResourceGroupName",($_.ResourceGroupName))
+ $logResource.Add("ResourceName",($_.ResourceName))
+ $logRemediatedResources += $logResource
+ }
+ else
+ {
+ $SubnetSkipped += $subnet
+ $logResource = @{}
+ $logResource.Add("ResourceGroupName",($_.ResourceGroupName))
+ $logResource.Add("ResourceName",($_.ResourceName))
+ $logResource.Add("Reason", "Error Configuring NSG on : [$($subnet)]")
+ $logSkippedResources += $logResource
+
+ }
+ }
+ else
+ {
+ $SubnetSkipped += $subnet
+ $logResource = @{}
+ $logResource.Add("ResourceGroupName",($_.ResourceGroupName))
+ $logResource.Add("ResourceName",($_.ResourceName))
+ $logResource.Add("Reason", "Error Configuring NSG on : [$($subnet)]")
+ $logSkippedResources += $logResource
+ }
+ }
+ else
+ {
+ Write-Host "Network Security Group Name or Resource Group can not be empty..." -ForegroundColor $([Constants]::MessageType.Info)
+ $SubnetSkipped += $subnet
+ return;
+ }
+
+
+
+
+
+ }
+ catch
+ {
+ $SubnetSkipped += $subnet
+ $logResource = @{}
+ $logResource.Add("ResourceGroupName",($_.ResourceGroupName))
+ $logResource.Add("ResourceName",($_.ResourceName))
+ $logResource.Add("Reason","Encountered error Enabling DDoS Plan")
+ $logSkippedResources += $logResource
+ Write-Host "Skipping this resource..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ }
+
+ Write-Host $([Constants]::DoubleDashLine)
+
+ Write-Host "Remediation Summary: " -ForegroundColor $([Constants]::MessageType.Info)
+ if ($($SubnetRemediated | Measure-Object).Count -gt 0)
+ {
+ Write-Host "Successfully configured the NSG on the Suvbnet(s) in the subscription:" -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ $SubnetRemediated | Format-Table -Property $colsProperty -Wrap
+
+ # Write this to a file.
+ $SubnetRemediatedFile = "$($backupFolderPath)\RemediatedSubnets.csv"
+ $SubnetRemediated | Export-CSV -Path $SubnetRemediatedFile -NoTypeInformation
+
+ Write-Host "This information has been saved to" -NoNewline
+ Write-Host " [$($SubnetRemediatedFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host "Use this file for any roll back that may be required." -ForegroundColor $([Constants]::MessageType.Info)
+ }
+
+
+
+ if ($($SubnetSkipped | Measure-Object).Count -gt 0)
+ {
+
+ Write-Host "Error while configuring NSG on the subnet(s) in the subscription:" -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::SingleDashLine)
+ $SubnetSkipped | Format-Table -Property $colsProperty -Wrap
+
+ # Write this to a file.
+ $SubnetSkippedFile = "$($backupFolderPath)\SkippedSubnet.csv"
+ $SubnetSkipped | Export-CSV -Path $SubnetSkippedFile -NoTypeInformation
+ Write-Host "This information has been saved to" -NoNewline
+ Write-Host " [$($SubnetSkippedFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ }
+
+
+ }
+
+}
+
+function Remove-NSGConfigurationOnSubnet
+{
+ <#
+ .SYNOPSIS
+ Rolls back remediation done for 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+
+ .DESCRIPTION
+ Rolls back remediation done for 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+ Remove NSG configuration from the subnet(s) in the Subscription.
+
+ .PARAMETER SubscriptionId
+ Specifies the ID of the Subscription that was previously remediated.
+
+ .Parameter PerformPreReqCheck
+ Specifies validation of prerequisites for the command.
+
+ .PARAMETER FilePath
+ Specifies the path to the file to be used as input for the roll back.
+
+ .INPUTS
+ None. You cannot pipe objects to Remove-NSGConfigurationOnSubnet.
+
+ .OUTPUTS
+ None. Remove-NSGConfigurationOnSubnet does not return anything that can be piped and used as an input to another command.
+
+ .EXAMPLE
+ PS> Remove-NSGConfigurationOnSubnet -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -FilePath C:\AzTS\Subscriptions\00000000-xxxx-0000-xxxx-000000000000\202109131040\RemoveNSGConfiguration\RemediatedSubnets.csv
+
+ .LINK
+ None
+ #>
+
+ param (
+ [String]
+ [Parameter(Mandatory = $true, HelpMessage="Specifies the ID of the Subscription that was previously remediated.")]
+ $SubscriptionId,
+
+ [Switch]
+ [Parameter(HelpMessage="Specifies validation of prerequisites for the command")]
+ $PerformPreReqCheck,
+
+ [String]
+ [Parameter(Mandatory = $true, HelpMessage="Specifies the path to the file to be used as input for the roll back")]
+ $FilePath
+ )
+
+ if ($PerformPreReqCheck)
+ {
+ try
+ {
+ Write-Host "[Step 1 of 3] Validate and install the modules required to run the script and validate the user..."
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Setting up prerequisites..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Setup-Prerequisites
+ Write-Host "Completed setting up prerequisites"
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ catch
+ {
+ Write-Host "Error occurred while setting up prerequisites. Error: $($_)" -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ }
+ else
+ {
+ Write-Host "[Step 1 of 3] Validate the user..."
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ # Connect to Azure account
+ $context = Get-AzContext
+
+ if ([String]::IsNullOrWhiteSpace($context))
+ {
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Connecting to Azure account..."
+ Connect-AzAccount -Subscription $SubscriptionId -ErrorAction Stop | Out-Null
+ Write-Host "Connected to Azure account." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ else
+ {
+ # Setting up context for the current Subscription.
+ $context = Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop
+ }
+
+
+
+
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Subscription Name: [$($context.Subscription.Name)]"
+ Write-Host "Subscription ID: [$($context.Subscription.SubscriptionId)]"
+ Write-Host "Account Name: [$($context.Account.Id)]"
+ Write-Host "Account Type: [$($context.Account.Type)]"
+ Write-Host $([Constants]::SingleDashLine)
+
+ # Note about the required access required for remediation
+
+ Write-Host "To remove NSG configuration from the Subnet(s) in a Subscription, Contributor or higher privileged role assignment on the Virtual Network(s) is required." -ForegroundColor $([Constants]::MessageType.Warning)
+
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "[Step 2 of 3] Prepare to fetch all Subnet(s)"
+ Write-Host $([Constants]::SingleDashLine)
+
+ if (-not (Test-Path -Path $FilePath))
+ {
+ Write-Host "Input file: [$($FilePath)] not found. Exiting..." -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Fetch all Subnet(s) from" -NoNewline
+ Write-Host " [$($FilePath)\...]..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ $SubnetDetails = Import-Csv -LiteralPath $FilePath
+
+ $validSubnetDetails = $SubnetDetails | Where-Object { ![String]::IsNullOrWhiteSpace($_.ResourceId) -and ![String]::IsNullOrWhiteSpace($_.ResourceGroupName) -and ![String]::IsNullOrWhiteSpace($_.ResourceName) }
+
+ $totalSubnet = $(($validSubnetDetails|Measure-Object).Count)
+
+ if ($totalSubnet -eq 0)
+ {
+ Write-Host "No Subnet(s) found. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$(($validSubnetDetails|Measure-Object).Count)] Subnet(s)." -ForegroundColor $([Constants]::MessageType.Update)
+
+ $colsProperty = @{Expression={$_.ResourceName};Label="ResourceName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceGroupName};Label="ResourceGroupName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceId};Label="ResourceId";Width=100;Alignment="left"},
+ @{Expression={$_.VirtualNetworkName};Label="VirtualNetworkName";Width=100;Alignment="left"}
+ @{Expression={$_.ResourceId};Label="IsNSGConfigured";Width=100;Alignment="left"},
+
+
+ $validSubnetDetails | Format-Table -Property $colsProperty -Wrap
+
+ # Back up snapshots to `%LocalApplicationData%'.
+ $backupFolderPath = "$([Environment]::GetFolderPath('LocalApplicationData'))\AzTS\Remediation\Subscriptions\$($context.Subscription.SubscriptionId.replace('-','_'))\$($(Get-Date).ToString('yyyyMMddhhmm'))\RemoveNSGfromSubnet"
+
+ if (-not (Test-Path -Path $backupFolderPath))
+ {
+ New-Item -ItemType Directory -Path $backupFolderPath | Out-Null
+ }
+
+
+ Write-Host $([Constants]::DoubleDashLine)
+ Write-Host "[Step 3 of 3] Remove NSG Configuration from all remediated Subnet(s) in the Subscription"
+ Write-Host $([Constants]::SingleDashLine)
+
+ if( -not $Force)
+ {
+
+ Write-Host "Do you want to remove NSG Configuration from Subnet(s) mentioned in the file?" -ForegroundColor $([Constants]::MessageType.Warning)
+ $userInput = Read-Host -Prompt "(Y|N)"
+
+ if($userInput -ne "Y")
+ {
+ Write-Host "NSG Configuration will not be rolled back on Subnet(s) mentioned in the file. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ Write-Host "NSG Configuration will be rolled back on Subnet(s) mentioned in the file." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ else
+ {
+ Write-Host "'Force' flag is provided. NSG Configuration will be rolled back on Subnet(s) in the Subscription without any further prompts." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ # List for storing rolled back Subnet resource.
+ $SubnetRolledBack = @()
+
+ # List for storing skipped rolled back Subnet resource.
+ $SubnetSkipped = @()
+
+
+ $validSubnetDetails | ForEach-Object {
+ $Subnet = $_
+ try
+ {
+
+ $vnet = Get-AzVirtualNetwork -Name $_.ResourceVirtualNetworkName -ResourceGroupName $_.ResourceGroupName
+ $VnetSubnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $Vnet -Name $_.ResourceName
+ $VnetSubnet.NetworkSecurityGroup = $null
+ # $remediatedVNet = Set-AzVirtualNetwork -VirtualNetwork $vnet
+ $remediatedVnet = $vnet | Set-AzVirtualNetwork
+ $remediatedSubnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $remediatedVnet -Name $_.ResourceName
+
+ if($remediatedSubnet.NetworkSecurityGroup -eq $null)
+ {
+ $Subnet.IsNSGConfigured = $false
+ $SubnetRolledBack += $Subnet
+ }
+ else
+ {
+ $SubnetSkipped += $Subnet
+ }
+
+ }
+ catch
+ {
+ $SubnetSkipped += $Subnet
+ }
+ }
+
+
+ Write-Host $([Constants]::DoubleDashLine)
+ Write-Host "Rollback Summary:`n" -ForegroundColor $([Constants]::MessageType.Info)
+
+ if ($($SubnetRolledBack | Measure-Object).Count -gt 0)
+ {
+ Write-Host "NSG configuration has been removed on the following subnet(s) in the Subscription.:" -ForegroundColor $([Constants]::MessageType.Update)
+ $SubnetRolledBack | Format-Table -Property $colsProperty -Wrap
+ Write-Host $([Constants]::SingleDashLine)
+
+ # Write this to a file.
+ $SubnetRolledBackFile = "$($backupFolderPath)\RolledBackSubnet.csv"
+ $SubnetRolledBack | Export-CSV -Path $$SubnetRolledBackFile -NoTypeInformation
+ Write-Host "This information has been saved to" -NoNewline
+ Write-Host " [$($SubnetRolledBackFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ }
+
+ if ($($SubnetSkipped | Measure-Object).Count -gt 0)
+ {
+ Write-Host "Error while removing NSG configuration on the Subnet(s) in the Subscription.:" -ForegroundColor $([Constants]::MessageType.Error)
+ $SubnetSkipped | Format-Table -Property $colsProperty -Wrap
+ Write-Host $([Constants]::SingleDashLine)
+
+
+ # Write this to a file.
+ $SubnetSkippedFile = "$($backupFolderPath)\RollbackSkippedSubnet.csv"
+ $SubnetSkipped | Export-CSV -Path $SubnetSkippedFile -NoTypeInformation
+ Write-Host "This information has been saved to" -NoNewline
+ Write-Host " [$($SubnetSkippedFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ }
+}
+
+
+# Defines commonly used constants.
+class Constants
+{
+ # Defines commonly used colour codes, corresponding to the severity of the log...
+ static [Hashtable] $MessageType = @{
+ Error = [System.ConsoleColor]::Red
+ Warning = [System.ConsoleColor]::Yellow
+ Info = [System.ConsoleColor]::Cyan
+ Update = [System.ConsoleColor]::Green
+ Default = [System.ConsoleColor]::White
+ }
+
+ static [String] $DoubleDashLine = "========================================================================================================================"
+ static [String] $SingleDashLine = "------------------------------------------------------------------------------------------------------------------------"
+}
diff --git a/Scripts/RemediationScripts/Remediate-EnableDDOSVirtualNetwork.ps1 b/Scripts/RemediationScripts/Remediate-EnableDDOSVirtualNetwork.ps1
new file mode 100644
index 00000000..039826b3
--- /dev/null
+++ b/Scripts/RemediationScripts/Remediate-EnableDDOSVirtualNetwork.ps1
@@ -0,0 +1,756 @@
+<###
+# Overview:
+ This script is used to enable the DDOS on virtual network available in the App Gateway in a Subscription.
+
+# Control ID:
+ Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial
+
+# Display Name:
+ DDoS must be configured.
+
+# Prerequisites:
+ Owner or higher priviliged role on the Virtual Network(s) is required for remediation.
+
+# Steps performed by the script:
+ To remediate:
+ 1. Validating and installing the modules required to run the script and validating the user.
+ 2. Get the list of Virtual Network(s) in a Subscription that have DDoS Protection Plan is not enabled.
+ 3. Back up details of Virtual Network(s) that are to be remediated.
+ 4. Enable the DDoS Protection Plan on the Virtual Network(s) in the Subscription.
+
+ To roll back:
+ 1. Validate and install the modules required to run the script and validating the user.
+ 2. Get the list of Virtual Network(s) in a Subscription, the changes made to which previously, are to be rolled back.
+ 3. Disable the DDoS Protection Plan on the Virtual Network(s) in the Subscription.
+
+# Instructions to execute the script:
+ To remediate:
+ 1. Download the script.
+ 2. Load the script in a PowerShell session. Refer https://aka.ms/AzTS-docs/RemediationscriptExcSteps to know more about loading the script.
+ 3. Execute the script to enable the DDoS Protection Plan on the Virtual Network(s) in the Subscription. Refer `Examples`, below.
+
+ To roll back:
+ 1. Download the script.
+ 2. Load the script in a PowerShell session. Refer https://aka.ms/AzTS-docs/RemediationscriptExcSteps to know more about loading the script.
+ 3. Execute the script to disable the DDoS Protection Plan on the Virtual Network(s) in the Subscription. Refer `Examples`, below.
+
+# Examples:
+ To remediate:
+ 1. To review the Virtual Network(s) in a Subscription that will be remediated:
+
+ File has already been generated using the previous script.
+
+ 2. Enable the DDoS Protection Plan on the Virtual Network(s)(s) in the Subscription:
+
+ Enable-DDoSProtectionPlanOnVirtualNetwork -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck
+
+ 3. Enable the DDoS Protection Plan on the Virtual Network(s) in the Subscription, from a previously taken snapshot:
+
+ Enable-DDoSProtectionPlanOnVirtualNetwork -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -FilePath C:\AzTS\Subscriptions\00000000-xxxx-0000-xxxx-000000000000\202109131040\EnableDDoSProtectionPlan\VirtualNetworkDetailsBackUp.csv
+
+ To know more about the options supported by the remediation command, execute:
+
+ Get-Help Enable-DDoSProtectionPlanOnVirtualNetwork -Detailed
+
+ To roll back:
+ 1. Disable the DDoS Protection Plan on the Virtual Network(s) in the Subscription, from a previously taken snapshot:
+ Disable-DDoSProtectionPlanOnVirtualNetwork -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -FilePath C:\AzTS\Subscriptions\00000000-xxxx-0000-xxxx-000000000000\202109131040\DisableDDoSProtectionPlan\RemediatedVirtualNetworkDetails.csv
+
+ To know more about the options supported by the roll back command, execute:
+
+ Get-Help Disable-DDoSProtectionPlanOnVirtualNetwork -Detailed
+###>
+
+
+function Setup-Prerequisites
+{
+ <#
+ .SYNOPSIS
+ Checks if the prerequisites are met, else, sets them up.
+
+ .DESCRIPTION
+ Checks if the prerequisites are met, else, sets them up.
+ Includes installing any required Azure modules.
+
+ .INPUTS
+ None. You cannot pipe objects to Setup-Prerequisites.
+
+ .OUTPUTS
+ None. Setup-Prerequisites does not return anything that can be piped and used as an input to another command.
+
+ .EXAMPLE
+ PS> Setup-Prerequisites
+
+ .LINK
+ None
+ #>
+
+ # List of required modules
+ $requiredModules = @("Az.Accounts", "Az.Network")
+
+ Write-Host "Required modules: $($requiredModules -join ', ')"
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Checking if the required modules are present..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+
+ $availableModules = $(Get-Module -ListAvailable $requiredModules -ErrorAction Stop)
+
+ # Check if the required modules are installed.
+ $requiredModules | ForEach-Object {
+ if ($availableModules.Name -notcontains $_)
+ {
+ Write-Host "$($_) module is not present." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host "Installing [$($_)] module..." -ForegroundColor $([Constants]::MessageType.Info)
+ Install-Module -Name $_ -Scope CurrentUser -Repository 'PSGallery' -ErrorAction Stop
+ Write-Host "[$($_)] module installed." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ else
+ {
+ Write-Host "[$($_)] module is present." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ }
+ Write-Host "$($_) module is not present." -ForegroundColor $([Constants]::MessageType.Warning)
+}
+
+
+function Enable-DDoSProtectionPlanOnVirtualNetwork
+{
+ <#
+ .SYNOPSIS
+ Remediates 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+
+ .DESCRIPTION
+ Remediates 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+ Enable the DDoS Protection Plan on the Virtual Network(s) in the Subscription.
+
+ .PARAMETER SubscriptionId
+ Specifies the ID of the Subscription to be remediated.
+
+ .PARAMETER Force
+ Specifies a forceful remediation without any prompts.
+
+ .Parameter PerformPreReqCheck
+ Specifies validation of prerequisites for the command.
+
+ .PARAMETER FilePath
+ Specifies the path to the file to be used as input for the remediation.
+
+ .INPUTS
+ None. You cannot pipe objects to Enable-DDoSProtectionPlanOnVirtualNetwork.
+
+ .OUTPUTS
+ None. Enable-DDoSProtectionPlanOnVirtualNetwork does not return anything that can be piped and used as an input to another command.
+
+ .EXAMPLE
+ PS> Enable-DDoSProtectionPlanOnVirtualNetwork -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck
+
+ .EXAMPLE
+ PS> Enable-DDoSProtectionPlanOnVirtualNetwork -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -FilePath C:\AzTS\Subscriptions\00000000-xxxx-0000-xxxx-000000000000\202109131040\EnableDDoSProtectionPlan\VirtualNetworkDetailsBackUp.csv
+
+ .LINK
+ None
+ #>
+
+ param (
+ [String]
+ [Parameter(ParameterSetName = "WetRun", Mandatory = $true, HelpMessage="Specifies the ID of the Subscription to be remediated")]
+ $SubscriptionId,
+
+ [Switch]
+ [Parameter(ParameterSetName = "WetRun", HelpMessage="Specifies validation of prerequisites for the command")]
+ $PerformPreReqCheck,
+
+ [String]
+ [Parameter(ParameterSetName = "WetRun", HelpMessage="Specifies the path to the file to be used as input for the remediation")]
+ $FilePath
+ )
+
+ Write-Host $([Constants]::DoubleDashLine)
+
+ if ($PerformPreReqCheck)
+ {
+ try
+ {
+ Write-Host "[Step 1 of 4] Validate and install the modules required to run the script and validate the user..."
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Setting up prerequisites..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Setup-Prerequisites
+ Write-Host "Completed setting up prerequisites." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ catch
+ {
+ Write-Host "Error occurred while setting up prerequisites. Error: $($_)" -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ }
+ else
+ {
+ Write-Host "[Step 1 of 4] Validate the user... "
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ # Connect to Azure account
+ $context = Get-AzContext
+
+ if ([String]::IsNullOrWhiteSpace($context))
+ {
+ Write-Host "Connecting to Azure account..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Connect-AzAccount -Subscription $SubscriptionId -ErrorAction Stop | Out-Null
+ Write-Host "Connected to Azure account." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ # Setting up context for the current Subscription.
+ $context = Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop
+
+
+ if(-not($AutoRemediation))
+ {
+ Write-Host "Subscription Name: [$($context.Subscription.Name)]"
+ Write-Host "Subscription ID: [$($context.Subscription.SubscriptionId)]"
+ Write-Host "Account Name: [$($context.Account.Id)]"
+ Write-Host "Account Type: [$($context.Account.Type)]"
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ Write-Host " To Enable the DDOS on the Virtual Network in a Subscription, Contributor or higher privileged role assignment on the Virtual Network(s) is required." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+
+ Write-Host "[Step 2 of 4] Fetch all Virtual Network(s)"
+ Write-Host $([Constants]::SingleDashLine)
+
+ # list to store Container details.
+ $VirtualNetworkDetails = @()
+
+ # To keep track of remediated and skipped resources
+ $logRemediatedResources = @()
+ $logSkippedResources=@()
+
+ # Control Id
+ $controlIds = "Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial"
+
+
+
+ if (-not (Test-Path -Path $FilePath))
+ {
+ Write-Host "ERROR: Input file: [$($FilePath)] not found. Exiting..." -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Fetch all Virtual Network(s) from [$($FilePath)]..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ $VirtualNetworkResources = Import-Csv -LiteralPath $FilePath
+
+ $validVirtualNetworkResources = $VirtualNetworkResources| Where-Object { ![String]::IsNullOrWhiteSpace($_.ResourceId) }
+
+ $validVirtualNetworkResources| ForEach-Object {
+ $resourceId = $_.ResourceId
+
+ try
+ {
+ $VirtualNetworkResource = Get-AzVirtualNetwork -ResourceGroupName $_.ResourceVNetRGName -Name $_.ResourceVNetName -ErrorAction SilentlyContinue
+
+ $VirtualNetworkDetails += $VirtualNetworkResource | Select-Object @{N='ResourceId';E={$_.Id}},
+ @{N='ResourceGroupName';E={$_.Id.Split("/")[4]}},
+ @{N='ResourceName';E={$_.Name}},
+ @{N='IsDDOSEnabled';E={$_.EnableDdosProtection}}
+
+
+ }
+ catch
+ {
+ Write-Host "Error fetching Virtual Network(s) resource: Resource ID: [$($ResourceVNetName)]. Error: $($_)" -ForegroundColor $([Constants]::MessageType.Error)
+ }
+
+ }
+
+
+
+ $totalVirtualNetwork = ($VirtualNetworkDetails| Measure-Object).Count
+
+ if ($totalVirtualNetwork -eq 0)
+ {
+ Write-Host "No Virtual Network(s) found. Exiting..." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$($totalVirtualNetwork)] Virtual Network(s)." -ForegroundColor $([Constants]::MessageType.Update)
+
+ Write-Host $([Constants]::SingleDashLine)
+
+ # list for storing Virtual Network(s) for which DDoS Protection Plan is not enabled.
+ $VirtualNetworkWithoutDDoSEnabled = @()
+
+ Write-Host "Separating Virtual Network(s) for which DDoS is not enabled..." -ForegroundColor $([Constants]::MessageType.Info)
+
+ $VirtualNetworkDetails | ForEach-Object {
+ $VirtualNetwork = $_
+ if($_.IsDDOSEnabled -eq $false)
+ {
+ $VirtualNetworkWithoutDDoSEnabled += $VirtualNetwork
+ }
+ }
+
+ $totalVirtualNetworkWithoutDDoSEnabled = ($VirtualNetworkWithoutDDoSEnabled | Measure-Object).Count
+
+ if ($totalVirtualNetworkWithoutDDoSEnabled -eq 0)
+ {
+ Write-Host "No Virtual Network(s) found with where DDOS is not enabled.. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$($totalVirtualNetworkWithoutDDoSEnabled)] Virtual Network(s) for which DDoS is not enabled ." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+
+ $colsProperty = @{Expression={$_.ResourceName};Label="ResourceName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceGroupName};Label="ResourceGroupName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceId};Label="ResourceId";Width=100;Alignment="left"},
+ @{Expression={$_.IsDDOSEnabled};Label="IsDDOSEnabled";Width=100;Alignment="left"}
+
+ if(-not $AutoRemediation)
+ {
+ Write-Host "Virtual Network(s) without DDOS enabled are as follows:"
+ $VirtualNetworkWithoutDDoSEnabled | Format-Table -Property $colsProperty -Wrap
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+
+ # Back up snapshots to `%LocalApplicationData%'.
+ $backupFolderPath = "$([Environment]::GetFolderPath('LocalApplicationData'))\AzTS\Remediation\Subscriptions\$($context.Subscription.SubscriptionId.replace('-','_'))\$($(Get-Date).ToString('yyyyMMddhhmm'))\EnableDDoSProtectionOnVNet"
+
+ if (-not (Test-Path -Path $backupFolderPath))
+ {
+ New-Item -ItemType Directory -Path $backupFolderPath | Out-Null
+ }
+
+ Write-Host "[Step 3 of 4] Back up Virtual Network(s) details..."
+ Write-Host $([Constants]::SingleDashLine)
+
+ if ([String]::IsNullOrWhiteSpace($FilePath))
+ {
+ # Backing up Virtual Network(s) details.
+ $backupFile = "$($backupFolderPath)\VirtualNetworkDetailsBackUp.csv"
+ $VirtualNetworkWithoutDDoSEnabled | Export-CSV -Path $backupFile -NoTypeInformation
+ Write-Host "Virtual Network(s) details have been backed up to [$($backupFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ else
+ {
+ Write-Host "Skipped as -FilePath is provided" -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ if (-not $DryRun)
+ {
+ Write-Host $([Constants]::DoubleDashLine)
+ Write-Host "[Step 4 of 4] Enable the DDoS Protection Plan on Virtual Network(s) in the Subscription..."
+ Write-Host $([Constants]::SingleDashLine)
+
+
+ if (-not $Force)
+ {
+ Write-Host "Do you want to enable DDoS Protection Plan on the Virtual Network(s) in the Subscription? " -ForegroundColor $([Constants]::MessageType.Warning)
+
+ $userInput = Read-Host -Prompt "(Y|N)"
+
+ if($userInput -ne "Y")
+ {
+ Write-Host "we are starting the procedure to enable the DDoS Protection Plan on Virtual Network(s) in the Subscription. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ }
+
+
+ # List for storing remediated Virtual Network(s)
+ $VirtualNetworkRemediated = @()
+
+ # List for storing skipped Virtual Network(s)
+ $VirtualNetworkSkipped = @()
+
+ Write-Host "Enabling the DDoS on Virtual Network(s)..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+
+ # Loop through the list of Virtual Network(s) which needs to be remediated.
+ $VirtualNetworkWithoutDDoSEnabled | ForEach-Object {
+ $VirtualNetwork = $_
+ try
+ {
+
+ Write-Host "To Start enabling the DDoS on Virtual Network(s), Please enter the DDoS Protection Plan Name..." -ForegroundColor $([Constants]::MessageType.Info)
+
+ # Ask about the DDoS Plan Name
+ $DDoSPlanName = Read-Host -Prompt "Please enter DDoS Plan Name"
+ # Ask about the DDoS Plan RG Name
+ $DDoSPlanRGName = Read-Host -Prompt "Please enter the name of Resource Group where this DDoS Plan is available"
+ if($DDoSPlanName -ne $null -and $DDoSPlanRGName -ne $null)
+ {
+
+ $ddosProtectionPlanID = Get-AzDdosProtectionPlan -Name $DDoSPlanName -ResourceGroupName $DDoSPlanRGName
+ if($DDoSPlanName -ne $null -and $DDoSPlanRGName -ne $null)
+ {
+ $vnet = Get-AzVirtualNetwork -Name $_.ResourceName -ResourceGroupName $_.ResourceGroupName
+ $vnet.DdosProtectionPlan = New-Object Microsoft.Azure.Commands.Network.Models.PSResourceId
+
+ # Update the properties and enable DDoS protection
+ $vnet.DdosProtectionPlan.Id = $ddosProtectionPlanID.Id
+ $vnet.EnableDdosProtection = $true
+ $vnet = Set-AzVirtualNetwork -VirtualNetwork $vnet
+ # $vnet | Set-AzVirtualNetwork
+ }
+ else
+ {
+ Write-Host "Could not find the DDoS Plan with the given details..." -ForegroundColor $([Constants]::MessageType.Info)
+ $VirtualNetworkSkipped += $VirtualNetwork
+ return
+ }
+
+ }
+ else
+ {
+ Write-Host "DDoS Protection Plan Name/RG Name can not be empty..." -ForegroundColor $([Constants]::MessageType.Info)
+ $VirtualNetworkSkipped += $VirtualNetwork
+ return
+ }
+
+
+
+ if($vnet.EnableDdosProtection -eq $true)
+ {
+ $VirtualNetwork.IsDDOSEnabled = $true
+ $VirtualNetworkRemediated += $VirtualNetwork
+ $logResource = @{}
+ $logResource.Add("ResourceGroupName",($_.ResourceGroupName))
+ $logResource.Add("ResourceName",($_.ResourceName))
+ $logRemediatedResources += $logResource
+ }
+ else
+ {
+ $VirtualNetworkSkipped += $VirtualNetwork
+ $logResource = @{}
+ $logResource.Add("ResourceGroupName",($_.ResourceGroupName))
+ $logResource.Add("ResourceName",($_.ResourceName))
+ $logResource.Add("Reason", "Error Enabling the DDoS Plan: [$($VirtualNetwork)]")
+ $logSkippedResources += $logResource
+
+ }
+
+ }
+ catch
+ {
+ $VirtualNetworkSkipped += $VirtualNetwork
+ $logResource = @{}
+ $logResource.Add("ResourceGroupName",($_.ResourceGroupName))
+ $logResource.Add("ResourceName",($_.ResourceName))
+ $logResource.Add("Reason","Encountered error Enabling DDoS Plan")
+ $logSkippedResources += $logResource
+ Write-Host "Skipping this resource..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ }
+
+ Write-Host $([Constants]::DoubleDashLine)
+
+ Write-Host "Remediation Summary: " -ForegroundColor $([Constants]::MessageType.Info)
+ if ($($VirtualNetworkRemediated | Measure-Object).Count -gt 0)
+ {
+ Write-Host "Successfully enabled the DDoS on Virtual Network(s) in the subscription:" -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ $VirtualNetworkRemediated | Format-Table -Property $colsProperty -Wrap
+
+ # Write this to a file.
+ $VirtualNetworkRemediatedFile = "$($backupFolderPath)\RemediatedVirtualNetwork.csv"
+ $VirtualNetworkRemediated | Export-CSV -Path $VirtualNetworkRemediatedFile -NoTypeInformation
+
+ Write-Host "This information has been saved to" -NoNewline
+ Write-Host " [$($VirtualNetworkRemediatedFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host "Use this file for any roll back that may be required." -ForegroundColor $([Constants]::MessageType.Info)
+ }
+
+
+
+ if ($($VirtualNetworkSkipped | Measure-Object).Count -gt 0)
+ {
+
+ Write-Host "Error while enabling DDoS Protection Plan On Virtual Network(s) in the subscription:" -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::SingleDashLine)
+ $VirtualNetworkSkipped | Format-Table -Property $colsProperty -Wrap
+
+ # Write this to a file.
+ $VirtualNetworkSkippedFile = "$($backupFolderPath)\SkippedVirtualNetwork.csv"
+ $VirtualNetworkSkipped | Export-CSV -Path $VirtualNetworkSkippedFile -NoTypeInformation
+ Write-Host "This information has been saved to" -NoNewline
+ Write-Host " [$($VirtualNetworkSkippedFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ }
+
+
+ }
+}
+
+function Disable-DDoSProtectionPlanOnVirtualNetwork
+{
+ <#
+ .SYNOPSIS
+ Rolls back remediation done for 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+
+ .DESCRIPTION
+ Rolls back remediation done for 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+ Disable DDoS Protecion Plan on Virtual Network(s) in the Subscription.
+
+ .PARAMETER SubscriptionId
+ Specifies the ID of the Subscription that was previously remediated.
+
+ .PARAMETER Force
+ Specifies a forceful roll back without any prompts.
+
+ .Parameter PerformPreReqCheck
+ Specifies validation of prerequisites for the command.
+
+ .PARAMETER FilePath
+ Specifies the path to the file to be used as input for the roll back.
+
+ .INPUTS
+ None. You cannot pipe objects to Disable-DDoSProtectionPlanOnVirtualNetwork.
+
+ .OUTPUTS
+ None. Disable-DDoSProtectionPlanOnVirtualNetwork does not return anything that can be piped and used as an input to another command.
+
+ .EXAMPLE
+ PS> Disable-DDoSProtectionPlanOnVirtualNetwork -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -FilePath C:\AzTS\Subscriptions\00000000-xxxx-0000-xxxx-000000000000\202109131040\EnableDDoSOnVNet\RemediatedVirtualNetwork.csv
+
+ .LINK
+ None
+ #>
+
+ param (
+ [String]
+ [Parameter(Mandatory = $true, HelpMessage="Specifies the ID of the Subscription that was previously remediated.")]
+ $SubscriptionId,
+
+ [Switch]
+ [Parameter(HelpMessage="Specifies a forceful roll back without any prompts")]
+ $Force,
+
+ [Switch]
+ [Parameter(HelpMessage="Specifies validation of prerequisites for the command")]
+ $PerformPreReqCheck,
+
+ [String]
+ [Parameter(Mandatory = $true, HelpMessage="Specifies the path to the file to be used as input for the roll back")]
+ $FilePath
+ )
+
+ if ($PerformPreReqCheck)
+ {
+ try
+ {
+ Write-Host "[Step 1 of 3] Validate and install the modules required to run the script and validate the user..."
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Setting up prerequisites..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Setup-Prerequisites
+ Write-Host "Completed setting up prerequisites"
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ catch
+ {
+ Write-Host "Error occurred while setting up prerequisites. Error: $($_)" -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ }
+ else
+ {
+ Write-Host "[Step 1 of 3] Validate the user..."
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ # Connect to Azure account
+ $context = Get-AzContext
+
+ if ([String]::IsNullOrWhiteSpace($context))
+ {
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Connecting to Azure account..."
+ Connect-AzAccount -Subscription $SubscriptionId -ErrorAction Stop | Out-Null
+ Write-Host "Connected to Azure account." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ else
+ {
+ # Setting up context for the current Subscription.
+ $context = Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop
+ }
+
+
+
+
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Subscription Name: [$($context.Subscription.Name)]"
+ Write-Host "Subscription ID: [$($context.Subscription.SubscriptionId)]"
+ Write-Host "Account Name: [$($context.Account.Id)]"
+ Write-Host "Account Type: [$($context.Account.Type)]"
+ Write-Host $([Constants]::SingleDashLine)
+
+ # Note about the required access required for remediation
+
+ Write-Host "To disable DDoS Protection Plan on Virtual Network(s) in a Subscription, Contributor or higher privileged role assignment on the Virtual Network(s) is required." -ForegroundColor $([Constants]::MessageType.Warning)
+
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "[Step 2 of 3] Prepare to fetch all Virtual Network(s)"
+ Write-Host $([Constants]::SingleDashLine)
+
+ if (-not (Test-Path -Path $FilePath))
+ {
+ Write-Host "Input file: [$($FilePath)] not found. Exiting..." -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Fetching all Virtual Network(s) from" -NoNewline
+ Write-Host " [$($FilePath)\...]..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ $VirtualNetworkDetails = Import-Csv -LiteralPath $FilePath
+
+ $validVirtualNetworkDetails = $VirtualNetworkDetails | Where-Object { ![String]::IsNullOrWhiteSpace($_.ResourceId) -and ![String]::IsNullOrWhiteSpace($_.ResourceGroupName) -and ![String]::IsNullOrWhiteSpace($_.ResourceName) }
+
+ $totalVirtualNetwork = $(($validVirtualNetworkDetails|Measure-Object).Count)
+
+ if ($totalVirtualNetwork -eq 0)
+ {
+ Write-Host "No Virtual Network(s) found. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$(($validVirtualNetworkDetails|Measure-Object).Count)] Virtual Network(s)." -ForegroundColor $([Constants]::MessageType.Update)
+
+ $colsProperty = @{Expression={$_.ResourceName};Label="ResourceName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceGroupName};Label="ResourceGroupName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceId};Label="ResourceId";Width=100;Alignment="left"},
+ @{Expression={$_.IsDDOSEnabled};Label="IsDDOSEnabled";Width=100;Alignment="left"}
+
+
+ $validVirtualNetworkDetails | Format-Table -Property $colsProperty -Wrap
+
+ # Back up snapshots to `%LocalApplicationData%'.
+ $backupFolderPath = "$([Environment]::GetFolderPath('LocalApplicationData'))\AzTS\Remediation\Subscriptions\$($context.Subscription.SubscriptionId.replace('-','_'))\$($(Get-Date).ToString('yyyyMMddhhmm'))\DisableDDoSOnVNet"
+
+ if (-not (Test-Path -Path $backupFolderPath))
+ {
+ New-Item -ItemType Directory -Path $backupFolderPath | Out-Null
+ }
+
+
+ Write-Host $([Constants]::DoubleDashLine)
+ Write-Host "[Step 3 of 3] Disable DDoS Protection Plan on all remediated Virtual Network(s) in the Subscription"
+ Write-Host $([Constants]::SingleDashLine)
+
+ if( -not $Force)
+ {
+
+ Write-Host "Do you want to disable DDoS Protection Plan on Virtual Network(s) mentioned in the file?" -ForegroundColor $([Constants]::MessageType.Warning)
+ $userInput = Read-Host -Prompt "(Y|N)"
+
+ if($userInput -ne "Y")
+ {
+ Write-Host "DDoS Protection Plan will not be rolled back on Virtual Network(s) mentioned in the file. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ Write-Host "DDoS Protection Plan will be rolled back on Virtual Network(s) mentioned in the file." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ else
+ {
+ Write-Host "'Force' flag is provided. DDoS Protection Plan will be rolled back on Virtual Network(s) in the Subscription without any further prompts." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ # List for storing rolled back Virtual Network resource.
+ $VirtualNetworkRolledBack = @()
+
+ # List for storing skipped rolled back Virtual Network resource.
+ $VirtualNetworkSkipped = @()
+
+
+ $validVirtualNetworkDetails | ForEach-Object {
+ $VirtualNetwork = $_
+ try
+ {
+
+ $vnet = Get-AzVirtualNetwork -ResourceGroupName $_.ResourceGroupName -Name $_.ResourceName -ErrorAction SilentlyContinue
+ $vnet.DdosProtectionPlan = $null
+ $vnet.EnableDdosProtection = $false
+ $vnet = Set-AzVirtualNetwork -VirtualNetwork $vnet
+ # $vnet | Set-AzVirtualNetwork
+
+ if($vnet.EnableDdosProtection -eq $false)
+ {
+ $VirtualNetwork.IsDDOSEnabled = $false
+ $VirtualNetworkRolledBack += $VirtualNetwork
+ }
+ else
+ {
+ $VirtualNetworkSkipped += $VirtualNetwork
+ }
+
+ }
+ catch
+ {
+ $VirtualNetworkSkipped += $VirtualNetwork
+ }
+ }
+
+
+ Write-Host $([Constants]::DoubleDashLine)
+ Write-Host "Rollback Summary:`n" -ForegroundColor $([Constants]::MessageType.Info)
+
+ if ($($VirtualNetworkRolledBack | Measure-Object).Count -gt 0)
+ {
+ Write-Host "DDoS Protection Plan has been disabled on the following Virtual Network(s) in the Subscription.:" -ForegroundColor $([Constants]::MessageType.Update)
+ $VirtualNetworkRolledBack | Format-Table -Property $colsProperty -Wrap
+ Write-Host $([Constants]::SingleDashLine)
+
+ # Write this to a file.
+ $VirtualNetworkRolledBackFile = "$($backupFolderPath)\RolledBackVirtualNetwork.csv"
+ $VirtualNetworkRolledBack | Export-CSV -Path $VirtualNetworkRolledBackFile -NoTypeInformation
+ Write-Host "This information has been saved to" -NoNewline
+ Write-Host " [$($VirtualNetworkRolledBackFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ }
+
+ if ($($VirtualNetworkSkipped | Measure-Object).Count -gt 0)
+ {
+ Write-Host "Error while disabling DDoS Protection Plan on Virtual Network(s) in the Subscription.:" -ForegroundColor $([Constants]::MessageType.Error)
+ $VirtualNetworkSkipped | Format-Table -Property $colsProperty -Wrap
+ Write-Host $([Constants]::SingleDashLine)
+
+
+ # Write this to a file.
+ $VirtualNetworkSkippedFile = "$($backupFolderPath)\RollbackSkippedVirtualNetwork.csv"
+ $VirtualNetworkSkipped | Export-CSV -Path $VirtualNetworkSkippedFile -NoTypeInformation
+ Write-Host "This information has been saved to" -NoNewline
+ Write-Host " [$($VirtualNetworkSkippedFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ }
+}
+
+
+# Defines commonly used constants.
+class Constants
+{
+ # Defines commonly used colour codes, corresponding to the severity of the log...
+ static [Hashtable] $MessageType = @{
+ Error = [System.ConsoleColor]::Red
+ Warning = [System.ConsoleColor]::Yellow
+ Info = [System.ConsoleColor]::Cyan
+ Update = [System.ConsoleColor]::Green
+ Default = [System.ConsoleColor]::White
+ }
+
+ static [String] $DoubleDashLine = "========================================================================================================================"
+ static [String] $SingleDashLine = "------------------------------------------------------------------------------------------------------------------------"
+}
diff --git a/Scripts/RemediationScripts/Remediate-RetrieveSubnetsOfAppGateway.ps1 b/Scripts/RemediationScripts/Remediate-RetrieveSubnetsOfAppGateway.ps1
new file mode 100644
index 00000000..377de764
--- /dev/null
+++ b/Scripts/RemediationScripts/Remediate-RetrieveSubnetsOfAppGateway.ps1
@@ -0,0 +1,363 @@
+<###
+# Overview:
+ This script is used to get the subnet(s) of Application Gateway which are not part of NetworkSecurityGroup in a Subscription.
+
+# Control ID:
+ Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial
+
+# Display Name:
+ Get the Data of Subnets where NSG is not configured.
+
+# Prerequisites:
+ Owner or higher priviliged role on the Application Gateway(s) is required.
+
+# Steps performed by the script:
+ To Retrieve the list of Subnet(s):
+ 1. Validating and installing the modules required to run the script and validating the user.
+ 2. Get the list of Application Gateway(s) in a Subscription that have subnets where NSG is not configured.
+ 3. Back up details of Application Gateway(s) that are to be remediated.
+ 4. Configure the NSG on the subnet associated in the Application Gateway(s) in the Subscription.
+
+# Instructions to execute the script:
+ To remediate:
+ 1. Download the script.
+ 2. Load the script in a PowerShell session. Refer https://aka.ms/AzTS-docs/RemediationscriptExcSteps to know more about loading the script.
+ 3. Execute the script to get the list of subnets of Application Gateway(s) in the Subscription. Refer `Examples`, below.
+
+# Examples:
+ To remediate:
+ 1. To review the list of Subnets of Application Gateway(s) in a Subscription:
+
+ Retrieve-ApplicationGatewaySubnetNSGNotConfigured -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -DryRun
+
+ To know more about the options supported by the remediation command, execute:
+
+ Get-Help Retrieve-ApplicationGatewaySubnetNSGNotConfigured -Detailed
+###>
+
+
+function Setup-Prerequisites
+{
+ <#
+ .SYNOPSIS
+ Checks if the prerequisites are met, else, sets them up.
+
+ .DESCRIPTION
+ Checks if the prerequisites are met, else, sets them up.
+ Includes installing any required Azure modules.
+
+ .INPUTS
+ None. You cannot pipe objects to Setup-Prerequisites.
+
+ .OUTPUTS
+ None. Setup-Prerequisites does not return anything that can be piped and used as an input to another command.
+
+ .EXAMPLE
+ PS> Setup-Prerequisites
+
+ .LINK
+ None
+ #>
+
+ # List of required modules
+ $requiredModules = @("Az.Accounts", "Az.Network")
+
+ Write-Host "Required modules: $($requiredModules -join ', ')"
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Checking if the required modules are present..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+
+ $availableModules = $(Get-Module -ListAvailable $requiredModules -ErrorAction Stop)
+
+ # Check if the required modules are installed.
+ $requiredModules | ForEach-Object {
+ if ($availableModules.Name -notcontains $_)
+ {
+ Write-Host "$($_) module is not present." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host "Installing [$($_)] module..." -ForegroundColor $([Constants]::MessageType.Info)
+ Install-Module -Name $_ -Scope CurrentUser -Repository 'PSGallery' -ErrorAction Stop
+ Write-Host "[$($_)] module installed." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ else
+ {
+ Write-Host "[$($_)] module is present." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ }
+ Write-Host "$($_) module is not present." -ForegroundColor $([Constants]::MessageType.Warning)
+}
+
+
+function Retrieve-ApplicationGatewaySubnetNSGNotConfigured
+{
+ <#
+ .SYNOPSIS
+ Remediates 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+
+ .DESCRIPTION
+ Remediates 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+ Get the list of subnets of Application Gateway(s) in the Subscription.
+
+ .PARAMETER SubscriptionId
+ Specifies the ID of the Subscription to be remediated.
+
+ .Parameter PerformPreReqCheck
+ Specifies validation of prerequisites for the command.
+
+ .PARAMETER DryRun
+ Specifies a dry run of the actual remediation.
+
+ .INPUTS
+ None. You cannot pipe objects to Retrieve-ApplicationGatewaySubnetNSGNotConfigured.
+
+ .OUTPUTS
+ None. Retrieve-ApplicationGatewaySubnetNSGNotConfigured does return the list of Subnets that can be piped and used as an input to another script where NSG would be configured for these Subnet(s).
+
+ .EXAMPLE
+ PS> Retrieve-ApplicationGatewaySubnetNSGNotConfigured -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -DryRun
+
+ .EXAMPLE
+ PS> Retrieve-ApplicationGatewaySubnetNSGNotConfigured -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck
+
+ .LINK
+ None
+ #>
+
+ param (
+ [String]
+ [Parameter(ParameterSetName = "DryRun", Mandatory = $true, HelpMessage="Specifies the ID of the Subscription to be remediated")]
+ [Parameter(ParameterSetName = "WetRun", Mandatory = $true, HelpMessage="Specifies the ID of the Subscription to be remediated")]
+ $SubscriptionId,
+
+ [Switch]
+ [Parameter(ParameterSetName = "DryRun", HelpMessage="Specifies validation of prerequisites for the command")]
+ [Parameter(ParameterSetName = "WetRun", HelpMessage="Specifies validation of prerequisites for the command")]
+ $PerformPreReqCheck,
+
+ [Switch]
+ [Parameter(ParameterSetName = "DryRun", Mandatory = $true, HelpMessage="Specifies a dry run of the actual remediation")]
+ $DryRun
+ )
+
+ Write-Host $([Constants]::DoubleDashLine)
+
+ if ($PerformPreReqCheck)
+ {
+ try
+ {
+ Write-Host "[Step 1 of 4] Validate and install the modules required to run the script and validate the user..."
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Setting up prerequisites..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Setup-Prerequisites
+ Write-Host "Completed setting up prerequisites." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ catch
+ {
+ Write-Host "Error occurred while setting up prerequisites. Error: $($_)" -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ }
+ else
+ {
+ Write-Host "[Step 1 of 4] Validate the user... "
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ # Connect to Azure account
+ $context = Get-AzContext
+
+ if ([String]::IsNullOrWhiteSpace($context))
+ {
+ Write-Host "Connecting to Azure account..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Connect-AzAccount -Subscription $SubscriptionId -ErrorAction Stop | Out-Null
+ Write-Host "Connected to Azure account." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ # Setting up context for the current Subscription.
+ $context = Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop
+
+
+ Write-Host "Subscription Name: [$($context.Subscription.Name)]"
+ Write-Host "Subscription ID: [$($context.Subscription.SubscriptionId)]"
+ Write-Host "Account Name: [$($context.Account.Id)]"
+ Write-Host "Account Type: [$($context.Account.Type)]"
+ Write-Host $([Constants]::SingleDashLine)
+
+ Write-Host " To get the data from Application Gateway(s) in a Subscription, Contributor or higher privileged role assignment on the Application Gateway(s) is required." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+
+ Write-Host "[Step 2 of 4] Fetch all Application Gateway(s)"
+ Write-Host $([Constants]::SingleDashLine)
+
+ # list to store Container details.
+ $ApplicationGatewayDetails = @()
+
+ # To keep track of remediated and skipped resources
+ $logRemediatedResources = @()
+ $logSkippedResources=@()
+
+ # Control Id
+ $controlIds = "Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial"
+
+
+ # No file path provided as input to the script. Fetch all Application Gateway(s) in the Subscription.
+
+
+
+ Write-Host "Fetching all Application Gateway(s) in Subscription: [$($context.Subscription.SubscriptionId)]" -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+
+ # Get all Application Gateway(s) in a Subscription
+ $ApplicationGatewayDetails = Get-AzApplicationGateway -ErrorAction Stop
+
+ # Seperating required properties
+ $ApplicationGatewayDetails = $ApplicationGatewayDetails | Select-Object @{N='ResourceId';E={$_.Id}},
+ @{N='ResourceGroupName';E={$_.Id.Split("/")[4]}},
+ @{N='ResourceName';E={$_.Name}},
+ @{N='ResourceSubNetId';E={$_.GatewayIPConfigurations.SubnetText}},
+ @{N='ResourceSubNetName';E={
+
+ $subnetDetails = $_.GatewayIPConfigurations.SubnetText | ConvertFrom-Json
+ $subnetDetails.Id.Split('/')[10]
+
+ }
+ },
+ @{N='ResourceVirtualNetworkName';E={$_.GatewayIPConfigurations.SubnetText.Split('/')[8]}},
+ @{N='ResourceVirtualNetworkRGName';E={$_.GatewayIPConfigurations.SubnetText.Split('/')[4]}},
+ @{N='IsNSGConfigured';E=
+ {
+ if($_.Sku.Name -ne "Standard_v2" -and $_.Sku.Name -ne "WAF_v2")
+ {
+ $VnetDetails = Get-AzVirtualNetwork -Name $_.GatewayIPConfigurations.SubnetText.Split('/')[8] -ErrorAction Stop
+ Foreach($subnet in $VnetDetails.Subnets)
+ {
+ $subnetDetails = $_.GatewayIPConfigurations.SubnetText | ConvertFrom-Json
+ if($subnet.Id -eq $subnetDetails.Id)
+ {
+ if($subnet.NetworkSecurityGroup.Id -eq $null)
+ {
+ $false;
+ }
+ else
+ {
+ $true;
+ }
+ }
+ }
+ }
+ else{
+ $true;
+ }
+
+ }
+ }
+
+
+
+
+
+ $totalApplicationGateways = ($ApplicationGatewayDetails| Measure-Object).Count
+
+ if ($totalApplicationGateways -eq 0)
+ {
+ Write-Host "No subnet of Application Gateway(s) found where NSG is not configured. Exiting..." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$($totalApplicationGateways)] Application Gateway(s)." -ForegroundColor $([Constants]::MessageType.Update)
+
+ Write-Host $([Constants]::SingleDashLine)
+
+ # list for storing Application Gateway(s) for which NSG is not configured on associated Subnet.
+ $ApplicationGatewaySubnetWithoutNSG = @()
+
+ Write-Host "Separating Application Gateway(s) for which NSG is already configured on associated subnet..." -ForegroundColor $([Constants]::MessageType.Info)
+
+ $ApplicationGatewayDetails | ForEach-Object {
+ $ApplicationGateway = $_
+ if($_.IsNSGConfigured -eq $false)
+ {
+ $ApplicationGatewaySubnetWithoutNSG += $ApplicationGateway
+ }
+ }
+
+ $totalApplicationGatewaySubnetWithoutNSG = ($ApplicationGatewaySubnetWithoutNSG | Measure-Object).Count
+
+ if ($totalApplicationGatewaySubnetWithoutNSG -eq 0)
+ {
+ Write-Host "No Application Gateway(s) found where NSG is not configured on associated subnets.. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$($totalApplicationGatewaySubnetWithoutNSG)] Application Gateway(s) found where NSG is not configured on associated Subnets." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+
+ $colsProperty = @{Expression={$_.ResourceName};Label="ResourceName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceGroupName};Label="ResourceGroupName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceId};Label="ResourceId";Width=100;Alignment="left"},
+ @{Expression={$_.ResourceSubNetId};Label="ResourceSubNetId";Width=100;Alignment="left"},
+ @{Expression={$_.ResourceSubNetName};Label="ResourceSubNetName";Width=100;Alignment="left"},
+ @{Expression={$_.ResourceVNetName};Label="ResourceVNetName";Width=100;Alignment="left"},
+ @{Expression={$_.ResourceVNetRGName};Label="ResourceVNetRGName";Width=100;Alignment="left"},
+ @{Expression={$_.IsNSGConfigured};Label="IsNSGConfigured";Width=100;Alignment="left"}
+
+ if(-not $AutoRemediation)
+ {
+ Write-Host "Application Gateway(s) where NSG is not configured on associated subnet are as follows:"
+ $ApplicationGatewaySubnetWithoutNSG | Format-Table -Property $colsProperty -Wrap
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+
+ # Back up snapshots to `%LocalApplicationData%'.
+ $backupFolderPath = "$([Environment]::GetFolderPath('LocalApplicationData'))\AzTS\Remediation\Subscriptions\$($context.Subscription.SubscriptionId.replace('-','_'))\$($(Get-Date).ToString('yyyyMMddhhmm'))\SetApplicationGatewaySubnetWithNSGConfigured"
+
+ if (-not (Test-Path -Path $backupFolderPath))
+ {
+ New-Item -ItemType Directory -Path $backupFolderPath | Out-Null
+ }
+
+ Write-Host "[Step 3 of 4] Back up Application Gateway(s) details..."
+ Write-Host $([Constants]::SingleDashLine)
+
+ if ([String]::IsNullOrWhiteSpace($FilePath))
+ {
+ # Backing up Application Gateway Subnet(s) details.
+ $backupFile = "$($backupFolderPath)\ApplicationGatewaySubnetDetailsBackUp.csv"
+ $ApplicationGatewaySubnetWithoutNSG | Export-CSV -Path $backupFile -NoTypeInformation
+ Write-Host "Application Gateway(s) details have been backed up to [$($backupFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+
+ Write-Host "Skipped as -DryRun switch is provided." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Next steps:" -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host "Run the next command with -FilePath [$($backupFile)] and without -DryRun, Enable the NSG on the Subnet of Application Gateway(s) listed in the file." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+
+}
+
+
+
+
+# Defines commonly used constants.
+class Constants
+{
+ # Defines commonly used colour codes, corresponding to the severity of the log...
+ static [Hashtable] $MessageType = @{
+ Error = [System.ConsoleColor]::Red
+ Warning = [System.ConsoleColor]::Yellow
+ Info = [System.ConsoleColor]::Cyan
+ Update = [System.ConsoleColor]::Green
+ Default = [System.ConsoleColor]::White
+ }
+
+ static [String] $DoubleDashLine = "========================================================================================================================"
+ static [String] $SingleDashLine = "------------------------------------------------------------------------------------------------------------------------"
+}
diff --git a/Scripts/RemediationScripts/Remediate-RetrieveVirtualNetworkOfAppGateway.ps1 b/Scripts/RemediationScripts/Remediate-RetrieveVirtualNetworkOfAppGateway.ps1
new file mode 100644
index 00000000..19cdd7a9
--- /dev/null
+++ b/Scripts/RemediationScripts/Remediate-RetrieveVirtualNetworkOfAppGateway.ps1
@@ -0,0 +1,331 @@
+<###
+# Overview:
+ This script is used to get the Virtual Network of Application Gateway where DDOS is disabled in a Subscription.
+
+# Control ID:
+ Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial
+
+# Display Name:
+ Get the Data of Virtual Network where DDOS is disabled.
+
+# Prerequisites:
+ Owner or higher priviliged role on the Application Gateway(s) is required.
+
+# Steps performed by the script:
+ To Retrieve the list of Virtual Network(s):
+ 1. Validating and installing the modules required to run the script and validating the user.
+ 2. Get the list of Application Gateway(s) in a Subscription that have Virtual Network where DDoS Protection Plan is not configured.
+ 3. Back up details of Application Gateway(s) that are to be remediated.
+ 4. Configure the DDoS Protection Plan on the Virtual Network of Application Gateway(s) in the Subscription.
+
+# Instructions to execute the script:
+ To remediate:
+ 1. Download the script.
+ 2. Load the script in a PowerShell session. Refer https://aka.ms/AzTS-docs/RemediationscriptExcSteps to know more about loading the script.
+ 3. Execute the script to get the list of Virtual Network of Application Gateway(s) in the Subscription. Refer `Examples`, below.
+
+# Examples:
+ To remediate:
+ 1. To review the list of Virtual Network of Application Gateway(s) in a Subscription:
+
+ Retrieve-ApplicationGatewayVirtualNetworkDDoSNotConfigured -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -DryRun
+
+ To know more about the options supported by the remediation command, execute:
+
+ Get-Help Retrieve-ApplicationGatewayVirtualNetworkDDoSNotConfigured -Detailed
+###>
+
+
+function Setup-Prerequisites
+{
+ <#
+ .SYNOPSIS
+ Checks if the prerequisites are met, else, sets them up.
+
+ .DESCRIPTION
+ Checks if the prerequisites are met, else, sets them up.
+ Includes installing any required Azure modules.
+
+ .INPUTS
+ None. You cannot pipe objects to Setup-Prerequisites.
+
+ .OUTPUTS
+ None. Setup-Prerequisites does not return anything that can be piped and used as an input to another command.
+
+ .EXAMPLE
+ PS> Setup-Prerequisites
+
+ .LINK
+ None
+ #>
+
+ # List of required modules
+ $requiredModules = @("Az.Accounts", "Az.Network")
+
+ Write-Host "Required modules: $($requiredModules -join ', ')"
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Checking if the required modules are present..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+
+ $availableModules = $(Get-Module -ListAvailable $requiredModules -ErrorAction Stop)
+
+ # Check if the required modules are installed.
+ $requiredModules | ForEach-Object {
+ if ($availableModules.Name -notcontains $_)
+ {
+ Write-Host "$($_) module is not present." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host "Installing [$($_)] module..." -ForegroundColor $([Constants]::MessageType.Info)
+ Install-Module -Name $_ -Scope CurrentUser -Repository 'PSGallery' -ErrorAction Stop
+ Write-Host "[$($_)] module installed." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ else
+ {
+ Write-Host "[$($_)] module is present." -ForegroundColor $([Constants]::MessageType.Update)
+ }
+ }
+ Write-Host "$($_) module is not present." -ForegroundColor $([Constants]::MessageType.Warning)
+}
+
+
+function Retrieve-ApplicationGatewayVirtualNetworkDDoSNotConfigured
+{
+ <#
+ .SYNOPSIS
+ Remediates 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+
+ .DESCRIPTION
+ Remediates 'Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial' Control.
+ Get the list of Virtual Network of Application Gateway(s) in the Subscription.
+
+ .PARAMETER SubscriptionId
+ Specifies the ID of the Subscription to be remediated.
+
+ .Parameter PerformPreReqCheck
+ Specifies validation of prerequisites for the command.
+
+ .PARAMETER DryRun
+ Specifies a dry run of the actual remediation.
+
+ .INPUTS
+ None. You cannot pipe objects to Retrieve-ApplicationGatewayVirtualNetworkDDoSNotConfigured.
+
+ .OUTPUTS
+ None. Retrieve-ApplicationGatewayVirtualNetworkDDoSNotConfigured does return the list of Virtual Network that can be piped and used as an input to another script where DDoS would be configured for these Virtual Network(s).
+
+ .EXAMPLE
+ PS> Retrieve-ApplicationGatewayVirtualNetworkDDoSNotConfigured -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck -DryRun
+
+ .EXAMPLE
+ PS> Retrieve-ApplicationGatewayVirtualNetworkDDoSNotConfigured -SubscriptionId 00000000-xxxx-0000-xxxx-000000000000 -PerformPreReqCheck
+
+ .LINK
+ None
+ #>
+
+ param (
+ [String]
+ [Parameter(ParameterSetName = "DryRun", Mandatory = $true, HelpMessage="Specifies the ID of the Subscription to be remediated")]
+ [Parameter(ParameterSetName = "WetRun", Mandatory = $true, HelpMessage="Specifies the ID of the Subscription to be remediated")]
+ $SubscriptionId,
+
+ [Switch]
+ [Parameter(ParameterSetName = "DryRun", HelpMessage="Specifies validation of prerequisites for the command")]
+ [Parameter(ParameterSetName = "WetRun", HelpMessage="Specifies validation of prerequisites for the command")]
+ $PerformPreReqCheck,
+
+ [Switch]
+ [Parameter(ParameterSetName = "DryRun", Mandatory = $true, HelpMessage="Specifies a dry run of the actual remediation")]
+ $DryRun
+ )
+
+ Write-Host $([Constants]::DoubleDashLine)
+
+ if ($PerformPreReqCheck)
+ {
+ try
+ {
+ Write-Host "[Step 1 of 4] Validate and install the modules required to run the script and validate the user..."
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Setting up prerequisites..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Setup-Prerequisites
+ Write-Host "Completed setting up prerequisites." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ catch
+ {
+ Write-Host "Error occurred while setting up prerequisites. Error: $($_)" -ForegroundColor $([Constants]::MessageType.Error)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+ }
+ else
+ {
+ Write-Host "[Step 1 of 4] Validate the user... "
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+ # Connect to Azure account
+ $context = Get-AzContext
+
+ if ([String]::IsNullOrWhiteSpace($context))
+ {
+ Write-Host "Connecting to Azure account..." -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+ Connect-AzAccount -Subscription $SubscriptionId -ErrorAction Stop | Out-Null
+ Write-Host "Connected to Azure account." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+ # Setting up context for the current Subscription.
+ $context = Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop
+
+
+ Write-Host "Subscription Name: [$($context.Subscription.Name)]"
+ Write-Host "Subscription ID: [$($context.Subscription.SubscriptionId)]"
+ Write-Host "Account Name: [$($context.Account.Id)]"
+ Write-Host "Account Type: [$($context.Account.Type)]"
+ Write-Host $([Constants]::SingleDashLine)
+
+ Write-Host " To get the data from Application Gateway(s) in a Subscription, Contributor or higher privileged role assignment on the Application Gateway(s) is required." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+
+ Write-Host "[Step 2 of 4] Fetch all Application Gateway(s)"
+ Write-Host $([Constants]::SingleDashLine)
+
+ # list to store Container details.
+ $ApplicationGatewayDetails = @()
+
+ # To keep track of remediated and skipped resources
+ $logRemediatedResources = @()
+ $logSkippedResources=@()
+
+ # Control Id
+ $controlIds = "Azure_ApplicationGateway_NetSec_Enable_WAF_Configuration_Trial"
+
+
+ # No file path provided as input to the script. Fetch all Application Gateway(s) in the Subscription.
+
+
+
+ Write-Host "Fetching all Application Gateway(s) in Subscription: [$($context.Subscription.SubscriptionId)]" -ForegroundColor $([Constants]::MessageType.Info)
+ Write-Host $([Constants]::SingleDashLine)
+
+ # Get all Application Gateway(s) in a Subscription
+ $ApplicationGatewayDetails = Get-AzApplicationGateway -ErrorAction Stop
+
+ # Seperating required properties
+ $ApplicationGatewayDetails = $ApplicationGatewayDetails | Select-Object @{N='ResourceId';E={$_.Id}},
+ @{N='ResourceGroupName';E={$_.Id.Split("/")[4]}},
+ @{N='ResourceName';E={$_.Name}},
+ @{N='ResourceSubNetId';E={$_.GatewayIPConfigurations.SubnetText}},
+ @{N='ResourceVNetName';E={$_.GatewayIPConfigurations.SubnetText.Split('/')[8]}},
+ @{N='ResourceVNetRGName';E={$_.GatewayIPConfigurations.SubnetText.Split('/')[4]}},
+ @{N='IsDDOSEnabled';E=
+ {
+ $VnetDetails = Get-AzVirtualNetwork -Name $_.GatewayIPConfigurations.SubnetText.Split('/')[8] -ErrorAction Stop
+ $VnetDetails.EnableDdosProtection
+ }}
+
+
+ $totalApplicationGateways = ($ApplicationGatewayDetails| Measure-Object).Count
+
+ if ($totalApplicationGateways -eq 0)
+ {
+ Write-Host "No Virtual Network of Application Gateway(s) found where DDoS Protection Plan is disabled. Exiting..." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$($totalApplicationGateways)] Application Gateway(s)." -ForegroundColor $([Constants]::MessageType.Update)
+
+ Write-Host $([Constants]::SingleDashLine)
+
+ # list for storing Application Gateway(s) for which DDoS Protection Plan is not configured on associated Virtual Network.
+ $ApplicationGatewayVNetWithoutDDoS = @()
+
+ Write-Host "Separating Application Gateway(s) for which DDoS Protection Plan is already enabled on associated VNet..." -ForegroundColor $([Constants]::MessageType.Info)
+
+ $ApplicationGatewayDetails | ForEach-Object {
+ $ApplicationGateway = $_
+ if($_.IsDDOSEnabled -eq $false)
+ {
+ $ApplicationGatewayVNetWithoutDDoS += $ApplicationGateway
+ }
+ }
+
+ $totalApplicationGatewayVNetWithoutDDoS = ($ApplicationGatewayVNetWithoutDDoS | Measure-Object).Count
+
+ if ($totalApplicationGatewayVNetWithoutDDoS -eq 0)
+ {
+ Write-Host "No Application Gateway(s) found where DDoS Protection Plan is disabled on associated Virtual Network.. Exiting..." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+ return
+ }
+
+ Write-Host "Found [$($totalApplicationGatewayVNetWithoutDDoS)] Application Gateway(s) found where DDoS Protection Plan is disabled on associated Virtual Network." -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+
+ $colsProperty = @{Expression={$_.ResourceName};Label="ResourceName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceGroupName};Label="ResourceGroupName";Width=30;Alignment="left"},
+ @{Expression={$_.ResourceId};Label="ResourceId";Width=100;Alignment="left"},
+ @{Expression={$_.ResourceSubNetId};Label="ResourceSubNetId";Width=100;Alignment="left"},
+ @{Expression={$_.ResourceVNetName};Label="Resource Virtual Network Name";Width=100;Alignment="left"},
+ @{Expression={$_.ResourceVNetRGName};Label="Resource Virtual Network RG Name";Width=100;Alignment="left"},
+ @{Expression={$_.IsDDOSEnabled};Label="IsDDOSEnabled";Width=100;Alignment="left"}
+ @{Expression={$_.IsNSGConfigured};Label="IsNSGConfigured";Width=100;Alignment="left"}
+
+ if(-not $AutoRemediation)
+ {
+ Write-Host "Application Gateway(s) where DDoS Protection Plan is disabled on associated Virtual Network are as follows:"
+ $ApplicationGatewayVNetWithoutDDoS | Format-Table -Property $colsProperty -Wrap
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+
+ # Back up snapshots to `%LocalApplicationData%'.
+ $backupFolderPath = "$([Environment]::GetFolderPath('LocalApplicationData'))\AzTS\Remediation\Subscriptions\$($context.Subscription.SubscriptionId.replace('-','_'))\$($(Get-Date).ToString('yyyyMMddhhmm'))\VNetWithoutDDoSEnabled"
+
+ if (-not (Test-Path -Path $backupFolderPath))
+ {
+ New-Item -ItemType Directory -Path $backupFolderPath | Out-Null
+ }
+
+ Write-Host "[Step 3 of 4] Back up Application Gateway(s) details..."
+ Write-Host $([Constants]::SingleDashLine)
+
+ if ([String]::IsNullOrWhiteSpace($FilePath))
+ {
+ # Backing up Application Gateway(s) details.
+ $backupFile = "$($backupFolderPath)\ApplicationGatewayDetailsBackUp.csv"
+ $ApplicationGatewayVNetWithoutDDoS | Export-CSV -Path $backupFile -NoTypeInformation
+ Write-Host "Application Gateway(s) details have been backed up to [$($backupFile)]" -ForegroundColor $([Constants]::MessageType.Update)
+ Write-Host $([Constants]::SingleDashLine)
+ }
+
+
+ Write-Host "Skipped as -DryRun switch is provided." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::SingleDashLine)
+ Write-Host "Next steps:" -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host "Run the next command with -FilePath [$($backupFile)] and without -DryRun, Enable the DDOS on the Vnet of Application Gateway(s) listed in the file." -ForegroundColor $([Constants]::MessageType.Warning)
+ Write-Host $([Constants]::DoubleDashLine)
+
+}
+
+
+
+
+# Defines commonly used constants.
+class Constants
+{
+ # Defines commonly used colour codes, corresponding to the severity of the log...
+ static [Hashtable] $MessageType = @{
+ Error = [System.ConsoleColor]::Red
+ Warning = [System.ConsoleColor]::Yellow
+ Info = [System.ConsoleColor]::Cyan
+ Update = [System.ConsoleColor]::Green
+ Default = [System.ConsoleColor]::White
+ }
+
+ static [String] $DoubleDashLine = "========================================================================================================================"
+ static [String] $SingleDashLine = "------------------------------------------------------------------------------------------------------------------------"
+}