Deploy Azure RemoteApp with VNET using PowerShell

Server Hero Network Cable Port
In this article, I will show you how you can speed up and automate the deployment of Azure RemoteApp, Microsoft’s managed Remote Desktop Services farm in the cloud, using PowerShell. I will also share how you can use PowerShell to publish applications in the app collection and assign users access to those applications.

RemoteApp Recap

I have written quite a few articles over the last year or so about Azure RemoteApp. In summary, RemoteApp allows you to present desktop applications to users as publish applications without the desktop to RDS clients:

  • Windows
  • Android
  • iOS
  • Mac
  • Windows “Phone”

If you wanted to build an RDS farm in Azure from virtual machines, then you’d need to start with RDS CALs acquired via:

  • Volume licensing with Software Assurance or
  • The hosting/leasing SPLA-R program

And then you’d need to build a complex infrastructure with load balanced SSL gateways, connection broker, and all that mess.
RemoteApp makes it easy:

  1. You supply it with a Sysprep-ed image for your new session hosts (terminal servers).
  2. Deploy an app collection with optional domain membership and Azure virtual network connectivity.
  3. RemoteApp deploys all the rest of the RDS infrastructure, including the session hosts.
  4. You assign users and publish apps from the session hosts.
  5. Azure bills you, per user, for using RemoteApp, with no RDS licensing required.

An overview of Azure RemoteApp [Image Credit: Microsoft]
An overview of Azure RemoteApp [Image Credit: Microsoft]
As you can see, there’s quite a bit of clicking involved in setting up RemoteApp. One of the scenarios that I recommend RemoteApp for is disaster recovery. In the event of a failover, RemoteApp can be used to grant users rapid access to their desktop applications with high performance and easy access to the services and data in the failed over virtual machines. But here’s the rub: You don’t want RemoteApp running all of the time because you’ll be charged a minimum rate per month for the app collection:

  • A minimum rate per assigned user per month
  • 5 or 20 users per month (depending on the plan), even if there are no users assigned

Ideally, you only want to create the app collection and assign users at the time of failover. Do you want to be clicking through lots of wizards then? Probably not, so my solution is to use PowerShell.
Note that in this example, a Sysprep-ed image is already imported into RemoteApp and the necessary Active Directory (Azure AD, service account, and organizational unit) elements have been deployed.

Deploying a RemoteApp App Collection

I’ve never had a real scenario where I’ve deployed the “cloud” model of RemoteApp; I’ve always deployed RemoteApp with a VNet and domain join. The first line will prompt you to enter a the user name and password for joining the new session hosts to your domain.
$cred=Get-Credential -Message “Please enter the details of the domain join account”

The following line will deploy a new app collection. Note the following variables:

  • $cred: The saved domain-join credentials
  • $CollectionName: The desired name of the new RemoteApp app collection
  • $CollectionDescription: The desired description of the new RemoteApp app collection
  • $ImageName: The image that you previously imported into RemoteApp for building new session hosts
  • $Plan: The tier of RemoteApp, affecting pricing and performance
  • $VNETName: The name of the VNet that the session hosts will be connected to. Remember that the DNS servers of the VNet must be able to resolve to your domain controllers and the domain must be available on this network.
  • $SubnetName: The name of the subnet in the VNet that will be used by the app collection
  • $DomainName: The name of the domain, for example “joeelway.com”
  • $DomainOU: The OU that you want the session hosts’ computer accounts to be created in, for example, “OU=RemoteApp, DC=joeelway, DC=com”. The user that you specified in $cred must have “create computer” and “delete computer” rights in this OU.

$Result = New-AzureRemoteAppCollection -Credential $cred -Collectionname $CollectionName -Description $CollectionDescription -ImageName $ImageName -Plan $Plan -VNetName $VNETName -SubnetName $SubnetName –Domain $DomainName -OrganizationalUnit $DomainOU
The above line does the equivalent of a lot of clicking in the Azure management portal. A job is created to create the app collection and the session hosts. My example stores details of that job in $Result. You can track progress of the job in the management portal, but I found that the portal can take a long time to report success (or failure) after a job has completed. I can use $result with PowerShell to track the job:
Get-AzureRemoteAppOperationResult –TrackingId $result.Tracking
In my deployments, I’ve seen a deployment complete in less than 30 minutes, but the UI continues to say that the job is still running (for up to one hour).

ResultsOfRunningTheScript
Tracking the result of New-AzureRemoteAppCollection [Image Credit: Aidan Finn]

Publishing Applications

The new session hosts will contain programs (installed in the original image that you captured and then imported into RemoteApp) that can be published. The next line of PowerShell will publish one such application, using some variables:

  • $CollectionName: The name of the previously created RemoteApp app collection
  • $ProgramName: The name that you want to give the published application, for example, “Notepad”
  • $ProgramPath: The path to the program file in the session host, for example, “C:\Windows\Notepad.exe”

Publish-AzureRemoteAppProgram -CollectionName $CollectionName -DisplayName $ProgramName -FileVirtualPath $ProgramPath

Assigning Users

You can grant users access to a RemoteApp app collection using their accounts in Azure AD. In the domain join example, use domain integration (such as Azure AD Connect). The next line of PowerShell will grant a single user access to the app collection and thus, access to all applications in the collection. The following variables are used:

  • $CollectionName: The name of the previously created RemoteApp app collection
  • $UserName: The UPN of the user being granted access to the app collection, for example, “[email protected]

Add-AzureRemoteAppUser -CollectionName $CollectionName -Type OrgId -UserUpn $UserName

Now you have the 3 key cmdlets for automating the deployment of RemoteApp. You can wrap these lines up in logic to have an end-to-end deployment script, or even convert it into an Azure Automation runbook that could be used by an Azure Site Recovery (ASR, Azure’s DR solution) recovery plan (orchestrated failover).