Powershell in the Cloud – Part 1 – Azure Automation – Managing your Infrastructure from the Cloud
I recently held a talk about Powershell in the Cloud in Powershell User Group Sweden, this 3 part series is an attempt to refine and expand on that talk. The series will focus on the functionality rather than the code behind it as I want the content to be accessible for not anyone, whether you the reader is of a technical background or not.
When you have read the entire post and have any questions or feedback feel free to contact me: firstname.lastname@example.org
The 3 part series is going to cover some basic ideas about managing infrastructure through Automation, Just Enough Administration (JEA), building HTTP APIs using Powershell and finally automating the infrastructure using Azure DevOps & Infrastructure As Code (IAC).
Even though we will talk about many different methods of running Powershell in the Cloud we are going to focus on one single use case:
Leveraging Automation to Reduce your Costs in Microsoft Azure
So the scenario we are presenting is that you have adopted Azure to some extent and have Virtual Machines in Microsoft Azure that are somewhat redundant, and to save cost you want to turn them off and deallocate them when they are not in use. The problem is that most of the redundant machines are not used by you or the IT department and you don’t want to give the end-users the option to access Azure in order to manage the machine powerstate.
To solve this problem we are going to use Azure Automation and build a super simple Runbook (Powershell script in the cloud) to control and delegate access to all our machines.
Azure Automation Accounts
”Azure Automation delivers a cloud-based automation and configuration service that provides consistent management across your Azure and non-Azure environments.” – https://docs.microsoft.com/en-us/azure/automation/automation-intro
In the content I’m displaying we will use as few features as we can to manage our infrastructure as well as keeping our code as simple as possible. If you’re interested in the full suite capabilities i highly suggest you read the Microsoft docs & create your own test environment.
The features we will use is the built in Run as Account and a single Powershell Runbook. In the Powershell Runbook we will create a simple weekly schedule as well as add webhooks to create JEA endpoints to end-users.
When creating a Azure Automation Account we will choose the option to create a Run as Account, this will create a service principle that has Contributor rights on the entire subscription. The Service Principal can later be delegated more granular access for security hardening and even be applied on other resources across the entire Azure Tenant. When we are done we will navigate to Process Automation\Runbooks, Create a Runbook and name it VirtualMachinePower, the runbook type is Powershell
We then add three parameters to the script. This is done exactly the same as in any powershell script and will allow us to control specific machines.
- Action – We want this to be a start/stop action.
- VMName – the displayname of the VM (in azure)
- ResourceGroupName – Where the VM resides in your Azure subscription
#Connect to Azure using the Run As Account
$servicePrincipalConnection=Get-AutomationConnection -Name "AzureRunAsConnection"
Add-AzureRmAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
$ErrorMessage = "Connection $connectionName not found."
Write-Error -Message $_.Exception
#Actual Code to start/stop virtual machines
Start-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMName -verbose
Stop-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMName -force -verbose
In the example above there is a Failed in Recent Jobs. This is the job queue history for this specific runbook. These are expandable so you can investigate the status, output and eventual error. In this specific case i entered a faulty Action and the ValidateSet threw an error.
”Cannot validate argument on parameter ’Action’. The argument ”asda” does not belong to the set ”start,stop” specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again. (The argument ”asda” does not belong to the set ”start,stop” specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again.)”
When the job is submitted to the queue we will se it cycle through Queued, Running and hopefully Completed
When Completed we will be able to see that the Virtual Machine went from Status Running to Stopped (deallocated) and thus the compute cost is reduced to zero as opposed to when the Virtual Machine is shut down from within the operating system.
How does this help me reduce costs? We have not accomplished anything new!
Well, yes we have. We have just pressed the ”Start/Stop” buttons using code. Now let’s connect all the dots and save some money.
The easy way to do this is Start/Stop the machines on a schedule. Azure Virtual Machines already has the option to automatically shut down, and if you know when to stop the machines by all means use the built-in functionality. Unfortunately we can’t use the same mechanism to start the Virtual Machines.
In this case we can easily from the runbook view press the Schedules and configure a daily start-up schedule, just specify the schedule and choose which Virtual Machine to start using the Parameters. This is nothing fancy so I will not go into any depth about this. What we will focus on is the Add Webhook functionality.
With this functionality we can create individual webhooks and distribute them to end-users and give them the option to either start and/or stop Virtual Machines from anywhere without access to Azure.
With the webhook created we can distribute the URL or a simple script to the end-user to allow the user to start/stop the Virtual Machine from without accessing Azure
[uri]$uri = 'https://s2events.azure-automation.net/webhooks?token=pXDplI%2botjqhMFTOINAWTnKVt%2bG9gk6nSkA7RoMn3Rs%3d'
Invoke-RestMethod -Method Post -Uri $uri
AND VOILÀ! We have just Leveraged Automation to Reduce Costs in Microsoft Azure
In the next part of this series we will go through how to create and deliver HTTP endpoints with Powershell that are accessible from your browser using Azure Function Apps.