Author : MD TAREQ HASSAN | Updated : 2021/10/18
Connect to Azure
- Use local powershell or use Azure CloudShell (required PowerShell modules are already installed in CloudShell)
- When MFA is Enabled: use “
-UseDeviceAuthentication
”
When MFA is enabled
Connect-AzAccount -UseDeviceAuthentication
# Copy device code and click the link
When MFA is not Enabled
#
# Enter id and password
#
$azureLoginCredential = Get-Credential -Message "Please Enter Azure Login Credential `r`n(Azure AD Login Id & Password)"
Connect-AzAccount -Credential $azureLoginCredential
#Set-AzContext -Subscription (Get-AzSubscription -SubscriptionName $targetSubscriptionName).Id
Connect using local PowerShell with default browser
- Taskbar search > Write “default apps” > Default apps settings > Web browser section
- Set Chrome as default browser (set browser of your choice if you want)
- Now open your dafault browser > login to Azure portal
- Keep your default browser open and stay logged in
#
# Connect to Azure
#
# Default browser will open, you are already logged in to Azure portal
#
Connect-AzAccount
Now, don’t forget to set AzContext to target subscription: see next section
Using Organizational Id Credentials This scenario works only in Windows PowerShell 5.1
- A popup will open
- Use your Azure AD login id and password
- WARNING: TenantId ‘xxx’ contains more than one active subscription. First one will be selected for further use. To select another subscription, use
Set-AzContext
#
# Use Azure AD login Id and Password
#
$Credential = Get-Credential
Connect-AzAccount -Credential $Credential
Now, don’t forget to set AzContext to target subscription: see next section
Azure VM using Managed Indentity
https://docs.microsoft.com/en-us/powershell/module/az.accounts/connect-azaccount?view=azps-6.4.0#example-6--connect-using-managed-service-identity-login-and-clientid
Set AzContext
First subscription (from the list of subscriptions belong to the tenant) will be selected. Therefore, you should set AzContext to your target subscription
#
# Set AzContext to target subscription
#
# Set-AzContext -Subscription "xxxx-xxxx-xxxx-xxxx"
#
# If target subscription belongs to different tenant:
# Get-AzSubscription -SubscriptionId "xxxx-xxxx-xxxx-xxxx" -TenantId "yyyy-yyyy-yyyy-yyyy" | Set-AzContext
# https://docs.microsoft.com/en-us/powershell/module/az.accounts/set-azcontext
#
$targetSubscriptionName = "xxx"
$targetSubscriptionId = (Get-AzSubscription -SubscriptionName $targetSubscriptionName).Id
Set-AzContext -Subscription $targetSubscriptionId
# Using name only
Set-AzContext -SubscriptionName $targetSubscriptionName
You should connect to a specific tenant and subscription (organization might have multiple tenants & each tenant might have a list of subscriptions), otherwise you might ended up performating action against wrong subscription
- Get tenant id and subscription id from Azure portal
- Use
-Tenant
&-SubscriptionId
flags
#
# Connect-AzAccount -Tenant 'xxxx-xxxx-xxxx-xxxx' -SubscriptionId 'yyyy-yyyy-yyyy-yyyy'
#
$tenantGuid = "xxx"
$subscriptionGuid = "xxx"
$Credential = Get-Credential
Connect-AzAccount -Credential $Credential -Tenant $tenantGuid -SubscriptionId $subscriptionGuid
Login and Set Target Subscription
azure_login.ps1
function Connect-AzAccountTargetSubscription {
param (
[Parameter(Mandatory)]
[string] $SubscriptionName
)
$currentContext = $null
$loggedInAccount = $null
$loginIsRequired = $false
$contextList = (Get-AzContext -ListAvailable -ErrorAction Continue) ?? @()
if ($contextList.Count -gt 0) {
$currentContext = Get-AzContext
}
if ($null -eq $currentContext) {
$loginIsRequired = $true
}
else {
$loggedInAccount = $currentContext.Account
# In Azure CloudShell,
# by default managed identity is used to connect to Azure Account (account will be some thing like "MSxxx")
#
if (-not "$loggedInAccount".Contains("@")) {
Write-Host "You must login since managed identity is being used `r`n"
$loginIsRequired = $true
}
else {
#
# Check if user wants to use currently logged in account
#
$userReply = Read-Host -Prompt "Use currently logged in user account? y [yes], n [no]"
while ("y", "n" -notcontains $userReply) {
$userReply = Read-Host -Prompt "Use currently logged in user account? y [yes], n [no]"
}
if ('n' -eq $userReply) {
# user wants to login again
$loginIsRequired = $true
Write-Host "Clearing Context → [Disconnect-AzAccount, Clear-AzContext] `r`n"
try {
Disconnect-AzAccount -ErrorAction Continue
Clear-AzContext -Force -ErrorAction Continue
}
catch {
Write-Warning $Error[0]
}
}
else {
Write-Host "`r`nUsing currently logged in account → [$loggedInAccount]"
}
}
}
Write-Host "Login required: $loginIsRequired `r`n"
if ($loginIsRequired) {
Connect-AzAccount -UseDeviceAuthentication
}
#
# Target susbcription as context
#
Set-AzContext -Subscription (Get-AzSubscription -SubscriptionName $SubscriptionName).Id
Start-Sleep -Seconds 1
#
# Re-check if context is set properly
#
$currentSubscriptionName = (Get-AzContext).Subscription.Name
if ($currentSubscriptionName -ne $SubscriptionName) {
throw "Context mismatch"
}
else {
Write-Host "Context set → [subscription: '$SubscriptionName'] `r`n"
}
}
Get Currently Logged In User Information
When using CloudShell, by default it used managed identity (MSI) to login. Use Device Authentication (described above) in order to connect using Azure AD user credentials.
#
# Azure AD User Principle Id (currently logged in user)
#
$currentlyLoggedInUserObjectId = (Get-AzADUser -UserPrincipalName (Get-AzContext).Account).Id
echo (Get-AzADUser -UserPrincipalName (Get-AzContext).Account).Id
#
# AzContext Id/SignInName (currently logged in user)
#
echo ((Get-AzContext).Account).Id
Using user defined function
function Get-LoggedInUserObjectId {
#$currentlyLoggedInUserObjectId = (Get-AzADUser -UserPrincipalName (Get-AzContext).Account).Id
#Write-Host "Object id of currently logged in user: $currentlyLoggedInUserObjectId"
(Get-AzADUser -UserPrincipalName (Get-AzContext).Account).Id
}
Get Subscription Id
#
# Taget subscription
#
$targetSubscriptionName = "xxx"
$targetSubscriptionId = (Get-AzSubscription -SubscriptionName $targetSubscriptionName).Id
echo $targetSubscriptionId
#
# Current (context) subscription
#
$currentContextSubscriptionId = ((Get-AzContext).Subscription).Id
echo $currentContextSubscriptionId
# https://docs.microsoft.com/en-us/powershell/module/az.accounts/get-azsubscription
Get Tenant Id
$tenantId = (Get-AzTenant).Id
echo $tenantId
# https://docs.microsoft.com/en-us/powershell/module/az.accounts/get-aztenant
Create Storage Account Context
Using Connected Account
$saContext = (New-AzStorageContext -StorageAccountName $StorageAccountName -UseConnectedAccount)
Using ResourceGroupName and StorageAccountName
$saContext = (Get-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName).Context
Using Storage Account Key
$accountKeys = Get-AzStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName
$storageContext = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $accountKeys[0].value
Using SAS Toekn
$saContext = New-AzStorageContext -StorageAccountName $storageAccountName -SasToken $sasToken
Using user defined function
function New-StorageAccountKeyContext {
param (
[Parameter(Mandatory)]
[string] $ResourceGroupName,
[Parameter(Mandatory)]
[string] $StorageAccountName
)
# Storage account context can be created in multiple ways,
# In some case using account key might be required i.e. for creating Stored Access Policy
#
# $storageAccountContext = (Get-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName).Context
# $saContext = (New-AzStorageContext -StorageAccountName $StorageAccountName -UseConnectedAccount)
#
$saKeys = Get-AzStorageAccountKey -ResourceGroupName $ResourceGroupName -Name $StorageAccountName
$saKeyContext = New-AzStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $saKeys[0].Value
return $saKeyContext
}
Create Service Principal
Make sure you are logged in and have enough preivilege to create service principal
function New-ServicePrincipal {
param (
[Parameter(Mandatory)]
[string] $ServicePrincipalDisplayName
)
$spCredential = @{}
try {
$newSp = (New-AzADServicePrincipal -DisplayName $ServicePrincipalDisplayName)
Start-Sleep -Seconds 3 # cool down
$spSecretAsStringObj = ConvertTo-String -SecureString $newSp.Secret
$spCredential[$envVarKeyServicePrincipalDisplayName] = $ServicePrincipalDisplayName
$spCredential[$envVarKeyServicePrincipalObjectId] = $newSp.Id
$spCredential[$envVarKeyTenantId] = (Get-AzTenant).Id
$spCredential[$envVarKeyClientId] = $newSp.ApplicationId
$spCredential[$envVarKeyClientSecret] = $spSecretAsStringObj
}
catch {
Write-Warning $Error[0]
}
return $spCredential
}
Save service principal credential to JsonFile: Write content to file
Role Assignment
function New-RoleAssignement {
param (
[Parameter(Mandatory)]
[string] $RoleDefinitionName,
[Parameter(Mandatory)]
[string] $ObjectId,
[Parameter(Mandatory)]
[string] $Scope
)
#
# Before trying to assign role,
# Check that is given role is already assigned or not
#
$existingRoleAssignment = (Get-AzRoleAssignment -RoleDefinitionName $RoleDefinitionName -ObjectId $ObjectId -Scope $Scope)
if ($null -eq $existingRoleAssignment) {
Write-Host "[Role '$($RoleDefinitionName)' at Scope '$($Scope)'] does not exist, creating new role assignment"
New-AzRoleAssignment -RoleDefinitionName $RoleDefinitionName `
-ObjectId $ObjectId `
-Scope $Scope `
| Out-Null
Write-Host "Role '$($RoleDefinitionName)' has been assigned to '$($Scope)'"
}
else {
Write-Host "[Role '$($RoleDefinitionName)' at Scope '$($Scope)'] already exists"
}
}
Create Stored Access Policy
function New-StoredAccessPolicy {
param (
[Parameter(Mandatory)]
[Microsoft.WindowsAzure.Commands.Storage.AzureStorageContext] $StorageAccountKeyContext,
[Parameter(Mandatory)]
[string] $ContainerName,
[Parameter(Mandatory)]
[string] $PolicyName,
[Parameter(Mandatory)]
[datetime] $ExpiryTime,
[Parameter(Mandatory)]
[string] $PermissionFlagString
)
$sap = $null
try {
$sap = Get-AzStorageContainerStoredAccessPolicy -Context $StorageAccountKeyContext -Container $ContainerName -Policy $PolicyName -ErrorAction Stop
}
catch {
Write-Warning $Error[0]
}
$noPolicyWithSameName = ($null -eq $sap)
if ($noPolicyWithSameName) {
Write-Host "Stored Access Policy '$($PolicyName)' does not exist, creating new"
$sapSplat = @{
Context = $StorageAccountKeyContext
Container = $ContainerName
Policy = $PolicyName
ExpiryTime = $ExpiryTime
Permission = $PermissionFlagString
}
$sap = New-AzStorageContainerStoredAccessPolicy @sapSplat
Write-Host "Stored Access Policy '$($PolicyName)' with expiry time '$($ExpiryTime)' has been created"
}
else {
Write-Host "Stored Access Policy '$($PolicyName)' already exists"
}
$sap | Out-Null
}
function New-StoredAccessPolicyAllPermissions {
param (
[Parameter(Mandatory)]
[Microsoft.WindowsAzure.Commands.Storage.AzureStorageContext] $StorageAccountKeyContext,
[Parameter(Mandatory)]
[string] $ContainerName,
[Parameter(Mandatory)]
[string] $PolicyName,
[Parameter(Mandatory)]
[datetime] $ExpiryTime
)
$splat = @{
StorageAccountKeyContext = $StorageAccountKeyContext
ContainerName = $ContainerName
PolicyName = $PolicyName
ExpiryTime = $ExpiryTime
PermissionFlagString = "racwdl"
}
New-StoredAccessPolicy @splat
}
Generate SAS Token
Create Stored Access policy first before generatting SAS token
function New-SasToken {
param (
[Parameter(Mandatory)]
[string] $ResourceGroupName,
[Parameter(Mandatory)]
[string] $StorageAccountName,
[Parameter(Mandatory)]
[string] $ContainerName,
[Parameter(Mandatory)]
[string] $StoredAccessPolicyName,
[Parameter(Mandatory)]
[datetime] $ExpiryTime
)
# To generate SAS, followings are needed
# 1. Storage Account Context
# 2. Stored Access Policy
#
$saKeys = Get-AzStorageAccountKey -ResourceGroupName $ResourceGroupName -Name $StorageAccountName
$saKeyContext = New-AzStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $saKeys[0].Value
$policySplat = @{
StorageAccountKeyContext = $saKeyContext
ContainerName = $ContainerName
PolicyName = $StoredAccessPolicyName
ExpiryTime = $ExpiryTime
}
New-StoredAccessPolicyAllPermissions @policySplat
# Generate SAS Token
#
$sasSplat = @{
Context = $saKeyContext
Container = $ContainerName
Policy = $StoredAccessPolicyName
}
$sasString = New-AzStorageContainerSASToken @sasSplat
$sasToken = "$($sasString.Substring(1))" # removing '?' in the token string
#Write-Host "Generated SAS token: $($sasToken)"
return $sasToken # returning token to caller
}
Iterate Over all Subscriptions and Resource Groups
Get-AzSubscription | ForEach-Object {
$subscriptionName = $_.Name
Set-AzContext -SubscriptionId $_.SubscriptionId
(Get-AzResourceGroup).ResourceGroupName | ForEach-Object {
[PSCustomObject] @{
Subscription = $subscriptionName
ResourceGroup = $_
}
}
}