Search code examples
powershellazurepowershell-remotingazure-automationhybrid-runbook-worker

Proper use of <Activity Common Parameters> for Inlinescript in PowerShell Workflow


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

  • On the runbook server I have all appropriate Powershell Modules installed.
  • It is joined to the domain.
  • It is added as a trustedhost on the DNSServer which is also a domain controller
  • The user I want to run this in the context of is MYDOMAIN\asrscripts, it is added as an Azure Automation Credential artifact
  • If I attempt to change the RUNAS user for the Hybrid Worker to CUSTOM and pick my asrscripts artifact, the job hangs, and NEVER runs. It stays at Queued until it suspends. I receive an error in the system event log that the user could not authenticate.
  • I've Exhausted the Remote Troubleshooting document below

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!


Solution

  • 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