Adventures with Azure DevOps: Populating Azure Table Storage

Lately, I have been playing around with Azure DevOps, specifically a web application deployment using ARM Templates and Azure PowerShell.

I have a project, and an associated GIT repository, in Azure DevOps where I keep my ARM Templates and PowerShell scripts that I use for the deployment of my web application.

The release pipeline is triggered off of a commit to the master branch.

I have a table in Azure Storage, called lookups.

This is where I store all my lookup data, in this case, a list of all the Sports data available for my web application.

I store the Sports data in my repository in a file called sports.json.

[
  {
    "RowKey": "7fa95637-67d8-4ead-a1de-7aa8c2846ff9",
    "Name": "Basketball",
    "IsPopular": "true"
  },
  {
    "RowKey": "063a601c-590d-468c-b9ea-a1d82c8fc673",
    "Name": "Football",
    "IsPopular": "true"
  },
  {
    "RowKey": "35f25d50-9b3d-41f7-b788-dc92678c7720",
    "Name": "Baseball",
    "IsPopular": "true"
  },
  {
    "RowKey": "84e14ebb-ff6a-4466-b976-46dff368afdb",
    "Name": "Soccer",
    "IsPopular": "true"
  },
  {
    "RowKey": "b8fd389b-de76-4c45-abec-2f1e7f569af5",
    "Name": "Hockey",
    "IsPopular": "true"
  },
  {
    "RowKey": "2bdc4cc8-5bda-4b37-9c02-5f4cfc2e4918",
    "Name": "Tennis",
    "IsPopular": "false"
  },
  {
    "RowKey": "50b5ab15-bbd9-444d-a70d-63c4dd28a990",
    "Name": "Lacrosse",
    "IsPopular": "false"
  }
]

In one of my release tasks, I would like to populate the lookups table with the Sports data.

This can be accomplished through an Azure PowerShell task with the help of the AzureRMStorageTable module.

I am very thankful to Paulo Marques da Costa’s for his article, Working with Azure Tables from PowerShell – AzureRmStorageTable/AzTable PS Module v2.0, this was a huge help in figuring all the nuances of working with Table Storage with Azure PowerShell 2.*.

This feature is only available using Azure PowerShell 2.*, so make sure you set the Task Version to 4.* preview.

Let’s take a look at the PowerShell script.

param (
    [string]$EnvironmentName = $(throw "-EnvironmentName is required."),
    [string]$EnvironmentShortName = $(throw "-EnvironmentShortName is required."),
    [string]$DataPath
)

Install-Module AzureRmStorageTable -Force

$resourceGroupName = "XXXXXXXXXXX-" + $EnvironmentShortName.ToLower() + "-rg"
$storageAccountName = "XXXXXXXXXXX" + $EnvironmentShortName.ToLower() + "001stgacc";
$storageAccount = Get-AzStorageAccount -ResourceGroupName $resourceGroupName -AccountName $storageAccountName

$storageTable = Get-AzStorageTable `
    -Name "lookups" `
    -Context $storageAccount.Context `
    -ErrorVariable ev `
    -ErrorAction SilentlyContinue

if ($ev) {
    New-AzStorageTable -Name "lookups" -Context $storageAccount.Context
    $storageTable = Get-AzStorageTable -Name "lookups" -Context $storageAccount.Context
}

$sportsPath = "sports.json"

Write-Host $DataPath

if ($DataPath) {
    $sportsPath = $DataPath + $sportsPath
}

$sports = Get-Content -Raw -Path $sportsPath | ConvertFrom-Json

ForEach ($sport in $sports) {
    try {
        Add-AzTableRow `
            -table $storageTable.CloudTable `
            -partitionKey "Sport" `
            -rowKey $sport.RowKey `
            -property @{"Name" = $sport.Name; "IsPopular" = $sport.IsPopular } `
            -ErrorVariable ev `
            -ErrorAction SilentlyContinue
    }
    catch [System.Management.Automation.MethodInvocationException] {
        $tableRow = Get-AzTableRow `
            -table $storageTable.CloudTable `
            -partitionKey "Sport" `
            -rowKey $sport.RowKey
            
        $tableRow.Name = $sport.Name
        $tableRow.IsPopular = $sport.IsPopular

        $tableRow | Update-AzTableRow -table $storageTable.CloudTable  

        Write-Host $tableRow
    }
}

The script attempts to get the Azure Table Storage table lookups, if it is not found, it then creates thelookups table in Azure Table Storage.

The script takes three parameters:

  • EnvironmentName and EnvironmentShortName are used for naming resources
  • DataPath points to location of the sports.json file

When working locally, I do not pass anything for the DataPath parameter, it will use the root location of the script, while in Azure DevOps, I pass the value of $(System.DefaultWorkingDirectory)/_Teamaloo.Infrastructure/ to the DataPath parameter.

The scripts loads up the sports.json file and starts iterating through each record. It tries to add the record, if that fails, the assumption is the record already exists, and it then updates the record.

One thing I want to call out, in order to get this script to run, I had to add the Install-Module AzureRmStorageTable -Force command at the beginning, using -Force disables any required user interaction.

The AzureRmStorageTable module was not available by default.

I tried using Install-Module AzTable, the updated namespace, but that did not work.

Once I imported this module, everything worked perfectly.

This took me a couple of days to figure out, so hopefully this saves someone else a day or two.

As always, if there is an easier way to do this, please share!

Leave a Reply

Your email address will not be published.