The New World of Tenant Provisioning - Technet Gallery

advertisement
The New World of
Tenant Provisioning
Published: 2014
For the latest information, please see
http://aka.ms/BuildingClouds
Introduction ..........................................................................................................................................................1
So, what is this white paper all about? ................................................................................................. 1
Background ...........................................................................................................................................................2
Looking Back .................................................................................................................................................... 2
What can we salvage? .................................................................................................................................. 2
What’s new? ..................................................................................................................................................... 2
Download ...............................................................................................................................................................3
Automated Deployment of Tenant Network and Identity Workload...........................................4
Automated Tenant Virtual Network Deployment ............................................................................ 4
Create a VM Network “OnBehalfOf” a User Role ............................................................................. 5
Automated Active Directory VMRole Deployment .......................................................................... 7
The Options ...................................................................................................................................................... 7
The Process ....................................................................................................................................................... 8
Even More Magic – Bearer Tokens ....................................................................................................... 10
The overall structure of the SMA Runbooks .................................................................................... 11
Deploy a Gallery Item VMRole ............................................................................................................... 13
BONUS - Example VMM PowerShell for Gallery Item VMRole Deployment!..................... 20
Use Cases ........................................................................................................................................................ 21
Automated Deployment of the Identity Workload as a Tenant Admin ................................... 22
The Options .................................................................................................................................................... 23
The Process ..................................................................................................................................................... 24
The Pre-Requisites ....................................................................................................................................... 25
The Pre-Requisite Setup ........................................................................................................................... 26
Active Directory Gallery Item VMRole Deployment as a Tenant Admin .............................. 27
Use Cases ........................................................................................................................................................ 31
Automated Deployment of Tenant Workloads (Lync, SharePoint, and Exchange).............. 32
The Scope........................................................................................................................................................ 33
Out of Scope .................................................................................................................................................. 34
Deployment as a Service Administrator in SMA (with the WAP Tenant API Only) .......... 34
Existing: SMA Runbook that is the same for each Gallery Item VMRole Deployment ... 34
New: Updated SMA Runbooks… ........................................................................................................... 35
The New World of Tenant Provisioning
…for the Lync Gallery Item VMRole Deployment ........................................................................... 36
…for the SharePoint Gallery Item VMRole Deployment .............................................................. 36
…for the Exchange Gallery Item VMRole Deployment ................................................................. 36
Future Discovery: How to enumerate ResDef/ResDefExt and ResDefConfig
Requirements for any Gallery Item VMRole ..................................................................................... 38
Deployment as a Tenant Administrator from a PowerShell Script (with the Public WAP
Tenant API) ..................................................................................................................................................... 40
New: Deployment Script for Active Directory, Lync, Exchange, or SharePoint .................. 40
Future Discovery: Modified Example PowerShell script to enumerate ResDef/ResDefExt
and ResDefConfig Requirements for any Gallery Item VMRole ............................................... 44
Use Cases ........................................................................................................................................................ 45
Appendix ............................................................................................................................................................. 46
Links Referenced within the Document.............................................................................................. 46
Links from the Related Blog Series ....................................................................................................... 47
Links to Other Related and Valuable Content ................................................................................. 47
The New World of Tenant Provisioning
Introduction
To be clear, this document is all about [on-prem] Automated Tenant
Provisioning with [Windows] Azure Pack (WAP). And WAP is just one of the
primary technologies leveraged within this example. In fact, Service
Management Automation (SMA), PowerShell, PowerShell Workflow, Virtual
Machine Manager (VMM), and VMRole Gallery Items, are the backbone of the
[example] solution.
Note
The guidance here was previously published blog content found on the
Building Clouds Blog.
So, what is this white paper all about?



1
Applying existing knowledge of tenant provisioning techniques in this
“new world”
Transforming existing knowledge (Service Templates) of tenant workload
deployments into “Azure Pack friendly” workload deployments (VMRoles)
Providing new automation (PowerShell scripts) for the latest tenant
provisioning technology (Azure Pack)
The New World of Tenant Provisioning
Background
Looking Back
If you have been following my work on the Building Clouds Blog, you may remember the
following two blog posts:

Automation–PowerShell Workflow Script Spotlight–Deploying Virtual
Machine Manager Service Templates “OnBehalfOf” Tenant Administrator
User Roles

Automation–PowerShell Workflow Script Spotlight–Creation and
Parameterization of Virtual Machine Manager Run As Accounts for
“OnBehalfOf” Service Template Deployment
Well, those were directly related to the initial learning around Tenant Provisioning my
team gathered during an internal Proof of Concept. Back then, it was all about the “VMM
Service Template”, and while some of that existing knowledge will work in this new
world of Azure Pack, the focus now is on VMRoles as the delivery mechanism for
application workloads.
What can we salvage?
At the very least, all the existing knowledge around automated deployment of the
Tenant Virtual Network (Isolated Software Defined Network (SDN)). As well as, some
previously undisclosed techniques for automatically initiating the deployments - all of
which still holds true, regardless of delivery mechanism.
What’s new?
The new automation involved in the deployment of VMRoles, as both a Service Admin
(via VMM “OnBehalfOf” PS Commands) and a Tenant Admin (via the Service Management
WS API).
2
The New World of Tenant Provisioning
Download
The download for all the artifacts within this example solution can be found on TechNet
Gallery. The downloadable content introduces a collection of example PowerShell Scripts
and SMA Runbooks that you can use to Automate Tenant Provisioning of Gallery Item
VMRoles within WAP.
URL: http://gallery.technet.microsoft.com/Windows-Azure-Pack-Tenant-3e8afd64
The download (Windows Azure Pack Tenant Provisioning Automation Toolkit.zip)
includes (14) files:
For the Service Administrator



SMA Runbook Exports (5 files)
o Create-VMNetwork.xml
o Deploy-TenantVMRole.xml
o Deploy-VMRole.xml
o Subscription-Create-Dispatcher.xml
o VMRole-Create-Dispatcher.xml
PowerShell Scripts (2 files)
o Deploy-VMRole_OptionalVMMCommands.ps1
o Get-GIResourceParams_asServiceAdmin.ps1
PowerShell Workflows (5 files)
o Create-VMNetwork.ps1
o Deploy-TenantVMRole.ps1
o Deploy-VMRole.ps1
o Subscription-Create-Dispatcher.ps1
o VMRole-Create-Dispatcher.ps1
For the Tenant Administrator

PowerShell Scripts (2 files)
o Deploy-TenantVMRoles_asTenantAdmin.ps1
o Get-GIResourceParams_asTenantAdmin.ps1
Note XML (SMA Runbooks) and PS1 (PowerShell Scripts) files are both provided in the
download. Use SMART for Runbook Import and Export to leverage the provided XML files in
the above download for an enhanced experience in importing the example solution into
your SMA environment.
Optional Some of the scripts within this download contain commented out “optional”
portions for Monitoring and Notifications. The associated Runbooks and Variables for these
options are not included in this download. For more information about Monitoring and
Notifications within SMA, please see the following blog post: Automation–Monitoring and
Notifying in Windows Azure Pack with SMA
3
The New World of Tenant Provisioning
Automated Deployment of
Tenant Network and Identity
Workload
What does that mean, exactly?
Well for the context of this document, it means I am going to provide the
PowerShell/SMA Runbook scripts necessary to create a Tenant Virtual Network (Isolated
Software Defined Network (SDN)) & Active Directory VMRole. So, for organization’s sake,
this section of the document will be split into two main sections – one for automated
Tenant Virtual Network deployment, and one for automated VMRole deployment.
Automated Tenant Virtual Network Deployment
For the most part, the PowerShell/SMA Runbook example for this already exists. Granted,
you would have to be a Building Clouds Blog super-fan to know exactly where it is, but it
does exist on the blog. That said, for this document, we want to promote it much more,
and underline the significance of it in this example solution.
So where did this example live before being reestablished here?
In this blog post: Automation–PowerShell Workflow Script Spotlight–Deploying
Virtual Machine Manager Service Templates “OnBehalfOf” Tenant Administrator
User Roles
An admittedly, under-promoted yet valuable blog post on the automation of various
VMM resources via PowerShell workflow, from the Service Administrator “OnBehalfOf”
the Tenant Administrator.
In fact, I believe now is a great time to take a moment and describe the “Scope of
Management” for these two personas in an image:
4
The New World of Tenant Provisioning
The reason I believe this is important, is that I will be referring to each persona
throughout the document. Now, this is not a comprehensive list of all the potential areas
each persona has management over, but it covers what we need here.
Note There may be other uses or ways to access the WAP Tenant API (non-Public)
than just as a Service Administrator. From what I have seen, it requires bearer token
authorization. And since the best way to get this token is via the WAP Admin
PowerShell Cmdlet (Get-MgmtSvcToken), I made some assumptions.
Create a VM Network “OnBehalfOf” a User Role
The following PowerShell workflow script (Create-VMNetwork) will create a VMM VM
Network with the following settings (leveraging VMM PowerShell Commands):









VM Network Name: <VM Network Name generated by Owner User Role Name
defined with parameter>
Subnet Name: <defined in script: “TenantSubnet”>
Subnet Value: <defined in script: “192.168.0.0/24”>
IP Address Pool Name: <defined in script: “TenantIPPool”>
IP Address Range Start: <defined in script: “192.168.0.100”>
IP Address Range End: <defined in script: “192.168.0.199” – providing for 100
available addresses>
DNS IP: <defined in script: “192.168.0.100” – first IP in Pool>
OnBehalfOfUser: <User Name parsed from Owner User Role Name defined with
parameter>
OnBehalfOfUserRole: <User Role parsed from Owner User Role Name defined
with parameter>
Note You may keep these example settings, or modify to fit your deployment
specifications.
Example PowerShell workflow script for Create-VMNetwork
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
5
workflow Create-VMNetwork
{
param
(
[string]$OwnerUserRole,
[string]$VmmServerName,
[string]$CloudName,
[string]$LogicalNetworkName
)
inlinescript
{
$subnetValue = "192.168.0.0/24"
$subnetName = "TenantSubnet"
$dnsIP = "192.168.0.100"
$ipAdressPoolName = "TenantIPPool"
$ipAddressRangeStart = "192.168.0.100"
$ipAddressRangeEnd = "192.168.0.199"
$UserRole = $Using:OwnerUserRole
$User = $UserRole.Split("_")[0]
$vmNetworkName = "Tenant Network ($User)"
Get-SCVMMServer -ComputerName $Using:VmmServerName -ForOnBehalfOf | Out-Null
$OwnerUserRoleObj = Get-SCUserRole | where {$_.Name -match $Using:OwnerUserRole}
The New World of Tenant Provisioning
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
$VMNetwork = Get-SCVMNetwork -OnBehalfOfUser $User -OnBehalfOfUserRole $OwnerUserRoleObj
if(!$VMNetwork) {
$CloudObj = Get-SCCloud -Name $Using:CloudName
$logicalNetwork = Get-SCLogicalNetwork -Cloud $CloudObj -Name $Using:LogicalNetworkName
$vmNetwork = New-SCVMNetwork -Name $vmNetworkName -LogicalNetwork $logicalNetwork `
-OnBehalfOfUser $User -OnBehalfOfUserRole $OwnerUserRoleObj
$subnet = New-SCSubnetVLan -Subnet $subnetValue
$vmSubnet = New-SCVMSubnet -Name $subnetName -VMNetwork $vmNetwork -SubnetVLan $subnet `
-OnBehalfOfUser $User -OnBehalfOfUserRole $OwnerUserRoleObj
$allDnsServer = @($dnsIP)
$staticIPAddressPool = New-SCStaticIPAddressPool -Name $ipAdressPoolName `
-VMSubnet $vmSubnet -Subnet $subnetValue -IPAddressRangeStart $ipAddressRangeStart `
-IPAddressRangeEnd $ipAddressRangeEnd -DNSServer $allDnsServer `
-RunAsynchronously -OnBehalfOfUser $User -OnBehalfOfUserRole $OwnerUserRoleObj
}
}
}
Note In general, the Create-VMNetwork workflow gets called once per Tenant Admin
(Owner User Role, which is the equivalent of User + Plan Subscription). In fact, this
workflow is most often called as part of the SMA Runbook linked to the
Subscription.Create event within WAP/SPF, meaning that as soon as a Tenant Admin
User Subscribes to the related Plan, the Tenant Virtual Network is created automatically
for that Subscription. For more information (and a specific example) about how WAP
leverages SPF events to initiate SMA Runbooks, see the following TechNet Article: Using
automation with Virtual Machine Clouds and blog post: Automation–Monitoring and
Notifying in Windows Azure Pack with SMA
Configuring more than just the basics…
For instance, what if you wanted to configure NAT with a specific Gateway Device and
External IP Address Pool?
Well, add the following PowerShell to the above example script:
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
6
#NAT, Gateway and External IP Address Pool Variables
$vmGWServiceName = "Gateway Service Name"
$vmNetworkGwName = "{0}_Gateway" -f $vmNetworkName
$vmExtStaticIPAddyPoolName = "External IP Address Pool Name"
$vmNetworkNATConnName = "{0}_NatConnection" -f $vmNetworkName
#NAT, Gateway and External IP Address Pool Commands
$gatewayDevice = Get-SCNetworkGateway -Name $vmGWServiceName
$VmNetworkGateway = Add-SCVMNetworkGateway -Name $vmNetworkGwName -EnableBGP $false `
-NetworkGateway $gatewayDevice -VMNetwork $vmNetwork `
-OnBehalfOfUser $User -OnBehalfOfUserRole $OwnerUserRoleObj
$externalIpPoolVar = Get-SCStaticIPAddressPool -Name $vmExtStaticIPAddyPoolName
$natConnection = Add-SCNATConnection -Name $vmNetworkNATConnName `
-VMNetworkGateway $VmNetworkGateway -ExternalIPPool $externalIpPoolVar `
-OnBehalfOfUser $User -OnBehalfOfUserRole $OwnerUserRoleObj
The New World of Tenant Provisioning
Note Many other options are available, these are just the most common for a given
scenario. The simple way to keep adding to this script is to make modifications in VMM,
capture the generated script(s) and work the new portions in to the existing script.
Also Note While the Add-SCVMNetworkGateway and Add-SCNATConnection
commands do allow for -OnBehalfOfUser and -OnBehalfOfUserRole the user and user role
specified may not have the necessary permissions to complete the operation (likely to the
Gateway). The command execution may fail with a “You do not have permission to access
one or more of the objects required by this operation.” error message. In this case, you may
want to consider granting that access, or forgoing the “OnBehalfOf” for these two
commands.
Calling the Create-VMNetwork PowerShell workflow
The following is a very basic example for calling this workflow:
001
002
003
004
005
006
$VMMServer = "MY_VMM_SERVER"
$UserRole = "USER_ROLE"
$CloudName = "My Tenant Cloud"
$LogicalNetworkName = "Contoso Logical Network"
Create-VMNetwork -VmmServerName $VMMServer -OwnerUserRoleName $UserRole.Name `
-CloudName $CloudName -LogicalNetworkName $LogicalNetworkName
Again, there are lots of options here, choose the one that makes sense for your
deployment. And I am not going to dive into the details for this example, but obviously
you can leverage alternate objects/variables to collect/pass the parameter data within
this call (as it is a 1:1 Tenant Admin User Role:VMNetwork in this example where Tenant
Admin User Role = User + Subscription to a Plan).
Why go directly against VMM, as opposed to leveraging the WAP Tenant API?
For two reasons, really – First, I wanted to highlight and leverage existing known-good
and well-used scripts; Second, the only available and published documentation /
examples on the VM Network API are written in C#, not PowerShell.
URL: http://msdn.microsoft.com/en-us/library/dn765986.aspx.
So, the above script is what we have been using on my team in our Demo/Test/Dev
environment for months now. Also, one might argue that Network belongs to Fabric
Management, which in turn belongs in VMM. Either way, based on what I could find,
VMM is your [current] best bet.
Automated Active Directory VMRole Deployment
The Options
In fact, this is another great time to illustrate this in image form, for these two personas:
7
The New World of Tenant Provisioning
Note These options are the same for any Automated VMRole Deployment, Active
Directory happens to be the first one to be deployed, so it gets all the attention.
The Process
I believe it is important for everyone to understand the current step-by-step process
necessary to automatically deploy a VMRole via PowerShell against the available
endpoints. It will let you appreciate the script that much more.
1.
Generate the Gallery Item VMRole Reference URI (based on Subscription ID
and Tenant Portal Address)
2. Invoke-WebRequest to Get the Gallery Item VMRole Reference (portion of
the Gallery Item VMRole Resource Definition (ResDef) URI specific to the Gallery
Item VMRole, based on the Gallery Item VMRole Name and data returned from
Step #1)
3. Generate the Gallery Item VMRole ResDef URI (based on data returned from
Step #2)
4. Invoke-WebRequest to Get the Gallery Item VMRole ResDef (based on the
URI from Step #3, data returned in JSON)
5. Convert (Deserialize) the returned ResDef JSON to a
'System.Collections.Generic.Dictionary[String,Object]
6. Create the Gallery Item VMRole Parameter Hashtable (based on custom
variable data)
7. Convert the Gallery Item VMRole Parameter Hashtable to JSON
8. Create the Gallery Item VMRole Resource Definition Configuration
(ResDefConfig) 'System.Collections.Generic.Dictionary[String,Object]'
(based on converted Gallery Item VMRole Parameter data (JSON) and Version
information)
9. Create the Gallery Item VMRole Payload Hashtable (based on custom
variable data, Gallery Item VMRole ResDef and ResDefConfig Dictionary
Objects)
10. Convert the Gallery Item VMRole Payload Hashtable to JSON
11. Verify/Create Cloud Service Name (based on custom variable data)
12. Generate the Gallery Item VMRole Deployment URI (based on Subscription
ID, Tenant Portal Address, and Cloud Service Name)
8
The New World of Tenant Provisioning
13. Invoke-WebRequest to Post the Gallery Item VMRole Payload JSON (based
on the URI from Step #14)
Step #11 (Cloud Service Creation/Verification) has several Sub-Steps:
1.
2.
3.
4.
5.
6.
7.
Generate the Cloud Service URI (based on Subscription ID and Tenant Portal
Address)
Invoke-WebRequest to Get the Cloud Service Data and verify if Cloud
Service already exists (based on the URI from Sub-Step #1)
If exists, Output Cloud Service Name
If notexists, Create the Cloud Service Parameter Hashtable (based on custom
variable data)
Convert the Cloud Service Parameter Hashtable to JSON
Invoke-WebRequest to Post the Cloud Service JSON (based on the URI from
Sub-Step #1)
Once created, Output Cloud Service Name
Some people like images better, so here is one that represents the text above:
9
The New World of Tenant Provisioning
So, if you were counting, that is…







4 URIs Dynamically Generated
3 Invoke-WebRequest GETs (for ResDef information)
4 Conversions (1 from JSON, 3 to JSON)
3 Hashtables Created
2 'System.Collections.Generic.Dictionary[String,Object]'
1 Cloud Service Creation (or reference to an existing Cloud Service)
2 Invoke-WebRequest POSTs (1 for the Cloud Service Creation, 1 for the
VMRole Deployment)
The magic here really exists in handling the data from JSON to Dictionary, Hashtable to
JSON, etc. In fact, as you will see in the final script, JSON is the preferred method for
data storage and transfer between sections of the script (from InlineScript to InlineScript
and workflow to workflow).
As a reference, be sure to review the following TechNet Article: Windows Azure Pack
VMRoles Tenant API
Even More Magic – Bearer Tokens
I realize I keep using this word to emphasize technical significance, but when I find
something so useful and so “simple”, I label it as such. That said, there is a CRITICAL
piece in this process that HAS to be pointed out specifically:
Get and Usage of the WAP MgmtSvcToken
I mention it in passing above, but this really makes everything work from a “Service
Administrator leveraging the WAP Tenant API (non-public)” perspective.
Here is the TechNet Library Article on the WAP command used to retrieve the token:
Get-MgmtSvcToken
Here is the snippet of script (you will see it within the larger script below) where the
token is retrieved from WAP, and then placed in a $Headers Hashtable, along with the
identity of the User (essentially the WAP Tenant API’s version of “OnBehalfOf”):
001
002
003
004
005
006
007
008
009
$AdminURI = "https://" + $Using:WAPServer + ":30004"
$AuthSite = "https://" + $Using:WAPServer + ":30072"
$ClientRealm = "http://azureservices/AdminSite"
$token = Get-MgmtSvcToken -Type Windows -AuthenticationSite $AuthSite `
-ClientRealm $ClientRealm -DisableCertificateValidation
$Headers = @{
Authorization = "Bearer $token"
"x-ms-principal-id" = $Using:UserID }
Note This $Headers Hashtable gets reused over and over, each time an InvokeWebRequest is made against the WAP Tenant API (non-Public). In fact, this bit of script is
10 The New World of Tenant Provisioning
the only reason the InlineScript is leveraged, remoting to the WAP Admin Server – the rest
of the calls are 100% Invoke-WebRequests and do not require the WAP Cmdlet. It is also
important to note, this functionality is not restricted to VM Clouds, but can be leveraged for
WAP Tenant API (non-public) calls, in general.
The Scripts
Based on the various options listed above, I am going to choose a [hopefully] winning
combination that will satisfy the masses. Here goes…
Colonel Mustard In The Study (With A Candlestick)
Oh wait - wrong combination!
Service Administrator in SMA (with the WAP Tenant API Only)
That’s better!
So, what does this mean?



Service Administrator – The persona the script will be executed from and
written for
in SMA – Service Management Automation, the PowerShell workflow engine in
WAP (the very same thing that will automatically Create a VM Network
“OnBehalfOf” a User Role, as described above)
(with the WAP Tenant API Only) – Because the script is executed from the
Service Admin persona, there are a couple options, one is a mix of WAP Tenant
API and VMM Cmdlet calls, the other is purely WAP Tenant API calls (no direct
VMM commands used). Going with the WAP Tenant API Only option, keeps the
script a bit more simple, and allows you to call the VMRole Deployments in the
same way the Tenant Portal calls them. This means you can leverage the
MicrosoftCompute.VMRole SPF event for monitoring and notification if
desired (again, see the following blog post: Automation–Monitoring and
Notifying in Windows Azure Pack with SMA for more information).
As you know, using SMA means using PowerShell workflow. It is a bit more complex than
just “regular PowerShell”, but many liberties can be taken when leveraging the
InlineScript functionality. Taking liberties, making my life easier, and built-in PowerShell
Remoting are the three main reasons I chose to go with InlineScript in these examples. I
am not opposed to other methods, this is just the one I chose.
The overall structure of the SMA Runbooks
1.
Subscription-Create-Dispatcher: Top Tier Dispatch Runbook; hooked directly
to the SPF event call; captures SPF event Data (Subscription and User info, etc.);
used to decide which Subscription to act against, and which User to act for;
calls numerous other Sub-Runbooks (including the one(s) for Tenant Virtual
Network Creation and VMRole Deployments – this is where multiple VMRole
Deployments can be called at once)
11 The New World of Tenant Provisioning
2.
3.
Deploy-TenantVMRole: Middle Tier Sub-Runbook; called by Dispatch
Runbook; collects, parses and organizes deployment data from input parameter
and variable data; calls Lowest Tier Sub-Runbook with specific deployment
criteria
Deploy-VMRole: Lowest Tier Sub-Runbook; called by Middle Tier SubRunbook; collects and uses input parameter data; executes all required VMRole
Deployment calls (this is where some of the “options” come in – for example,
instead of executing only against the WAP Tenant API, the actual VMRole
Deployment could execute the required VMM Cmdlet command (AddCloudResource)
And to help with the overall visualization as well as where these SMA Runbooks fit in the
all-up process, here is another image:
Did someone say Scripts?
Yeah, yeah. I am getting there. Remember, it is not only about the “code”, but also how
that “code” came to be. Or at least that is my reasoning for taking you on this journey.
12 The New World of Tenant Provisioning
Deploy a Gallery Item VMRole
I am going to start with the Lowest Tier Sub-Runbook (Deploy-VMRole), and work up.
The following PowerShell workflow script (Deploy-VMRole) will deploy a WAP Gallery
Item VMRole with the following settings (with the WAP Tenant API Only):










WAP Server: <Name of WAP Admin Server defined with parameter used by
InlineScript Remoting and by WAP Admin PowerShell Cmdlet>
Credentials: <PSCredential defined with parameter used by InlineScript
Remoting>
Tenant Portal Address: <FQDN of the WAP Tenant Portal Server defined with
parameter used to generate URIs for Invoke-WebRequest API Calls to WAP
Tenant API>
Subscription ID: <Subscription ID for the User for whom the VMRoles will be
deployed, defined with parameter>
User ID: <User ID of the User for whom the VMRoles will be deployed, defined
with parameter>
Gallery Item Name: <Partial or Full Name of the Gallery Item VMRole to be
Deployed, defined with parameter, used to match the Gallery Item Reference
Data to generate the Gallery Item ResDef URI>
Gallery Item Version: <Version of the Gallery Item VMRole to be Deployed,
defined with parameter, used to identify correct version of the Gallery Item
VMRole>
ResDefConfig JSON: <Resource Definition Configuration data (in JSON format),
defined with parameter, used to satisfy the ResDef, part of the Gallery Item
VMRole Payload>
Cloud Service Name: <Name of the Cloud Service, defined with parameter, used
in the Gallery Item VMRole Deployment>
VMRole Name: <Name of the VMRole to be Deployed, defined with parameter,
part of the Gallery Item VMRole Payload>
Note Each of these parameters are leveraged throughout the Deploy-VMRole workflow
and are configured for maximum re-use and flexibility. The intention of this Low Tier SubRunbook is to remain as generic as possible. Specific parameter setting occurs at the Top
and Middle Tier Runbooks.
Example PowerShell workflow script for Deploy-VMRole
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
workflow Deploy-VMRole
{
param
(
[string]$WAPServer,
[PSCredential]$Creds,
[string]$TenantPortalAddress,
[string]$SubscriptionID,
[string]$UserID,
[string]$GalleryItemName,
[string]$GIVersion,
[string]$ResDefConfigJSON,
[string]$CloudServiceName,
[string]$VMRoleName
)
$VMRole = InlineScript {
13 The New World of Tenant Provisioning
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
$AdminURI = "https://" + $Using:WAPServer + ":30004"
$AuthSite = "https://" + $Using:WAPServer + ":30072"
$ClientRealm = "http://azureservices/AdminSite"
$token = Get-MgmtSvcToken -Type Windows -AuthenticationSite $AuthSite -ClientRealm $ClientRealm -DisableCertificateValidation
$Headers = @{
Authorization = "Bearer $token"
"x-ms-principal-id" = $Using:UserID }
# Get Gallery Item Reference
$GIReferenceUri = "https://{0}:30005/{1}/Gallery/GalleryItems/$/MicrosoftCompute.VMRoleGalleryItem?api-version=2013-03" -f $Using:TenantPortalAddress,$Using:SubscriptionID
$GIReferenceData = [xml](Invoke-WebRequest -Uri $GIReferenceUri -Headers $Headers -UseBasicParsing | Select-Object -ExpandProperty Content)
$GalleryItemREF = $GIReferenceData.feed.entry.content.properties.resourcedefinitionUrl | ? {$_ -match $Using:GalleryItemName}
# Get Gallery Item Resource Definition
$GIResDEFUri = "https://{0}:30005/{1}/{2}/?api-version=2013-03" -f $Using:TenantPortalAddress,$Using:SubscriptionID,$GalleryItemREF
$GIResourceDEFJSON = Invoke-WebRequest -Uri $GIResDEFUri -Headers $Headers -UseBasicParsing | 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)
#Add ResDefConfig JSON to Dictionary
$ResDefConfig = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
$ResDefConfig.Add("Version",$Using:GIVersion)
$ResDefConfig.Add("ParameterValues",$Using:ResDefConfigJSON)
# Set Gallery Item Payload Variables
$GISubstate = $null
$GILabel = $Using:VMRoleName
$GIName = $Using: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
# Get Cloud Services
$CloudServicesUri = "https://{0}:30005/{1}/CloudServices?api-version=2013-03" -f $Using:TenantPortalAddress,$Using:SubscriptionID
$CloudServicesData = [xml](Invoke-WebRequest -Uri $CloudServicesUri -Headers $Headers -UseBasicParsing | Select-Object -ExpandProperty Content)
$CloudService = $CloudServicesData.feed.entry.content.properties.Name | ? {$_ -match $Using:CloudServiceName}
if (!$CloudService) {
# Set Cloud Service Configuration
$CloudServiceConfig = @{
"Name" = $Using:CloudServiceName
"Label" = $Using:CloudServiceName
}
# Convert Cloud Service Configuration To JSON
$CloudServiceConfigJSON = ConvertTo-Json $CloudServiceConfig
$CloudServicesData = [xml](Invoke-WebRequest -Uri $CloudServicesUri -Headers $Headers -Method Post -Body $CloudServiceConfigJSON -ContentType "application/json" UseBasicParsing)
$CloudService = $CloudServicesData.entry.content.properties.Name | ? {$_ -match $Using:CloudServiceName}
}
# Set Gallery Item VMRole Deploy URI
$GIDeployUri = "https://{0}:30005/{1}/CloudServices/{2}/Resources/MicrosoftCompute/VMRoles/?api-version=2013-03" f $Using:TenantPortalAddress,$Using:SubscriptionID,$CloudService
# Deploy Gallery Item VMRole
$VMRoleDeployed = Invoke-WebRequest -Uri $GIDeployUri -Headers $Headers -Method Post -Body $GIPayloadJSON -ContentType "application/json" -UseBasicParsing
Return $VMRoleDeployed
} -PSComputerName $WAPServer -PSCredential $Creds
$VMRole
}
Note There are a ton of nuances within this example workflow. It is because of this, I
outlined The Process above. In fact, this example workflow includes the following process
steps: 1-5, 8-13 and all Cloud Service Creation sub-steps. Steps 6 and 7 occur in the Middle
Tier Sub-Runbook.
14 The New World of Tenant Provisioning
Calling the Deploy-VMRole PowerShell workflow
The following PowerShell workflow script (Deploy-TenantVMRole) will call the DeployVMRole workflow with the following settings:











WAP Server: <Name of WAP Admin Server, defined by SMA Variable>
Credentials: <PSCredential, defined by SMA Variable>
Tenant Portal Address: <FQDN of the WAP Tenant Portal Server, defined by
SMA Variable>
Subscription ID: <Subscription ID for the User for whom the VMRoles will be
deployed, defined by parsing the $OwnerUserRole parameter>
User ID: <User ID of the User for whom the VMRoles will be deployed, defined by
parsing the $OwnerUserRole parameter>
Gallery Item Name: <Partial or Full Name of the Gallery Item VMRole to be
Deployed, defined by parsing the $GalleryItemToDeploy parameter>
Gallery Item Version: <Version of the Gallery Item VMRole to be Deployed,
defined by parsing the $GalleryItemToDeploy parameter>
Cloud Service Name: <Name of the Cloud Service, generated by combining
hardcoded custom variable data and $SubscriptionID variable>
OS Disk: <Name of the Default OS Disk to be used in the Gallery Item VMRole
Deployment, defined by SMA Variable>
Password: <Password used in the Gallery Item VMRole Deployment, defined by
SMA Variable>
ResDefConfig JSON: <Resource Definition Configuration data (in JSON format),
defined by numerous parameters/variables, contains common and Gallery Item
VMRole specific data>
Note You may keep these example settings, or modify to fit your deployment
specifications. Each of these parameters/variables are leveraged in the Deploy-VMRole
workflow call and are configured for maximum re-use and flexibility. The intention of this
Middle Tier Sub-Runbook is to balance common and Gallery Item VMRole specific data so
that the line between them is clear and updates are simple (as the number of Gallery Item
VMRoles in your environment grows). Even more specific parameter settings occur in the
Top Tier Runbook.
Example PowerShell workflow script for Deploy-TenantVMRole
001
002
003
004
005
006
007
008
009
010
011
012
013
014
workflow Deploy-TenantVMRole
{
param
(
[string]$OwnerUserRole,
[string]$GalleryItemToDeploy,
[string]$VMRoleName,
[string]$VMRoleNamePattern,
[string]$VMRoleSize
)
#Define Variables
$WAPServer = Get-AutomationVariable -Name 'WAP Admin Server'
$Creds = Get-AutomationPSCredential -Name 'PSCredential Name'
15 The New World of Tenant Provisioning
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
$TenantPortalAddress = Get-AutomationVariable -Name 'WAP Tenant Server FQDN'
$SubscriptionID = $OwnerUserRole.Split("_")[1]
$UserID = $OwnerUserRole.Split("_")[0]
$GalleryItemName = $GalleryItemToDeploy.Split(";")[0]
$GIVersion = $GalleryItemToDeploy.Split(";")[1]
$CloudServiceName = "CloudService-4-{0}" -f $SubscriptionID
$OSDisk = Get-AutomationVariable -Name 'Default VMRole OS Disk'
$Password = Get-AutomationVariable -Name 'Password'
# Create Gallery Item Parameter Hashtable (for Common Data)
$GIParamList = @{
VMRoleVMSize = $VMRoleSize
VMRoleOSVirtualHardDiskImage = $OSDisk
VMRoleAdminCredential = "administrator:{0}" -f $Password
VMRoleTimeZone = "Pacific Standard Time"
VMRoleComputerNamePattern = $VMRoleNamePattern
VMRoleNetworkRef = "Tenant Network ({0})" -f $UserID
}
# Add to Gallery Item Parameter Hashtable (for GI Specific Data)
if ($GalleryItemName -eq "DomainController")
{
$GIParamList += @{DomainControllerWindows2012DomainDNSName = $UserID.Split("@")[1]}
$GIParamList += @{DomainControllerWindows2012DomainNETBIOSName = ($UserID.Split("@")[1]).Split(".")[0]}
$GIParamList += @{DomainControllerWindows2012SafeModeAdminPassword = $Password}
}
# Convert Gallery Item Parameter Hash To JSON
$ResDefConfigJSON = ConvertTo-Json $GIParamList
Deploy-VMRole -WAPServer $WAPServer -creds $Creds -TenantPortalAddress $TenantPortalAddress `
-SubscriptionID $SubscriptionID -UserID $UserID -GalleryItemName $GalleryItemName `
-GIVersion $GIVersion -ResDefConfigJSON $ResDefConfigJSON -CloudServiceName $CloudServiceName `
-VMRoleName $VMRoleName
}
Did you miss it?
Up to this point, you have been inundated with “generic” workflow examples to Deploy
any Gallery Item VMRole. So, you may have actually missed where this went from
“generic” to “specific”. If you did, look up at the Deploy-TenantVMRole workflow script
again, and checkout lines 34-40ish. For this Middle Tier Sub-Runbook, that is the extent
of the “specific”. Believe me, I would have loved to make this and the Lowest Tier SubRunbook 100% Generic, but it is just not possible. More about this, and the decisions I
made are in the note below.
Note The Gallery Item VMRole specific data (as it relates to the other Gallery Item
VMRoles in this document, and from the Building Clouds Blog Gallery) is kept in a separate
section (lines 34-40ish above) and is surrounded by “if” logic. The intention of this section
is to logically store the Gallery Item VMRole specific data by $GalleryItemName. I put
quite a bit of thought on where the best place for this “unique” data should live within
these example workflows, as well as more dynamic ways to process it – this happens to be
where it landed and what it looks like. And obviously, this will not work for every possible
VMRole created. But it is one idea/implementation that has worked for my team’s
deployment scenario. Oh, and before I forget, this is the portion of the examples where
Steps 6 and 7 of The Process take place.
16 The New World of Tenant Provisioning
Calling the Deploy-TenantVMRole PowerShell workflow
The following PowerShell workflow script (Subscription-Create-Dispatcher) will call the
Deploy-TenantVMRole workflow with the following settings:





Gallery Item To Deploy: <Concatenated string made up of the Gallery Item
Name (full or partial) and Gallery Item Version in GalleryItemName:1.0.0.0
format, defined by custom data>
Owner User Role: <Concatenated string made up of the User ID (email address)
and Subscription ID (GUID) in
email@address.com_SUBSC_RIPTION_GUID_STRING, defined by SPF event Data
stored in the $resourceObject input variable>
VMRole Name: <Name of the VMRole to be Deployed (will be how the VMRole
is seen in the Tenant Portal), defined by custom data>
VMRole Name Pattern: <Name Pattern of the VM to be Deployed (will be how
the VM is named within the hypervisor) in NN## format, defined by custom
data>
VMRole Size: <Size of the VMRole to be Deployed, restricted to available VMM
Hardware Profile/Gallery Item VMRole definitions, defined by custom data>
Note The data entered here is completely customizable and should fit your deployment
specifications. The intention of this Top Tier Runbook is to set Gallery Item VMRole specific
variables and parameters to be passed on to the much more generic Middle and Lowest
Tier Sub-Runbooks. In fact, this Top Tier Runbook is where the Tenant configuration is built
out:





Virtual Network Creation
Multiple concurrent (and/or dependent) Gallery Item VMRole Deployments
Job Monitoring
Notifications
Etc.
Remember, as the Top Tier Runbook, it is the one called by the Subscription.Create
WAP/SPF event, configured in the VM Clouds Resource Provider:
It is the main “hook” for the Tenant Provisioning Process of “Subscribe to a Plan, Get
a Fully Deployed Set of Collaborative Workloads”.
17 The New World of Tenant Provisioning
Example PowerShell workflow script for Subscribe-Create-Dispatcher
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
workflow Subscription-Create-Dispatcher
{
param
(
[object]$resourceObject
)
if ($resourceObject.AdminID.Length -gt 27) { $AdminId = $AdminId.SubString(0,27) } else { $AdminId = $resourceObject.AdminId }
$OwnerUserRole = $AdminId + "_" + $resourceObject.SubscriptionID
$SubscriptionName = $resourceObject.SubscriptionName
$VMMServer = Get-AutomationVariable -Name 'VMM Server'
$LogicalNetworkName = Get-AutomationVariable -Name 'Default VMM Logical Network'
$PSEmailServer = Get-AutomationVariable -Name 'SMTP Server'
$PSEmailFrom = Get-AutomationVariable -Name 'SMTP From Email'
$PSEmailCC = Get-AutomationVariable -Name 'PSEmailCC'
if ($SubscriptionName -eq "Collaboration Workloads")
{
$CloudName = "Tenant Cloud"
Create-VMNetwork -VmmServerName $VMMServer -OwnerUserRole $OwnerUserRole -CloudName $CloudName -LogicalNetworkName $LogicalNetworkName
Send-SMTPNotification -SendNotificationType "Plans" -PSEmailFrom $PSEmailFrom -PSEmailTo $AdminId `
-PSEmailServer $PSEmailServer -PSEmailCC $PSEmailCC -WorkloadName $SubscriptionName
$SubscriptionName + " Plan Selected"
"Deploying Active Directory"
Deploy-TenantVMRole -GalleryItemToDeploy "DomainController;1.0.0.0" `
-OwnerUserRole $OwnerUserRole -VMRoleName "ActiveDirectory" `
-VMRoleNamePattern "DC##" -VMRoleSize "ExtraSmall"
}
}
Note This example is exactly what we have been using on my team in our
Demo/Test/Dev environment. As you can see, it includes more than just a call to the
Deploy-TenantVMRole workflow. In fact, it also includes:







Extraction of SPF event data from the $resourceObject input variable
Example generation of the $OwnerUserRole string
Usage of SMA Variables
Logic for Subscription dispatching based on Subscription Name (one example
provided)
Invocation of the Create-VMNetwork workflow (to create the Tenant Virtual
Network described above)
Invocation of the Send-SMTPNotification workflow (to send email notifications
to the user about post-subscription activities) - For more information (and a
specific example) about how the Send-SMTPNotification workflow, see the
following blog post: Automation–Monitoring and Notifying in Windows Azure
Pack with SMA
And finally, Invocation of the Deploy-TenantVMRole workflow (with Gallery
Item VMRole specific data)
By the way - I realize that some of the direct text output and use of hardcoded values could
be better served in Write-Verbose commands and usage of variables (respectively), but for
our environment, and for this example, this is what I went with. That said, you may keep
these example settings, or modify to fit your deployment specifications.
18 The New World of Tenant Provisioning
Oh, and if you are wondering about Job Monitoring, our environment has that too – it just
so happens to be hooked to a different Top Level Dispatch Runbook: VMRole-CreateDispatcher. And because the Deploy-VMRole workflow leverages the same exact method
for VMRole creation as the Tenant Portal, the WAP/SPF event for
MicrosoftCompute.VMRole works the same:
So, for fun…
Example PowerShell workflow script for VMRole-Create-Dispatcher
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
workflow VMRole-Create-Dispatcher
{
param
(
[object]$resourceObject
)
$VMRoleOwner = $resourceObject.Owner
$VMRoleName = $resourceObject.Name
$SCJobID = $resourceObject.MostRecentTask.ID
$PSEmailServer = Get-AutomationVariable -Name 'SMTP Server'
$PSEmailFrom = Get-AutomationVariable -Name 'SMTP From Email'
$PSEmailCC = Get-AutomationVariable -Name 'PSEmailCC'
Send-SMTPNotification -SendNotificationType "Workloads" -PSEmailFrom $PSEmailFrom `
-PSEmailTo $VMRoleOwner -PSEmailServer $PSEmailServer -PSEmailCC $PSEmailCC -WorkloadName $VMRoleName
"Job ID ($SCJobID) is being monitored"
$VMRoleDeploy = Monitor-VMMJobStatus -SleepDuration 300 -SCJobID $SCJobID -OutputStatus $false
"Deploy of $VMRoleName : $VMRoleDeploy"
Send-SMTPNotification -JobState $VMRoleDeploy -SendNotificationType "Workloads-Complete" -PSEmailFrom $PSEmailFrom `
-PSEmailTo $VMRoleOwner -PSEmailServer $PSEmailServer -PSEmailCC $PSEmailCC -WorkloadName $VMRoleName
}
The combination of Monitoring and Notifications allow for the creation of emails like:
19 The New World of Tenant Provisioning
BONUS - Example VMM PowerShell for Gallery Item VMRole Deployment!
Oh, alright…Here is another example script.
What does it do?
It is the portion of the Deploy-VMRole required if you wanted to leverage the
VMM Cmdlet command Add-CloudResource instead of going WAP Tenant API
Only
Note If you want to go this route, this example script replaces the existing script
portion within the Deploy-VMRole starting around line 45, right through to the end
(before the workflow’s end bracket).
Sound interesting?
Alternate Example PowerShell workflow script for a portion of the Deploy-VMRole
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
$GIVMRole = InlineScript {
#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($Using:ResDefJSON)
#Add ResDefConfig JSON to Dictionary
$ResDefConfig = New-Object 'System.Collections.Generic.Dictionary[String,Object]'
$ResDefConfig.Add("Version",$Using:GIVersion)
$ResDefConfig.Add("ParameterValues",$Using:ResDefConfigJSON)
Get-SCVMMServer -ComputerName $Using:VMMServer -ForOnBehalfOf | Out-Null
$OwnerUserRole = Get-SCUserRole | ? {$_.Name -match $Using:UserID}
#Create a CloudService
$Cloud = Get-SCCloud -Name $Using:CloudName -OnBehalfOfUser $Using:UserID -OnBehalfofUserRole $OwnerUserRole
$CloudSevice = Get-CloudService -Name $Using:CloudServiceName -OnBehalfOfUser $Using:UserID -OnBehalfofUserRole $OwnerUserRole
if (!$CloudSevice) {
$CloudSevice = New-CloudService -Cloud $Cloud -Name $Using:CloudServiceName -OnBehalfOfUser $Using:UserID -OnBehalfofUserRole $OwnerUserRole
}
$CloudResource = Add-CloudResource -CloudService $CloudSevice -ResourceDefinition $ResDef -ResourceName $Using:VMRoleName `
-OnBehalfOfUser $Using:UserID -OnBehalfofUserRole $OwnerUserRole -ResourceConfiguration $ResDefConfig -RunREST
Return $CloudResource
} -PSComputerName $VMMServer -PSCredential $Creds
$GIVMRole
Note Again, this is still example workflow script to be executed as the Service
Admin, this time against VMM directly, instead of leveraging the WAP Tenant API.
You will see that I leveraged a second InlineScript, this time to connect to the VMM
Server (as the WAP Tenant API calls that come before it execute via InlineScript
connected to the WAP Server). You will also see that we are still leveraging
“OnBehalfOf” functionality for the VMM commands, this is required if you want
proper Tenant ownership of the deployed resources.
The biggest thing to know about the Add-CloudResource command is that the ResourceDefinition and -ResourceConfiguration parameters require Dictionary
Objects. This is why I have both the ResDef and ResDefConfig convert/deserialization
20 The New World of Tenant Provisioning
steps in this section. In fact, this portion of the script includes steps 8-13 and all Cloud
Service Creation sub-steps from The Process described above.
Finally, it is worth restating - JSON is the preferred method for data storage and
transfer between sections of the script (from InlineScript to InlineScript and workflow
to workflow).
Use Cases
But wait, WHY would I want to do this?
Here are some use cases (all from the Service Admin persona):




Use Case 1: Provision a nearly complete environment to your Tenants/End
Users at the click of a self-service button (Subscription to a Plan)
Use Case 2: Enable Gallery Item VMRole deployment from a custom selfservice portal, feeding the SMA Runbooks with more dynamic parameter
data
Use Case 3: Integrate Gallery Item VMRole deployment with an existing
customer facing interface
Use Case 4: Develop and Execute SMA Runbooks (potential to take in
Parameters during execution) to deliver Gallery Item VMRoles on-demand
21 The New World of Tenant Provisioning
Automated Deployment of
the Identity Workload as a
Tenant Admin
I realize the heading of this section is very similar to the last, and there is very good
reason for that. Though they look similar, they are different. Different personas; different
scripts; different context. The scope of this section is illustrated by the portion of the image
with the red outline:
To clear things up, let’s expand on the title for this section, (now with more sub-title!):
Automated Deployment of the Identity Workload as a Tenant Admin
(Active Directory VMRole; from the Tenant Admin Persona)
The last section of this document was all about deployment as the Service Administrator
persona. Now, in this section, it is all about deployment as the Tenant Administrator.
I think it is time for another quick rehash (with image):
22 The New World of Tenant Provisioning
In the above image, we see my view of these two personas, as well as what we will be
getting into for this post (the first two bullets in the box on the right).
The Options
How about another image?
This time, to visualize the high-level process for the Tenant Admin:
So, as you can see, the Tenant Admin has options.
Note Automatically adding the Isolated Tenant Virtual Network (Isolated Software
Defined Network (SDN)) is completely optional, as the Service Admin can simply
recommend that the Tenant Admin manually create Virtual Networks from the Tenant
Portal before deploying VMRoles.
Reminder These options are the same for any VMRole Deployment, Active Directory
happens to be the first one to be deployed, so it gets all the attention.
23 The New World of Tenant Provisioning
The Process
Remember that multi-step process I described in the last section?
Well, it is basically the same.
So, to save you from going back and forth, here is the representative image for “The
Process”:
What’s the difference?
Primarily, it is the Web Service Endpoint PORT and Authorization method.
As a Service Admin, you can leverage Bearer Token authorization and make WS calls
against the Tenant API (non-Public), Port 30005
As a Tenant Admin, you leverage Certificates and make WS calls against the Public
Tenant API, Port 30006
In fact, if you are familiar with Automating Windows Azure with PowerShell, the prerequisite process has a very similar look and feel.
Care to venture a guess what we leverage to setup/use the Certificate?
24 The New World of Tenant Provisioning
The Windows Azure PowerShell Module (It is one of the options anyway.)
That’s right. The very same – and if you haven’t checked it out, or downloaded the latest
version, you may have missed all the “new-ish” commands that contain *-WAPack*
Which is a great segue to…
The Pre-Requisites
1.
Valid Account and Subscription to a Plan within WAP (have the ability to login to
the WAP Tenant Portal and provision Gallery Items (VMRoles)):
2.
The latest Windows Azure PowerShell module (contains the latest *-WAPack*
Commands):
3.
Ability to Execute Windows Azure PowerShell Commands
25 The New World of Tenant Provisioning
4.
Creation and Usage of a Management Certificate (derived from WAP Publish
Settings File – see the Pre-Requisite Setup steps below)
The Pre-Requisite Setup
1.
2.
Download and Install the Windows Azure PowerShell Commands
Get the Published Settings File for your Subscription – Navigate to your version
of the following URL: https://tenant.portal.com:30081/publishsettings
This will prompt to download the file locally – My recommendation is to
download to the machine where the PowerShell Scripts will be executed.
Note If the target portal leverages ADFS, do not include the port (30081) in the
address while attempting to retrieve the .publishsettings file. At least this is what I
experienced between the two environments we have, one without ADFS (required
port in URL), and one with ADFS (port not used in URL).
(Example Path: C:\LocalPath\SubscriptionName-MM-d-YYYYcredentials.publishsettings)
3.
4.
Open PowerShell and ensure the Windows Azure PowerShell module is loaded
Execute the following command (modify the command text based on the name
and where the publishsettings file is located):
Import-WAPackPublishSettingsFile C:\WAP\Collaboration Workloads
(Tenant Deployed)-3-11-2014-credentials.publishsettings
26 The New World of Tenant Provisioning
Note These steps not only import the certificate into the Management
Certificates section in the Tenant Portal:
But ALSO add it to the Certificate Store for the Current User:
Resulting in the following, when Get-WAPackSubscription is executed from
PowerShell:
Reminder The security best practice for the publishsettings file is to store it
temporarily, and then delete it after the settings have been imported. A malicious
user gaining access to the publishsettings file can edit, create, and delete your
WAP resources.
So, there you go - All the theory and pre-requisites you can handle, right?
The good news…With these pre-requisites out of the way, we can now get on to the
actual deployment script!
Active Directory Gallery Item VMRole Deployment as a Tenant Admin
(Against the Public WAP API)
001
002
003
#region GetWAPConnectionData
# Get WAP Subscription Information
27 The New World of Tenant Provisioning
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
$WAPSubscription = Get-WAPackSubscription
# Set Subscription
$SubscriptionID = $WAPSubscription.SubscriptionId
# Get Management Certificate Info
$CertThumb = $WAPSubscription.Certificate.Thumbprint
$CertPath = "Cert:\CurrentUser\My\{0}" -f $CertThumb
$Cert = Get-Item $CertPath
# Set Tenant Portal Address
$TenantPortalAddress = $WAPSubscription.ServiceEndpoint.Host
# Set Port
$Port = $WAPSubscription.ServiceEndpoint.Port
#endregion GetWAPConnectionData
#region SetVariables
# Set Gallery Item Name and Version for Match and Deploy
$GalleryItemName = "DomainController"
$GIVersion = "1.0.0.0"
# Set Common Gallery Item Parameters
$UserID = "tenant@company.com"
$VMRoleNetwork = "Tenant Network ({0})" -f $UserID
$CloudServiceName = "CloudService-4-{0}" -f $SubscriptionID
$VMRoleName = "ActiveDirectory"
$VMRoleNamePattern = "DC##"
$VMRoleSize = "ExtraSmall"
$VMRoleTZ = "Pacific Standard Time"
$OSDisk = "Windows Server 2012 Datacenter"
$OSDiskVersion = "1.0.0.0"
$Password = "Password"
#endregion SetVariables
#region GetResDef
# Get Gallery Item Reference
$GIReferenceUri = "https://{0}:{1}/{2}/Gallery/GalleryItems/$/MicrosoftCompute.VMRoleGalleryItem?api-version=2013-03" -f $TenantPortalAddress,$Port,$SubscriptionID
$GIReferenceData = [xml](Invoke-WebRequest -Certificate $Cert -Uri $GIReferenceUri | Select-Object -ExpandProperty Content)
$GalleryItemREF = $GIReferenceData.feed.entry.content.properties.resourcedefinitionUrl | ? {$_ -match $GalleryItemName}
# Get Gallery Item Resource Definition
$GIResDEFUri = "https://{0}:{1}/{2}/{3}/?api-version=2013-03" -f $TenantPortalAddress,$Port,$SubscriptionID,$GalleryItemREF
$GIResourceDEFJSON = Invoke-WebRequest -Certificate $Cert -Uri $GIResDEFUri | 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 "DomainController")
{
$GIParamList += @{DomainControllerWindows2012DomainDNSName = $UserID.Split("@")[1]}
$GIParamList += @{DomainControllerWindows2012DomainNETBIOSName = ($UserID.Split("@")[1]).Split(".")[0]}
$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]'
$ResDefConfig.Add("Version",$GIVersion)
$ResDefConfig.Add("ParameterValues",$ResDefConfigJSON)
#endregion SetResDefConfig
#region GenerateGIPayloadJSON
# Set Gallery Item Payload Variables
$GISubstate = $null
$GILabel = $VMRoleName
$GIName = $VMRoleName
$GIProvisioningState = $null
$GIInstanceView = $null
28 The New World of Tenant Provisioning
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# 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
#region GetOrSetCloudService
# Get Cloud Services
$CloudServicesUri = "https://{0}:{1}/{2}/CloudServices?api-version=2013-03" -f $TenantPortalAddress,$Port,$SubscriptionID
$CloudServicesData = [xml](Invoke-WebRequest -Uri $CloudServicesUri -Certificate $Cert | Select-Object -ExpandProperty Content)
$CloudService = $CloudServicesData.feed.entry.content.properties.Name | ? {$_ -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 -Certificate $Cert -Method Post -Body $CloudServiceConfigJSON -ContentType "application/json")
$CloudService = $CloudServicesData.entry.content.properties.Name | ? {$_ -match $CloudServiceName}
}
#endregion GetOrSetCloudService
#region DeployGIVMRole
# Set Gallery Item VMRole Deploy URI
$GIDeployUri = "https://{0}:{1}/{2}/CloudServices/{3}/Resources/MicrosoftCompute/VMRoles/?api-version=2013-03" -f $TenantPortalAddress,$Port,$SubscriptionID,$CloudService
# Deploy Gallery Item VMRole
$VMRoleDeployed = Invoke-WebRequest -Uri $GIDeployUri -Certificate $Cert -Method Post -Body $GIPayloadJSON -ContentType "application/json"
$VMRoleDeployed
#endregion DeployGIVMRole
Note(s)






I have several notes about the above script. So I will list them here:
This is just an example script.
It has been tested against our Demo/Test/Dev environment multiple times.
It absolutely requires the pre-requisites discussed above. And while there are
alternatives to getting the required variable data based on the GetWAPackSubscription command, I have found this to be the most
efficient/dynamic method.
The $TenantPortalAddress Variable may need to be set to a specific string,
rather than being extracted from the information available from the GetWAPackSubscription command, specifically if the public portal address is
different than the FQDN of WAP Admin Server.
If you are getting errors during deployment like, “Disk with Name (Windows
Server 2012 Datacenter) and Version (1.0.0.0) not found while translating
Resource Definition for cloud resource.” it is likely that the $OSDisk and/or
$OSDiskVersion Variables have incorrect data. The Tenant API does not care so
much for the actual OS Disk name, instead, it appears to require the Family
Name of the OS Disk.
I chose to leave all the Variable settings within the script. These could very easily
be presented as Script Parameters, and fed into the script to make it a bit more
generic.
29 The New World of Tenant Provisioning




Just like the Service Admin example script, there is a portion of the Resource
Definition Configuration (ResDefConfig) that is tied directly to the
ResDef/ResDefExt for a given Gallery Item VMRole. When generating the Gallery
Item Parameter Hashtable, I have separated the GI specific data from the
common GI data. In most cases (especially for the Gallery Item VMRoles produced
by my team), the only portion of the script that has to change per VMRole is this
GI specific data (and, of course any specific Variable data).
This script (for the Tenant Admin) should look nearly identical to the script from
Part 2 (for the Service Admin). This is by design, as I wanted to keep as many
synergies in play as possible. Remember, there are only subtle differences (Ports
and Auth).
While the steps in the Gallery Item VMRole deployment process will likely remain
the same, the actual script could be improved in various ways: Addition of Script
Parameters, Separated into Functions, Transformed into a Set of Cmdlets, etc. If
anyone takes these improvements on, I will be happy to reference / endorse the
published work here in this document.
Finally, as you can see, I have broken the script up into “regions”, each of which
builds on the last, to eventually complete all the data collection / command
execution for the final Invoke-WebRequest POST to deploy the Gallery Item
VMRole. Here is an image illustrating the seven regions:
All that said, if everything goes right during the execution of this example script, you
should see something very similar to this:
30 The New World of Tenant Provisioning
Use Cases
But wait, WHY would I want to do this?
Here are some use cases (from both the Service Admin and Tenant Admin personas):




Use Case 1: As a Tenant – Simple avoidance of manual clicking to deploy
Gallery Item VMRoles
Use Case 2: As a Tenant – Develop scripts to fully deploy a set of multiple
concurrent (and/or dependent) Gallery Item VMRole Deployments (with scripts
like this, you have complete control over the “what” and “when”)
Use Case 3: As a Service Provider (or Enterprise acting like one) – Create a
custom set of cmdlets encapsulating the parameters and logic into easily
consumable/executable commands
Use Case 4: As a Service Provider (or Enterprise acting like one) – Enabling your
Tenants/End Users to automate their own Gallery Item VMRole deployments
(external to any SMA efforts on the Service Admin side)
And with that, we can do another status check on the scope of the document so far:
Note In this diagram, we also see that deployment options for both administrator
personas have been covered. And we did this with a specific example in mind: the Active
Directory Gallery Item VMRole. This was due to the fact that the subsequent example
Gallery Item VMRole deployments in this document take a strong dependency on Active
Directory. In this way, both the Gallery Item VMRole for Active Directory and the Tenant
Network are “table stakes”.
So, at this point, based on this and the previous section of this document, you really
have everything necessary to deploy not only the Gallery Item VMRole for Active
Directory, but any Gallery Item VMRole you have built (or pulled down off of WebPI
(or the Building Clouds Blog)).
But hey, I am not going to leave you hanging. The very next section is all about Tenant
Workloads, where I will be providing the necessary script updates (to what you have
seen so far) to deploy the Gallery Item VMRoles for Lync, SharePoint, and Exchange
(for both personas).
31 The New World of Tenant Provisioning
Automated Deployment of
Tenant Workloads (Lync,
SharePoint, and Exchange)
This section of the document is all about describing what it takes and providing the
necessary script updates (to what you have seen so far) to deploy the Gallery Item
VMRoles for Lync, SharePoint, and Exchange (for both personas).
Which means, at least in part, these (previously seen) three diagrams happen to also
apply to this section:
Automated Deployment of Tenant Workloads
(Lync, SharePoint, and Exchange VMRoles; from both Service Admin and Tenant Admin
Personas)
Because we established a solid foundation in the previous section of the document, this
section really just highlights the script updates necessary to get Automated WAP
Deployments to work for OUR PUBLISHED Lync, SharePoint, and Exchange Gallery Item
32 The New World of Tenant Provisioning
VMRoles. The reason I say “OUR PUBLISHED”, in yelling-case, is to emphasize which
Gallery Item VMRoles the example scripts in this section actually directly relate. If you are
wondering, “OUR PUBLISHED” Lync, SharePoint, and Exchange Gallery Item VMRoles can
be found here: Windows Azure Pack VMRole Gallery Items for Collaboration
Workloads
Wait! Wait! Wait! What’s the difference in the script from VMRole to VMRole?
Well, as you saw in the previous sections of the document, no one generic script can be
created that handles the deployment from beginning to end. This is due to the fact that
each VMRole Definition can vary, based on how that VMRole was created, what fields
were included, and which Resource Extensions were added. And while I did my best to
keep my scripts generic, there were just portions that had to be hardcoded - dun! dun!
dun! The good news is, the hardcoded – dun! dun! dun! stuff is kept to where the scripts
differ. Meaning, logic can be introduced to dynamically add the appropriate hardcoded dun! dun! dun! script portions based on VMRole type.
Will I be able to apply what I learn here against the VMRoles I create?
Yes. There will be a “discovery” section in the post which takes you through how to
enumerate “What’s different” or “What’s required” as it relates to the Resource Definition
(ResDef/ResDefExt), and Resource Definition Configuration (ResDefConfig).
What about the Tenant Virtual Network?
This topic will not be discussed again here in this post. Please refer to the “Automated
Tenant Virtual Network Deployment” section of this document for more information and
example script.
Note The TechNet Gallery Contribution download also includes the example script(s) for
automatically creating a Tenant Virtual Network.
The Scope
Just like in the previous two sections, there are various options to choose from when
deploying Gallery Item VMRoles. These options are depicted above (the one with all the
green checkmarks). To keep this section manageable, I will be providing the example
Runbooks / Scripts / Guidance in the following order:
Service Administrator in SMA (with the WAP Tenant API Only)





Existing: SMA Runbook that is the same for each Gallery Item VMRole
Deployment
New: Updated SMA Runbooks for the Lync Gallery Item VMRole Deployment
New: Updated SMA Runbooks for the SharePoint Gallery Item VMRole
Deployment
New: Updated SMA Runbooks for the Exchange Gallery Item VMRole
Deployment
Future Discovery: How to enumerate ResDef/ResDefExt and ResDefConfig
Requirements for any Gallery Item VMRole
33 The New World of Tenant Provisioning
Tenant Administrator from a PowerShell Script (With the Public WAP Tenant API)
Instead of making a whole big section, reiterating the same thing over and over, I will
simply be providing the following:


New: Example Gallery Item VMRole Deployment Script for Active Directory,
Lync, Exchange, or SharePoint (as a Tenant Admin against the Public WAP API)
Future Discovery: Modified Example PowerShell script to enumerate
ResDef/ResDefExt and ResDefConfig Requirements for any Gallery Item VMRole
(as a Tenant Admin against the Public WAP API)
Out of Scope
There are a couple topics out of scope for this particular section, as they have been
covered previously within the document:
1.
2.
3.
4.
5.
6.
Automated Tenant Virtual Network Creation
Automated Active Directory Gallery Item VMRole Deployment
Detailed Review of “The Process” for constructing a Gallery Item VMRole
Deployment Script
Example VMM PowerShell for Gallery Item VMRole Deployment (“AddCloudResource”)
Pre-Requisites for WAP Tenant API Authentication (“bearer token
authorization”)
Pre-Requisites for Public WAP Tenant API Authentication (“Windows Azure
PowerShell Module” and “certificates”)
In other words, from a deployment perspective (and from the Tenant’s view), this is our
starting point:
Deployment as a Service Administrator in SMA (with the WAP Tenant API
Only)
Existing: SMA Runbook that is the same for each Gallery Item VMRole
Deployment
If we take a look at the “overall structure of the SMA Runbooks” section above, the
following SMA Runbook will be the same for each Gallery Item VMRole Deployment
34 The New World of Tenant Provisioning
(well, depending on your implementation, but definitely for this example) and can be
leveraged generically:
For the example script reference here, refer to the “Example PowerShell workflow script
for Deploy-VMRole” section above.
New: Updated SMA Runbooks…
If we take another look at the “overall structure of my SMA Runbooks” section from Part
2, these two SMA Runbooks will have subtle differences for each Gallery Item VMRole
Deployment:
Note I provide the updated SMA Runbook examples for each Tenant Workload
Deployment below.
But before we dive into the SMA Runbook updates, I want to level-set…
Because more significant updates take place in the Deploy-TenantVMRole SMA
Runbook, this section will concentrate more on it, rather than the Subscription-CreateDispatcher SMA Runbook.
Remember in both previous sections there was a portion of the example PowerShell that
created the Gallery Item Parameter Hashtable (for Common Data) and then added to the
Gallery Item Parameter Hashtable (for GI Specific Data)?
If not, here is an image to help jog your memory:
35 The New World of Tenant Provisioning
It is right below this section in the Deploy-TenantVMRole SMA Runbook where we will
be adding the updates. Essentially, more logic will be introduced to dynamically add the
appropriate hardcoded - dun! dun! dun! script portions based on VMRole type.
Note I will be including the script portions in each respective Tenant Workload subsection below. Then an all-up Deploy-TenantVMRole SMA Runbook with configuration
for all 4 (including Active Directory) Tenant Workload Deployments will be made available
after the last sub-section. Also included, will be the all-up Subscription-CreateDispatcher SMA Runbook with calls for all 4 (including Active Directory) Tenant Workload
Deployments.
…for the Lync Gallery Item VMRole Deployment
001
002
003
004
005
if ($GalleryItemName -eq "Lync")
{
$GIParamList += @{RunAsDomainToJoin = $UserID.Split("@")[1]}
$GIParamList += @{LyncServer2013RunAsCredential = "{0}\administrator:{1}" -f ($UserID.Split("@")[1]).Split(".")[0],$Password}
}
…for the SharePoint Gallery Item VMRole Deployment
01
002
003
004
005
006
if ($GalleryItemName -eq "SharePoint")
{
$GIParamList += @{RunAsDomainToJoin = $UserID.Split("@")[1]}
$GIParamList += @{SharePointServer2013RunAsCredential = "{0}\administrator:{1}" -f ($UserID.Split("@")[1]).Split(".")[0],$Password}
$GIParamList += @{SharePointServer2013InstallChoice = "SingleServer"}
}
…for the Exchange Gallery Item VMRole Deployment
001
002
003
004
005
006
if ($GalleryItemName -eq "Exchange")
{
$GIParamList += @{DomainJoinDomainToJoin = $UserID.Split("@")[1]}
$GIParamList += @{ExchangeServer2013CU2RunAsCredential = "{0}\administrator:{1}" -f ($UserID.Split("@")[1]).Split(".")[0],$Password}
$GIParamList += @{ExchangeServer2013CU2ExchangeServer2013CU2Organization = "ExchangeOrg"}
}
Note For each of these example script portions, I kept most of the Hashtable Variable
building “complex” and/or hardcoded – dun! dun! dun! on purpose. I wanted to avoid
creating and leveraging extra variables outside these individual IF blocks. In these
examples, much of the string formatting is the same from IF block to IF block, so you can
create a “Credential” string before all this, and leverage it throughout.
Options You may want to move some of what I have deemed as “Common Data” to
these “GI Specific Data” Hashtables. A good example of this is
“VMRoleOSVirtualHardDiskImage = $OSDisk”. Not every VMRole will leverage the same
“Common” OS Disk, so to assign different OS Disks to different VMRoles, all you have to do
is move the $OSDisk variable assignment to the “GI Specific” Hashtable(s).
Disclaimer This is a set of examples to handle the GI Specific Data. There are other (and
likely better) ways to do this same thing. If you have improvements, please leverage them.
If you would like to share those improvements with the community, please let me know, or
send a link to your related blog post. I am always happy to cross-post.
36 The New World of Tenant Provisioning
Example PowerShell workflow script for Deploy-TenantVMRole
(with IF blocks for DomainController, Lync, SharePoint, and Exchange)
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
workflow Deploy-TenantVMRole
{
param
(
[string]$OwnerUserRole,
[string]$GalleryItemToDeploy,
[string]$VMRoleName,
[string]$VMRoleNamePattern,
[string]$VMRoleSize
)
#Define Variables
$WAPServer = Get-AutomationVariable -Name 'WAP Admin Server'
$Creds = Get-AutomationPSCredential -Name 'PSCredential Name'
$TenantPortalAddress = Get-AutomationVariable -Name 'WAP Tenant Server FQDN'
$SubscriptionID = $OwnerUserRole.Split("_")[1]
$UserID = $OwnerUserRole.Split("_")[0]
$GalleryItemName = $GalleryItemToDeploy.Split(";")[0]
$GIVersion = $GalleryItemToDeploy.Split(";")[1]
$CloudServiceName = "CloudService-4-{0}" -f $SubscriptionID
$OSDisk = Get-AutomationVariable -Name 'Default VMRole OS Disk'
$Password = Get-AutomationVariable -Name 'Password'
# Create Gallery Item Parameter Hashtable (for Common Data)
$GIParamList = @{
VMRoleVMSize = $VMRoleSize
VMRoleOSVirtualHardDiskImage = $OSDisk
VMRoleAdminCredential = "administrator:{0}" -f $Password
VMRoleTimeZone = "Pacific Standard Time"
VMRoleComputerNamePattern = $VMRoleNamePattern
VMRoleNetworkRef = "Tenant Network ({0})" -f $UserID
}
# Add to Gallery Item Parameter Hashtable (for GI Specific Data)
if ($GalleryItemName -eq "DomainController")
{
$GIParamList += @{DomainControllerWindows2012DomainDNSName = $UserID.Split("@")[1]}
$GIParamList += @{DomainControllerWindows2012DomainNETBIOSName = ($UserID.Split("@")[1]).Split(".")[0]}
$GIParamList += @{DomainControllerWindows2012SafeModeAdminPassword = $Password}
}
if ($GalleryItemName -eq "Lync")
{
$GIParamList += @{RunAsDomainToJoin = $UserID.Split("@")[1]}
$GIParamList += @{LyncServer2013RunAsCredential = "{0}\administrator:{1}" -f ($UserID.Split("@")[1]).Split(".")[0],$Password}
}
if ($GalleryItemName -eq "SharePoint")
{
$GIParamList += @{RunAsDomainToJoin = $UserID.Split("@")[1]}
$GIParamList += @{SharePointServer2013RunAsCredential = "{0}\administrator:{1}" -f ($UserID.Split("@")[1]).Split(".")[0],$Password}
$GIParamList += @{SharePointServer2013InstallChoice = "SingleServer"}
}
if ($GalleryItemName -eq "Exchange")
{
$GIParamList += @{DomainJoinDomainToJoin = $UserID.Split("@")[1]}
$GIParamList += @{ExchangeServer2013CU2RunAsCredential = "{0}\administrator:{1}" -f ($UserID.Split("@")[1]).Split(".")[0],$Password}
$GIParamList += @{ExchangeServer2013CU2ExchangeServer2013CU2Organization = "ExchangeOrg"}
}
# Convert Gallery Item Parameter Hash To JSON
$ResDefConfigJSON = ConvertTo-Json $GIParamList
Deploy-VMRole -WAPServer $WAPServer -creds $Creds -TenantPortalAddress $TenantPortalAddress `
-SubscriptionID $SubscriptionID -UserID $UserID -GalleryItemName $GalleryItemName `
-GIVersion $GIVersion -ResDefConfigJSON $ResDefConfigJSON -CloudServiceName $CloudServiceName `
-VMRoleName $VMRoleName
}
Note Obviously I took some liberties with the data sharing in this example. Before I
started this SMA Runbook, I knew that each of our Gallery Item VMRoles shared a set of
“Common Data” for the Gallery Item Parameter Hashtable. At that point, I just had to
figure out which parameters fell into the “GI Specific Data” for each Gallery Item VMRole
to be included in the SMA Runbook. Each set of “GI Specific Data” then gets its own IF
block, appending to the “Common Data” already in the Gallery Item Parameter Hashtable.
More information on “Discovery” of “GI Specific Data” can be found below!
37 The New World of Tenant Provisioning
Example PowerShell workflow script for Subscribe-Create-Dispatcher
(with calls for each Tenant Workload)
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
workflow Subscription-Create-Dispatcher
{
param
(
[object]$resourceObject
)
if ($resourceObject.AdminID.Length -gt 27) { $AdminId = $AdminId.SubString(0,27) } else { $AdminId = $resourceObject.AdminId }
$OwnerUserRole = $AdminId + "_" + $resourceObject.SubscriptionID
$SubscriptionName = $resourceObject.SubscriptionName
$VMMServer = Get-AutomationVariable -Name 'VMM Server'
$LogicalNetworkName = Get-AutomationVariable -Name 'Default VMM Logical Network'
$PSEmailServer = Get-AutomationVariable -Name 'SMTP Server'
$PSEmailFrom = Get-AutomationVariable -Name 'SMTP From Email'
$PSEmailCC = Get-AutomationVariable -Name 'PSEmailCC'
if ($SubscriptionName -eq "Collaboration Workloads")
{
$CloudName = "Tenant Cloud"
Create-VMNetwork -VmmServerName $VMMServer -OwnerUserRole $OwnerUserRole `
-CloudName $CloudName -LogicalNetworkName $LogicalNetworkName
Send-SMTPNotification -SendNotificationType "Plans" -PSEmailFrom $PSEmailFrom `
-PSEmailTo $AdminId -PSEmailServer $PSEmailServer -PSEmailCC $PSEmailCC `
-WorkloadName $SubscriptionName
$SubscriptionName + " Plan Selected"
"Deploying Active Directory"
Deploy-TenantVMRole -GalleryItemToDeploy "DomainController;1.0.0.0" `
-OwnerUserRole $OwnerUserRole -VMRoleName "ActiveDirectory" `
-VMRoleNamePattern "DC##" -VMRoleSize "ExtraSmall"
#No Logic, Just Sleep in this example
Start-Sleep -Seconds 600
"Deploying Lync"
Deploy-TenantVMRole -GalleryItemToDeploy "Lync;1.0.0.0" `
-OwnerUserRole $OwnerUserRole -VMRoleName "Lync" `
-VMRoleNamePattern "LY##" -VMRoleSize "ExtraLarge"
"Deploying SharePoint"
Deploy-TenantVMRole -GalleryItemToDeploy "SharePoint;1.0.0.0" `
-OwnerUserRole $OwnerUserRole -VMRoleName "SharePoint" `
-VMRoleNamePattern "SP##" -VMRoleSize "ExtraLarge"
"Deploying Exchange"
Deploy-TenantVMRole -GalleryItemToDeploy "Exchange;1.0.0.0" `
-OwnerUserRole $OwnerUserRole -VMRoleName "Exchange" `
-VMRoleNamePattern "EX##" -VMRoleSize "ExtraLarge"
}
}
Note I did not add any “wait logic” in this example. It simply deploys Active Directory,
waits 10 minutes and then deploys the other workloads (Lync, SharePoint, and Exchange).
For more information on Monitoring and Notifications, refer to this blog post: Automation–
Monitoring and Notifying in Windows Azure Pack with SMA.
Future Discovery: How to enumerate ResDef/ResDefExt and ResDefConfig
Requirements for any Gallery Item VMRole
So, how did I know which items in the Gallery Item Parameter Hashtable were “Common”
and which were “GI Specific”?
Well, other than tearing apart the JSON during my learning process for all this, there is a
pretty simple method to extract the necessary data for review.
The following is an example PowerShell script which leverages the WAP Tenant API (nonPublic), pulls down the specified Gallery Item VMRoles desired for comparison, and
38 The New World of Tenant Provisioning
outputs a Hashtable containing the Gallery Item VMRole Name and its required
Resource Parameters.
Example PowerShell script for Get-GIResourceParams
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
function Get-GIResourceParams {
param
(
[object]$Headers,
[string]$TenantPortalAddress,
[string]$SubscriptionID,
[string]$GalleryItemName
)
# Get Gallery Item Reference
$GIReferenceUri = "https://{0}:30005/{1}/Gallery/GalleryItems/$/MicrosoftCompute.VMRoleGalleryItem?api-version=2013-03" -f $TenantPortalAddress,$SubscriptionID
$GIReferenceData = [xml](Invoke-WebRequest -Uri $GIReferenceUri -Headers $Headers -UseBasicParsing | Select-Object -ExpandProperty Content)
$GalleryItemREF = $GIReferenceData.feed.entry.content.properties.resourcedefinitionUrl | ? {$_ -match $GalleryItemName}
# Get Gallery Item Resource Definition
$GIResDEFUri = "https://{0}:30005/{1}/{2}/?api-version=2013-03" -f $TenantPortalAddress,$SubscriptionID,$GalleryItemREF
$GIResourceDEFJSON = Invoke-WebRequest -Uri $GIResDEFUri -Headers $Headers -UseBasicParsing | Select-Object -ExpandProperty Content
$ResDef = ConvertFrom-Json $GIResourceDEFJSON
Return $ResDef.ResourceParameters.Name
}
$WAPServer = "WAP Admin Server Name"
$UserID = "User ID (email) of User with Subscription"
$TenantPortalAddress = "FQDN of Tenant Portal Address"
$SubscriptionID = "Subscription ID for Specified User"
$GalleryItems = @("DomainController","Lync","SharePoint","Exchange")
$AdminURI = "https://" + $WAPServer + ":30004"
$AuthSite = "https://" + $WAPServer + ":30072"
$ClientRealm = "http://azureservices/AdminSite"
$token = Get-MgmtSvcToken -Type Windows -AuthenticationSite $AuthSite -ClientRealm $ClientRealm -DisableCertificateValidation
$Headers = @{
Authorization = "Bearer $token"
"x-ms-principal-id" = $UserID }
$GIandResourceParams = @{}
foreach ($GalleryItem in $GalleryItems)
{
$GIResourceParams = Get-GIResourceParams -Headers $Headers -TenantPortalAddress $TenantPortalAddress `
-SubscriptionID $SubscriptionID -GalleryItemName $GalleryItem
$GIandResourceParams += @{$GalleryItem = $GIResourceParams}
}
$GIandResourceParams
Note I leveraged a function within this example script, to minimize duplicate command
execution. Modify this example as you see fit. Oh, and it needs to be executed (at least in
part) from the WAP Admin Server, or wherever the MgmtSvcAdmin Cmdlets live.
What is the output of this script?
A Hashtable of values you can use to compare/contrast Gallery Item VMRole Resource
Parameters:
Challenge I simply provide the Hashtable worth of data, it is up to you to enumerate
the data and make something fancy with Compare-Object command to dynamically
compare the Resource Parameters on the fly!
39 The New World of Tenant Provisioning
Deployment as a Tenant Administrator from a PowerShell Script (with the
Public WAP Tenant API)
New: Deployment Script for Active Directory, Lync, Exchange, or
SharePoint
Example PowerShell script for Active Directory, Lync, Exchange, or SharePoint VMRole
Deployment (as a Tenant Admin against the Public WAP API)
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
#region GetWAPConnectionData
# Get WAP Subscription Information
$WAPSubscription = Get-WAPackSubscription
# Set Subscription
$SubscriptionID = $WAPSubscription.SubscriptionId
# Get Management Certificate Info
$CertThumb = $WAPSubscription.Certificate.Thumbprint
$CertPath = "Cert:\CurrentUser\My\{0}" -f $CertThumb
$Cert = Get-Item $CertPath
# Set Tenant Portal Address
$TenantPortalAddress = $WAPSubscription.ServiceEndpoint.Host
# Set Port
$Port = $WAPSubscription.ServiceEndpoint.Port
#endregion GetWAPConnectionData
#region SetVariables
# Set Gallery Item Name and Version for Match and Deploy
$GalleryItemName = "Lync"
$GIVersion = "1.0.0.0"
# Set Common Gallery Item Parameters
$UserID = "tenant@company.com"
$VMRoleNetwork = "Tenant Network ({0})" -f $UserID
$CloudServiceName = "CloudService-4-{0}" -f $SubscriptionID
$VMRoleTZ = "Pacific Standard Time"
$OSDisk = "Windows Server 2012 Datacenter"
$OSDiskVersion = "1.0.0.0"
$Password = "Password"
#Set GI Specific Gallery Item Parameters
if ($GalleryItemName -eq "DomainController")
{
$VMRoleName = "ActiveDirectory"
$VMRoleNamePattern = "DC##"
$VMRoleSize = "ExtraSmall"
}
if ($GalleryItemName -eq "Lync")
{
$VMRoleName = "Lync"
$VMRoleNamePattern = "LY##"
$VMRoleSize = "ExtraLarge"
}
if ($GalleryItemName -eq "SharePoint")
{
$VMRoleName = "SharePoint"
$VMRoleNamePattern = "SP##"
$VMRoleSize = "ExtraLarge"
$SPInstallChoice = "SingleServer"
}
if ($GalleryItemName -eq "Exchange")
{
$VMRoleName = "Exchange"
$VMRoleNamePattern = "EX##"
$VMRoleSize = "ExtraLarge"
$ExchangeOrg = "ExchangeOrg"
}
#endregion SetVariables
#region GetResDef
# Get Gallery Item Reference
$GIReferenceUri = "https://{0}:{1}/{2}/Gallery/GalleryItems/$/MicrosoftCompute.VMRoleGalleryItem?api-version=2013-03" -f $TenantPortalAddress,$Port,$SubscriptionID
$GIReferenceData = [xml](Invoke-WebRequest -Certificate $Cert -Uri $GIReferenceUri | Select-Object -ExpandProperty Content)
$GalleryItemREF = $GIReferenceData.feed.entry.content.properties.resourcedefinitionUrl | ? {$_ -match $GalleryItemName}
# Get Gallery Item Resource Definition
40 The New World of Tenant Provisioning
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
$GIResDEFUri = "https://{0}:{1}/{2}/{3}/?api-version=2013-03" -f $TenantPortalAddress,$Port,$SubscriptionID,$GalleryItemREF
$GIResourceDEFJSON = Invoke-WebRequest -Certificate $Cert -Uri $GIResDEFUri | 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 "DomainController")
{
$GIParamList += @{DomainControllerWindows2012DomainDNSName = $UserID.Split("@")[1]}
$GIParamList += @{DomainControllerWindows2012DomainNETBIOSName = ($UserID.Split("@")[1]).Split(".")[0]}
$GIParamList += @{DomainControllerWindows2012SafeModeAdminPassword = $Password}
}
if ($GalleryItemName -eq "Lync")
{
$GIParamList += @{RunAsDomainToJoin = $UserID.Split("@")[1]}
$GIParamList += @{LyncServer2013RunAsCredential = "{0}\administrator:{1}" -f ($UserID.Split("@")[1]).Split(".")[0],$Password}
}
if ($GalleryItemName -eq "SharePoint")
{
$GIParamList += @{RunAsDomainToJoin = $UserID.Split("@")[1]}
$GIParamList += @{SharePointServer2013RunAsCredential = "{0}\administrator:{1}" -f ($UserID.Split("@")[1]).Split(".")[0],$Password}
$GIParamList += @{SharePointServer2013InstallChoice = $SPInstallChoice}
}
if ($GalleryItemName -eq "Exchange")
{
$GIParamList += @{DomainJoinDomainToJoin = $UserID.Split("@")[1]}
$GIParamList += @{ExchangeServer2013CU2RunAsCredential = "{0}\administrator:{1}" -f ($UserID.Split("@")[1]).Split(".")[0],$Password}
$GIParamList += @{ExchangeServer2013CU2ExchangeServer2013CU2Organization = $ExchangeOrg}
}
# 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]'
$ResDefConfig.Add("Version",$GIVersion)
$ResDefConfig.Add("ParameterValues",$ResDefConfigJSON)
#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
#region GetOrSetCloudService
# Get Cloud Services
$CloudServicesUri = "https://{0}:{1}/{2}/CloudServices?api-version=2013-03" -f $TenantPortalAddress,$Port,$SubscriptionID
$CloudServicesData = [xml](Invoke-WebRequest -Uri $CloudServicesUri -Certificate $Cert | Select-Object -ExpandProperty Content)
$CloudService = $CloudServicesData.feed.entry.content.properties.Name | ? {$_ -match $CloudServiceName}
if (!$CloudService) {
# Set Cloud Service Configuration
$CloudServiceConfig = @{
"Name" = $CloudServiceName
41 The New World of Tenant Provisioning
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
"Label" = $CloudServiceName
}
# Convert Cloud Service Configuration To JSON
$CloudServiceConfigJSON = ConvertTo-Json $CloudServiceConfig
$CloudServicesData = [xml](Invoke-WebRequest -Uri $CloudServicesUri -Certificate $Cert -Method Post -Body $CloudServiceConfigJSON -ContentType "application/json")
$CloudService = $CloudServicesData.entry.content.properties.Name | ? {$_ -match $CloudServiceName}
}
#endregion GetOrSetCloudService
#region DeployGIVMRole
# Set Gallery Item VMRole Deploy URI
$GIDeployUri = "https://{0}:{1}/{2}/CloudServices/{3}/Resources/MicrosoftCompute/VMRoles/?api-version=2013-03" -f $TenantPortalAddress,$Port,$SubscriptionID,$CloudService
# Deploy Gallery Item VMRole
$VMRoleDeployed = Invoke-WebRequest -Uri $GIDeployUri -Certificate $Cert -Method Post -Body $GIPayloadJSON -ContentType "application/json"
$VMRoleDeployed
#endregion DeployGIVMRole
Note(s)



Once again, I have several notes about the above script. So I will list them here:
This is an example script.
It has been tested against our Demo/Test/Dev environment multiple times.
The following section of the script controls the execution, simply modify these
Variables to Deploy the other available VMRoles included within the script:
The logic is all based on the included IF blocks (two per Gallery Item VMRole).



and
It absolutely requires the pre-requisites discussed in Part 3. And while there are
alternatives to getting the required variable data based on the GetWAPackSubscription command, I have found this to be the most
efficient/dynamic method.
The $TenantPortalAddress Variable may need to be set to a specific string,
rather than being extracted from the information available from the GetWAPackSubscription command, specifically if the public portal address is
different than the FQDN of WAP Admin Server.
If you are getting errors during deployment like, “Disk with Name (Windows
Server 2012 Datacenter) and Version (1.0.0.0) not found while translating
Resource Definition for cloud resource.” it is likely that the $OSDisk and/or
42 The New World of Tenant Provisioning





$OSDiskVersion Variables have incorrect data. The Tenant API does not care so
much for the actual OS Disk name, instead, it appears to require the Family
Name of the OS Disk.
I chose to leave all the Variable settings within the script. These could very easily
be presented as Script Parameters, and fed into the script to make it a bit more
generic.
Just like the Service Admin example script, there is a portion of the Resource
Definition Configuration (ResDefConfig) that is tied directly to the
ResDef/ResDefExt for a given Gallery Item VMRole. When generating the Gallery
Item Parameter Hashtable, I have separated the GI specific data from the
common GI data. In most cases (especially for the Gallery Item VMRoles produced
by my team), the only portion of the script that has to change per VMRole is this
GI specific data (and, of course any specific Variable data).
This script (for the Tenant Admin) should look nearly identical to the script from
Part 2 (for the Service Admin). This is by design, as I wanted to keep as many
synergies in play as possible. Remember, there are only subtle differences (Ports
and Auth).
While the steps in the Gallery Item VMRole deployment process will likely remain
the same, the actual script could be improved in various ways: Addition of Script
Parameters, Separated into Functions, Transformed into a Set of Cmdlets, etc. If
anyone takes these improvements on, I will be happy to reference / endorse the
published work here in this document.
Finally, and once again, the script has been broken up into “regions”, each of
which builds on the last, to eventually complete all the data collection /
command execution for the final Invoke-WebRequest POST to deploy the
Gallery Item VMRole. Here is an image illustrating the seven regions:
After the dust settles on back to back executions, you should see something similar to
this in the Tenant Portal:
43 The New World of Tenant Provisioning
Future Discovery: Modified Example PowerShell script to enumerate
ResDef/ResDefExt and ResDefConfig Requirements for any Gallery Item
VMRole
Modified Example PowerShell script for Get-GIResourceParams (as a Tenant Admin
against the Public WAP API)
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
function Get-GIResourceParams {
param
(
[object]$Cert,
[string]$TenantPortalAddress,
[string]$SubscriptionID,
[string]$GalleryItemName
)
# Get Gallery Item Reference
$GIReferenceUri = "https://{0}:30006/{1}/Gallery/GalleryItems/$/MicrosoftCompute.VMRoleGalleryItem?api-version=2013-03" -f $TenantPortalAddress,$SubscriptionID
$GIReferenceData = [xml](Invoke-WebRequest -Uri $GIReferenceUri -Certificate $Cert -UseBasicParsing | Select-Object -ExpandProperty Content)
$GalleryItemREF = $GIReferenceData.feed.entry.content.properties.resourcedefinitionUrl | ? {$_ -match $GalleryItemName}
# Get Gallery Item Resource Definition
$GIResDEFUri = "https://{0}:30006/{1}/{2}/?api-version=2013-03" -f $TenantPortalAddress,$SubscriptionID,$GalleryItemREF
$GIResourceDEFJSON = Invoke-WebRequest -Uri $GIResDEFUri -Certificate $Cert -UseBasicParsing | Select-Object -ExpandProperty Content
$ResDef = ConvertFrom-Json $GIResourceDEFJSON
Return $ResDef.ResourceParameters.Name
}
$WAPSubscription = Get-WAPackSubscription
$CertThumb = $WAPSubscription.Certificate.Thumbprint
$CertPath = "Cert:\CurrentUser\My\{0}" -f $CertThumb
$Cert = Get-Item $CertPath
$TenantPortalAddress = $WAPSubscription.ServiceEndpoint.Host
$SubscriptionID = $WAPSubscription.SubscriptionId
$GalleryItems = @("DomainController","Lync","SharePoint","Exchange")
$GIandResourceParams = @{}
foreach ($GalleryItem in $GalleryItems)
{
$GIResourceParams = Get-GIResourceParams -Cert $Cert -TenantPortalAddress $TenantPortalAddress `
-SubscriptionID $SubscriptionID -GalleryItemName $GalleryItem
$GIandResourceParams += @{$GalleryItem = $GIResourceParams}
}
$GIandResourceParams
Note This is essentially a copy/paste of the Service Admin script, with modifications
to work against the Public WAP Tenant API. The major updates: URL port (changed
from 30005 to 30006); and Authorization method (changed from Header with bearer
token to Certificate).
And once again, the output of this script is:
44 The New World of Tenant Provisioning
Use Cases
But wait, WHY would I want to do this?
Here are some use cases (from both the Service Admin and Tenant Admin personas):




Use Case 1: As a Tenant – Simple avoidance of manual clicking to deploy
Gallery Item VMRoles
Use Case 2: As a Tenant – Develop scripts to fully deploy a set of multiple
concurrent (and/or dependent) Gallery Item VMRole Deployments (with
scripts like this, you have complete control over the “what” and “when”)
Use Case 3: As a Service Provider (or Enterprise acting like one) – Create a
custom set of cmdlets encapsulating the parameters and logic into easily
consumable/executable commands
Use Case 4: As a Service Provider (or Enterprise acting like one) – Enabling
your Tenants/End Users to automate their own Gallery Item VMRole
deployments (external to any SMA efforts on the Service Admin side)
45 The New World of Tenant Provisioning
Appendix
The following are the links referenced throughout this document as well as links related
directly to the content:
Links Referenced within the Document

Building Clouds Blog: http://aka.ms/BuildingClouds

Windows Azure Pack Tenant Provisioning Automation Toolkit TechNet Gallery
Contribution: http://gallery.technet.microsoft.com/Windows-Azure-PackTenant-3e8afd64

VMNetworks Collection API Documentation on MSDN:
http://msdn.microsoft.com/en-us/library/dn765986.aspx

Automation–PowerShell Workflow Script Spotlight–Deploying Virtual Machine
Manager Service Templates “OnBehalfOf” Tenant Administrator User Roles:
http://blogs.technet.com/b/privatecloud/archive/2013/10/24/automationpowershell-workflow-script-spotlight-deploying-virtual-machine-managerservice-templates-onbehalfof-tenant-administrator-user-roles.aspx

Automation–PowerShell Workflow Script Spotlight–Creation and
Parameterization of Virtual Machine Manager Run As Accounts for “OnBehalfOf”
Service Template Deployment:
http://blogs.technet.com/b/privatecloud/archive/2013/10/30/automationpowershell-workflow-script-spotlight-creation-and-parameterization-of-virtualmachine-manager-run-as-accounts-for-onbehalfof-service-templatedeployment.aspx

SMART for Runbook Import and Export:
http://blogs.technet.com/b/privatecloud/archive/2013/10/23/automationservice-management-automation-sma-runbook-toolkit-spotlight-smart-forrunbook-import-and-export.aspx

Automation–Monitoring and Notifying in Windows Azure Pack with SMA:
http://blogs.technet.com/b/privatecloud/archive/2014/01/30/automationmonitoring-and-notifying-in-windows-azure-pack-with-sma.aspx

Bearer Token Bing Search:
http://www.bing.com/search?q=bearer+token+authorization&qs=n&form=QB
RE&pq=bearer+token+authorization

TechNet Documentation about Get-MgmtSvcToken:
http://technet.microsoft.com/en-us/library/dn520915(v=sc.20).aspx

Using automation with Virtual Machine Clouds: http://technet.microsoft.com/enus/library/dn457800.aspx

VMRoles Tenant Service Documentation on MSDN:
http://msdn.microsoft.com/en-us/library/dn502556.aspx
46 The New World of Tenant Provisioning

TechNet Documentation about Add-CloudResource:
http://technet.microsoft.com/en-us/library/dn472838(v=sc.20).aspx

Automation–Automating Hybrid Clouds with Windows Azure and PowerShell
(Part 2): Public Cloud Environment Provisioning PowerShell Examples:
http://blogs.technet.com/b/privatecloud/archive/2013/11/19/automationautomating-hybrid-clouds-with-windows-azure-and-powershell-part-2-publiccloud-environment-provisioning-powershell-examples.aspx

How to install and configure Azure PowerShell:
http://www.windowsazure.com/en-us/documentation/articles/install-configurepowershell/

Microsoft Azure CMD Line Tools: http://www.windowsazure.com/enus/downloads/#cmd-line-tools

Windows Azure Pack VMRole Gallery Items for Collaboration Workloads:
http://blogs.technet.com/b/privatecloud/archive/2013/12/11/building-cloudsblog-windows-azure-pack-vmrole-gallery-items.aspx
Links from the Related Blog Series
Automation–The New World of Tenant Provisioning with Windows Azure Pack

Part 1: Intro & TOC

Part 2: Automated Deployment of Tenant Network and Identity Workload
(Isolated Tenant Virtual Network & Active Directory VMRole; from the Service
Admin Persona)

Part 3: Automated Deployment of the Identity Workload as a Tenant Admin
(Active Directory VMRole; from the Tenant Admin Persona)

Part 4: Automated Deployment of Tenant Workloads (Lync, SharePoint, and
Exchange) (Lync, SharePoint, and Exchange VMRoles; from both Service Admin
and Tenant Admin Personas)

Part 5: Working with the SQL Server resource provider, and the ITIL dilemma
(by Bruno Saille)
Links to Other Related and Valuable Content

Windows Azure Pack–Gallery Item VMRole–References for Creation,
Configuration, and Automation:
http://blogs.technet.com/b/privatecloud/archive/2014/03/11/windows-azurepack-gallery-item-vm-role-resources-for-creation-configuration-andautomation.aspx

8-Minute-Demo: Automated Tenant Provisioning Video:
http://www.youtube.com/watch?v=xZIgPAyyg7E
47 The New World of Tenant Provisioning
Download