I have an Azure Automation Powershell Workflow Runbook, that I wish to run on a Hybrid Runbook Worker server, as part of an Azure Site Recovery failover post-action step.
At the high level the runbook utilizes Azure Run AS connection to gather the private IP address of one of the VMs that will be failed over. Stores this IP address and then will write it to a STATIC A record in the Active Directory DNS that is configured in the environment.
> NOTE I promise you there's a good reason we're doing this. I realize that the machine itself as it comes up on AD will refresh it's personal DNS name entry, this is a separate A record, that we want to point to the IP address of the failed over server. We aren't using CNAME because of a defined issue with the application this server hosts.
So I have to update this A record. Below you will find the script that does this. This script below works without fail when I run it on the Hybrid Runbook Server while I'm logged into the server with the appropriate credentials (mydomain\asrscripts).
workflow VisionWebFailover-Test
{
inlineScript {
$connectionName = 'AzureRunAsConnection'
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
$rg = "RG03ASR" #ResoureGroup where ASR Machines will come up
$vmName = "ASRJUMP01" #VMname of the VM I need to get the IP from for updating in DNS
Write-output "Getting IP"
$ip = (Get-AzureRmNetworkInterface | Where-Object {($_.VirtualMachine.id).Split("/")[-1] -like $vmname}).IpConfigurations.PrivateIpAddress #find the primary nic and store it's IP address
Write-Output "Returned VM IP"
Write-Output $ip
#PowerShell to be executed locally
Import-Module dnsserver
$hostname = 'customArecord'
$zonname = 'mydomain.com'
$DNSServer = 'MYDNSServer.mydomain.com'
#Grab the existing DNS record and store it in the variable $oldobj
$oldobj = Get-DnsServerResourceRecord -Name $hostname -ZoneName $zonname -RRType A -ComputerName $DNSServer
Write-Output $oldobj
#Copy the DNS record into $newobj
$newobj = $oldobj.Clone()
#Change the value of the IP address in $newobj to equal the IP address assigned to the visionwebdev server in Azure
[System.Net.IPAddress]$NewIP = [System.Net.IPAddress]($ip)
$newobj.RecordData.IPv4Address = $NewIp
Write-Output $NewIP "this is the new IP that will be updated to DNS"
write-output $newobj
#Here is where we actually apply the change to the DNS record
Set-DnsServerResourceRecord -ZoneName $zonname -OldInputObject $oldobj -NewInputObject $newobj -Computername $DNSServer -passthru
Write-Output "DNS entry updated, replication may take 15 minutes"
}
Every step in the above code progresses successfully until it arrives at the Set-DNSServerResourceRecord statement, and fails with a Permission Denied Error shown below. This is when I run the job from Azure Automation portal. When I run it locally on the box logged in as the user it works correctly.
Set-DnsServerResourceRecord : Failed to update record customArecord.mydomain.com.
At VisionWebFailover-Test:27 char:27
+
+ CategoryInfo : PermissionDenied:(customArecord.mydomain.com:root/Microsoft/...rResourceRecord)
[Set-DnsServerResourceRecord], CimException
+ FullyQualifiedErrorId : WIN32 5,Set-DnsServerResourceRecord
> I'm thinking I need to use at the end of my InlineScript block to force the code to execute against the DNS server in the defined user context that I want. Although what I really want is for the commands to execute ON the hybrid runbook worker in the defined user context.
about_inlinescript documentation says it accepts https://learn.microsoft.com/en-us/powershell/module/psworkflow/about/about_inlinescript?view=powershell-5.1
and provides me an example like this
InlineScript {<script block>} <ActivityCommonParameters>
Activity Common Parameters are defined by this doc https://learn.microsoft.com/en-us/powershell/module/psworkflow/about/about_activitycommonparameters?view=powershell-5.1
It references two parameters that I wish to use -PSComputerName
and -PSCredential
I build a credential object like this
$secpasswd = ConvertTo-SecureString "MyAwesomePassword" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("MYDOMAIN\asrscripts", $secpasswd)
I've even pulled the asset from Automation using
$domainCred = Get-AutomationPSCredential -Name 'asrscripts'
When I run my code and attempt to mimic the example, by adding -PSComputername or -PSCredential to the end of the InlineScript I get errors.
At line:94 char:7 + -PSComputerName 'MYDNSServer' -PSCredential $domainCred + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Cannot find the '-PSComputerName' command. If this command is defined as a workflow, ensure it is defined before the workflow that calls it. If it is a command intended to run directly within Windows PowerShell (or is not available on this system), place it in an InlineScript: 'InlineScript { -PSComputerName }'
If I follow the advice of the above error and put the -PSComputerName and -PSCredential INSIDE the InlineScript block I get an error that it cannot find the arguments for Set-DNSServerResourceRecord for -PSComputerName and -PSCredential
> I don't know what I'm doing wrong
About Remote Troubleshooting - https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_troubleshooting?view=powershell-5.1
Hopefully someone out there can assist. Thanks!
The "Cannot find the '-PSComputerName' command" suggests a syntax error caused by incorrect code formatting. PowerShell is having troubles interpreting this as a parameter, and it thinks this is a separate command. Could you please show how you apply this parameter to InlineScript exactly? For example, you will get this error if you do this:
InlineScript {
...
}
-PSComputerName MyComputer
Instead, you need to do:
InlineScript {
...
} -PSComputerName MyComputer
or:
InlineScript {
...
} `
-PSComputerName MyComputer