12.1 Azure PowerShell, Azure CLI, and Deployment Monitoring
Key Takeaways
- The Az.Sql module cmdlets (New-AzSqlServer, New-AzSqlDatabase, Set-AzSqlDatabase, New-AzSqlElasticPool) provision and manage Azure SQL; Azure CLI mirrors them with az sql server create, az sql db create, and az sql db update
- Choose Azure PowerShell for Windows/PowerShell ecosystems and rich object pipelines; choose Azure CLI for cross-platform Bash, Linux CI runners, or Cloud Shell one-liners
- Connect-AzAccount and az login support interactive, service-principal, and managed-identity auth; service principals fit headless CI/CD, managed identities fit Azure-hosted runbooks
- Deployment failures are diagnosed through Get-AzDeployment or az deployment group show plus activity-log and deployment operations filtered by correlationId; common causes are quota, names, region/SKU, NSG, and locks
- Use -Force to suppress confirmation prompts in scripts, wrap cmdlets in try/catch, and use -AsJob for long-running deployments so the script can poll rather than block
Why PowerShell and CLI Matter for DP-300
Domain 4 of the DP-300 exam ("Configure and manage automation of tasks", weighted 15-20%) explicitly tests your ability to automate deployment by using Azure PowerShell and automate deployment by using Azure CLI, and to monitor and troubleshoot deployments. You will not be asked to memorize every flag, but you must recognize the right cmdlet or command for a scenario, know how to authenticate a script non-interactively, and know where to look when a deployment fails. Treat this section as the scripting vocabulary you need to read and write infrastructure-as-code for Azure SQL.
The Az.Sql Module: Core Cmdlets
Azure PowerShell organizes SQL management in the Az.Sql module. The verbs follow PowerShell's standard verb-noun convention, so once you internalize a handful of verbs you can predict most cmdlets. The table below covers the ones the exam draws from:
| Cmdlet | Purpose | Common parameters |
|---|---|---|
| New-AzSqlServer | Create a logical server | -ResourceGroupName, -ServerName, -Location, -SqlAdministratorCredentials |
| New-AzSqlDatabase | Create a database on a server | -ServerName, -DatabaseName, -RequestedServiceObjectiveName / -Edition / -VCore |
| Get-AzSqlDatabase | Retrieve a database object | -ServerName, -DatabaseName, -ResourceGroupName |
| Set-AzSqlDatabase | Modify a database (scale tier, rename, move pool) | -DatabaseName, -Edition, -VCore, -ElasticPoolName |
| New-AzSqlElasticPool | Create an elastic pool | -ElasticPoolName, -Edition, -Dtu / -VCore |
| Set-AzSqlElasticPool | Resize an elastic pool | -VCore, -DatabaseDtuMin, -DatabaseDtuMax |
| New-AzSqlDatabaseCopy | Create a geo-secondary or copy | -CopyResourceGroupName, -PartnerServerName |
| Get-AzSqlDatabaseActivity | Watch an async database operation | -DatabaseName, -State |
Two operational facts are worth highlighting. First, New-AzSqlServer requires credentials for the server admin in PSCredential form (a username plus a strongly typed SecureString password), so the usual pattern is $cred = Get-Credential interactively or constructed from a stored secret in automation. Second, scaling a database is a Set-AzSqlDatabase call with the new service objective - it is an online operation that ends in a brief connection drop, exactly as covered in Chapter 3.
Azure CLI: az sql Commands
The Azure CLI exposes the same operations through the az sql command group, which is cross-platform (Windows, macOS, Linux) and especially at home in Bash and CI pipelines. The core commands:
| Command | Purpose |
|---|---|
| az sql server create --name --resource-group --location --admin-user --admin-password | Create a logical server |
| az sql server show / list / update | Retrieve or modify a server |
| az sql db create --server --name --resource-group --service-objective | Create a database at a given SKU |
| az sql db show / list / update | Inspect or modify a database |
| az sql db update --service-objective GP_Gen5_8 | Scale a database |
| az sql elastic-pool create / update | Create or resize an elastic pool |
| az sql server firewall-rule create / update | Manage server-level firewall rules |
Service objective names (GP_Gen5_8, BC_Gen5_16, HS_Gen5_2, S3, P1) are the same string vocabulary the cmdlets and T-SQL ALTER DATABASE accept. A typical one-liner:
az sql db create \
--resource-group rg-sql --server sql-prod \
--name SalesDB --service-objective GP_Gen5_4
PowerShell vs CLI: Selection Criteria
The exam will present scenarios that lean toward one tool. Use this decision table:
| Criterion | Pick PowerShell | Pick CLI |
|---|---|---|
| Existing Windows / PowerShell ecosystem, staff skill | Yes | |
| Object pipeline, rich .NET objects in variables | Yes | |
| Linux/macOS developers, Bash heredocs, jq | Yes | |
| Cross-platform CI runners (GitHub Actions on ubuntu-latest) | Yes | |
| Cloud Shell one-liners you can paste from docs | Either | Either |
| DSC, Azure Policy guest config integrations | Yes |
Both tools are first-class and idempotent when you add -Force (PowerShell) or run create commands that return the existing resource if it already exists. Neither is deprecated; the exam does not penalize choosing either, only choosing the wrong authentication or the wrong cmdlet for a scenario.
A team runs their deployment pipeline on GitHub Actions hosted ubuntu-latest runners and wants to provision an Azure SQL logical server and database in Bash. Which approach best fits the runner and ecosystem?
Authentication: Service Principals and Managed Identities
Both tools authenticate through Microsoft Entra ID (formerly Azure AD). Interactive Connect-AzAccount and az login are fine for a human at a workstation, but automation needs a non-interactive identity:
- Service principal: an Entra app registration with a client ID and either a client secret or a certificate. Authenticate with
Connect-AzAccount -ServicePrincipal -Credential $sp -TenantId $tenant(PowerShell) oraz login --service-principal -u $appId -p $secret --tenant $tenant(CLI). Grant it the minimum RBAC role needed - typically SQL Server Contributor (or a custom role) on the resource group. Service principals are the right answer for CI/CD pipelines running outside Azure. - Managed identity: a system-assigned or user-assigned identity tied to an Azure resource (Automation account, VM, App Service, Function). No secret to rotate; the platform issues short-lived tokens. Authenticate with
Connect-AzAccount -Identityoraz login --identity. Managed identities are the right answer when the script itself runs inside Azure.
A common exam trap: storing the service principal secret in plaintext inside a runbook or pipeline variable. The correct pattern is to store it in Azure Key Vault (or a CI secret store) and retrieve it at runtime, or to eliminate the secret entirely by using a managed identity.
Scripting Patterns: Loops, Error Handling, Async
Production automation must be idempotent and observable. Three patterns show up repeatedly:
- Wrap cmdlets in try/catch so a failed resource creation does not silently continue. Azure PowerShell throws terminating errors you can catch; Azure CLI returns a non-zero exit code you can test with
$?orif ! az ...in Bash. - Use -Force to suppress confirmation prompts (
-ForceonNew-AzSqlServer,Remove-AzSqlDatabase, etc.) so scripts do not hang waiting for a human. - Use -AsJob / Start-Job for long-running deployments.
New-AzSqlDatabase -AsJobreturns a job object you poll withGet-Job | Wait-Jobso the script can proceed, log progress, or parallelize. The CLI equivalent is appending&in Bash or using--no-waiton supported commands.
A typical idempotent provisioning loop that creates several tenant databases from an array:
$tenants = 'northwind','contoso','fabrikam'
foreach ($t in $tenants) {
try {
New-AzSqlDatabase -ResourceGroupName rg-sql -ServerName sql-prod `
-DatabaseName \"db-$t\" -Edition GeneralPurpose -VCore 2 -Force -ErrorAction Stop
Write-Output \"Provisioned db-$t\"
} catch {
Write-Warning \"Failed to provision db-$t: $($_.Exception.Message)\"
}
}
Notice -Force (no prompt), -ErrorAction Stop (so the catch fires), and the loop-friendly structure. The CLI equivalent uses a Bash for-loop and relies on the shell exit code.
Monitoring and Troubleshooting Deployments
Once you kick off a deployment, you need to watch it. Azure Resource Manager (ARM) records every deployment at three levels: subscription, resource group, and (for some resources) resource. The key inspection commands:
Get-AzDeployment -ResourceGroupName rg-sqllists deployments in a resource group;Get-AzDeployment -Name <deployment> -ResourceGroupName rg-sqlreturns one deployment's details.az deployment group show -g rg-sql -n <deployment>is the CLI equivalent;az deployment operation group list -g rg-sql -n <deployment>lists the deployment operations - the individual resource-level steps inside that deployment.- The Activity Log (Portal: Monitor > Activity log, or
Get-AzActivityLog,az monitor activity-log list) shows every control-plane write operation across the subscription and is the place to look for operations that never produced a deployment record at all.
Every deployment carries a correlationId. Filtering the activity log by that correlationId returns every operation that belonged to the same deployment - invaluable when a deployment created five resources, three succeeded, and two failed and you need to see them together.
The most common deployment failures and their signatures:
| Symptom | Likely root cause | Fix |
|---|---|---|
Resource type 'Microsoft.Sql/servers' is not available in location <x> | Unsupported region for the resource/SKU | Pick a supported region or SKU |
Sql server name 'sql-prod' is already taken | Globally unique name collision | Use a unique suffix (random, hash, or prefix) |
The subscription has reached its quota for total server capacity | Regional quota exhausted | Request a quota increase or clean up unused servers |
Cannot create server because subnet is not delegated / NSG blocks | Network/NSG/subnet misconfiguration | Add Microsoft.Sql delegation, open NSG rules |
Cannot perform operation because resource is locked | Resource lock (CanNotDelete / ReadOnly) | Remove or scope the lock before the operation |
The client has authorization to perform action but the scope is invalid | RBAC role not scoped to the resource | Re-scope the service principal role assignment |
A troubleshooting workflow to internalize: (1) read the error message from the cmdlet/CLI output - it is specific; (2) az deployment operation group list or Get-AzDeploymentOperation to see which step failed; (3) if the deployment says "Accepted" but the resource never appears, filter the activity log by correlationId for the operation's status; (4) check for resource locks, NSG rules, and quota via the portal or az resource list --query. The exam pattern: a scenario describes a deployment that partially succeeded, and the correct answer is to inspect deployment operations (not just the deployment's overall status) to find the failing step.
An ARM template deployment in a CI pipeline reported overall success, but one of three databases the template was supposed to create is missing from the resource group. What is the most direct way to identify which step failed and why?