VMware Cloud Community
Jason_Cornick
Contributor
Contributor

Add a VM to a vApp using PowerShell

Hello,

I am trying to add a VM to a vApp using PowerShell.  I know that there is no explicit cmdlet to do it, and I need to recompose the vApp.

I've used the great Instantiation script from http://velemental.com/2012/03/27/deploying-a-vapp-in-vcd-from-a-catalog-using-powercli-part-two-the-... to successfully create vApps, but I need to be able to add additional VMs to the vApp that is created, and don't want to have a huge catalog to accomodate all the various server configurations required for our different vApps.

Unfortunately - I am completely failing trying to create a powershell script to recompose a vApp.  I'm trying to start with the basics even, and just call recompose to rename a vApp, and it fails...

Does anyone have an example of a recompose script that they have created and can share?

If not, I'm juggling a few things and will post my broken script shortly for any assistance...

Thanks,

Jason

0 Kudos
4 Replies
Jason_Cornick
Contributor
Contributor

I finally got some time to sit down and figure this out myself.  There is nothing native in powershell, so I use the REST API to do the work.  This is fairly crude but gets the job done!

Thanks to Jake's post at http://geekafterfive.com/2012/06/29/add-vcloud-harddisks-with-powercli/ I was able to figure out how to do the HTTP Post and make it work.  I also use the get-ci* cmdlets from Velemental.com, although with the new VCD 5.1 commands I probably won't need them in the future.

A note about my environment - the Catalog vApp Templates only have one VM each - I believe that if I had multiple VMs in a Template it would add them all to the vApp.

function new-vAppVM ($vAppName,$vAppTemplate)

{
    #Connect to the vApp and Template so we can grab some info
    $vapp = get-civapp $vappname
    $templ = get-civapptemplate $vAppTemplate
    $recomposeContentType = "application/vnd.vmware.vcloud.recomposeVAppParams+xml"
    $recomposeURL = $vapp.href+'/action/recomposeVApp'
    $name=$VApp.name
    $tempurl=$templ.href
    #Read the existing Network from the vApp
    $netwk = $recomposeXML.vapp.NetworkSection.Network.name
    #Reat the network in the Template - I assume only one exists...  This allows me to use a template in a different network than the vApp
    $tempcfg=$templ.ExtensionData.GetNetworkConfigSection()
    $tempntwk = $tempCfg.NetworkConfig[0].NetworkName
    #Build the XML file that will get posted.  It is pretty simple so I just make it as a string, then convert it to XML.  Hard to read, but works.
    $xstring='<?xml version="1.0" encoding="UTF-8"?><RecomposeVAppParams xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" name="'+$Name+'" deploy="false" powerOn="false"><SourcedItem><Source href="'+$tempURL+'" /><NetworkAssignment innerNetwork="'+$tempntwk+'" containerNetwork="'+$netwk+'"/></SourcedItem></RecomposeVAppParams>'
    $xstring=[xml]$xstring
  
    #open a request to the server
    [System.Net.WebRequest]$request = [System.Net.WebRequest]::Create($recomposeURL);
    $request.Headers.Add("x-vCloud-authorization",$vapp.ExtensionData.Client.SessionKey)
    $request.Accept="application/*+xml;version=1.5"
    #POST!  I used PUT for a long time and the error was driving me nuts...duh.
    $request.Method="POST"
    $request.ContentType = "application/vnd.vmware.vcloud.recomposeVAppParams+xml"
    $postdata = $xstring.outerxml
    [byte[]]$xmlEnc = [System.Text.Encoding]::UTF8.GetBytes($postdata)
    $request.ContentLength = $xmlEnc.length
    [System.IO.Stream]$requestStream = $request.GetRequestStream()
    $requestStream.write($xmlEnc, 0, $xmlEnc.Length)
    $requestStream.Close()
    $response = $request.GetResponse()
    $responseStream = $response.getResponseStream()
    $streamReader = new-object System.IO.StreamReader($responseStream)
    $result = $streamReader.ReadtoEnd()
    $streamReader.close()
    $response.close()
    write-host (get-date) "VM Added to vApp $name"
}
0 Kudos
jake_robinson_b
Hot Shot
Hot Shot

Nicely done! :smileygrin:

Since New-CIVapp didn't make it in this release, I think a lot of people will find this useful!

Cheers,

Jake

Jake Robinson VCP, vExpert - geekafterfive.com - Twitter: @jakerobinson
0 Kudos
Nandan_Alok
Contributor
Contributor

Hi All,

I get following error while using the function (executing following part of the function)

#open a request to the server..

    [System.Net.WebRequest]$request = [System.Net.WebRequest]::Create($recomposeURL);

    $request.Headers.Add("x-vCloud-authorization",$vapp.ExtensionData.Client.SessionKey)

    $request.Accept="application/*+xml;version=1.5"

    #POST!  I used PUT for a long time and the error was driving me nuts...duh.

    $request.Method="POST"

    $request.ContentType = "application/vnd.vmware.vcloud.recomposeVAppParams+xml"

    $postdata = $xstring.outerxml

    [byte[]]$xmlEnc = [System.Text.Encoding]::UTF8.GetBytes($postdata)

    $request.ContentLength = $xmlEnc.length

    [System.IO.Stream]$requestStream = $request.GetRequestStream()

    $requestStream.write($xmlEnc, 0, $xmlEnc.Length)

    $requestStream.Close()

    $response = $request.GetResponse()

    $responseStream = $response.getResponseStream()

    $streamReader = new-object System.IO.StreamReader($responseStream)

    $result = $streamReader.ReadtoEnd()

    $streamReader.close()

    $response.close()

    write-host (get-date) "VM Added to vApp $name"

Exception calling "GetResponse" with "0" argument(s): "The remote server returned an error: (406) Not Acceptable."

At C:\Users\dddd\Desktop\OO_Automation\WIP\AddtoVappFn.ps1:97 char:5

+     $response = $request.GetResponse()

+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : WebException

You cannot call a method on a null-valued expression.

At C:\Users\dddd\Desktop\OO_Automation\WIP\AddtoVappFn.ps1:99 char:5

+     $responseStream = $response.getResponseStream()

+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException

    + FullyQualifiedErrorId : InvokeMethodOnNull

It will be great help if someone guide me to resolve this issue.

Thanks

Alok

0 Kudos
BainHAMMER
Contributor
Contributor

ok, I know this is outdated topic, but still it pops-up at top for google query so I have to add this info.

Nowadays, at least on Vcloud Director ver 10.2.2. which I have, it works by far more simplistic way:

Connect to Vcenter where Vm is resided using Connect-VIserver

Connect to VCD using Connect-CIServer

$VM = Get-VM -name <name>

Import-CIVApp -Vm $VM -VApp <name of vapp you are importing to>

0 Kudos