Contents

Using Azure Storage Tables REST API with PowerShell

If you’ve interacted with Azure Storage using PowerShell, you’ve probably come across the AzTable community module. But, given this module’s developer abandonment, to reduce reliance on third-party packages, and to enable modern authentication, you can interact directly with Azure Tables using its REST API.

Background

What is Azure Tables?

Azure Tables is one of the easiest, cheapest ways to store schemaless key-value data in the cloud. It allows developers, platform engineers, and operations administrators to easily integrate durable, flexible data storage into their applications without needing to provision or manage a full database. Azure Tables is also popular for use with serverless, event-driven applications due to its high throughput and low latency.

Accessing Azure Tables

Like many Azure resources, Azure Tables supports access management configuration at both the Control Plane and Data Plane. Many developers will choose to use the Azure SDK to access the Data Plane, as it provides native abstractions for their language of choice and includes functionality such as authentication context management, retry logic, and rate limiting.

However, PowerShell is not a supported language of the Azure SDK. Therefore, to perform Azure Tables Data Plane operations using PowerShell, developers and engineers must utilize alternative methods: community-provided PowerShell modules, manually manipulating the .NET SDK, or the REST API.

AzTable module

The AzTable PowerShell module, originally authored by a Microsoft employee named Paulo Marques, has for years been the defacto method of performing Azure Table Storage operations with PowerShell. However, development of this module has been abandoned by both Paulo and Microsoft, with the last release over 2.5 years ago (April 9, 2021). Additionally, the module lacks modern functionality such as Microsoft Entra ID (f/k/a Azure Active Directory) authentication.

Setup

Using the Azure Tables REST API with PowerShell is incredibly simple and provides the most flexibility when interacting with the Data Plane.

Install

To start using the Azure Tables REST API with PowerShell, install the Azure PowerShell module and download the sample code from my Github. Sample code for common Entity operations is also provided in the Perform Operations section of this post.

Authentication

In your implementation, you can choose to support either Shared Key Authorization, Entra ID Authorization, or both.

Shared (Master) Key

Shared Key Authorization is the standard way of authenticating Azure Tables REST API requests. The Storage Account Key provides full, administrative access to all Storage Account Data Plane operations including creating, updating, and removing Azure Tables Entities (records).

Using Shared Key Authorization with the REST API does not require the assignment of any Data Plane Azure RBAC Roles, and only requires that the calling principal can list the Storage Account Keys. Built-in Azure RBAC Roles that include this permission are: Contributor and Reader and Data Access.

See the AccessKey #region of the Gist for code samples.

Entra ID (OAuth)

Microsoft Entra ID Authorization is the modern, preferred way of authenticating Azure Tables REST API requests. Using the built-in authentication and authorization capabilities of Microsoft Entra ID (such as Identity Protection, Identity Governance, PIM, and Conditional Access) enables greater security, control, and traceability for Azure Tables Data Plane operations when compared to Shared Key Authorization.

Access can be scoped to specific Data Plane operations by assigning either the Storage Table Data Reader or the Storage Table Data Contributor built-in Azure RBAC Role.

See the OAuth #region of the Gist for code samples.

Use

The Azure Tables REST API can be accessed either interactively as a user in a PowerShell session or unattended using a PowerShell automation service such as Azure Automation or Azure Functions.

Before continuing, please ensure that your user or Workload Identity has been granted the required Azure RBAC Role(s) to access your Storage Account and Table(s).

Note
All following setup guidance and code samples demonstrate the use of Entra ID, rather than Shared Key Authorization.

Interactive

To start using the Azure Tables REST API interactively, open a PowerShell session and run Connect-AzAccount. This will connect your Microsoft Entra ID identity to your PowerShell session.

My identity has been granted the Storage Table Data Contributor Role at the Storage Account scope. This assignment allows my identity to both read and write all Entities within all Tables in the Storage Account.

Azure Table Storage user RBAC Role

Automated

The following example uses an Azure Automation Account.

To start using the Azure Tables REST API in an unattended configuration, create an Automation Account and enabled the Managed Identity.

Azure Automation Account Managed Identity

Then, assign the Managed Identity the Storage Table Data Contributor Role at the Storage Account scope. This assignment allows the Automation Account to both read and write all Entities within all Tables in the Storage Account.

Azure Table Storage MI RBAC Role

Finally, create a PowerShell Runbook within the Automation Account. Add the following code to the top of the Runbook:

1
2
3
4
5
# Ensures you do not inherit an AzContext in your runbook
Disable-AzContextAutosave -Scope Process

# Connect to Azure with system-assigned managed identity
Connect-AzAccount -Identity

Then, paste the required sample Azure Tables REST API code into the Runbook (see below for samples).

Perform operations

Below is sample PowerShell code that can be used to perform CRUD operations on Azure Tables Entities using the REST API.

All samples assume you have already connected Azure PowerShell to your Azure environment using either the Interactive or Automated Microsoft Entra ID authentication flow.

All samples will reference a Storage Account named sttabledemouse2dev and an Azure Table named RestApi.

Create Entity

All Azure Tables Entities require the following properties to be defined at creation time:

  • PartitionKey
    • Used to group Entities.
  • RowKey
    • Used to uniquely identify an Entity within a Table.

All other properties are optional and are based on the schema of the Entity being created. Azure Tables is a schemaless data store, so each Entity within the Table can potentially have different properties defined. Below is a PowerShell code sample that creates an Azure Tables Entity with two user-defined properties: Name and Status.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Storage Account and Table details
$StorageAccount = 'sttabledemouse2dev'
$Table          = 'RestApi'

# Entity details
$PartitionKey   = 'partition1'
$RowKey         = (New-Guid).Guid

# Azure Table Storage request headers
$Date = [DateTime]::UtcNow.ToString('R')
$AzTableHeaders = @{
    'Accept'        = 'application/json;odata=nometadata'
    'x-ms-version'  = '2020-08-04'
    'x-ms-date'     = $Date
}

# Azure Table Storage Entra ID Authorization
$AzStorageToken = Get-AzAccessToken -ResourceTypeName Storage
$AzTableHeaders += @{'Authorization' = "$($AzStorageToken.Type) $($AzStorageToken.Token)"}

# Define Entity
$InsertBody = @{
    PartitionKey = $PartitionKey
    RowKey       = $RowKey.ToString()
    Name         = 'myEntity'
    Status       = 'Active'
} | ConvertTo-Json

# Create Entity using REST API
Invoke-RestMethod -Method Post -Uri "https://$StorageAccount.table.core.windows.net/$Table" -Body $InsertBody -Headers $AzTableHeaders -ContentType 'application/json'

The REST API will respond with a PSCustomObject representation of the new Entity.

PowerShell Create Entity response

You can view the Entity within the Azure Portal or the Azure Storage Explorer.

Azure Table Create Entity result

Get Entity

Retrieve an Azure Tables Entity by providing its PartitionKey and RowKey.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Storage Account and Table details
$StorageAccount = 'sttabledemouse2dev'
$Table          = 'RestApi'

# Entity details
$PartitionKey   = 'partition1'
$RowKey         = 'b748030d-f434-47d9-b6a2-2f0f05df59c1'

# Azure Table Storage request headers
$Date = [DateTime]::UtcNow.ToString('R')
$AzTableHeaders = @{
    'Accept'        = 'application/json;odata=nometadata'
    'x-ms-version'  = '2020-08-04'
    'x-ms-date'     = $Date
}

# Azure Table Storage Entra ID Authorization
$AzStorageToken = Get-AzAccessToken -ResourceTypeName Storage
$AzTableHeaders += @{'Authorization' = "$($AzStorageToken.Type) $($AzStorageToken.Token)"}

# Get Entity using REST API
Invoke-RestMethod -Method Get -Uri "https://$StorageAccount.table.core.windows.net/$Table(PartitionKey='$PartitionKey',RowKey='$RowKey')" -Headers $AzTableHeaders

The REST API will respond with a PSCustomObject representation of the Entity.

PowerShell Get Entity response

Query Entities

The Azure Tables REST API supports the OData specification for querying Entities.

Get all Entities with a specific PartitionKey

Retrieve all Entities within an Azure Storage Table that share a PartitionKey.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Storage Account and Table details
$StorageAccount = 'sttabledemouse2dev'
$Table          = 'RestApi'

# Entity details
$PartitionKey   = 'partition1'

# Azure Table Storage request headers
$Date = [DateTime]::UtcNow.ToString('R')
$AzTableHeaders = @{
    'Accept'        = 'application/json;odata=nometadata'
    'x-ms-version'  = '2020-08-04'
    'x-ms-date'     = $Date
}

# Azure Table Storage Entra ID Authorization
$AzStorageToken = Get-AzAccessToken -ResourceTypeName Storage
$AzTableHeaders += @{'Authorization' = "$($AzStorageToken.Type) $($AzStorageToken.Token)"}

# Get all Entities by using a PartitionKey filter with the REST API
Invoke-RestMethod -Method Get -Uri "https://$StorageAccount.table.core.windows.net/$Table()?`$filter=PartitionKey eq '$PartitionKey'" -Headers $AzTableHeaders | Select-Object -ExpandProperty value

The REST API will respond with an array of PSCustomObjects representing the Entities.

PowerShell Query Entities response

Get all Entities in a Table

Pagination is required to retrieve all Entities within an Azure Storage Table. The following sample shows one potential pagination implementation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Storage Account and Table details
$StorageAccount = 'sttabledemouse2dev'
$Table          = 'RestApi'

# Azure Table Storage request headers
$Date = [DateTime]::UtcNow.ToString('R')
$AzTableHeaders = @{
    'Accept'        = 'application/json;odata=nometadata'
    'x-ms-version'  = '2020-08-04'
    'x-ms-date'     = $Date
}

# Azure Table Storage Entra ID Authorization
$AzStorageToken = Get-AzAccessToken -ResourceTypeName Storage
$AzTableHeaders += @{'Authorization' = "$($AzStorageToken.Type) $($AzStorageToken.Token)"}

# Get all Entities in Table using REST API
# Invoke-WebRequest is used rather than Invoke-RestMethod to access response headers
$TableRecords = @()
$TableResponse = Invoke-WebRequest -Method Get -Uri "https://$StorageAccount.table.core.windows.net/$Table()" -Headers $AzTableHeaders
$TableRecords += $TableResponse | Select-Object -ExpandProperty Content | ConvertFrom-Json | Select-Object -ExpandProperty value
$TableRecords += while ($TableResponse.Headers.'x-ms-continuation-NextPartitionKey') {
    $TableResponse = Invoke-WebRequest -Method Get -Uri "https://$StorageAccount.table.core.windows.net/$Table()?NextPartitionKey=$($TableResponse.Headers.'x-ms-continuation-NextPartitionKey')&NextRowKey=$($TableResponse.Headers.'x-ms-continuation-NextRowKey')" -Headers $AzTableHeaders
    $TableResponse | Select-Object -ExpandProperty Content | ConvertFrom-Json | Select-Object -ExpandProperty value
}

The REST API will respond with an array of PSCustomObjects representing the Entities.

PowerShell all Entities response

Update Entity

Update an existing Entity by providing the PartitionKey and RowKey properties, along with an object representing the modified user-defined properties.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Storage Account and Table details
$StorageAccount = 'sttabledemouse2dev'
$Table          = 'RestApi'

# Entity details
$PartitionKey   = 'partition1'
$RowKey         = 'b748030d-f434-47d9-b6a2-2f0f05df59c1'

# Azure Table Storage request headers
$Date = [DateTime]::UtcNow.ToString('R')
$AzTableHeaders = @{
    'Accept'        = 'application/json;odata=nometadata'
    'x-ms-version'  = '2020-08-04'
    'x-ms-date'     = $Date
}

# Azure Table Storage Entra ID Authorization
$AzStorageToken = Get-AzAccessToken -ResourceTypeName Storage
$AzTableHeaders += @{'Authorization' = "$($AzStorageToken.Type) $($AzStorageToken.Token)"}

# Define updated object
$UpdateBody = @{
    Name = 'NewName'
} | ConvertTo-Json

# Update Entity using REST API
Invoke-RestMethod -Method Put -Uri "https://$StorageAccount.table.core.windows.net/$Table(PartitionKey='$PartitionKey',RowKey='$RowKey')" -Body $UpdateBody -Headers $AzTableHeaders -ContentType 'application/json'

The REST API will not provide a response message for Entity update operations.

You can view the updated Entity within the Azure Portal or the Azure Storage Explorer.

Azure Table Update Entity result

Remove Entity

Remove an existing Entity by providing the PartitionKey and RowKey.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Storage Account and Table details
$StorageAccount = 'sttabledemouse2dev'
$Table          = 'RestApi'

# Entity details
$PartitionKey   = 'partition1'
$RowKey         = 'b748030d-f434-47d9-b6a2-2f0f05df59c1'

# Azure Table Storage request headers
$Date = [DateTime]::UtcNow.ToString('R')
$AzTableHeaders = @{
    'Accept'        = 'application/json;odata=nometadata'
    'x-ms-version'  = '2020-08-04'
    'x-ms-date'     = $Date
}

# Azure Table Storage Entra ID Authorization
$AzStorageToken = Get-AzAccessToken -ResourceTypeName Storage
$AzTableHeaders += @{'Authorization' = "$($AzStorageToken.Type) $($AzStorageToken.Token)"}

# Remove Entity using REST API
$DeleteHeaders = $AzTableHeaders += @{'If-Match' = '*'}
Invoke-RestMethod -Method Delete -Uri "https://$StorageAccount.table.core.windows.net/$Table(PartitionKey='$PartitionKey',RowKey='$RowKey')" -Headers $DeleteHeaders

The REST API will not provide a response message for Entity delete operations.

You can view the results of the Entity removal within the Azure Portal or the Azure Storage Explorer.

Azure Table Remove Entity result

Next Steps

To further enhance your experience when interacting with the Azure Tables REST API, you can explore creating your own PowerShell module to wrap common Entity operations into re-usable commands.

If you find yourself looking for more features, resilience, and performance from your key-value datastore, you can explore Azure Cosmos DB and its Table API. This variant of Cosmos DB uses the same REST API format that you can access directly from PowerShell, and behaves very similarly to the Azure Storage Tables REST API.