Start Azure VM and Open Bastion

The following snippet will check if a VM is turned on, and if not start it, then launch the Bastion connection window in Edge.

$VM = Get-AzVM -Name 'LN-TCTester-01' -Status
if($VM.PowerState -eq 'VM deallocated'){
    $VM | Start-AzVM
}
Start-Process -Path msedge -ArgumentList "https://portal.azure.com/#/resource$($VM.Id)/bastionHost"
  |  
Find Java Based Azure App Services

A quick Azure PowerShell command to locate any Java based Azure App Services and Functions so you can check if they are vulnerable to the CVE-2021-44228 Apache Log4j2 vulnerability.

Get-AzWebApp | ForEach-Object{
    Get-AzWebApp -ResourceGroupName $_.ResourceGroup -Name $_.Name | 
    Select-Object -Property Name, @{l='JavaVersion';e={$_.SiteConfig.JavaVersion}}, ResourceGroup, Id 
} | Format-Table
  |  
Resubmit Azure Automation Runbook Job

This snippet will allow you to re-run any Azure Automation Runbook job with the same parameters and in the same context (Azure or Hybrid Worker Group).

# Set the variables from the previous job
$AutomationAccountName = ''
$ResourceGroupName     = ''
$JobId                 = ''

# Get the previous job
$AutoAccount = @{
    AutomationAccountName = $AutomationAccountName
    ResourceGroupName     = $ResourceGroupName
}
$PreviousJob = Get-AzAutomationJob @AutoAccount -Id $JobId

# Build the parameters to resubmit
$StartRunbook = $AutoAccount.Clone()
# Add Runbook Name
$StartRunbook.Add('Name',$PreviousJob.RunbookName)
# If Hybrid Worker used, add it
if(-not [string]::IsNullOrEmpty($PreviousJob.HybridWorker)){
    $StartRunbook.Add('RunOn',$PreviousJob.HybridWorker)
}
# Create a hashtable with the parameters
if($PreviousJob.JobParameters.Count -gt 0){
    $Parameters = @{}
    $PreviousJob.JobParameters.GetEnumerator() | ForEach-Object{
        $Parameters.Add($_.Key,$_.Value)
    }
    $StartRunbook.Add('Parameters',$Parameters)
}

# Start the job
$RBjob = Start-AzAutomationRunbook @StartRunbook
$RBjob
  |  |  
Copy Azure Permissions

I was replacing an old service account with a service principal, and needed to replicate the permissions in Azure. I was able to do that without missing anything, using the command below.

$CopyFrom = 'Object to copy from'
$CopyTo = 'Object to copy to'
Get-AzRoleAssignment -ObjectId $CopyFrom | ForEach-Object{
    New-AzRoleAssignment -ObjectId $CopyTo -RoleDefinitionId $_.RoleDefinitionId -Scope $_.Scope
}
  |  |  
Testing and Deploying ARM Templates

I often find that when building an ARM template, I need to test it multiple times. So, I created the script below that will create the resource group (is it doesn’t exist), run the test cmdlet (and stop if there is a problem), and deploy the template to Azure. It will create a new name for the deployment each time based on the file name, and the current time. This will allow you to view the details of each individual deployment in Azure.

$ResourceGroupName = ''
$TemplateFile = '' 
$ParameterFile = ''

# Create the resource group, if not already there
try {
    Get-AzResourceGroup -Name $ResourceGroupName -ErrorAction Stop | Out-Null
} catch {
    New-AzResourceGroup -Name $ResourceGroupName -Location "EastUS" 
}

# Create parameter hashtable for splatting
$params = @{
    ResourceGroupName = $ResourceGroupName
    TemplateFile = $TemplateFile
    TemplateParameterFile = $ParameterFile
}

# Test the template first, stop execution if test fails
$test = Test-AzResourceGroupDeployment @params
if($test){
    $test
    $test.Details.Details
    break
}

$DeploymentName = [System.IO.Path]::GetFileNameWithoutExtension($TemplateFile) + '_' +
    (Get-Date).ToString('yyyyMMddHHmm')

New-AzResourceGroupDeployment @params -Name $DeploymentName
  
Quickly Switch Azure Subscriptions with PSNotes

If you are now aware, PSNotes is a PowerShell module I developed that allows you save code snippets, and recall them right in you PowerShell using an alias. One great use for this I have found is for switching between Azure subscriptions. 

I work in multiple different subscriptions throughout the day. Some are in the same tenant, but some require me to authenticate with different accounts. So, I wrote the code block below that attempts to switch subscriptions, but if it can’t with the current logged in user, it prompts me to authenticate.

$SubscriptionId = ''
if($(Get-AzContext).Subscription.SubscriptionId -ne $SubscriptionId){
    Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction SilentlyContinue
    if($(Get-AzContext).Subscription.SubscriptionId -ne $SubscriptionId){
        Clear-AzContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue
        Clear-AzDefault -Force -ErrorAction SilentlyContinue
        $connect = Add-AzAccount -SubscriptionId $SubscriptionId
    }
}

This works great, but I still need to remember the GUID of every subscription I need to connect to. This is where the PSNotes module comes in handy. Using the New-PSNote command, I can create an alias for every subscription I regularly connect to. For example, I used the command below to create an alias for my development subscription.

New-PSNote -Note 'AzDev' -Tags 'AzConnect' -Alias 'AzDev' -ScriptBlock{
	$SubscriptionId = 'ca21f08b-8a8e-4997-9e6e-515aa470c0a2'
	if($(Get-AzContext).Subscription.SubscriptionId -ne $SubscriptionId){
		Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction SilentlyContinue
		if($(Get-AzContext).Subscription.SubscriptionId -ne $SubscriptionId){
			Clear-AzContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue
			Clear-AzDefault -Force -ErrorAction SilentlyContinue
			$connect = Add-AzAccount -SubscriptionId $SubscriptionId
		}
	}
	Write-Host "You are now connected to $($(Get-AzContext).Subscription.Name)"
}

Now all I need to do to connect to this subscription is type “AzDev -run” into my console, and I’m connected to my development subscription.

  |  
Encrypt All Azure Automation Variables
$ResourceGroupName = ''
$AutomationAccountName = ''

# Get all variables
$variables = Get-AzureRMAutomationVariable -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName

# parse through each unencrypted variable
Foreach($var in $variables | Where-Object{$_.Encrypted -ne $True}){
    
    # remove the unencrypted variable
    Remove-AzureRMAutomationVariable -ResourceGroupName $var.ResourceGroupName -AutomationAccountName $var.AutomationAccountName -Name $var.Name
    
    # recreate the variable, with the same values and encrypt it
    New-AzureRMAutomationVariable -ResourceGroupName $var.ResourceGroupName -AutomationAccountName $var.AutomationAccountName -Name $var.Name -Encrypted $True -Value $var.Value -Description $var.Description
}

Details

It is best practices to encrypt all of your Azure Automation Account variables. However, it is not possible to convert an unencrypted variable to an encrypted one. So this snippet will return all variables and if any are unencrypted, it will remove them, the recreate it as an encrypted variable.

Get All Azure Virtual Machine IP Addresses
[System.Collections.Generic.List[PSObject]] $IPAddresses = @()
$VMs = Get-AzureRMVM
foreach($VM in $VMs){
    foreach($interface in $VM.NetworkProfile.NetworkInterfaces){
        $resource = Get-AzureRMResource -id $interface.Id
        $nic = Get-AzureRmNetworkInterface -Name $resource.Name -ResourceGroupName $resource.ResourceGroupName
        Get-AzureRmNetworkInterfaceIpConfig -NetworkInterface $nic | Select-Object @{l='VM';e={$VM.Name}}, PrivateIpAddress, PrivateIpAllocationMethod |
            ForEach-Object{ $IPAddresses.Add($_) }
    }
}
$IPAddresses

Details

This snippet will get all virtual machines in your Azure subscription, then return the internal IP Adresses

  
Find and Load the Azure Automation Hybrid Registration Module
$installPath = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\System Center Operations Manager\12\Setup\Agent").InstallDirectory
$modulePath = Get-ChildItem (Join-Path $installPath "AzureAutomation") -Recurse -Include 'HybridRegistration.psd1' | Select-Object -ExpandProperty FullName
Import-Module $modulePath

Details

The module to setup an Azure Automation Hybrid Runbook Worker is included in the install directory of the Microsoft Monitoring Agent. Since install directories can change, and since this module will include a version number in the path, you cannot hard code the path into a script. Instead you can query the registry for the install path, then lookup the modules psd1 file, bypassing the need to manually check the path every time you want to onboard a hybrid worker.

Easily Switch Between Azure Subscriptions and Tenants
$SubscriptionId = "Your-Subscription-Guid"
if($(Get-AzureRmContext).Subscription.SubscriptionId -ne $SubscriptionId){
    Set-AzureRmContext -SubscriptionId $SubscriptionId -ErrorAction SilentlyContinue
    if($(Get-AzureRmContext).Subscription.SubscriptionId -ne $SubscriptionId){
        Clear-AzureRMContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue
        Clear-AzureRmDefault -Force -ErrorAction SilentlyContinue
        $connect = Add-AzureRmAccount -SubscriptionId $SubscriptionId
    }
}

Details

This snippet will check that the value of $SubscriptionId variable is the current Azure Subscription your session is connected to. If not then it will attempt to switch to it. If the subscription is not in the same context, then it will clear your current session and prompt for credentials to connect to the new subscription.