Tuesday, June 23, 2015

PowerShell : XML schema validation



I have this script to validate an XML file against a schema. The module exposes a Test-XmlSchema function that accepts an XML file and a Schema file as parameters and validates the XML file against the schema.

function Test-XmlSchema
{
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateScript({Test-Path $_})]
        [String]
        $XmlPath,
       
        [Parameter(Mandatory = $true)]
        [ValidateScript({Test-Path $_})]
        [String]
        $SchemaPath
    )

    $schemas = New-Object System.Xml.Schema.XmlSchemaSet
       $schemas.CompilationSettings.EnableUpaCheck = $false
       $schema = ReadSchema $SchemaPath
       [void]($schemas.Add($schema))
       $schemas.Compile()
      
       try
    {
        [xml]$xmlData = Get-Content $XmlPath
              $xmlData.Schemas = $schemas

        #Validate the schema. This will fail if is invalid schema
              $xmlData.Validate($null)
              return $true
       }
    catch [System.Xml.Schema.XmlSchemaValidationException]
    {
              return $false
       }
}

Function ReadSchema
{
       param($SchemaPath)
       try
    {
              $schemaItem = Get-Item $SchemaPath
              $stream = $schemaItem.OpenRead()
              $schema = [Xml.Schema.XmlSchema]::Read($stream, $null)
              return $schema
       }
       catch
    {
              throw
       }
       finally
    {
              if($stream)
        {
                     $stream.Close()
              }
       }
}

Export-ModuleMember -Function Test-XmlSchema


Usage:

PS C:\> Import-Module XML

PS C:\> Test-XMLSchema -XmlPath E:\Test.xml -SchemaPath E:\Test.xsd
True




PowerShell : Trigger a release in Release Management from TFS builds

With TFS 2013, the default template provides the ability to extend the out of box capabilities by providing post build process scripts, that can be used to execute custom PowerShell scripts as part of the build process. With the combination of the post build scripts and the TF_BUILd environment variables its very easy to provide PowerShell customization and execute them during the build. In this post, we'll see how we can combine these together to trigger a release from Release management using the Orchestration service API from release management. If you want to see the details of the REST API, use Fiddler to tract the calls through the Release Management Client application.
I'm using the InitializeReleaseFromBuild API to trigger a release in Release Management. The formatted uri should look like http://RMSERVER:PortNumber/account/releaseManagementService/_apis/releaseManagement/OrchestratorService/InitiateReleaseFromBuild?teamFoundationServerUrl=”tfsserverurl"&teamProject="project"&buildDefinition="definition"&buildNumber="build”&targetStageName="targetStage”

Later using the ReleaseStatus API, we can query the status of the release.
http://RMSERVER:PortNumber/account/releaseManagementService/_apis/releaseManagement/OrchestratorService/ReleaseStatus?releaseId=releaseId&api-version=2.0

param
(
    [string]$rmserver,
    [string]$port, 
    [string]$teamProject,  
    [string]$targetStageName,
    [string]$tfsUrl
)
$buildDefinition = $env:TF_BUILD_BUILDDEFINITIONNAME
$buildNumber = $env:TF_BUILD_BUILDNUMBER

$location = $MyInvocation.MyCommand.Name
 | Split-Path -Parent (Get-Variable MyInvocation -Scope Script).Value.MyCommand.Path

Push-Location $location

$server = [System.Uri]::EscapeDataString($tfsUrl)
$project = [System.Uri]::EscapeDataString($teamProject)
$definition = [System.Uri]::EscapeDataString($buildDefinition)
$build = [System.Uri]::EscapeDataString($buildNumber)
$targetStage = [System.Uri]::EscapeDataString($targetStageName)

$serverName = $rmserver + ":" + $port
$orchestratorService = "http://$serverName/account/releaseManagementService/_apis/releaseManagement/OrchestratorService"

$status = @{
    "2" = "InProgress";
    "3" = "Released";
    "4" = "Stopped";
    "5" = "Rejected";
    "6" = "Abandoned";
}

$uri = "$orchestratorService/InitiateReleaseFromBuild?teamFoundationServerUrl=$server&teamProject=$project&buildDefinition=$definition&buildNumber=$build&targetStageName=$targetStage"

$webClient = New-Object System.Net.WebClient
$webClient.UseDefaultCredentials = $true

$releaseId = $webClient.DownloadString($uri)
$url = "$orchestratorService/ReleaseStatus?releaseId=$releaseId"
$releaseStatusId = $webClient.DownloadString($url)
$releaseStatus = $status[$releaseStatusId]

Pop-Location



Tuesday, June 16, 2015

Azure DocumentDB - First look

DocumentDB is the Microsofts NoSQL database as a service implementation on Azure for modern web and mobile applications. Some of the benefits of DocumentDB is that it can deliver consistently fast reads and writes, allow schema flexibility as in the case of all NoSQL databases and thus with the ability to easily scale a database up and down on demand.

It’s well integrated with JavaScript and supports complex queries in a SQL language and also has a strong server side programming model of UDFs, functions and stored procedures. If you have a valid Azure subscription, you can create a document db account and start working immediately. All resources within DocumentDB are modeled and stored as JSON documents. Resources are managed as items, which are JSON documents containing metadata, and as feeds which are collections of items. Sets of items are contained within their respective feeds.

You can create a DocumentDB account by logging into Azure and choosing Azure Document DB under the Data + Storage options.

Enter a valid AccountId, choose a resource group and create.

Once the DocumentDB account is created successfully, you can see the notifications changed with the details and the account details in the home page.

Click on the account details on the home page and then navigate to the Keys section to see, the details of the uri and keys for the account. Also note the databases section which is empty right now.

We’ll see how we can use the .NET APIs to use code first approach on creating a database and add entries to the collection. For that, we’ll use an ASP.NET MVC application.

The DocumentDB .NET SDK is packaged and distributed as a NuGet package, which can be installed using the Install-Package cmdlet.

The uri and key management for our demo application is handled in the configuration file as app settings.

Once we have these settings configured, we can use these details to create an instance of the DocumentClient object which we’ll use to create the database and collections.

var endpoint = ConfigurationManager.AppSettings["endpoint"];
var authKey = ConfigurationManager.AppSettings["authKey"];
var endpointUri = new Uri(endpoint);

_client = new DocumentClient(endpointUri, authKey);

A database instance can be created like

_database = _client.CreateDatabaseAsync(new Database { Id = DatabaseId }).Result;

If you have the database created, then using the database instance the collection can be created as


_client.CreateDocumentCollectionAsync(_database.SelfLink, new DocumentCollection { Id = CollectionId }).Result;


Friday, June 12, 2015

Managing snapshots on Azure Virtual machines

1      Introduction

One of the challenges working with Azure infrastructure and VM’s on Azure is that there is native functionality provided by Azure to manage snapshots on the machine. With traditional on premise virtualization infrastructures this was a very easy and simple task to perform.
In this post, we’ll see how to use the combination of various Azure PowerShell cmdlets available to create a backup of the OSDisks and data disks on the VM to a storage container and later use these backups to restore the VM to the state we wanted to restore to. Later we’ll combine all these options into a PowerShell module and use the functions exposed to create and restore backups whenever needed.

2      Connecting to Azure Subscription

Before we start, the first step is to connect to the Azure subscription. You can use the Add-AzureAccount cmdlet to connect to the Azure subscription.
Add-AzureAccount
Get-AzureSubscription
PS C:\Windows\System32\WindowsPowerShell\v1.0> Add-AzureAccount

Id                             Type       Subscriptions                                         Tenants                                            
--                             ----       -------------                                         -------                                            
p.prathap@prowareness.nl       User       2a9f4b1c-91fd-4fe6-8f9a-fd2ea8aa4840                  24b080cd-5874-44ab-9862-8d7e0e0781ab               



PS C:\Windows\System32\WindowsPowerShell\v1.0> Get-AzureSubscription


SubscriptionId            : 2a9f4b1c-91fd-4fe6-8f9a-fd2ea8aa4840
SubscriptionName          : Prajeesh Prathap
Environment               : AzureCloud
SupportedModes            : AzureServiceManagement,AzureResourceManager
DefaultAccount            : p.prathap@prowareness.nl
Accounts                  : {p.prathap@prowareness.nl}
IsDefault                 : True
IsCurrent                 : True
CurrentStorageAccountName :
TenantId                  : 24b080cd-5874-44ab-9862-8d7e0e0781ab

2.1    Associate storage account

After logging to the azure account, you need to check the Azure subscription details by using the Get-AzureSubcription cmdlet. Sometimes, you need to use the Set-AzureSubscription cmdlet to associate a storage account to the subscription.
To find out which storage accounts are available and then register to the subscription, use the Get-AzureStorageAccount cmdlet as given below. If you have multiple storage accounts available, all of them will be listed as given below.
PS C:\Windows\System32\WindowsPowerShell\v1.0> Get-AzureStorageAccount


StorageAccountDescription : devvm015
AffinityGroup             :
Location                  : West Europe
GeoReplicationEnabled     : True
GeoPrimaryLocation        : West Europe
GeoSecondaryLocation      : North Europe
Label                     : devvm015
StorageAccountStatus      : Created
StatusOfPrimary           : Available
StatusOfSecondary         : Available
Endpoints                 : {https://devvm015.blob.core.windows.net/, https://devvm015.queue.core.windows.net/,
                            https://devvm015.table.core.windows.net/}
AccountType               : Standard_GRS
StorageAccountName        : devvm015
OperationDescription      : Get-AzureStorageAccount
OperationId               : 247cc1a6-4748-aef6-82c6-bf970a21f4cc
OperationStatus           : Succeeded

StorageAccountDescription : Implicitly created storage service
AffinityGroup             :
Location                  : West Europe
GeoReplicationEnabled     : True
GeoPrimaryLocation        : West Europe
GeoSecondaryLocation      : North Europe
Label                     : portalvhds9zh30b55gfhx8
StorageAccountStatus      : Created
StatusOfPrimary           : Available
StatusOfSecondary         : Available
Endpoints                 : {https://portalvhds9zh30b55gfhx8.blob.core.windows.net/, https://portalvhds9zh30b55gfhx8.queue.core.windows.net/,
                            https://portalvhds9zh30b55gfhx8.table.core.windows.net/}
AccountType               : Standard_GRS
StorageAccountName        : portalvhds9zh30b55gfhx8
OperationDescription      : Get-AzureStorageAccount
OperationId               : 247cc1a6-4748-aef6-82c6-bf970a21f4cc
OperationStatus           : Succeeded

WARNING: GeoReplicationEnabled property will be deprecated in a future release of Azure PowerShell. The value will be merged into the AccountType propert
y.

From the list use the storage account label property value to associate to the subscription using the Set-AzureSubscription cmdlet as given below.
Set-AzureSubscription -SubscriptionId  $subId -CurrentStorageAccountName $accName -PassThru



PS C:\Windows\System32\WindowsPowerShell\v1.0> Set-AzureSubscription -SubscriptionId  2a9f4b1c-91fd-4fe6-8f9a-fd2ea8aa4840 -CurrentStorageAccountName portalvhds9zh30b55gfhx8 -PassThru


Id          : 2a9f4b1c-91fd-4fe6-8f9a-fd2ea8aa4840
Name        : Prajeesh Prathap
Environment : AzureCloud
Account     : p.prathap@prowareness.nl
Properties  : {[SupportedModes, AzureServiceManagement,AzureResourceManager], [Tenants, 24b080cd-5874-44ab-9862-8d7e0e0781ab], [Default, True],
              [StorageAccount, portalvhds9zh30b55gfhx8]}

Next, we need to find out the virtual machine that we need to create a backup for. Using the Get-AzureVM cmdlet, you can list all the available machines in your subscription.

PS C:\Windows\System32\WindowsPowerShell\v1.0> Get-AzureVM

ServiceName         Name         Status           
-----------         ----         ------           
ChefTestVM00        ChefTestVM00 StoppedDeallocated
DEVMachine-auyh2433 DEVMachine   ReadyRole        
DevVS2015-p25312tj  DevVS2015    StoppedDeallocated

3      Backup Azure VM Disks

From the list to choose a machine, use the –ServiceName and –Name option for the Get-AzureVM cmdlet. Later we can use the Get-AzureOSDisk and Get-AzureDataDisk cmdlets to retrieve the operating system disks and data disks for the virtual machine.
$azureVM = Get-AzureVM -ServiceName $serviceName -Name $vmName
Get-AzureOSDisk -VM $azureVM
Get-AzureDataDisk -VM $azureVM



PS C:\Windows\System32\WindowsPowerShell\v1.0> $azureVM = Get-AzureVM -ServiceName DevVS2015-p25312tj -Name DevVS2015

PS C:\Windows\System32\WindowsPowerShell\v1.0> Get-AzureOSDisk -VM $azureVM


HostCaching     : ReadWrite
DiskLabel       :
DiskName        : DevVS2015-p25312tj-DevVS2015-os-1432737990155
MediaLink       : https://devvm015.blob.core.windows.net/vhds/DevVS2015-p25312tj-DevVS2015-os-1432737990155.vhd
SourceImageName : 03f55de797f546a1b29d1b8d66be687a__Visual-Studio-2015-Community-RC-AzureSDK-2.6-WS2012R2-201505.15
OS              : Windows
IOType          : Standard
ResizedSizeInGB :
ExtensionData   :


PS C:\Windows\System32\WindowsPowerShell\v1.0> Get-AzureDataDisk -VM $azureVM

To access the storage accounts, we need to create a storage context. To copy the disk image of the operating system disk, we need to first create a storage context, both for the source and destination context. To create a storage context, we need to have a storage account name and storage account key.

3.1    Create storage context

To get the storage account name of the Azure VM disk, we can make use of the MediaLink property of the Azure VM. The host property of the MediaLink contains the storage account name as the first part of the host. To get the storage account name use the cmdlet as below.

PS C:\Windows\System32\WindowsPowerShell\v1.0> $osDisk = Get-AzureOSDisk -VM $azureVM

PS C:\Windows\System32\WindowsPowerShell\v1.0> $osDisk.MediaLink | select -ExpandProperty Host
devvm015.blob.core.windows.net

PS C:\Windows\System32\WindowsPowerShell\v1.0> ($osDisk.MediaLink | select -ExpandProperty Host).Split('.')[0]
devvm015

PS C:\Windows\System32\WindowsPowerShell\v1.0> $sourceStorageAccount = ($osDisk.MediaLink | select -ExpandProperty Host).Split('.')[0]

3.2    Create the source storage context

From the storage account name, we retrieve the storage key by using the Get-AzureStorageKey cmdlet as given below.
$osDisk = Get-AzureOSDisk -VM $azureVM
$sourceStorageAccount = ($osDisk.MediaLink | select -ExpandProperty Host).Split('.')[0]
$sourceStorageAccountKey = Get-AzureStorageKey -StorageAccountName $sourceStorageAccount |% {$_.Primary}
$sourceStorageContext = New-AzureStorageContext -StorageAccountName $sourceStorageAccount -StorageAccountKey $sourceStorageAccountKey

PS C:\Windows\System32\WindowsPowerShell\v1.0> $sourceStorageAccount = ($osDisk.MediaLink | select -ExpandProperty Host).Split('.')[0]

PS C:\Windows\System32\WindowsPowerShell\v1.0> Get-AzureStorageAccount -StorageAccountName $sourceStorageAccount


StorageAccountDescription : devvm015
AffinityGroup             :
Location                  : West Europe
GeoReplicationEnabled     : True
GeoPrimaryLocation        : West Europe
GeoSecondaryLocation      : North Europe
Label                     : devvm015
StorageAccountStatus      : Created
StatusOfPrimary           : Available
StatusOfSecondary         : Available
Endpoints                 : {https://devvm015.blob.core.windows.net/, https://devvm015.queue.core.windows.net/,
                            https://devvm015.table.core.windows.net/}
AccountType               : Standard_GRS
StorageAccountName        : devvm015
OperationDescription      : Get-AzureStorageAccount
OperationId               : 5abb7dc6-fe18-a21c-acd4-0b746078513e
OperationStatus           : Succeeded

WARNING: GeoReplicationEnabled property will be deprecated in a future release of Azure PowerShell. The value will be merged into the AccountType propert
y.



PS C:\Windows\System32\WindowsPowerShell\v1.0> $sourceStorageAccountKey = Get-AzureStorageKey -StorageAccountName $sourceStorageAccount

Once we have the storage account name and the storage key, we can use these information to create the storage context object.
PS C:\Windows\System32\WindowsPowerShell\v1.0> $sourceStorageAccountKey = Get-AzureStorageKey -StorageAccountName $sourceStorageAccount |% {$_.Primary}

PS C:\Windows\System32\WindowsPowerShell\v1.0> $sourceStorageContext = New-AzureStorageContext -StorageAccountName $sourceStorageAccount -StorageAccountKey $sourceStorageAccountKey

3.3    Create destination storage account

To create a new storage account use the New-AzureStorageAccount cmdlet
New-AzureStorageAccount -StorageAccountName "vmbackupstorage6787" `
                        -Label "vmbackupstorage"  `
                        -Location "West Europe"

PS C:\Windows\System32\WindowsPowerShell\v1.0> Get-AzureLocation | select -ExpandProperty displayname
West US
Central US
South Central US
East US
East US 2
North Europe
West Europe
Southeast Asia
East Asia
Japan West


PS C:\Windows\System32\WindowsPowerShell\v1.0> New-AzureStorageAccount -StorageAccountName "vmbackupstorage6787" -Label "vmbackupstorage"  -Location "West Europe"

OperationDescription    OperationId                          OperationStatus
--------------------    -----------                          ---------------
New-AzureStorageAccount c32c52c7-6c1e-a4dc-8cff-1977de7ee935 Succeeded     

3.4    Create the destination storage context

To create the destination storage context, we will follow the same steps that we used to create the source storage context.
$destStorageAccountName = "vmbackupstorage6787"
$destStorageAccountKey = Get-AzureStorageKey -StorageAccountName $destStorageAccountName |% {$_.Primary}
$destStorageContext = New-AzureStorageContext -StorageAccountName $destStorageAccountName `
                                              -StorageAccountKey $destStorageAccountKey

PS C:\Windows\System32\WindowsPowerShell\v1.0> $destStorageAccountName = "vmbackupstorage6787"

PS C:\Windows\System32\WindowsPowerShell\v1.0> $destStorageAccountKey = Get-AzureStorageKey -StorageAccountName $destStorageAccountName |% {$_.Primary}

PS C:\Windows\System32\WindowsPowerShell\v1.0> $destStorageContext = New-AzureStorageContext -StorageAccountName $destStorageAccountName -StorageAccountKey $destStorageAccountKey

3.5    Create a storage container for the backups

To store the backups we’ll next create a storage container using the New-AzureStorageContainer cmdlet
New-AzureStorageContainer -Name "vmbackupstoragecontainer" `
                          -Permission Off `
                          -Context $destStorageContext


PS C:\Windows\System32\WindowsPowerShell\v1.0> New-AzureStorageContainer -Name "vmbackupstoragecontainer" -Permission Off -Context $destStorageContext


   Blob End Point: https://vmbackupstorage6787.blob.core.windows.net/

Name                     PublicAccess LastModified              
----                     ------------ ------------              
vmbackupstoragecontainer Off          6/11/2015 2:17:03 PM +00:00

3.6    Start backup process

Now we have the source and destination context available and a storage container created to store the backups, we can start the copy process by using the Start-AzureStorageBlobCopy cmdlet. Before performing the copy operation, we need to get the source blob and source container names. From the medialink property these values are addressable as http://.blob.core.windows.net//
$sourceUri = $osDisk.MediaLink.OriginalString
$sourceBlob = $sourceUri.Split('/')[-1]
$sourceContainer = $sourceUri.Split('/')[($sourceUri.Split('/').length - 2)]

PS C:\Windows\System32\WindowsPowerShell\v1.0> $sourceUri = $osDisk.MediaLink.OriginalString

PS C:\Windows\System32\WindowsPowerShell\v1.0> $sourceBlob = $sourceUri.Split('/')[-1]

PS C:\Windows\System32\WindowsPowerShell\v1.0> $sourceContainer = $sourceUri.Split('/')[($sourceUri.Split('/').length - 2)]

Before starting the copy process, we need to ensure that the VM is stopped.
$vmState = $azureVM | select -ExpandProperty PowerState
if($vmState -ne 'Stopped')
{
    Stop-AzureVM -VM $azureVM -StayProvisioned
}
do
{
    Start-Sleep -Seconds 5
    $azureVM = Get-AzureVM -ServiceName $serviceName -Name $vmName
} while(($azureVM.InstanceStatus -eq 'ReadyRole') -and ($azureVM.PowerState -eq 'Started')) 

Now we can use the State-AzureStorageBlobCopy cmdlet as
Start-AzureStorageBlobCopy -SrcBlob $sourceBlob `
                           -SrcContainer $sourceContainer `
                           -Context $sourceStorageContext `
                           -DestBlob "vmstoragebackup.vhd" `
                           -DestContainer "vmbackupstoragecontainer" `
                           -DestContext $destStorageContext

PS C:\Windows\System32\WindowsPowerShell\v1.0> Start-AzureStorageBlobCopy -SrcBlob $sourceBlob -SrcContainer $sourceContainer -Context $sourceStorageContext -DestBlob "vmstoragebackup.vhd" -DestContainer "vmbackupstoragecontainer" -DestContext $destStorageContext


   Container Uri: https://vmbackupstorage6787.blob.core.windows.net/vmbackupstoragecontainer

Name                BlobType Length       ContentType              LastModified                SnapshotTime
----                -------- ------       -----------              ------------                ------------
vmstoragebackup.vhd PageBlob 136367309312 application/octet-stream 6/11/2015 2:40:18 PM +00:00  

Once the copy begins it is completely asynchronous meaning you could immediately start other copy operations without waiting for the previous to complete. It is useful of course to determine the progress of your blob copy. This is made possible through the Get-AzureStorageBlobCopyState cmdlet
Get-AzureStorageBlobCopyState -Container vmbackupstoragecontainer `
                              -Blob vmstoragebackup.vhd `
                              -WaitForComplete `
                              -Context $destStorageContext

Note: If you have data disks then you need to copy the data disks also. Please note that while copying data disks you need to ensure that all the data disks are copied  during the process.
Get-AzureDataDisk -VM $azureVM |% {
    $sourceAccountName = ($_.MediaLink | select -ExpandProperty Host).Split('.')[0]
    $sourceAccountKey = Get-AzureStorageKey -StorageAccountName $sourceAccountName |% {$_.Primary}
    $sourceContext = New-AzureStorageContext -StorageAccountName $sourceAccountName -StorageAccountKey $sourceAccountKey

    $destAccountName = "vmbackupstorage6787"
    $destAccountKey = Get-AzureStorageKey -StorageAccountName $destAccountName |% {$_.Primary}
    $destContext = New-AzureStorageContext -StorageAccountName $destAccountName `
                                              -StorageAccountKey $destAccountKey

    $uri = $_.MediaLink.OriginalString
    $blob = $uri.Split('/')[-1]
    $container = $uri.Split('/')[($uri.Split('/').length - 2)]

    Start-AzureStorageBlobCopy -SrcBlob $blob `
                               -SrcContainer $container `
                               -Context $sourceContext `
                               -DestContainer "vmbackupstoragecontainer" `
                               -DestContext $destContext

    Get-AzureStorageBlobCopyState -Container vmbackupstoragecontainer `
                                  -WaitForComplete `
                                  -Context $destContext
}


4      Restoring the VM backup

To restore the VM, we need to first get the VM instance as in the same case of creating the backup. To get the VM, you can use the Get-AzureVM cmdlet with the service name and virtual machine name
$azureVM = Get-AzureVM -ServiceName $serviceName -Name $vmName

Next we need to ensure that the virtual machine is stopped and stays provisioned.
$vmState = $azureVM | select -ExpandProperty PowerState
if($vmState -ne 'Stopped')
{
    Stop-AzureVM -VM $azureVM -StayProvisioned
    Write-Host "Stopping the Azure virtual machine"
    do
    {
        Write-Host ".." -NoNewline -ForegroundColor Yellow
        Start-Sleep -Seconds 5
        $azureVM = Get-AzureVM -ServiceName $serviceName -Name $vmName
    } while(($azureVM.InstanceStatus -eq 'ReadyRole') -and ($azureVM.PowerState -eq 'Started'))
    Write-Host " "
    Write-Host "Successfully stopped the Azure virtual machine" -ForegroundColor DarkGreen

}

4.1    Fetch the OS Disk and Data disks

Once we have the virtual machines stopped, we can now fetch the OS disk and data disks to restore to an old state
$osDisk = Get-AzureOSDisk -VM $azureVM
$dataDisks = Get-AzureDataDisk -VM $azureVM


PS C:\Windows\System32\WindowsPowerShell\v1.0> $osDisk = Get-AzureOSDisk -VM $azureVM

PS C:\Windows\System32\WindowsPowerShell\v1.0> $dataDisks = Get-AzureDataDisk -VM $azureVM

4.2    Removing the Virtual Machine

Before removing the virtual machine, it’s a good practice to export the virtual machine state to a file that we’ll use later. The Export-AzureVM cmdlet helps you export the state of a virtual machine to a file. The resulting file is a serialized version of your VM settings including endpoints, subnets, data disks and cache settings.  We can use this information to easily recreate the same virtual machine in a new or existing cloud service.
To create a backup location we’ll use the New-Item cmdlet to create a directory to store the serialized file.
$vmConfigFolder = “C:\VMConfigs”

if (!(Test-Path –Path $vmConfigFolder))
{
    New-Item –Path $vmConfigFolder –ItemType Directory
}

$vmExportPath = $vmConfigFolder + “\” + $azureVM.Name + “.xml”
Export-AzureVM –Path $vmExportPath -ServiceName $serviceName -Name $vmName

Now as we have the configuration backed up, we can safely remove the virtual machine by using the Remove-AzureVM cmdlet
$osDiskName = $osDisk.DiskName
$osDiskUri = $osDisk.MediaLink
$sourceStorageAccount = ($osDisk.MediaLink | select -ExpandProperty Host).Split('.')[0]

$sourceUri = $osDisk.MediaLink.OriginalString
$sourceBlob = $sourceUri.Split('/')[-1]
$sourceContainer = $sourceUri.Split('/')[($sourceUri.Split('/').length - 2)]

$destContainer = "vmbackupstoragecontainer"

Remove-AzureVM -ServiceName $serviceName -Name $vmName

Write-Host "Detaching the OS Disk"
do
{
    Write-Host ".." -NoNewline -ForegroundColor Yellow
    Start-Sleep 5
}While ( (Get-AzureDisk –DiskName $osDiskName).AttachedTo ) 


PS C:\> Remove-AzureVM -ServiceName $serviceName -Name $vmName

OperationDescription OperationId                          OperationStatus
-------------------- -----------                          ---------------
Remove-AzureVM       5efc417c-c97b-a649-8cd2-e5cd1b9ef1e8 Succeeded  


4.3    Removing the OS disk

After the disks are completely ditached from the virtual machine, you can now remove the disk using the Remove-AzureDisk cmdlet
Remove-AzureDisk –DiskName $osDiskName –DeleteVHD


PS C:\> Remove-AzureDisk –DiskName $osDiskName –DeleteVHD

OperationDescription OperationId                          OperationStatus
-------------------- -----------                          ---------------
Remove-AzureDisk     387ed682-f185-ae47-95b6-c8b4a522fb78 Succeeded   


4.4    Restore the disk data

Now we can perform the blob copy of the data from the destination container to the source container back, that we have created while creating the backup of the OS Disk. But before that we need to create the source and destination contexts using the cmdlets given below.
$sourceStorageAccountKey = Get-AzureStorageKey -StorageAccountName $sourceStorageAccount |% {$_.Primary}
$sourceStorageContext = New-AzureStorageContext -StorageAccountName $sourceStorageAccount -StorageAccountKey $sourceStorageAccountKey


$destStorageAccountName = "vmbackupstorage6787"
$destStorageAccountKey = Get-AzureStorageKey -StorageAccountName $destStorageAccountName |% {$_.Primary}
$destStorageContext = New-AzureStorageContext -StorageAccountName $destStorageAccountName `
                                              -StorageAccountKey $destStorageAccountKey

PS C:\>

$sourceStorageAccountKey = Get-AzureStorageKey -StorageAccountName $sourceStorageAccount |% {$_.Primary}
$sourceStorageContext = New-AzureStorageContext -StorageAccountName $sourceStorageAccount -StorageAccountKey $sourceStorageAccountKey


$destStorageAccountName = "vmbackupstorage6787"
$destStorageAccountKey = Get-AzureStorageKey -StorageAccountName $destStorageAccountName |% {$_.Primary}
$destStorageContext = New-AzureStorageContext -StorageAccountName $destStorageAccountName `
                                              -StorageAccountKey $destStorageAccountKey

PS C:\> 

We need to perform the blob copy now reverse. That means the source and destination in the case of backup are reversed in this case.
Start-AzureStorageBlobCopy -SrcBlob "vmstoragebackup.vhd" `
                           -SrcContainer $destContainer `
                           -Context $destStorageContext `
                           -DestBlob $sourceBlob `
                           -DestContainer $sourceContainer `
                           -DestContext $sourceStorageContext


PS C:\> Start-AzureStorageBlobCopy -SrcBlob "vmstoragebackup.vhd" `
                           -SrcContainer $destContainer `
                           -Context $destStorageContext `
                           -DestBlob $sourceBlob `
                           -DestContainer $sourceContainer `
                           -DestContext $sourceStorageContext


   Container Uri: https://devvm015.blob.core.windows.net/vhds

Name                                              BlobType Length       ContentType              LastModified                SnapshotTime
----                                              -------- ------       -----------              ------------                ------------
DevVS2015-p25312tj-DevVS2015-os-1432737990155.vhd PageBlob 136367309312 application/octet-stream 6/11/2015 7:21:25 PM +00:00            


Get-AzureStorageBlobCopyState -Container $sourceContainer `
                              -Blob $sourceBlob `
                              -WaitForComplete `
                              -Context $sourceStorageContext

4.5    Re provision the azure vm

Once the copy is completed, you can now add the OS disk back and re provision the Azure VM by using the New-AzureVM cmdlet. We’ll make use of the configuration data that was exported before removing the VM to recreate the VM.


Add-AzureDisk –DiskName $osDiskName –MediaLocation $osDiskUri.AbsoluteUri –OS Windows

Import-AzureVM –Path $vmExportPath | New-AzureVM –ServiceName $serviceName -VNetName "Group DevVS2015GRP DevVS2015" -WaitForBoot
serviceName

Note: For the data disks, you need to follow the same approach we did while creating the backup. Iterate and restore. This should be done before importing the VM back.

PS C:\> Get-AzureVNetConfig -ExportToFile C:\VMConfigs\vnetConfigs.xml

XMLConfiguration                                                                                                                                        
----------------                                                                                                                                       
...                                                                                                               



PS C:\> Import-AzureVM –Path $vmExportPath | New-AzureVM –ServiceName $serviceName -VNetName "Group DevVS2015GRP DevVS2015" -WaitForBoot

OperationDescription OperationId                          OperationStatus
-------------------- -----------                          ---------------
New-AzureVM          2526e0c2-e2a8-b3e9-b061-08dc7e976ad1 Succeeded     



PS C:\> Get-AzureVM

ServiceName         Name         Status           
-----------         ----         ------           
ChefTestVM00        ChefTestVM00 StoppedDeallocated
DEVMachine-auyh2433 DEVMachine   ReadyRole        

DevVS2015-p25312tj  DevVS2015    ReadyRole