Provisioning RPA Test Environments With Azure Automation Runbooks

Microsoft Power Automate Flows, UI Flows, & Automation Runbooks: Part Two of a series

 

In the first part of this blog series, I outlined the use case, created the flow trigger and three parallel branches that defined three different variables. In this post, I will cover how to use an Azure Automation runbook to provision a test environment that will be used for robotic process automation.

 

With the email trigger defined and Owner, Vendor and IP variables defined, the next step in the process will be passing these variables into an Azure Automation Action in order to create the resources needed for the Azure test environment. The test environment will be used to run a user workflow, simulated with robotic process automation.

 

Microsoft Power Automate Flows_Part2_image 1

 

There are a few different ways within Azure to provision resources. One of them is through the use of Azure Automation runbooks. Azure Automation is separate from Power Automate and Logic Apps. Azure Automation provides an orchestration platform through PowerShell, Python or graphical runbooks. I decided I wanted to create all of the resources with some of type of command line entry for two reasons. One, I was curious and wanted to learn. Two, I needed to automate the process and anything done within the Azure console wasn’t going to work. After some research, I decided to use an Automation Account and custom runbook.

 

To create a custom automation runbook, I used a previously configured Automation Account. Available runbooks can be found under each Azure Automation account as seen in the screenshot below.

 

Microsoft Power Automate Flows_Part2_image 2

 

 

Azure provides a few different ways to create custom runbooks,
but as someone familiar with PowerShell, it only made sense for me
to use it to create my runbook. Other options are shown here.

Microsoft Power Automate Flows_Part2_image 3

 

 

The runbook I created to provision my resources has three mandatory parameters that are defined at the top of the script: the owner, vendor and source IP address. These parameters must be defined in order to successfully execute the runbook.

Microsoft Power Automate Flows_Part2_image 4

 

While I am not going to go into extreme detail on the script below, the runbook, using Az PowerShell cmdlets and a service principal, creates the following Azure resources for our test environment:

 

  • Resource Group
  • Operating System Disk
  • Public IP
  • Network Interface
  • Security Group
  • Virtual Network
  • Subnet
  • Virtual Machine

 

#Resource Creation Script
#Required Parameters
Param(
[Parameter (Mandatory= $true)]
[string]$owner,
[Parameter (Mandatory= $true)]
[string]$vendor,
[Parameter (Mandatory= $true)]
[string]$SourceRDPAddress
)

#Service Principal Parameters
$Thumbprint = 'YOUR-THUMBPRINT-HERE'
$TenantId = 'YOUR-TENANTID-HERE’
$ApplicationId = 'YOUR-APPLICATIONID-HERE’

#Service Principal Authentication
Connect-AzAccount -CertificateThumbprint $Thumbprint -ApplicationId $ApplicationId -
Tenant $TenantId -ServicePrincipal

#Additional Parameters
$ResourceGroupName = "$vendor-ResourceGroup"
$location = 'centralus'
$VirtualNetworkName = "$vendor-VirtualNetwork"
$vnetname = "$vendor-vnet"
$subnetName = 'default-subnet'
$osDiskName = "$vendor-osDisk"
$nicName = "$vendor-nic"
$templateVMName = "$vendor-VM"
$PublicIPName = "$vendor-PublicIP"
$ipconfigname = 'ipconfig1'

#ResourceGroup Creation
New-AzResourceGroup -Name $ResourceGroupName -Location $location -Force

#Tag ResourceGroup
$tags = @{"Owner"="$owner"}
$resourceGroup = Get-AzResourceGroup -Name $ResourceGroupName
Update-AzTag -ResourceId $resourceGroup.ResourceId -Tag $tags -Operation Merge

#Network Creation
$virtualNetwork = New-AzVirtualNetwork `
-ResourceGroupName $ResourceGroupName `
-Location $location `
-Name $VirtualNetworkName `
-AddressPrefix 172.16.0.0/16

#Subnet Creation
$subnetConfig = Add-AzVirtualNetworkSubnetConfig `
-Name $subnetName `
-AddressPrefix 172.16.3.0/24 `
-VirtualNetwork $virtualNetwork

#Associate the subnet to the virtual network
$virtualNetwork | Set-AzVirtualNetwork

#Network Creation w/ named path for OS DISK
$vnet = Get-AzVirtualNetwork -Name $VirtualNetworkName -ResourceGroupName $ResourceGroupName
$subnetID = Get-AzVirtualNetworkSubnetConfig -Name $subnetName -VirtualNetwork $vnet

#Disk Creation ****NOTE: In this section I am using a snapshot**** In order to use a snapshot of your own, change the following line in the code below /subscriptions/YOUR-SUBSCRIPTION-ID-HERE/resourceGroups/RPA-Template/providers/Microsoft.Compute/snapshots/RPA-Snapshot01)

$osDisk = New-AzDisk -DiskName $osDiskName -Disk (New-AzDiskConfig -Location $location -CreateOption Copy -SourceResourceId /subscriptions/YOUR-SUBSCRIPTION-ID-HERE/resourceGroups/RPA-Template/providers/Microsoft.Compute/snapshots/RPA-Snapshot01) -ResourceGroupName $ResourceGroupName

#Nic Creation
$nic = New-AzNetworkInterface -Name $nicName -ResourceGroupName $ResourceGroupName -Location $location -SubnetId $subnetID.Id -Force

#Virtual Machine Object Creation
$vmConfig = New-AzVMConfig -VMName $templateVMName -VMSize 'Standard_B2s'

#Add The Network Interface
$vm = Add-AzVMNetworkInterface -VM $vmConfig -Id $nic.Id

#Add the OS to Disk
$vm = Set-AzVMOSDisk -VM $vm -ManagedDiskId $osDisk.Id -StorageAccountType Standard_LRS -DiskSizeInGB 128 -CreateOption Attach -Windows

#Create the VM Template
New-AzVM -ResourceGroupName $ResourceGroupName -Location $location -VM $vm

#Add Custom RDP SecurityGroup
New-AzNetworkSecurityGroup -Name "$vendor-RDPSecurityGroup" -
ResourceGroupName $ResourceGroupName -Location $location

#SecurityGroup Parameters
$RGname="$ResourceGroupName"
$port= 3389
$rulename="$owner-RDPAccess"
$nsgname="$vendor-RDPSecurityGroup"

#Get the NSG resource
$nsg = Get-AzNetworkSecurityGroup -Name $nsgname -ResourceGroupName $RGname

#Add the inbound security rule.
$nsg | Add-AzNetworkSecurityRuleConfig -Name $rulename -Description "Allow RDP port" -
Access Allow `-Protocol * -Direction Inbound -Priority 3891 -
SourceAddressPrefix $SourceRDPAddress -SourcePortRange * `-DestinationAddressPrefix * -
DestinationPortRange $port

#Update the NSG.
$nsg | Set-AzNetworkSecurityGroup

#Create and assign New Public IP Address
New-AzPublicIpAddress -Name $PublicIPName -ResourceGroupName $ResourceGroupName -
AllocationMethod Dynamic -Location $location
$vnet = Get-AzVirtualNetwork -Name $VirtualNetworkName -
ResourceGroupName $ResourceGroupName
$subnet = Get-AzVirtualNetworkSubnetConfig -Name $SubnetName -VirtualNetwork $vnet
$nic = Get-AzNetworkInterface -Name $nicName -ResourceGroupName $ResourceGroupName
$pip = Get-AzPublicIpAddress -Name $PublicIPName -ResourceGroupName $ResourceGroupName
$nic | Set-AzNetworkInterfaceIpConfig -Name $ipconfigname -PublicIPAddress $pip -
Subnet $subnet
$nic | Set-AzNetworkInterface

#Assign NSG to Nic
$nic = Get-AzNetworkInterface -Name $nicName -ResourceGroupName $ResourceGroupName
$nic.NetworkSecurityGroup = $nsg
Set-AzNetworkInterface -NetworkInterface $nic

 

It is important to understand that the script uses a snapshot of an Azure virtual machine when creating the new virtual machine. The virtual machine has some preinstalled software required for parts of the use case. It was easy to have some of the software preinstalled to reduce the complexity of this flow. The snapshot includes PowerShell v7, Az Copy, WinAutomation, and an on-premises data gateway. PowerShell v7 and Az Copy are used to upload files to Azure Container Storage in a later action. WinAutomation is our RPA software and the on-premises data gateway is already registered with Power Automate, so that when the virtual machine is turned on, Power Automate UI Flows knows which host to execute the robotic process automation on. This software, properly configured, is crucial to the success of the flow.

 

With the script in place. I can use the Create job action (shown below) under the Azure Automation connector to trigger the PowerShell runbook above.

 

Microsoft Power Automate Flows_Part2_image 5

 

With Create job selected as the action, several additional sections are required by Power Automate. These are shown in red in the image below. A connection (below on right) needs to be selected and then each of the values needs to be selected. The resource group is the group that the runbook is located. This was selected under the automation account, which was shown above.

 

Microsoft Power Automate Flows_Part2_image 6

 

In the image above, each highlighted blue box shows the required parameters needed by the custom runbook I created. The values shown are the owner, vendor, and IP variables that I defined in earlier in the flow from the initialize and set variable actions. This was covered in part one of the series. Using the dynamic value button as seen in the smaller image below I am able to select these values.

 

Microsoft Power Automate Flows_Part2_image 7

 

Microsoft Power Automate Flows_Part2_image 8

 

When the action is reached in the flow, it will pass the owner, vendor, and IP values to the PowerShell runbook. Azure will create a resource group and resources based on the vendor value that was pulled from the body of the email trigger. It will also create a tag value Owner: Kiraly for the resource group. This can be seen in the image below.

 

Microsoft Power Automate Flows_Part2_image 9

 

Not only does the script above create all of the resources, but it also adds the IP address from the body of the email and places it in a security group called Microsoft-Edge-RDPSecurityGroup. This allows the requestor to RDP into the new Azure virtual machine from the IP address they submitted in the original email.

 

The next blog post will cover the next action in the flow, assigning the virtual machine an approved IP address.

 

Microsoft Power Automate Flows_Part2_image 10


Additional Reference Information:
Azure Automation: https://docs.microsoft.com/en-us/azure/automation/automation-intro
Automation Account: https://docs.microsoft.com/en-us/azure/automation/automation-create-standalone-account
Azure PowerShell Az module: https://docs.microsoft.com/en-us/powershell/azure/new-azureps-module-az?view=azps-4.7.0
Manage Modules in Azure Automation: https://docs.microsoft.com/en-us/azure/automation/shared-resources/modules
Application and service principal objects in Azure Active Directory: https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals
PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/whats-new/what-s-new-in-powershell-70?view=powershell-7
Az Copy: https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10
Softomotive WinAutomation: https://www.winautomation.com/
On-premises data gateway: https://docs.microsoft.com/en-us/power-automate/gateway-reference
Power Automate UI Flows: https://flow.microsoft.com/en-us/ui-flows/

 

Additional note: PowerShell Az Module Import
It is worth noting that the Azure Az modules needed to be imported from the Modules gallery in order for automation service to be made aware of the cmdlets and successfully execute the runbook. It can get a little confusing with the nuances between Az, AzureRM, and Azure CLI. It is also important to know that Azure cli commands are not available in the automation service. Az and AzureRM modules can be imported through the Modules gallery. The modules that an automation account has available can be found under Modules seen below.

 

Microsoft Power Automate Flows_Part2_image 11

 


Here's a review of related posts on this series:

Dan Kiraly
Senior Research Scientist | Optiv
Dan Kiraly is senior research scientist on Optiv’s R&D team. In this role he's responsible for use case development and the vetting of security products for Optiv.