Edit

Application installation by using a RemoteApp virtual machine

Use the Virtual Machine service catalog template to install and configure an application on a RemoteApp virtual machine.

The application installation scripting supports the following scenarios:

  • The most common use case for RemoteApp application installation is to deploy remote applications that you can access from an Azure Virtual Desktop.
  • Install your prerequisites such as cyber security and monitoring agents.
  • Script configuration changes for compliance or application setup.

Note

This sample deployment is just for demo purposes and doesn't represent all the best practices for network, systems, or applications administration.

Prerequisites

The RemoteApp template supports scripting to automate the process of installing applications and configuring the Virtual Machine. Before you can start using the RemoteApp app installation, you need to make sure you have:

Note

If the storage account is in a different enclave, create an enclave endpoint in the enclave with the storage account. Then create an enclave connection between that storage account enclave and the enclave where you're installing the application.

Azure Resources Deployed

  • RemoteApp example Virtual Machine
    • Disk
    • Windows Virtual Machine
    • Windows Virtual Machine Extension

Software Deployed

  • Windows
  • Application of your choice

Deploy the template

Prepare application files

  1. Add app folder to container within storage account. Diagram showing method of installation within the same enclave. Diagram showing method of installation outside enclave that contains the storage account.
    • File structure:
          - artifacts container
              - app folder
                  - app installer
                  - main script to install app
                  - (optional) additional scripts
                  - (optional) azcopy.exe
      
  2. Download the application installer you need. In this example, download Visual Studio Code and upload the installer into the storage account app folder.
  3. Upload the main.ps1 application installer script compatible with the version of Visual Studio Code you added to the storage account app folder:
        # Main PowerShell script that installs the application
    
        Start-Process 'C:\vscode\VSCodeSetup-x64-<version>.exe' -ArgumentList '/VERYSILENT /MERGETASKS=!runcode'
    

Configure the template

  1. On the workload overview page, select +Add an Azure Service.

Screenshot showing workload overview page.

  1. For Service, select Virtual Machine.

Screenshot showing Virtual Machine selected from the service catalog list.

  1. Confirm the resource group selection, and then select Next.

  2. Basics Tab:

    • For Virtual Machine name, input the name of the Virtual Machine.
    • For Admin username and Admin password, enter the username and password you use to sign in to your virtual machine.
  3. App Tab:

    • For App folder URI, enter the URI to the container. Select an artifact within the container, copy its URI, and remove everything after the folder name in the URI. Screenshot showing the application folder URI for use in this deployment.

      Original URI Fixed URI
      https://<storage-account>.blob.core.windows.net/<container-name>/<folder-name>/<script>.ps1 https://<storage-account>.blob.core.windows.net/<container-name>/<folder-name>
    • Example:

      • storageaccountexample.blob.core.windows.net/artifacts/vscode
    • For Main Script, enter the name (for example, main.ps1) of the script that installs the application.

    Screenshot showing the App tab during a Virtual Machine deployment.

Private Container:

  1. For App folder in private container, select true to grant the virtual machine identity container-level Storage Blob Data Reader access.

  2. For Storage container resource id, combine these three parts: <storage-account-resource-id> + /blobServices/default/containers/ + <container-name>.

    • To get Storage container resource id, from the storage account, select Overview, select JSON View in the far right corner, and copy the storage account resource ID.

    Screenshot of account resource id for use in this deployment.

    • For the container name, copy the name of the private container that holds the artifacts.
    • Example storage container resource ID: /subscriptions/000000a0-a0a0-000a-00a0-0000aaa0a000/resourceGroups/resource-group-example/providers/Microsoft.Storage/storageAccounts/storage-account-example/blobServices/default/containers/container-name
  3. If the parameter AzCopy File URI is displayed, enter the URI to azcopy.exe from the container.

    • Select the file, and copy its URL:

    Screenshot showing storage container organization structure with azcopy.exe file.

    Screenshot showing the URI for the azcopy.exe file.

Example Private Container Parameters:

Screenshot showing the App tab parameters completed.

  1. Select Review and Create. If validation passes, select Create.
  2. Once resources are deployed, check to see if app is installed on application Virtual Machine by connecting to the Application Virtual Machine. Connect to the Application Virtual Machine

Install WinGet and additional applications

Folder structure:

- artifacts container
    - WinGet app folder ('winget')
        - WinGet installer ('Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle')
        - Windows UI Library ('Microsoft.UI.Xaml.2.8.x64.appx')
        - main script to schedule install ('main.ps1')
        - script to install and schedule reboot ('install_winget.ps1')
        - script to restart the virtual machine ('restart.ps1')

Screenshot showing the artifacts needed to install winget onto the RemoteApp to then install and manage other applications using winget.

  1. Download installers and upload them to the winget folder in storage container
  2. Create and upload scripts
    1. main.ps1
      # This script creates and runs a scheduled task to install the appx package and msix bundle with elevated privileges
      
      $installScriptPath = "C:\winget\install_winget.ps1"
      
      # Create a scheduled task action to run the installation script with elevated permissions
      $taskAction = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-ExecutionPolicy Bypass -File $installScriptPath"
      
      # Set the task to start 30 seconds from now
      $taskTrigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddSeconds(30)
      $taskPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
      
      # Register the scheduled task
      Register-ScheduledTask -TaskName "InstallWinget" -Action $taskAction -Trigger $taskTrigger -Principal $taskPrincipal
      
    2. install_winget.ps1
      Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
      
      Start-Process -FilePath "DISM.exe" -ArgumentList "/Online /Add-ProvisionedAppxPackage /PackagePath:C:\winget\Microsoft.UI.Xaml.2.8.x64.appx /SkipLicense" -NoNewWindow -Wait
      Start-Process -FilePath "DISM.exe" -ArgumentList "/Online /Add-ProvisionedAppxPackage /PackagePath:C:\winget\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle /SkipLicense" -NoNewWindow -Wait
      
      $wingetDir = 'C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.23.1791.0_x64__8wekyb3d8bbwe'
      $currentPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine)
      [System.Environment]::SetEnvironmentVariable("Path", "$currentPath;$wingetDir", [System.EnvironmentVariableTarget]::Machine)
      
      # Schedule the restart script
      $rebootScriptPath = "C:\winget\restart.ps1"
      $taskAction = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-ExecutionPolicy Bypass -File $rebootScriptPath"
      
      # Set the task to start 30 seconds from now
      $taskTrigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddSeconds(30))
      $taskPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
      
      # Register the scheduled task
      Register-ScheduledTask -TaskName "Reboot" -Action $taskAction -Trigger $taskTrigger -Principal $taskPrincipal
      
    3. restart.ps1
      Restart-Computer -Force
      
  3. Proceed to Configure the template.