Using PowerShell Remoting for disk provisioning automation

Windows Azure PowerShell cmdlets allow you to automate the construction of your infrastructure, typically creating and starting VMs, and attaching additional disks to expand the default storage configuration. This articles show a little recipe to also use Remote PowerShell to create and format a striped volume in the same script.

Attaching disks

The first thing to do is to attach some new disks to the virtual machine. I will not detail the process here as it is well documented elsewhere. Here is one way to do it:

 Get-AzureVM -ServiceName $sn -Name $n | Add-AzureDataDisk -CreateNew -DiskSizeInGB 128 -DiskLabel "DataDisk0" -LUN 1 | Add-AzureDataDisk -CreateNew -DiskSizeInGB 128 -DiskLabel "DataDisk1" -LUN 2 | Update-AzureVM

This will create two new raw devices in your virtual machine.

Remote PowerShell

We are going to use PowerShell remoting to run scripts on a Virtual Machine without having to connect using Remote Desktop. You can read a complete overview of Remote PowerShell on Scripting Guy's blog for example, but here is what we need to use in a nutshell:

First, we need to retrieve the WinRM URI that will be used to connect to the remote VM:

 $uri = Get-AzureWinRMUri -ServiceName $sn -Name $n

Then we need to construction a PowerShell session option object to work around those pesky security restrictions... Of course I wouldn't advise doing this in production, and read up on how to install the correct certificates.

 $option = New-PSSessionOption -SkipCACheck -SkipCNCheck

And finally we need to collect some credentials, this command will open a UI prompt for you to type in a username and password.

 $cred = Get-Credential

Using these variables, we should be able to start an interactive PowerShell session on the remote host:

 Enter-PSSession -ConnectionUri $uri -SessionOption $option -Credential $cred

Later, we will use Invoke-Command to run a script remotely.

Using DISKPART

You can feed DISKPART a text file containing the commands to run. Here is what you typically need to do to create a striped volume using the two disks we just attached. The disk and volume indices are hard-coded, so make sure to change them if your disk configuration differs from the Windows Azure standard! The indices below are based on the standard VM configuration of one persistent disk on C: and one temporary, local disk on D:.

 select disk 2
clean
convert dynamic
select disk 3
clean
convert dynamic
create volume stripe disk=2,3
select volume 2
assign letter=E
format fs=ntfs quick

Putting it all together

Now we can assemble our two scripts. The first one creates the disks, then calls the second one on the remote instance via Invoke-Command.

remote_createstripe.ps1:

 $sn = 'arriis'
$n = 'iis1'

$uri = Get-AzureWinRMUri -ServiceName $sn -Name $n
$option = New-PSSessionOption -SkipCACheck -SkipCNCheck
$cred = Get-Credential

Get-AzureVM -ServiceName $sn -Name $n | Add-AzureDataDisk -CreateNew -DiskSizeInGB 128 -DiskLabel "DataDisk0" -LUN 1 | Add-AzureDataDisk -CreateNew -DiskSizeInGB 128 -DiskLabel "DataDisk1" -LUN 2 | Update-AzureVM

$session = New-PSSession -ConnectionUri $uri -SessionOption $option -Credential $cred

Invoke-Command -Session $session -FilePath C:\dev\ps\diskstripe\createstripe.ps1

The second script just creates a text file containing the DISKPART commands and runs it.

createstripe.ps1:

 New-Item -Name createstripe.txt -ItemType file -Force

Add-Content -Path createstripe.txt "select disk 2"
Add-Content -Path createstripe.txt "clean"
Add-Content -Path createstripe.txt "convert dynamic"
Add-Content -Path createstripe.txt "select disk 3"
Add-Content -Path createstripe.txt "clean"
Add-Content -Path createstripe.txt "convert dynamic"
Add-Content -Path createstripe.txt "create volume stripe disk=2,3"
Add-Content -Path createstripe.txt "select volume 2"
Add-Content -Path createstripe.txt "assign letter=E"
Add-Content -Path createstripe.txt "format fs=ntfs quick"

diskpart /s createstripe.txt

Hope this helps!