Get-Process Power* As anyone learning PowerShell quickly finds out, there are a number of basic patterns of usage that work well across a huge range of PowerShell cmdlets/modules. One of the most basic pair of patterns I try to teach, by way of example here, are early vs late filtering. The following two commands accomplish the same result:
Get-Process | Where-Object name -like Power*
I wrote a little script to measure the performance difference between these two (http://pastebin.com/4N2YYqnZ). Running each of these 1000 times, the result was that early filtering was 3 times as fast as later filtering. So as a general rule – always early filter. BUT: sadly some cmdlets that emit useful objects do not support early filtering, so the later filtering pattern always works. I try to teach both of these patterns and why they are different since so many scripts can make use of these patterns.
Which brings me to Azure. In much of my PowerShell use, there is a cmdlet to set some value for some object or perform some operation on an object. For example, to change the number of CPUs in a Hyper-V VM, you use the Set-VM cmdlet, like this:
To do this in Azure is a bit more complicated. To change the number of processors in an Azure VM, you need to change a different property on the Azure VM object. Plus, the say you do it is different. With Azure, each VM runs in a given instance. The instance determines the number of CPUs and memory each Azure VM gets. So I would expect to do something like this:
Set-AzureVM –name xxx –service xxx –instancesize 'extrasmall'
Unfortunately, that cmdlet does not exist, and that wouldn't be the right way to do it anyway. The good news is that in Azure, there is a specific cmdlet to change the instance size (Set-AzureVMSize). So Azure VMs, the most common pattern is like this:
Get-AzureVM –VM psh1 –Service psh1 -Verbose |
Set-AzureVMSize -Instancesize $VmSize -Verbose |
A different pattern. Unlike Set-VM, Set-AzureVMSize takes an Azure VM object (not the name of the VM). Secondly, Set-AzureVMSize does not persist the updated instance size value – it just updates an in memory object relating to the VM. To persist the value you have to write it back to Azure using Update-AzureVM. While you can do it step at a time, and avoid using the pipeline – in this case, using the pipeline makes seems easier.
In the Azure VM cmdlets, we see a great deal of use of the Pipeline based patterns. For example, to create an Azure VM, you first create a VM config object (Technically, New-AzureVMConfig produces an object of type Microsoft.WindowsAzure.Commands.ServiceManagement.Model.PersistentVM) which you then pipe to New-AzureVM (see http://tfl09.blogspot.co.uk/2015/01/managing-azure-vms-with-powershell.html). This general pattern of getting or creating an in-memory object, updating that in-memory object typically via the pipeline and finally persisting it to Azure is easy to apply.
When you start to use Azure you quickly find that while many of the features of Azure are similar to those in Windows – in this case, Azure VMs – the methods you use to manage the features does differ. You have different patterns of usage you need to learn and understand. When I explained this to a class this week, I got the obvious question: why? Why is it different?
Since I was not on the dev team, I can't really answer that. But, I suspect the main technical reason is that the Azure VMs are, in effect, a wrapper around the REST API exposed by Azure. I am guessing it was easier to write the cmdlets using this pipeline pattern (or the cmdlet's approach of passing a VM object vs a VM name). Having said this, incorporating the Get-AzureVM and the Update-AzureVM cmdlets inside the Set-AzureVMSize cmdlet would have not been that difficult. But that wasn't what MS implemented.
So go with the flow; learn the patterns and enjoy Azure!