Skip to content

Instantly share code, notes, and snippets.

@tyconsulting
Last active November 27, 2020 02:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tyconsulting/b485ce73e70c0b1b2fadf31ffbea2fdb to your computer and use it in GitHub Desktop.
Save tyconsulting/b485ce73e70c0b1b2fadf31ffbea2fdb to your computer and use it in GitHub Desktop.
An Azure Automation Runbook for dynamic DNS registration based on Azure Log Analytics and Azure DNS
#requires -modules Az.Accounts, Az.DNS, Az.OperationalInsights
<#
================================================================================================================
AUTHOR: Tao Yang
DATE: 15/06/2019
Version: 2.0
Comment: Register / update Azure DNS record set based on IP address retrieved from Log Analytics query
Requirements:
- the Azure account MUST have permission to query Log Analytics workspace and update Azure DNS recordset
================================================================================================================
#>
[CmdletBinding()]
# SP with password
Param (
[Parameter(Mandatory = $false, HelpMessage="Specify the name of the Azure Automation connection object")][ValidateNotNullOrEmpty()][String]$AzureConnectionName = 'AzureRunAsConnection',
[Parameter(Mandatory = $true, HelpMessage="Azure Log Analytics workspace name")]
[ValidateNotNullOrEmpty()][String]$WorkspaceName,
[Parameter(Mandatory = $true, HelpMessage="Azure Log Analytics workspace resource group")]
[ValidateNotNullOrEmpty()][String]$WorkspaceResourceGroup,
[Parameter(Mandatory = $true, HelpMessage="specify name of the Azure DNZ zone")]
[ValidateNotNullOrEmpty()][String]$DNSZone,
[Parameter(Mandatory = $true, HelpMessage="Azure DNZ record set name")]
[ValidateNotNullOrEmpty()][String]$DNSRecordSet,
[Parameter(Mandatory = $false, HelpMessage="Azure DNS record set TTL in minute")]
[ValidateRange(1,60)][int]$TTLMinute=10,
[Parameter(Mandatory = $true, HelpMessage="Computer name search string used in Log Analytics search query when searching for heartbeat record. the query uses endswith operator (case insensitive)")]
[ValidateNotNullOrEmpty()][String]$ComputerNameSearchString,
[Parameter(Mandatory = $false, HelpMessage="Maximum allowed age (in minute) for the Log Analytics heartbeat record. If the most recent record is older than this value, DNS record set will not be updated")]
[ValidateRange(20,60)][int]$MaxAllowedLogAnalyticsRecordAgeMinute=60
)
#Log in to Azure
try
{
# Get the connection object
$AzConnection = Get-AutomationConnection -Name $AzureConnectionName
"Logging in to Azure..."
Connect-AzAccount -ServicePrincipal -TenantId $AzConnection.TenantId -ApplicationId $AzConnection.ApplicationId -CertificateThumbprint $AzConnection.CertificateThumbprint
}
catch {
if (!$AzConnection)
{
$ErrorMessage = "Connection $AzureConnectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
#Invoke Log Analytics query to find the IP address
$Workspace = Get-AzOperationalInsightsWorkspace -ResourceGroupName $WorkspaceResourceGroup -Name $WorkspaceName
$workspaceId = $workspace.CustomerId
$query = "Heartbeat | where Computer endswith '$ComputerNameSearchString' | top 1 by TimeGenerated | project TimeGenerated, Computer, ComputerIP "
$SearchResult = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspaceId -Query $query
$ResultArray = [System.Linq.Enumerable]::ToArray($SearchResult.Results)
If ($ResultArray.count -eq 0)
{
Write-Error "Found 0 heartbeat log using query `"$query`""
exit -1
}
#Determine age of the search result record
$now = (Get-date)
$timespan = New-TimeSpan -Start $ResultArray[0].TimeGenerated -End $now
If ($timespan.TotalMinutes -gt $MaxAllowedLogAnalyticsRecordAgeMinute)
{
Write-Error "The Heartbeat log returned from Log Analytics search was generated $([math]::round($timespan.TotalMinutes, 2)) minutes ago, which is greater than the maximum allowed age of $MaxAllowedLogAnalyticsRecordAgeMinute minutes. The DNS record will not be updated. Exiting now."
Exit 0
} else {
#Get IP address from Log Analytics search result
$ip = $ResultArray[0].ComputerIP
$computer = $ResultArray[0].Computer
Write-Output "The most recent heartbeat log based on the Log Analytics workspace was generated $([math]::round($timespan.TotalMinutes, 2)) minutes ago, from computer $computer. The IP address is $ip"
}
#Register / Update DNS recordset
$objAzDNSZone = Get-AzDnsZone | where-object {$_.name -ieq $DNSZone}
if (!$objAzDNSZone)
{
Write-Error "Azure DNS Zone '$DNSZone' not found!"
Exit -1
}
$record = Get-AzDnsRecordSet -Name $DNSRecordSet -ZoneName $objAzDNSZone.name -ResourceGroupName $objAzDNSZone.ResourceGroupName -RecordType A -ErrorAction SilentlyContinue
If ($record)
{
$bUpdateRequired = $false
If ($record.Records.count -ne 1)
{
Write-output "More than one IP addresses are configured for the record set '$DNSRecordSet'. It will be updated"
$bUpdateRequired = $true
} else {
if ($record.Records[0].tostring() -ine $ip)
{
Write-output "THe IP addresses for the record set '$DNSRecordSet' is current set to $($record.Records[0].tostring()), which does not match $ip. It will be updated"
$bUpdateRequired = $true
}
}
$RecordIP = $record.Records
Write-output "DNZ Record set '$DNSRecordSet' exists."
If ($bUpdateRequired)
{
Write-Output "Updating record set '$DNSRecordSet' to $ip"
#remove existing IPs
$ExistingIPs = @()
Foreach ($item in $record.Records)
{
$ExistingIPs += $item.Ipv4Address
}
Foreach ($ExistingIP in $ExistingIPs)
{
Write-Output "Removing existing IP address '$ExistingIP' from recordset '$DNSRecordSet'."
$RemoveIP = Remove-AzDnsRecordConfig -RecordSet $record -Ipv4Address $ExistingIP
}
#Set updated IP
Add-AzDnsRecordConfig -RecordSet $record -Ipv4Address $ip
$UpdateDNSRecordSet = Set-AzDnsRecordSet -RecordSet $record
} else {
Write-Output "IP address DNZ record set '$DNSRecordset' matches IP retrieved from Log Analytics search - '$ip'. No need to udpate."
}
} else {
Write-output "DNS record set '$DNSRecordset' does not exist in zone '$DNSZone. Creating it now."
$NewRecords = @(New-AzDnsRecordConfig -Ipv4Address $ip)
$NewRecordSet = New-AzDnsRecordSet -Name $DNSRecordSet -ZoneName $objAzDNSZone.Name -ResourceGroupName $objAzDNSZone.ResourceGroupName -ttl $($TTLMinute*60) -RecordType A -DnsRecords $NewRecords
$NewRecordSet
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment