0
votes

Does anyone know a way, and/or have sample code, to retrieve the following information from an Azure IaaS Virtual Machine implementation?

  1. The associated Virtual Network, by name - NOT the subnet; I can get this already and, as it's not unique for all Virtual Network's in a subscription, can't be used.
  2. The storage account for the VM's attached disks

For additional context to the question, we're attempting to generate XML for DR purposes which will allow us to rebuild our IaaS implementation on a secondary data centre in the event of primary failure. We've managed to retrieve most, if not all, the information we require, but can't find a way to get the VNet(s) from the VM (or vice-versa) or the storage account(s)/container(s) for the VM's disks.

3

3 Answers

0
votes

On (2), wouldn't you be able to pull the MediaLocation value for each disk?

<PersistentVMRole xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <RoleName>name-of-the-virtual-machine</RoleName>
  <RoleType>PersistentVMRole</RoleType>
  <VMImage>name-of-vm-image</VMImage>
  <MediaLocation>path-to-vhds</MediaLocation>

This would be done using a GET on:

https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments/<deployment-name>/roles/<role-name>

-matt

0
votes

I will answer the second part of your question. That's pretty easy using powershell. suppose vm name as "testvm" and service name as "testservice". Powershell to get the storage account name-

 $disk = Get-AzureVM -ServiceName "testservice" –Name "testvm" | Get-AzureOSDisk
 $mediaLink = $disk.MediaLink
 $storageAccountName = $mediaLink.Host.Split('.')[0]
 $storageAccountName 

Hope this answers your question.

0
votes

I know this question is old but it doesn't have a complete answer. I use this PowerShell script to gather XML data of the VMs in a single subscription in to a file. In essence, it gets everything and then filters.

$VMs = Get-AzureRmVM
$NICs = Get-AzureRmNetworkInterface
$VNETs = Get-AzureRmVirtualNetwork

$AzureVMInventory = foreach ($VM in $VMs) {

    $NIC = $NICs | Where { $_.Id -eq $VM.NetworkProfile.NetworkInterfaces.Id }
    $Subnet = $VNETs.Subnets | Where { $_.Id -eq $NIC.IPConfigurations.Subnet.Id }
    $VNET = $VNETs | Where {$_.Subnets.Id -eq $NIC.IPConfigurations.Subnet.Id}

    $Property = [ordered]@{
        Name = $VM.OSProfile.ComputerName
        VMSize = $VM.HardwareProfile.VmSize
        ResourceGroup = $VM.ResourceGroupName
        OSDisk = $VM.StorageProfile.OsDisk.Vhd.Uri
        DataDisk = $VM.StorageProfile.DataDisks.Vhd.Uri -join "#"
        IPAddresses = $NIC.IpConfigurations.PrivateIPAddress
        IPAllocationMethod = $NIC.IpConfigurations.PrivateIPAllocationMethod
        nicName = $NIC.Name
        vNet = $VNET.Name
        Subnet = $Subnet.Name
        Location = $NIC.Location
    }

    New-Object -TypeName PSObject -Property $Property
}

$XML = $AzureVMInventory | ConvertTo-Xml -Depth 99

# Inject XSLT processing into the XML
$ProcessInstruction = $XML.CreateProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="style.xsl"')
$XML.InsertBefore($ProcessInstruction, $XML.DocumentElement)

$XML.Save("$PSScriptRoot\ProductionVMs.xml")

Since reading XML is a royal nightmare, I insert a process instruction and call an XSL Stylesheet so that when the XML file is opened by a browser, it can be formatted as HTML and made readable as a table. This suits the XML generated above but has some specific code in for my purposes.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="ISO-8859-1"/>

    <xsl:template name="tokenizeString">
        <!--passed template parameter -->
        <xsl:param name="list"/>
        <xsl:param name="delimiter"/>
        <xsl:choose>
            <xsl:when test="contains($list, $delimiter)">                
                    <!-- get everything in front of the first delimiter -->
                    <xsl:value-of select="substring-before($list,$delimiter)"/>
                <br />
                <xsl:call-template name="tokenizeString">
                    <!-- store anything left in another variable -->
                    <xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
                    <xsl:with-param name="delimiter" select="$delimiter"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:choose>
                    <xsl:when test="$list = ''">
                        <xsl:text/>
                    </xsl:when>
                    <xsl:otherwise>
                            <xsl:value-of select="$list"/>
                        <br />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template> 

 <xsl:template match="/">

<html>
<head>
<title>Azure Virtual Machines</title>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
    <table>
    <tr>
      <th>Name</th>
      <th>IP Addresses</th>
      <th>IP Allocation Method</th>
      <th>Virtual Network</th>
      <th>Subnet</th>
      <th>VMSize</th>
      <th>Resource Group</th>
      <th>Network Interface</th>
      <th>Location</th>
      <th>OS Disk</th>
      <th>Data Disks</th>
    </tr>
    <xsl:for-each select="//Objects/Object">
    <xsl:sort select="Property[@Name='Name']" order="ascending" data-type="text"/>
        <xsl:variable name="datadisks" select="Property[@Name='DataDisk']"/>
        <tr>
            <td><xsl:value-of select="Property[@Name='Name']" /></td>
            <td><xsl:value-of select="Property[@Name='IPAddresses']" /></td>
            <td><xsl:value-of select="Property[@Name='IPAllocationMethod']" /></td>
            <td><xsl:value-of select="Property[@Name='vNet']" /></td>
            <td><xsl:value-of select="Property[@Name='Subnet']" /></td>
            <td><xsl:value-of select="Property[@Name='VMSize']" /></td>
            <td><xsl:value-of select="Property[@Name='ResourceGroup']" /></td>
            <td><xsl:value-of select="Property[@Name='nicName']" /></td>

                <!-- <td><xsl:value-of select="Property[@Name='Location']" /></td> -->
                <xsl:choose>
                    <xsl:when test="Property[@Name='Location'] = 'northeurope'">
                        <td class="loc_ne">North Europe</td>
                    </xsl:when>
                    <xsl:when test="Property[@Name='Location'] = 'westeurope'">
                        <td class="loc_we">West Europe</td>
                    </xsl:when>
                    <xsl:otherwise>
                        <td class="loc_err">NOT EUROPE</td>
                    </xsl:otherwise>
                </xsl:choose>

            <td><xsl:value-of select="Property[@Name='OSDisk']" /></td>
            <td>
                <!-- <xsl:value-of select="Property[@Name='DataDisk']" /> -->
                <xsl:choose>
                    <xsl:when test="boolean(Property[@Name='DataDisk'])">
                        <xsl:call-template name="tokenizeString">
                            <xsl:with-param name="list" select="Property[@Name='DataDisk']"/>
                            <xsl:with-param name="delimiter" select="'#'"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise/>
                </xsl:choose>
            </td>
        </tr>
    </xsl:for-each> 
    </table>

</body>
</html>

</xsl:template>

</xsl:stylesheet>

Finally a little CSS to make it tidy and presentable.

body * {
    font-family: 'Segoe UI', Arial, Helvetica, sans-serif;
    font-size: 9pt;
}
table {
    width: 100%;
}
table, th, td {
    border: 1px solid rgba(0,188,242,0.2);
    border-collapse: collapse;
    text-align: center;
}
th {
    background: rgb(0,32,80);
    color: #fff;
    font-size: 11pt;
}
td {
    width: 10%;
    padding: 2px;
}
td.loc_ne {
    background: rgba(0,188,242,0.5);
}
td.loc_we {
    background: rgba(0,127,0,0.5);
}
td.loc_err {
    background: rgba(219,20,61,0.5);
}
tr:nth-child(even) {background: rgba(0,188,242,0.5);}
tr:nth-child(odd) {background: #fff}
tr:hover {background-color: #ddd}

Since the object is a PowerShell object, it doesn't have to be exported to XML, it can be exported to JSON, CSV etc. By tagging a little extra code on to the bottom of the PowerShell script, you can import the XSL directly and then export to pure HTML if you need to share a single file.

# Convert to HTML (if required)
$XSLT = New-Object System.Xml.Xsl.XslCompiledTransform;
$XSLT.Load("style.xsl");
$XSLT.Transform("VMs.xml", "VMs.html");