Desktop and Application Streaming

Create a PowerShell-Based dynamic app provider in Amazon AppStream 2.0

The Amazon AppStream 2.0 dynamic application framework provides API operations within an AppStream 2.0 streaming instance that you can use to build a dynamic app provider. Dynamic app providers use these API operations to modify the catalog of applications that your users can access in real time. For example, you can add applications to the catalog based on Active Directory domain group membership, or other business logic. AppStream 2.0 uses Apache Thrift to define the inter-process messages used in the API.

Apache Thrift lets you build clients and servers by defining the data types and service interfaces in a simple definition file. You can use those definitions to generate code files in any number of programing languages.

This post describes how to create .NET dynamic-link libraries (DLLs) from the AppStream 2.0 dynamic application framework Thrift definition files. After you create the DLLs, you can use it with a PowerShell dynamic application framework client script.

*** Updated 9/26/2023 by Justin Grego to support latest version of Thrift (v0.19.0 as of writing). ***

Time to read 10 minutes
Time to complete 2 hours
Cost to complete (estimated) $0
Learning level Expert (400)
Services used Amazon AppStream 2.0

Walkthrough

This post shows you how to perform the following tasks:

  1. Download the Apache Thrift compiler and prepare the AppStream 2.0 Thrift definition files.
  2. Generate the Microsoft .NET Standard code files from the Thrift definition files.
  3. Create a new Visual Studio project with the .NET code files.
  4. Compile the dynamic application framework .NET DLLs.
  5. Use the .NET DLLs with the example PowerShell dynamic application framework client script.

Step 1: Download the Apache Thrift compiler and prepare the AppStream 2.0 Thrift definition files

Go to https://thrift.apache.org/download and download the latest version of the Thrift compiler.

After you download the Thrift compiler, create the AppStreamServer.thrift definition file in the same directory where you downloaded the Thrift compiler. The syntax the thrift definition file can be found in the AppStream 2.0 Administration Guide under Dynamic Application Framework Thrift Definitions and Named Pipe Name.

Step 2: Generate .NET Standard code files from the Thrift definitions

With the compiler downloaded and the Thrift definition files created, we can now generate the .NET Standard code files we will need to compile our DLLs.

From a Command or PowerShell prompt run the following:

thrift-<version>.exe -r --gen netstd AppStreamServer.thrift

That command will output a gen-netstd directory in the same folder as your definition files.

In the Model sub-folder (gen-netstd→AppStream→ApplicationCatalogService→Model) there should be the following .NET Standard code files:

Step 3: Create a new Visual Studio project with the generated .NET Standard code files

Now that you have the necessary code files, you can begin compiling your DLLs. Although this post shows you how to use Visual Studio 2022, any recent version of Visual Studio should work.

  1. Open Visual Studio, and if prompted with a launch the wizard, choose Continue without code.
  2. Choose FileNew, then Project from Existing Code.
  3. Within the Create New Project from Existing Code Files wizard, for What type of project would you like to create, select C#. Choose Next.
  4. On the Specify Project Details page, do the following:
    • For Where are the files?, choose and browse to the location of the .NET Standard files that were just generated (gen-netstd folder). Keep Include subfolders checked.
    • For Name, type AS2DAF as the name for your project.
    • For Output type, choose Class Library.
  1. Choose Finish.
  2. In Solution Explorer, right-click your solution (AS2DAF) and choose Properties.
  3. On the Application tab, for Target framework, select .Net Framework 4.8 or higher. The list of options may different depending on the versions of the .Net Framework installed on your system.
  4. If prompted for the Target Framework Change, choose Yes.

Now it’s time to add the Thrift .NET library to your project solution. This post shows you how to use NuGet, a Visual Studio extension for package management, to do so.

  1. In Solution Explorer, right-click your solution (AS2DAF) and choose Manage NuGet Packages.
  2. On the Browse tab, in the search box, type thrift. In the results list, select ApacheThrift (by Apache Thrift Developers).
  3. Choose Install, then on the Preview Changes page choose OK.
  4. If prompted with a License Acceptance, choose I Accept to continue the installation.

Step 4: Compile the dynamic application framework .NET DLLs

You’re now ready to compile the DLLs.

  1. On the top toolbar, choose Build.
  2. Choose Build solution.
  3. If the build is successful, several new folders and files will appear inside your gen-netstd folder from step 2.
  4. Browse into the gen-netstd→bin→Debug folder.

  1. Rename the file ClassLibrary.dll to AS2DAF.dll.
  2. Copy the AS2DAF.dll and Thrift.dll files to a folder on your AppStream 2.0 image builder. These files are referenced by the PowerShell script in the next step.

Step 5: Use the .NET DLLs with an example PowerShell dynamic application framework client script

The following PowerShell script is a simple dynamic application framework client. This client takes in application data from a CSV that was separately generated and adds them to the AppStream 2.0 application catalog that is displayed to the user.

For a complete list of the dynamic application framework API actions that you can use, see API Actions for Managing App Entitlement for AppStream 2.0.

This PowerShell script and compiled DLLs require that PowerShell version 7.x or above is installed on your AppStream 2.0 image builder and included in the image assigned to your fleet. By default, Windows Server 2016 and Windows Server 2019 have a previous version of PowerShell installed.

Add-Type -Path C:\Path\To\AS2DAF.dll #Define the full path to the DAF DLL
Add-Type -Path C:\Path\To\Thrift.dll #Define the full path to the Thrift DLL

$csvpath = "<Path to CSV>" #Define the CSV path

#Logging Function
Function Write-Log {
    Param ([string]$message)
    $stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
    $logoutput = "$stamp $message"
    Add-content $logfile -value $logoutput
}

#Create Log file
$currentuser = (Get-CimInstance -ClassName Win32_ComputerSystem).UserName.Split('\')[1]
$logfile = "C:\Users\$currentuser\Documents\Logs\DAFClient\$currentuser-$(get-date -f MM-dd-yyyy_HH_mm_ss)-dafupdate.log"
New-Item -path $logfile -ItemType File -Force | Out-Null


#If the CSV does not exist, exit the script
if (!(Test-Path -Path $csvpath)) {
    Write-Log "No application catalog update file. Exiting..."
    Exit
}

#Establish a connection to the Thirft server, exposed via Named Pipes
Write-Log "Opening connection to AS2 Thrift server..."
$token =  New-Object -TypeName System.Threading.CancellationToken
$transport = New-Object Thrift.Transport.Client.TNamedPipeTransport("D56C0258-2173-48D5-B0E6-1EC85AC67893", (New-Object Thrift.TConfiguration))
$protocol = New-Object -TypeName Thrift.Protocol.TBinaryProtocol($transport)
$thriftclient = New-Object -TypeName AppStream.ApplicationCatalogService.Model.ApplicationCatalogService+Client($protocol)
$task = $transport.OpenAsync($token)

#Wait up to 10 seconds for connection to complete
$count = 0
While ((-not $task.IsCompleted) -and ($count -lt 1000)) {
    Start-Sleep -Milliseconds 10
    $count = $count + 10
}

Write-Log "Connected..."

#Get the current user's SID
$usersid = (New-Object System.Security.Principal.NTAccount(($currentuser))).Translate([System.Security.Principal.SecurityIdentifier]).value

Write-Log "Getting applist for $currentuser, SID: $usersid..."

#Get the content of the CSV and add each application to dynamic application catalog 
foreach ($app in (Import-Csv -path $csvpath)) {

    $appId = $app.Id
    $appdname = $app.DisplayName
    $apppath = $app.LaunchPath
    $appicon = $app.IconData

    Write-Log "Adding $appdname to the dynamic application catalog..."

    $applist = New-Object -TypeName AppStream.ApplicationCatalogService.Model.Application("$appId", "$appdname", "$apppath", "$appicon") 
    $getappreq = New-Object -TypeName Appstream.ApplicationCatalogService.Model.AddApplicationsRequest($usersid, $applist)
    $task = $thriftclient.AddApplications($getappreq)

    # Wait up to 10 seconds for asynchronous task to complete
    $count = 0
    While ((-not $task.IsCompleted) -and ($count -lt 1000)) {
        Start-Sleep -Milliseconds 10
        $count = $count + 10
    }
}

#Close the connection to the Thrift server
Write-Log "Closing connection..."
$transport.close()

Exit

For a successful connection to the Thrift server to occur, this client script must be run in the SYSTEM context. Use a Windows Scheduled Task or the AppStream 2.0 Session Scripts feature. Ensure the task is configured to use the PowerShell 7.x or above executable and not the older system default version.

Regardless of the method, the script should be triggered at the login (or session start) of the user. This ensures that the user sees any dynamically provided apps shortly after login to their AppStream 2.0 instance.

The CSV file that the client reads contains the following information for each application:

  • An ID number.
  • The application name.
  • The full path to the executable file (can be on– or off-instance).
  • The icon image (in base64). Images can be converted to base64 with PowerShell by using the .NET method Convert.ToBase64String.

$icondata = [convert]::ToBase64String((get-content "Path\to\image.png" -Encoding byte))

In a production deployment of the dynamic application framework client, you would dynamically generate the CSV file. You would do so based on your users’ application entitlements as determined by your business logic. However, while testing your client script, use a static CSV with application metadata to validate that the script works as expected.

NOTE: Before testing, you will need to enable dynamic app providers in Image Assistant on the AppStream 2.0 image builder. For more information, see Enable and Test Dynamic App Providers in the AppStream 2.0 documentation.

After you have validated the script adds applications from the CSV successfully, you must add or create the business logic for generating the application entitlements and metadata to be added to the AppStream 2.0 catalog. Examples of building this logic can be found in the blogs Active Directory Group Membership Based AppStream 2.0 Application Targeting and Bring your App-V packages to AppStream 2.0 with the dynamic application framework.

Conclusion

You now have the .NET DLLs required for a dynamic application framework client PowerShell script. You also have an example dynamic application framework client PowerShell script that you can use to develop your client script.