Disclaimer: The below process is adapted, not to include any client specific details or information that can affect or impact the private form of business.

Scenario: Imagine that you have multiple sites running in the Azure web app, IIS is behind and it contains rewrite rules, which you are using to allow access to a certain part of your site by whitelisting the IP address, but also imagine that your public IP is dynamic – changing very often.

Solution: We came up with the idea to create Powershell function which will automate the addition of the IP address into the web site rewrite rules.

Note: The complete solution will not be functional until you change the appropriate parts of the code to fit your organization since we had to remove them in order to preserve client privacy and security.

Process break-down:

  • We have packaged the whole process into a Powershell module, at the end of this blog post I will share the complete package.
  • The first step is to create a service principal and application which will be authorized to access limited resources, in our case these are few web apps, for this, you can refer to This Post , in our case we are using the newest set of AZ modules instead of AzureRM.
  • The module is constructed of one public function and multiple private helper functions, I will post the code just from two major ones.
  • The first one which will target the web apps and execute the code against them.
#Requires -Module Az.Websites
Function Publish-AzWebAppFile {
    [CmdletBinding(DefaultParameterSetName="Set1")]
    param (
        # Affect all web apps.
        [Parameter(Mandatory=$true,
        ParameterSetName="Set1")]
        [switch]$All,
        # Name of the application that you want to affect.
        [Parameter(Mandatory=$true,
        ParameterSetName="Set2")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Webapp01","Webapp02","Webapp03","Webapp04")]
        [string[]]$WebApp,
        # File system path - where files should be stored.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Path,
        # IP address to add to the web app.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Ipaddress

    )
	# Service principal user name
    $UserName = "YourServicePrincipal/ApplicationName"
	# Get parent path of your script / module root
    $Parentpath = Split-Path -Parent $PSScriptRoot
	# Fetch the password file
    $File = "$Parentpath\Private\.sppw.txt"
	# Construct credential object
    $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, (Get-Content $File | ConvertTo-SecureString)
	# Connect to your azure tenant
    [void](Connect-AzAccount -TenantId "YourtenantID" -Credential $Credential -ServicePrincipal)
	# Use private function to confirm that you are connected to the azure context
    Confirm-AzSession
	# In case switch All is used, loop over all web apps
    if ($PSCmdlet.ParameterSetName -eq "Set1") {
        $Applist = @("Webapp01","Webapp02","Webapp03","Webapp04")
        foreach ($Application in $Applist) {
			# Use private function to confirm that web app exists
            Confirm-AzWebApp -Name $Application
			# Use private function to publish the new rewrite rule file to the web app
            Publish-WebAppFile -Name $Application -Path $Path
        }
    }
	# In case specific apps are specified, loop over them
    if ($PSCmdlet.ParameterSetName -eq "Set2") {
        foreach ($Application in $WebApp) {
			# Use private function to confirm that web app exists
            Confirm-AzWebApp -Name $Application
			# Use private function to publish the new rewrite rule file to the web app
            Publish-WebAppFile -Name $Application -Path $Path
        }
    }
}
  • The second one which is the actual process of what is happening behind the public function.
Function Publish-WebAppFile {
    [CmdletBinding()]
    param (
        # Name of the web app
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Name,
		# Path to the folder where you will store the configuration file.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Path
    )
    process {
		# Find the web app
        $Checkwebapp = (Get-AzWebApp -Name $Name)
		# Extract the FTP credentials from the web app
        $xml = [xml](
            Get-AzWebAppPublishingProfile -Name $Checkwebapp.RepositorySiteName -ResourceGroupName $Checkwebapp.ResourceGroup -OutputFile null
        )
        $username = $xml.SelectNodes("//publishProfile[@publishMethod=`"FTP`"]/@userName").value
        $password = $xml.SelectNodes("//publishProfile[@publishMethod=`"FTP`"]/@userPWD").value
        $url = $xml.SelectNodes("//publishProfile[@publishMethod=`"FTP`"]/@publishUrl").value
		# Check if the configuration location that you specified exist, if not create it
        $CheckLocation = (Get-item $Path -ErrorAction SilentlyContinue)
        if ([string]::IsNullOrWhiteSpace($CheckLocation)) {
            try {
                [void](New-Item -Path $Path -ItemType Directory -ErrorAction Stop)
            }
            catch {
                Write-Error "$_" -ErrorAction Stop
            }
        }
		# Construct the web client
        $Webclient = New-Object -TypeName System.Net.Webclient
        $Webclient.Credentials = New-Object System.Net.NetworkCredential($username,$password)
		# This block is targeting the rewrite rules file in the site/wwwroot
        $Filename = "rewriterules.config"
        $uri = New-Object System.Uri("$Url/$Filename")
        $Outputpath = "$Path\$FileName-"+$Name
		# Download the rewriterules file
        $Webclient.DownloadFile($uri,$Outputpath)
        $date = (get-date -Format dd-MM-yyyy)
		# Create a backup of the original config with appending the todays date
        Copy-Item $Outputpath -Destination "$Path\$FileName-$($Date)"
		# KEY component - insert whitelisting rule at the line number 20 of the config file, this is specific for our purpose.
        $filecontent = (get-content $Outputpath)
$text = @"
`n      <add input="{REMOTE_ADDR}" pattern="$Ipaddress" negate="true" />
"@
        $filecontent[20] += $text
        $filecontent | Set-Content $Outputpath
        # Upload file back to the web app
        $Filename = (Get-Item -Path $Outputpath).Name
        $Fullfilepath = (Get-Item -Path $Outputpath).FullName
        $TargetName = $Filename.split("-")[0]
        $uri = New-Object System.Uri("$Url/$TargetName")
        $Webclient.UploadFile($Uri,$Fullfilepath)
        $Webclient.Dispose()
        # Cleanup of the new file.
        Remove-Item $Fullfilepath -Force -Confirm:$false
		# Restart the web app to affect the changes
        [void](Restart-AzWebApp -Name $Checkwebapp.RepositorySiteName -ResourceGroupName $Checkwebapp.ResourceGroup)
    }
}

Wrap-up: At the end, we have installed the module on the clients’ computer, the client is now able to execute one command in the Powershell prompt while specifying its new IP address, in the manner of minutes it will be whitelisted, everyone happy.

Conclusion: Powershell is a very powerful tool, it can automate very difficult and trivial tasks, today we showed how it can be used to save a lot of time.

Download the module: