We are going to use Azure Resource Graph to find items with a specific tag, in this case {“toBeLocked”=“Yes”} and then place a resource lock on them.
## create resource group
$rgName = "toberesourcelocked"
$rgLocation = "northeurope"
$rg = new-azresourcegroup -name $rgname -location $rgLocation
## create items
$guid = New-Guid
$saName = "sa"
$saSuffix = $guid.ToString().Split("-")[0]+$guid.ToString().Split("-")[1]
$saName = (($saName.replace("-",""))+$saSuffix)
New-AzStorageAccount -ResourceGroupName $rgName -Name $saName -Location $rgLocation -AccountType Standard_LRS
## create tag(s)
$tags = @{"toBeLocked"="Yes"}
## get items in Resource Group and tag them
$items = Get-AzResource -ResourceGroupName $rgName
foreach ($item in $items)
{
Update-AzTag -ResourceId $item.ResourceId -Tag $tags -Operation Replace
}
## update resource group with tag(s)
Update-AzTag -ResourceId $rg.ResourceId -Tag $tags -Operation Replace
resourcecontainers
| where type == "microsoft.resources/subscriptions/resourcegroups"
| mv-expand bagexpansion=array tags
| where isnotempty(tags)
| where tags[0] =~ 'toBeLocked' and tags[1] =~ 'Yes'
| project name,type,location,subscriptionId,tags
| union (resources
| mv-expand bagexpansion=array tags
| where isnotempty(tags)
| where tags[0] =~ 'toBeLocked' and tags[1] =~ 'Yes'
| project name,type,location,subscriptionId,tags,id)
Resources
| mv-expand bagexpansion=array tags
| where isnotempty(tags)
| where tags[0] =~ 'toBeLocked' and tags[1] =~ 'Yes'
ResourceContainers
| where type =~ 'microsoft.resources/subscriptions/resourcegroups'
| where tags['toBeLocked'] =~ 'Yes'
We now have the required queries and you can pick whichever one above suits your needs, I am going to be using Including Resource Groups. Now we need a way to act against these resources. I am personally quite a fan of PowerShell so I will provide this sample. You can use this as a base for my example below. When running the query in PowerShell, I find splatting is easiest for Azure Resource Graph queries
# Install the Resource Graph module from PowerShell Gallery
Install-Module -Name Az.ResourceGraph
# Get a list of commands for the imported Az.ResourceGraph module
Get-Command -Module 'Az.ResourceGraph' -CommandType 'Cmdlet'
# Run Azure Resource Graph query
$query = @"
resourcecontainers
| where type == "microsoft.resources/subscriptions/resourcegroups"
| mv-expand bagexpansion=array tags
| where isnotempty(tags)
| where tags[0] =~ 'toBeLocked' and tags[1] =~ 'Yes'
| project name,type,location,subscriptionId,tags
| union (resources
| mv-expand bagexpansion=array tags
| where isnotempty(tags)
| where tags[0] =~ 'toBeLocked' and tags[1] =~ 'Yes'
| project name,type,location,subscriptionId,tags,id)
"@
$queryItems = Search-AzGraph -Query $query
So now we have the items that have been tagged, now we can go through the process of adding a Resource Lock. The New-AzResourceLock will be used for this task.
$lockLevel = "CanNotDelete" ## can be changed to "ReadOnly" as well
$lockNotes = "Lock for demo blog purposes"
$lockName = "Demo Lock"
foreach ($queryItem in $queryItems)
{
$name = $queryItem.Name
$type = $queryItem.Type
write-host "Locking $name ($type)"
if ($type -eq "microsoft.resources/subscriptions/resourcegroups"){
New-AzResourceLock -LockName $lockName -LockLevel $lockLevel -LockNotes $lockNotes -ResourceGroupName $name
} else {
$resourceGroupName = ($queryItem.id).split("/")[4]
New-AzResourceLock -LockLevel $lockLevel -LockNotes $lockNotes -LockName $lockName -ResourceName $queryItem.Name -ResourceType $queryItem.Type -ResourceGroupName $resourceGroupName
}
}
Results can be seen below. Our Locks are now in place. Since my account is an owner, I can delete the lock(s), non-owner(s) would NOT be able to delete locks.
This code and concept can be easily updated or modified to meet different your specific requirements.