Deploying Gallery Item trough SPF

This blog post aims at exploring Service Provider Foundation. Charles Joy already covered how to deploy Gallery item trough WAP API and VMM PowerShell in series of blog posts. Although the SPF API for Gallery Items is similar I will show you how it is done there and what are the differences.

Let’s first from the beginning by creating a Tenant in SPF and VMM similarly the Windows Azure Pack does it:

#Create Tenant SPF
$URI="https://{0}:8090/SC2012R2/Admin/Microsoft.Management.Odata.svc/Tenants" -f $TenantPortalAddress
$TenantRole = @{
        "Name" = "Tenant3333"
        "SubscriptionID" ="$Guid2"
$TenantRoleJSON = ConvertTo-Json $TenantRole

Invoke-WebRequest -Uri $URI -Credential $cred -Method Post -Body $TenantRoleJSON -ContentType 'application/json'

First we need the FQDN of the SPF server ($TenantPortalAddress). We will use it to create the URLs to which will make web requests.

Than we get credentials ($cred) that have rights against the SPF Admin API.

Third we generate GUID  ($Guid2). This guid we will use for subscription ID.

We create hash table ($TenantRole ) that will represent our body in the web request. That hash table contains information to create the Tenant in SPF.

Than we convert that hash table to json format.

With Method Post we make Web request to SPF API.

The web request will return status code 201 that he object is created:


Now that we have the Tenant in SPF the next step is to create the same tenant in VMM. Basically creating User Role in VMM with the same name and ID as the SPF tenant links them. That easily happens trough SPF by assigning they created SPF Tenant to Stamp:

$URI3="https://{0}:8090/SC2012R2/Admin/Microsoft.Management.Odata.svc/Tenants(guid’$Guid2′)/`$links/Stamps" -f $TenantPortalAddress
$stampURL="https://{0}:8090/SC2012R2/Admin/Microsoft.Management.Odata.svc/Stamps(guid’2dcbb497-2b41-4dad-a883-09212c21e9e5′)" -f $TenantPortalAddress

$TenantRoleAssignStamp = @{
        "url" = "$stampURL"
$TenantRoleAssignStampJSON = ConvertTo-Json $TenantRoleAssignStamp

Invoke-WebRequest -Uri $URI3 -Credential $cred -Method Post -Body $TenantRoleAssignStampJSON -ContentType "application/json"

Again e need URL ($URL3) that represents the newly created SPF tenant.

The URL of our stamp ($stampURL).

Again we need to create hash table ($TenantRoleAssignStamp ). This time with only one property url.

We convert the hash table again to json.

And we invoke again the SPF Admin API.

<a href=""><img style="background-image:none;padding-top:0;padding-left:0;display:inline;padding-right:0;border:0;" title="image" src="; alt="image" width="440" height="126" border="0" /></a>

This will return status content 204 (no Content) and you will see the user role created in VMM:

<a href=""><img style="background-image:none;padding-top:0;padding-left:0;display:inline;padding-right:0;border:0;" title="image" src="; alt="image" width="577" height="442" border="0" /></a>

Now to that User Role you can assign cloud, library and other resources trough the GUI as I do not currently web requests how to do that.

I also I do not have web request to SPF how to add gallery item to specific Tenant/User role but you can use WAP to create your tenant and assign Gallery Items. Other way is to import your Gallery item in VMM and SPF. Than assign that gallery item to the VMM user  Role with powershell:

$re=Get-CloudResourceExtension -Name "DomainControllerWindows2012"
$userRole=Get-SCUserRole -Name Tenant3333

Grant-SCResource -Resource $re -JobGroup $Guid2
Set-SCUserRole -UserRole $userRole -JobGroup $Guid2

and you will need to add the gallery item for the SPF tenant also.

You can do that by adding record in SPF database. Specifically in TenantGalleryItems table. You need to add the Gallery item name, the version, the published and the Tenant ID. Tenant ID is the same guid that was generated during creation.

<a href=""><img style="background-image:none;padding-top:0;padding-left:0;display:inline;padding-right:0;border:0;" title="image" src="; alt="image" width="547" height="409" border="0" /></a>

Ok now that we have these things done is time for the actual deployment of Gallery Item trough SPF. Most of the code below is taken from Charles Joy’s articles plus additional changes needed that to happen trough SPF.

#region SetVariables


$GIVersion = ""

# Set Common Gallery Item Parameters
$UserID = $UserPrincipalName
$VMRoleNetwork = "Tenant3333 Network"
$CloudServiceName = "CloudService-4-{0}" -f $TenantID
$VMRoleTZ = "Pacific Standard Time"
$OSDisk = "WindowsServer2012-R1"
$OSDiskVersion = ""
$Password = P@$$w0rd

if ($GalleryItemName -eq "DomainControllerWindows2012")
    $VMRoleName = "ActiveDirectory"
    $VMRoleNamePattern = "DC##"
    $VMRoleSize = "ExtraSmall"

#endregion SetVariables

as we can see we need to define some variables that we will use.

#region GetResDef

# Get Gallery Item Reference


We defined header for our requests to include the user UPN that will execute these requests. That UPN is transferred in VMM and it is owner of the most jobs.

$GIReferenceUri="https://{0}:8090/SC2012R2/VMM/{1}/GalleryService.svc/GalleryItems?api-version=2013-03" -f $TenantPortalAddress,$TenantID
$GIReferenceData=[xml](Invoke-WebRequest -Uri $GIReferenceUri -Method Get -Headers $Header -Credential $cred | Select-Object -ExpandProperty Content)

$GalleryItemREF=$ | ? {$_ -match $GalleryItemName}
$GalleryItemREF =$GalleryItemREF.Trim("Gallery")


As the URL for Gallery items in SPF is different from the one in WAP I need to trim some part of it and more specifically the word “Gallery” in the beginning . Seems the urls for Gallery items in SPF are made for WAP.


# Get Gallery Item Resource Definition
$GIResDEFUri = "https://{0}:8090/SC2012R2/VMM/{1}/GalleryService.svc{2}?api-version=2013-03" -f $TenantPortalAddress,$TenantID,$GalleryItemREF
$GIResourceDEFJSON = Invoke-WebRequest -Uri $GIResDEFUri -Headers $Header -Credential $cred | Select-Object -ExpandProperty Content

#Convert ResDef JSON to Dictionary
[System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions”) | Out-Null
$JSSerializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$ResDef = $JSSerializer.DeserializeObject($GIResourceDEFJSON)

#endregion GetResDef

#region SetResDefConfig
# Create Gallery Item Parameter Hashtable (for Common Data)
$GIParamList = @{
    VMRoleVMSize = $VMRoleSize
    VMRoleOSVirtualHardDiskImage = "{0}:{1}” -f $OSDisk,$OSDiskVersion
    VMRoleAdminCredential = "administrator:{0}” -f $Password
    VMRoleTimeZone = $VMRoleTZ
    VMRoleComputerNamePattern = $VMRoleNamePattern
    VMRoleNetworkRef = $VMRoleNetwork
# Add to Gallery Item Parameter Hashtable (for GI Specific Data)
if ($GalleryItemName -eq "DomainControllerWindows2012”)
    $GIParamList += @{DomainControllerWindows2012DomainDNSName = $DNSDomainName}
    $GIParamList += @{DomainControllerWindows2012DomainNETBIOSName = $NETBIOSName}
    $GIParamList += @{DomainControllerWindows2012SafeModeAdminPassword = $Password}

# Convert Gallery Item Parameter Hashtable To JSON
$ResDefConfigJSON = ConvertTo-Json $GIParamList

#Add ResDefConfig JSON to Dictionary
$ResDefConfig = New-Object ‘System.Collections.Generic.Dictionary[String,Object]’

#endregion SetResDefConfig

#region GenerateGIPayloadJSON
# Set Gallery Item Payload Variables
$GISubstate = $null
$GILabel = $VMRoleName
$GIName = $VMRoleName
$GIProvisioningState = $null
$GIInstanceView = $null

# Set Gallery Item Payload Info
$GIPayload = @{
    "InstanceView” = $GIInstanceView
    "Substate” = $GISubstate
    "Name” = $GIName
    "Label” = $GILabel
    "ProvisioningState” = $GIProvisioningState
    "ResourceConfiguration” = $ResDefConfig
    "ResourceDefinition” = $ResDef

# Convert Gallery Item Payload Info To JSON
$GIPayloadJSON = ConvertTo-Json $GIPayload -Depth 7

#endregion GenerateGIPayloadJSON

# Get Cloud Services
$CloudServicesUri = "https://{0}:8090/SC2012R2/VMM/{1}/Microsoft.Management.Odata.svc/CloudServices?api-version=2013-03" -f $TenantPortalAddress,$TenantID
$CloudServicesData = [xml](Invoke-WebRequest -Uri $CloudServicesUri -Method Get -Headers $Header -Credential $cred | Select-Object -ExpandProperty Content)
$CloudService = $ | ? {$_ -match $CloudServiceName}
if (!$CloudService) {
    # Set Cloud Service Configuration
    $CloudServiceConfig = @{
        "Name” = $CloudServiceName
        "Label” = $CloudServiceName

    # Convert Cloud Service Configuration To JSON
    $CloudServiceConfigJSON = ConvertTo-Json $CloudServiceConfig

    $CloudServicesData = [xml](Invoke-WebRequest -Uri $CloudServicesUri -Method Post -Headers $Header -Credential $cred -Body $CloudServiceConfigJSON -ContentType "application/json”)
    $CloudService = $ | ? {$_ -match $CloudServiceName}

#endregion GetOrSetCloudService

This part creates cloud service in VMM if it is not present. Basically cloud service is needed VM role to be deployed in it. Many VM roles can be deployed in one cloud service. Every Tenant has its own cloud service. WAP creates cloud service for every VM role deployed.

#region DeployGIVMRole

# Set Gallery Item VM Role Deploy URI
$GIDeployUri ="https://{0}:8090/SC2012R2/VMM/{1}/Microsoft.Management.Odata.svc/CloudServices/{2}/Resources/MicrosoftCompute/VMRoles?api-version=2013-03" -f $TenantPortalAddress,$TenantID,$CloudService

# Deploy Gallery Item VM Role
$VMRoleDeployed = Invoke-WebRequest -Uri $GIDeployUri -Credential $cred -Method Post -Headers $Header -Body $GIPayloadJSON -ContentType "application/json”

#endregion DeployGIVMRole

This last part is the actual Deployment web request that is send against SPF. The request will return status code 201 (created). This will actually start a job in VMM and in order to see if the actual deployment is successful you will need to query that job and see what will be the end status of it. Here is a sample request that is returned from the invoke:

#StatusCode        : 201
#StatusDescription : Created
#Content           : <entry
#                    xml:base=
#                    xmlns=”http://ww...
#RawContent        : HTTP/1.1 201 Created
#                    x-ms-request-id: d7600d5c-55a7-4a29-851a-e879eb073394
#                    X-Content-Type-Options: nosniff
#                    request-id: 18e1d0a5-0768-0001-d3bb-e6186807d001
#                    DataServiceVersion: 3.0;
#                    Persistent-Aut…
#Forms             : {}
#Headers           : {[x-ms-request-id, d7600d5c-55a7-4a29-851a-e879eb073394], [X-Content-Type-Options, nosniff], [request-id, 18e1d0a5-0768-0001-d3bb-e6186807d001],
#                    [DataServiceVersion, 3.0;]…}
#Images            : {}
#InputFields       : {}
#Links             : {}
#ParsedHtml        : mshtml.HTMLDocumentClass
#RawContentLength  : 11989


From this request you can find the ID if the job that is deploying the gallery item:


With simple command to get the job with VMM PowerShell we can see the status:


#Name                 : Add VM Role resource
#Description          : Add VM Role resource
#Progress             : 99 %
#Status               : Running
#CmdletName           : AddCloudResource
#ErrorInfo            : Success (0)
#StartTime            : 11/28/2014 17:28:12
#EndTime              :
#Owner                :
#ErrorInfo            : Success (0)
#AdditionalMessages   : {}
#ResultName           : ActiveDirectory
#ResultObjectTypeName : Cloud VMRole Resource
#IsStoppable          : True
#IsRestartable        : False


As you can see the jobs is running and progress is 99%. and later



So that is folks. If you need more explanation about the PowerShell code check the blogs by Charles as most of it comes from there and he explains very good what he is doing.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.