Using PowerShell to Install an SDK in a DevOps Build Pipeline

I have an open source UWP project that relies on the Ad SDK and Engagement SDK to be installed to Visual Studio. This normally isn’t a problem, because you can just run the MSI on your PC (see installation instructions here and here).

I decided to move the project into DevOps so that I get some of that CI/CD goodness to build and publish new releases automatically to the Microsoft Store. However, there was a problem, when trying to build the project in a DevOps build pipeline, you’ll get the following error:

This means that the Hosted VS2017 Agent that DevOps uses to build a UWP project doesn’t have the Extensions SDKs installed. I have two choices to move forward:

  • Use a private Agent (this uses your local PC to build the project via a server connection )
  • Find a way to install the SDK into the Hosted agent

I did try the first option. I set up the Windows Agent on my Surface Book, connected it to DevOps and it works nicely (this is why you see that early successful build early in the first screenshot above). However, it’s not a solution for me because it means my PC has to be always on and network-connected.

My friend, and MVP peer, Oren Novotny mentioned that you can actually use a PowerShell script to download the MSI file and install it to the Hosted VS2017, this was the break I was looking for!

To implement this, I downloaded the MSI files I needed from the Visual Studio Marketplace and put them into an Azure Blob. It provides me with two reliable URLs to download the files in the PowerShell script.

Next, I wrote the very simple script. It has two phases: a download phase and an install phase (with a quiet switch “/q”). Here’s what that looks like:

# Predefined Variables
$adSdkUrl = "https://dvlup.blob.core.windows.net/general-app-files/MSIs/MicrosoftAdvertisingSDK.msi"
 $servicesSdkUrl = "https://dvlup.blob.core.windows.net/general-app-files/MSIs/MicrosoftStoreServicesSDK.msi"
 $adSdkPath = Join-Path $env:TEMP "MicrosoftAdvertisingSDK.msi"
 $servicesSdkPath = Join-Path $env:TEMP "MicrosoftStoreServicesSDK.msi"

# Download the files to local temp folder
 Write-Output "downloading $adSdkUrl…"
 Invoke-WebRequest -Uri $adSdkUrl -OutFile $adSDKPath
 Write-Output "downloading $servicesSdkUrl…"
 Invoke-WebRequest -Uri $servicesSdkUrl -OutFile $servicesSdkPath

# Install the SDKs (use the "qn" flag to install silently)
 Write-Output "installing $adSdkPath…"
 Start-Process $adSdkPath -ArgumentList "/q" -Wait
 Write-Output "installing $servicesSdkPath…"
 Start-Process $servicesSdkPath -ArgumentList "/q" -Wait

Next, you need to add a Powershell step to your DevOps Build pipeline and paste in the script. Here’s a screenshot to help guide you:

Now, when the build is triggered, it will download and install the missing SDKs before building the project! Here’s the result of that build step in the Hosted agent’s console:

I hope this post finds you as soon as you need help. It took me several days, a dozen different documentation articles (some are hyperlinked above) and my MVP peers to find a good simple solution that didn’t require my PC .

LoginDialog for easy Live SDK OAuth

Almost every developer I speak with agrees that getting a nicely working OAuth flow can be difficult. After much trial and error, I’ve built a UWP ContentDialog that makes this easy and has built-in refresh token support.

Using the LoginDialog

This is very simple to use, when the app launches, instantiate the dialog by passing your Live SDK ClientID and let the LoginDialog do the heavy lifting:

// Pass your app's OAuth ClientId (sometimes called an AppId)
var loginDialog = new LoginDialog("YourAppClientId");

// *** Perform login **** //
// Case 1 - If the user was previously signed in, there is a refresh_token stored and no user-entered credentials are needed.
// Case 2 - If the access token fails, or if it's the first sign-in, the user will see a popup to enter credentials.
await loginDialog.SignInAsync();

if(!string.IsNullOrEmpty(loginDialog.Authentication))
{
    // This will be the access token you can use for API calls.
    var accessToken = loginDialog.Authentication;

    // Make your API calls with the accessToken, for example:
    var user = await apiService.GetUSerProfileAsync(accessToken);
}

This works just like a MessageDialog, but instead will show a WebView for the user to sign in, or automatically sign them in silently if they were previously logged in.

Get the full source code in this GitHub Gist.

See this tweet for a video of what it looks like when it automatically logs you in and here’s a screenshot what it looks like when the dialog needs to appear:

Dialog Visible

Operational Summary

Explaining OAuth 2.0 is outside the scope of this article, but to summarize there are a couple round trip to the authentication endpoints.

  1. Load the sign-in landing page and the user signs in with their credentials.
  2. In the redirect after successful sign-in, you’ll get an access_token and a refresh_token for that authenticated user.

The access_token is what is used in all of your API calls that verifies the application is operating on the behalf of that user. The access_token expires after a preset amount of time (e.g. 60 minutes), after which time you have to request another access_token.

Here is where the refresh_token comes in handy. You could go back to step #1 above, but this would require the user re-enter their credentials. Instead, you can just use the refresh_token  you already have for the user to get a new access_token without ever interrupting them to show a WebView.

This is what the LoginDialog does for you, when you call SignInAsync() the following happens:

  • Checks to see if there is a refresh_token stored locally. If there isn’t one, show the WebView and have the user sign in for the first time.
  • If there is a refresh_token stored locally, then use that to automatically get a new access_token without showing the dialog

Since this is general OAuth 2.0 workflow, you could probably adapt the dialog to work for other OAuth 2 endpoints by changing the dialog’s _signInUri, _signOutUri and _redirectUrl values.

Wrapping Up

The LoginDialog lets you have the least amount of interruption to the user while quickly getting an access token for your API use.

The RS5 Update Resources and Tutorials

My friends at Microsoft have put together an amazing compilation of resources of all the new stuff available in the Windows 10 October 2018 Update (aka RS5). Below is a list of some of those resources relevant to developers and enthusiasts, enjoy!

SDK Downloads

New Samples and Sample Updates

  • XAML Hosting API Sample uses the new XAML hosting API and C++/WinRT to demonstrate usage of XAML controls within a Win32 application.
  • Customer Orders Database Sample has been updated to use the new Data Grid and other new controls in RS5.
  • Photo Editor C++/WinRT Sample has been updated to build with the RS5 SDK and to use the new single_threaded_observable_vector function to create an IObservableVector for data binding. An additional performance update will be coming out in a couple weeks.
  • Data binding and MVVM is a new topic that was identified as a need based on the Code First program. The topic describes the benefits of using the MVVM design pattern and how it has been applied to the sample apps.

Videos

Application Developer Resources

Driver Developer Resources

Creating 3D Icons for your Mixed Reality UWP app

Microsoft has opened up the ability to have a 3D app launcher to all developers in the Fall Creator’s Update. In this blog post, I’m going to show you how to build your own 3D app launcher from scratch (accompanying YouTube tutorial video embedded below).

What is a 3D app launcher?

App Launchers

Up until now, you’ve only been able to have a regular 2D tile in the Start menu and the user could place a 2D frame of your app on a surface in the Cliff House (the Mixed Reality home) or on a surface in your HoloLens mapped area. Clicking the app frame would launch the app in the same frame.

If your app was a 3D app, then it would launch the immersive experience, but the launcher was just a 2D . The user wouldn’t be able to intuitively know that the application is an immersive app. There are some apps that have 3D launchers, for example the HoloTour app that you see in this article’s featured headline image.

Wouldn’t it be nice if your immersive application had a 3D launcher, too? By the end of this blog post, you’ll be able to! To get started, let’s take a look at the model and how to build one yourself.

The Model

First thing you’ll need to understand is that Microsoft requires your model to use gITF 2.0 specification and more specifically, the binary format (.glb). To accomplish this, we are going to use Blender.

Blender is a modeling and animation application that is open source and free. You can choose to build your model directly in Blender if you’re familiar with it. Alternatively, build the model in another application but use the Blender gITF Exporter add-on, which is what I’ll show you today.

NOTE: If you already have an FBX model, jump to the Importing a Model section below

Building The Model From Scratch

To keep this tutorial simple, I’ll create a simple UVSphere in Blender and use a solid color texture. Creating complex models in Blender is a bit out of the scope of this post, however I cover doing it from scratch in this video (if the video doesn’t load, here’s the direct link).

Just be sure to read the next section, even if you followed the video, so that you’re familiar with the restrictions you’ll inevitability encounter while trying to use different models.

Importing a Model

Alternatively, you can import other model types, like FBX, into Blender. This is easy, as FBX importing is available out-of-the-box .Take following steps once you’ve opened Blender

  1. Select File
  2. Expand Import
  3. Select FBX
  4. Locate and load the file

One thing you’re going to notice is that model may not be visible in your area, it’s far too large and off center. To get it in your view, you can use the “View All” shortcut (Home key) or drill into the menu “View > View All” (this menu is underneath the 3D view area). Here’s a screenshot:

Now, look in the Outliner panel (located at the top right of Blender) and find the object named “root” this is the imported model. Then, to get the right editing options, select the Object properties button (see the red arrow in this screenshot).

Outliner and Object properties editor

Take note of the highlighted Transform properties, we’ll change those next. However, before we do, let’s review some of the guidelines Microsoft has set for 3D app launchers:

  1. The Up axis should be set to “Y”.
  2. The asset should face “forward” towards the positive Z axis.
  3. All assets should be built on the ground plane at the scene origin (0,0,0)
  4. Working Units should be set to meters and assets so that assets can be authored at world scale
  5. All meshes do not need to be combined but it is recommended if you are targeting resource constrained devices
  6. All meshes should share 1 material, with only 1 texture sheet being used for the whole asset
  7. UVs must be laid out in a square arrangement in the 0-1 space. Avoid tiling textures although they are permitted.
  8. Multi-UVs are not supported
  9. Double sided materials are not supported

With these in mind, let’s start editing our mesh, under the Transform section, take the following actions:

  1. Set Location to 0,0,0
  2. Set Scale to 1,1,1
  3. Now, lets re-frame the 3D view so we can see the model by using the “View All” shortcut again.

You should see that your model is now at the right place and close to the right scale. Now that you can see what you’re doing, make any additional tweaks so that your model meets #1 and #2 of the Microsoft guidelines.

Lastly, we need to check the model’s triangle count, there is a limit of 10,000 triangles for a 3D app launcher (you can see the triangle count in the top toolbar when the model is selected). Here’s what it looks like:

Mesh Triangle Count

If you need to reduce your triangle count, you can use the Decimate Modifier on your model. Go here to learn more on how to use Decimate (I also recommend checking out a couple YouTube videos on the topic, Blender is complex app).

I strongly urge you to go to this documentation and read all the model restrictions and recommendation, such as texture resolutions and workflow. If you use a model that doesn’t meet the guidelines, you’ll see a big red X like this:

Invalid Model

Now that your model is done, it’s time to export it as a gITF binary file.

Exporting GLB

By default, Blender doesn’t have a gITF export option, so you’ll want to use the KhronosGroup glTF-Blender-Exporter. Installation of the add-on is pretty straight forward, go here to read the instructions.

You get to choose between two options to add it:

  • Option 1: Set Blender to use repo’s scripts folder (to stay in sync with the exporter’s development)
  • Option 2: Copying a folder into Blender’s folders (I chose this option, scroll down to where the author starts a sentence with “Otherwise”)

Finally, enable the add-on in Blender (last step in the instructions). Once the add-on is enabled, go ahead and export your model! You’ll see a glb option in the File > Export list.

Here’s a screenshot:

Export as glb

UPDATE Jan 2018

You can now pack your more complex textures using a new tool released by Microsoft a few weeks ago! It takes away the requirement to be a shader ninja by importing your existing glb, packing the textures properly and exports an updated glb that will work in the Mixed Reality home.

Go here to get the converter and read how to use it https://github.com/Microsoft/glTF-Toolkit

Setting the 3D Launcher

Now that you have a glb file, it’s time to open your Mixed Reality UWP app in Visual Studio. Once it’s loaded, we need to add the glb file to your app’s Assets folder (right click on the folder and select “Add > Existing Item”). Once it’s been pulled in make sure you set the Build Action to Content (right click on the file, select Properties and change Build Action to content).

File’s Build Action

Lastly, we need to edit the app’s Package.appxmanifest file XML manually, to do this, right click on the file and select “View Code”. At the top of the file, add a new xmlns and also put it in the IgnorableNamespaces list


xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"

IgnorableNamespaces="uap uap2 uap5 mp"

Next, locate the DefaultTile tag (under Application > VisualElements), expand it and add the MixedRealityModel option with your


<uap:DefaultTile ShortName="Channel9 Space Station" Wide310x150Logo="Assets\Wide310x150Logo.png" >
<uap5:MixedRealityModel Path="Assets\Dog.glb" />
</uap:DefaultTile>

Here’s a screenshot, with the additions highlighted:

Package.appxmanifest changes

Final Result

You can see the final result at the end of the video above. Keep in mind that I keep the triangle count down for this, but next time I’ll likely increase it to 64 segments and 32 rings. Additionally, I’ll use a texture that can be mapped around a sphere (the Earth for example).

If you’re having trouble with your model and want to check your app settings with a known working mode, download the glb I created for here. I hope this tutorial was helpful, enjoy!

More Resources

“Cannot download Windows Mixed Reality software” error fix!

Did you just get a new Mixed Reality headset? Were you so excited that you ripped open the box and plugged it in only to to find that after setting up  your floor and boundaries that you got the following error:

Cannot download Windows Mixed Reality software

Screeching halt!

I spent a lot of time digging around the Hololens forums and long conversations on the Holodevelopers Slack and it seemed there was a wide variety of reason for this. However, after looking at my Developer Mode settings page (in Windows Settings), there was an incomplete dev package installation.

At this point, I suspected I needed to “side load” these packages, bypassing the on-demand download over network. I just didn’t know where to find it until… my hero,  and holographic Jedi, Joost van Schaik (@localjoost) had the same problem and found a fix for his. Joost followed a suggestion from Matteo Pagani (@qmatteoq) to use dism to install the packages manually.

I tweaked his solution (basically just found different packages) so that that it worked for a non-Insider Preview build and it worked!

Fix

It turns out that you can get the ISO file for the On-Demand-Features for your version of Windows 10 and install the packages manually.

Here are the steps:

1 – Go to the appropriate downloads page for your version of Windows 10 (these links use my.visualstudio.com, you may need to use whatever download

  • Go here if you’re running 1703 (Creator’s Update)
  • Go here if you’re running 1709 (Fall Creator’s Update)
  • Go here if you’re running 1803 (Spring 2018 Update)
  • Go here if you’re running 1809 (October 2018 Update)

2 – Download the Windows 10 Features on Demand file (ISO file) listed there. Note: There may be two ISOs offered for download, I found the cabs I needed in the 1st ISO.

2 – Mount the ISO file and make sure you see the following files (if you don’t, you got the wrong ISO):

2017-08-03_1200

Note: I’ve noticed since 1803, there is now a GUID in the filename, you’ll need to include that in your cmd as well (e.g. Microsoft-OneCore-DeveloperMode-Desktop-Package~31bf3856ad364e35~amd64~~.cab )

3 – Open an elevated Command Prompt and run the following commands (replace “E:” with your mounted ISO’s drive letter)

— Install the holographic package (this is what the Mixed Reality Portal app is failing to download)

dism /online /add-package /packagepath:"[YOUR-DRIVE-LETTER]:\Microsoft-Windows-Holographic-Desktop-FOD-Package.cab"

— Then install the Developer Mode package

dism /online /add-package /packagepath:"[YOUR-DRIVE-LETTER]:\Microsoft-OneCore-DeveloperMode-Desktop-Package.cab"

Here’s a screenshot of the result

2017-08-03_1136

 

4 – Open the Mixed Reality Portal app again and bingo, success!!!

2017-08-03_1206

 

Underlying Cause of the Issue

After some discussion with the folks at Microsoft, it turns out that if your PC is using WSUS (Windows Update Service), which is normal for a domain-joined PC under a corporate domain policy, this can prevent the download of some components (like .NET 3.5, Developer Package and Holographic Package).

You can talk to your IT department and ask them to unblock the following KBs:

  • 4016509
  • 3180030
  • 3197985

 

BIG THANKS to Joost and Matteo 🙂

 

Article Edits

Update 1 : Added attribution Matteo, fix some grammar and add the info about the KBs.

Update 2: Added Windows 10 (1803) download links. Added note about filenames containing a GUID.

Easy XamlCompositionBrushBase

The upcoming Windows 10 update, the Fall Creator’s Update, introduces a new design system, Microsoft Fluent Design System. The design system has 5 major building blocks:

  • Light
  • Depth
  • Motion
  • Material
  • Scale

You can use any of these in a multitude of ways, however Microsoft has made it very easy to use in the latest Preview SDK (16190). Some of the things that used to be relatively hard, or at the least verbose, can now be done with a few lines of code.

Today, I want to show you the XamlCompositionBrushBase (aka XCBB). Before I do, let’s briefly run through a XAML Brush and a Composition Brush.

The XAML Brush

We use Brushes in almost everything we do, they paint the elements in an application’s UI. For example, UIElement.Foreground and UIElement.Background both are of type Brush.

The most commonly used Brush is the SolidColorBrush, an example of setting the Foreground brush:

XAML

<TextBlock x:Name="myTextBlock" Foreground="Black"/>

C#

myTextBlock.Foreground = new SolidColorBrush(Colors.Black);

There are other brush types, such as ImageBrush, that are good for specific approaches, that make our live easier because it would otherwise require more work to achieve the same result.

The Composition Brush

A composition brush utilizes the relatively new Composition layer in Windows 10. This layer sits underneath the XAML layer where all your XAML elements live. You can do a lot with the composition layer, animations, effects and more. The mechanism that paints Composition layer elements also uses a “Brush”, however it’s a type of Composition Brush and cannot be used with your XAML directly.

XamlCompositionBrushBase

With the release of the 16190 preview SDK, you can now use the Composition layer and XAML layer together by using the XamlCompositionBrushBase!

This is BIG news because the XCBB allows for interoperability between the Composition layer and the XAML layer and lets you set up composition effect without needing to implement a behavior or other more advanced setups. As an example, let’s create a Brush that applies the Win2D Invert Effect,

Note: I wanted to keep this as simple as possible to focus on XCBB, you can expand on this with more complex Effects, such as the GaussianBlur here.

First, let’s example the XCBB’s two methods that you want to override:

  • OnConnected
  • OnDisconnected

So, here’s our starting point:

public class InvertBrush : XamlCompositionBrushBase
{
    protected override void OnConnected()
    {
        // Set up CompositionBrush
        base.OnConnected();
    }

    protected override void OnDisconnected()
    {
        //Clean up
        base.OnDisconnected();
    }
}

Now, for the awesome part… the XCBB has a CompositionBrush property! All you need to do is instantiate your effect. Here’s the completed Brush code and I’ve broken it down to the important steps:

public class InvertBrush : XamlCompositionBrushBase
{
    protected override void OnConnected()
    {
        // Back out if it's not ready yet
        if (CompositionBrush == null) return;

        // 1 - Get the BackdropBrush
        // NOTE: BackdropBrush is what is behind the current UI element (also useful for Blur effects)
        var backdrop = Window.Current.Compositor.CreateBackdropBrush();

        // 2 - Create your Effect
        // New-up a Win2D InvertEffect and use the BackdropBrush as it's Source
        var invertEffect = new InvertEffect
        {
            Source = new CompositionEffectSourceParameter("backdrop")
        };

        // 3 - Get an EffectFactory
        var effectFactory = Window.Current.Compositor.CreateEffectFactory(invertEffect);

        // 4 - Get a CompositionEffectBrush
        var effectBrush = effectFactory.CreateBrush();

        // and set the backdrop as the original source
        effectBrush.SetSourceParameter("backdrop", backdrop);

        // 5 - Finally, assign your CompositionEffectBrush to the XCBB's CompositionBrush property
        CompositionBrush = effectBrush;

    }

    protected override void OnDisconnected()
    {
        // Clean up
        CompositionBrush?.Dispose();
        CompositionBrush = null;
    }
}

Now that the Brush’s definition is complete, how do we actually use it? This is the most exciting part… you use it like any other Brush in XAML!


<Grid>
    <Grid.Background>
        <brushes:InvertBrush />
    </Grid.Background>
</Grid>

Showtime

Here’s an example implementation. I have an Ellipse with an ImageBrush and it’s currently showing Tuvok (full disclosure: I’m a Trekkie AND a Star Wars fan)

<Ellipse x:Name="ImageEllipse">
    <Ellipse.Fill>
        <ImageBrush ImageSource="{Binding SelectedCharacter.ImagePath}" Stretch="UniformToFill" />
    </Ellipse.Fill>
</Ellipse>

Sketch (2)

If I put another matching Ellipse using my custom InvertBrush on top of the Tuvok Ellipse, here’s the result:


<Ellipse x:Name="ImageEllipse">
    <Ellipse.Fill>
        <ImageBrush ImageSource="{Binding SelectedCharacter.ImagePath}" Stretch="UniformToFill" />
    </Ellipse.Fill>
</Ellipse>
<Ellipse>
    <Ellipse.Fill>
        <strong><brushes:InvertBrush /></strong>
    </Ellipse.Fill>
</Ellipse>

Sketch (3)

Notice how it only inverted what was directly behind the Ellipse and not the page background or the drop shadow?

Level Up

In the case of the InvertEffect, we don’t have any effect variables to update, so there’s no need for a DependencyProperty to set initial values of the effect. However, in most cases, you will need a DependencyProperty in your XCBB to tweak the effect’s values.

To see this, look at the BackdropBlurBrush example here and notice how the Blur.BlurAmount effect property can be updated by using a ScalarParameter when calling CreateEffectFactory.

I hope I was able to clarify how easy it is to get started using the XCBB and how this makes things easier for XAML devs to get the benefits of working with the Composition layer without doing a lot of work.

Happy coding!

Lance

Adding Telerik Universal

Telerik has released a new toolset, UI for Windows Universal. You can now use many components like Charts and Calendars in a shared XAML page in your application. If you already have the Telerik Windows Phone or Windows 8.1 XAML controls, you now have a license for the Universal controls, too.

It is very simple to add it to your project. Let me show you in a quick File > New example:

1- Open Visual Studio 2013 and create a new Universal Store app.

Select File > New > Project > Visual C# > Store Apps > Universal Apps and choose the HubApp template (you can choose Blank App if you prefer, we’re only going to use the Shared folder to add content).

S1

2- After the project generates, let’s focus on the solution Explorer. First, lets add the Telerik reference to the Windows project.

Right click on References > Add Reference > select Windows 8.1 (in the left tree) > Extensions. Now you’ll see a list of extensions, choose “Telerik UI for Windows Universal

S2

3- Now add the Telerik extension to the Windows Phone project.

The steps are the sames as you did in step 2, but the extension’s name is “Telerik UI for Windows Phone 8.1

S3

4- Now we are ready to start building, let’s add a RadCalendar to a shared XAML page.

  1. Build the solution (F6)
  2. Right click on the Shared Project and select Add > New Item > Blank Page
  3. In the Visual Studio Toolbox type in “RadCalendar“, drag and drop it onto your new blank page. You can also type it in, but make sure you add the namespace (see screenshot)

S4

You can also see how the control will on Phone by simply toggling the view:

S5

That’s all there is to it!

Here are some more resources for you:

One last thing I should mention is that not all the Windows 8.1 controls are Universal right now. We are hard at work to bring more over. Here is a list as of Q3 2014: