Bootstrapping a Virtual Machine with Windows Azure

In my Advanced IaaS Talk at Build I showed a demo where you can configure a PowerShell script that can download a zip file with multiple actions (unzip or execute) that gives you similar functionality to a Windows Azure startup task for web and worker roles.

This is a very simple example but it does show some of the capabilities you can do.

The bootstrap.ps1 file below is the main script that is responsible for downloading the bootstrap.zip file from your storage account. You should create a directory called c:BootStrap and place the script inside and reference it from the startup task on your virtual machine.

In this demonstration I am pulling from a public storage container. If you want to contain anything secure in your bootstrap.zip you should modify the url below to use a shared access signature..

bootstrap.ps1

cls
 
$rootpath = 'C:BootStrap'
$manifest = 'C:BootStrapWorkingmanifest.xml'
$workingdir = 'C:BootStrapWorking'
$downloaddir = 'C:BootStrapWorkingconfig1.zip'
$packagesource = 'http://YOURSTORAGEACCOUNT.blob.core.windows.net/bootstrap/config1.zip'
 
function GetPayload()
{
    $retries = 5
	while($retries -gt 0)
	{
		CheckFolder $workingdir
	    try {
		    $wc = New-Object System.Net.WebClient
		    $wc.DownloadFile($packagesource, $downloaddir)
			break
	     } 
	     catch [System.Net.WebException] {
		    # $_ is set to the ErrorRecord of the exception
	        if ($_.Exception.InnerException) {
	     	   $_.Exception.InnerException.Message | Out-File c:BootStraperror.txt -Append
	        } else {
	           $_.Exception.Message | Out-File c:BootStraperror.txt -Append
	        }
			Start-Sleep -Seconds 15
			$retries = $retries - 1
	     }
	 }
     UnzipFileTo $downloaddir $workingdir
}
 
function BootStrapVM()
{
  if((Test-Path HKLM:SoftwareVMBootStrap) -eq $true)
  {
     Write-Host "Already Ran"
	 return
  }
 
  [xml] $manifest = Get-Content $manifest
  $counter = 0
  $manifest.StartupManifest.Items.Item | foreach { 
	$action = $_.action 
	$path = $_."#text"
	$target = $_.target 
	$sourcefullpath = $workingdir + $path
 
	switch($action)
	{
	   "execute" {
		  Write-Host "Executing command: " $sourcefullpath
		  ExecuteCommand $sourcefullpath
	   }
	   "unzip" {
		  $sourcefullpath = $workingdir + $path
		  Write-Host "Unzipping " $sourcefullpath " to " $target 
	      UnzipFileTo $sourcefullpath $target
	   }
 
	}
 
  }
  New-Item -Path HKLM:Software -Name VMBootStrap –Force | Out-Null
  Set-Item -Path HKLM:SoftwareVMBootStrap -Value "ran" | Out-Null
}
 
function ExecuteCommand($commandpath)
{
	& $commandpath
}
 
function UnzipFileTo($sourcepath, $destinationpath)
{
	CheckFolder $destinationpath
	$shell_app = new-object -com shell.application
	$zip_file = $shell_app.namespace($sourcepath)
	$destination = $shell_app.namespace($destinationpath)
	$destination.Copyhere($zip_file.items(), 16)
}
 
function CheckFolder($path)
{
	if((Test-Path $path) -eq $false)
	{
   		New-Item -ItemType directory -Path $path -Force | Out-Null
	}
}
GetPayload
BootStrapVM

Here are two sample configs I put together:

config1.zip Enables Remote PowerShell

http://mwweststorage.blob.core.windows.net/bootstrapblog/config1.zip

config2.zip Installs IIS, WebPI, MySQL and WordPress

http://mwweststorage.blob.core.windows.net/bootstrapblog/config2.zip

The config1.zip file contains a manifest.xml file and all of the entities you need to upload.

Example of the manifest.xml section of the config2.zip
[sourcecode language="xml"]
<StartupManifest>
<Items>
<Item action="execute">InstallRolesConfigureRoles.ps1</Item>
<Item action="unzip" target="c:webpi">WebPIWebpiCmd.zip</Item>
<Item action="execute">InstallPackagesEnableWebPI.cmd</Item>
</Items>
</StartupManifest>

All that is needed to configure the script to run when your VM boots is to configure a startup task using group policy.

Run: mmc
File -> Add/Remove Snapin
Select -> Group Policy Object Editor (Local Computer)
Expand -> Computer Configuration -> Windows Settings -> Scripts Startup/Shutdown

Once the script is configured you will need to change the execution policy on the virtual machine before you run sysprep and capture on your image otherwise the script will not execute on the next boot.

 Set-ExecutionPolicy RemoteSigned

Finally, if you do enable to the remote PowerShell task here is the command line you can use to connect.

Enter-PSSession -ComputerName {hostname}.cloudapp.net -Authentication Basic -Credential Administrator -UseSSL -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>