-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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