<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Stuart Leeks</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/stuartleeks/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/stuartleeks/feed.xml</link>
    <description>Stuart Leeks - Web and Cloud Geek</description>
    <lastBuildDate>Mon, 21 May 2018 13:56:35 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Azure Container Registry Global Webhooks–with a helping of Azure Durable Functions</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/azure-container-registry-global-webhooks-with-a-helping-of-azure-durable-functions</link>
      <pubDate>Mon, 21 May 2018 13:55:45 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/?p=1385</guid>
      <description><![CDATA[I spend quite a lot of my time working with containerised solutions in Azure, so I make use of Azure...]]></description>
      <content:encoded><![CDATA[<p>I spend quite a lot of my time working with containerised solutions in Azure, so I make use of <a href="https://docs.microsoft.com/en-us/azure/container-registry/container-registry-intro">Azure Container Registry (ACR)</a>. ACR has a couple of features that I really like: webhooks and geo-replication. With ACR, webhooks are not global (i.e. they are fired for each replicated region). Sometimes this is what you want, but other times you might want to have a webhook that is invoked when the push operation has completed across all replicated regions. In this post I will show how you can build that relatively easily with another technology that I like: <a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-overview">Azure Durable Functions</a>.</p><h1>Background</h1><p>Before digging in to the solution, let's take a quick look at the different pieces involved and how they relate to this sceNario.<h2>ACR webhooks</h2><p>With <a href="https://docs.microsoft.com/en-us/azure/container-registry/container-registry-webhook">webhooks</a> in ACR you can register for HTTP notifications when images are pushed (or deleted).<p>An example usage of webhooks is to use <a href="https://brigade.sh">Brigade</a> to respond to new images pushed to your registry to kick of a deployment of the new version (or something like that): <a href="https://github.com/Azure/brigade/blob/master/docs/topics/dockerhub.md">example</a>.<h2>Geo-replication</h2><p>If you're deploying your services in Azure then a definite benefit of ACR is that your images are network-close to where you are deploying them. If you are deploying services across multiple regions then having your images in each of those regions preserves this network-locality benefit. Whilst you could deploy separate ACR instances in each region and update your build to push to each region, ACR lets you have one logical registry instance that automatically replicates images across the regions that you choose. This is pretty cool - you get a single registry endpoint that you use to push/pull and the images automatically replicated across your chosen regions. When you push/pull you are directed to the nearest replicated instance for performance.<p>However, as mentioned earlier the webhooks are fired per-region. For some scenarios this is desirable but for others you might want to get a notification once the image that you've pushed has been replicated across all the regions you have configured. To achieve this with minimal effort (and cost) we'll use Azure Durable Functions...<h2>Azure Durable Functions</h2><p>Azure Durable Functions build on top of Azure Functions and add an orchestration/coordination layer. There is some great documentation that shows some of the common patterns that you can use Durable Functions for. The pattern that we will use here is the <a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-external-events">External Event</a> pattern (also referred to as <a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-phone-verification">Human Interaction</a> in some of the documentation scenarios).<p><a href="https://azure.microsoft.com/en-us/blog/break-through-the-serverless-barriers-with-azure-functions/">Durable Functions just hit General Availability</a> for C# on Functions v1, so for this post I will show C#. There is preview support for JavaScript Durable Functions on Functions v2 with support for more languages coming.<h1>Creating the solution</h1><p>The first part of the solution will be an HTTP-triggered function. This will be the function that subscribes to the ACR webhook.<p>We will also have an orchestration function. This will be responsible for determining whether we have had notifications from all of the regions. You can have multiple instances of an orchestration, each having its own set of state. We will have an instance of the orchestration per set of regional notifications. The id property of the webhook body is the id for the logical operation for the registry, i.e. it is the same across regional webhook invocations for the same image push/delete, so we will use this as the instance id for our orchestration. <p>Each invocation of the HTTP-triggered function will get a reference to the orchestration instance for the for creating the orchestration instance if required. (Typically an orchestration instance is created without specifying the ID, but in this case we want to use the ID from the webhook notification to allow us to route notifications to the correct instance.) Once the trigger function has the reference to the orchestration instance it will raise an external event for the region that the notification corresponds to. In this way the trigger function translates the webhook notification for each region into a Durable Function external event for each region.<p>Inside the orchestration function we can call WaitForExternalEvent to wait for the event for each region. This is an async method so returns a Task. Rather than awaiting these Tasks we capture them all and pass them to Task.WhenAll which gives us back a new Task that represents all of the external event Tasks completing. By awaiting this new Task we handle the join or fan-in over the notifications.<h2>Show me the code</h2><p>All of this is handled in the <a href="https://github.com/stuartleeks/acr-global-webhook">sample code</a> for the blog post.<p>I named the HTTP-triggered function "ImagePush"<blockquote><p>[FunctionName("ImagePush")]<br>public static async Task&lt;HttpResponseMessage&gt; ImagePush(<br>&nbsp;&nbsp;&nbsp; [HttpTrigger(AuthorizationLevel.Function, "get", "post")]<br>&nbsp;&nbsp;&nbsp; HttpRequestMessage request,<br>&nbsp;&nbsp;&nbsp; [OrchestrationClient]<br>&nbsp;&nbsp;&nbsp; DurableOrchestrationClient starter,<br>&nbsp;&nbsp;&nbsp; TraceWriter log)</p></blockquote><p>Notice the DurableOrchestrationClient that is passed in. This is a special type for use in Durable Functions and lets us create and query orchestration instances, as well as raise external events against them (as we'll see later).<p>The HttpRequestMessage parameter gives us access to the HTTP Request that triggered the function (in our case the webhook notification). When I registered the ACR webhooks I simply added a querystring parameter to the function URL to identify which region the webhook is firing for. The following code retrieves this:<blockquote><p>var query = request.RequestUri.ParseQueryString();<br>var region = query["region"];</p></blockquote><p>Similarly, the request is used to read the body of the HTTP Request to retrieve the notification id. From there, we look up the orchestration instance and create it if required:<blockquote><p>var status = await starter.GetStatusAsync(instanceId);<br>if (status == null)<br>{<br>&nbsp;&nbsp;&nbsp; await starter.StartNewAsync("WaitForAllRegions", instanceId, notification);<br>}</p></blockquote><p>And then finally raise the event for that region that the webhook fired for<blockquote><p>await starter.RaiseEventAsync(instanceId, GetEventName(region), null);</p></blockquote><p>Now that we've seen the core parts of the trigger function , let's turn to the orchestrator function. It has a pretty simple declaration:<blockquote><p>[FunctionName("WaitForAllRegions")]<br>public static async Task WaitForAllRegions([OrchestrationTrigger] DurableOrchestrationContext context)</p></blockquote><p>This time we have a Durable Functions orchestration context that allows us to call into activity functions or wait for external events. In our case we want to wait for an external event for each region that we're replicated to. The orchestration context has a WaitForExternalEvent method that allows us to wait for an external event by awaiting the Task it returns. In our case, we won't await the Task - instead we will build up a list of Tasks (one per region). We can then take this List and pass it to Task.WhenAll. This gives us a single Task that represents all of the Tasks in the List completing.<blockquote><p>var eventTasks = new List&lt;Task&gt;();<br>foreach (var region in GetRegions())<br>{<br>&nbsp;&nbsp;&nbsp; eventTasks.Add(context.WaitForExternalEvent&lt;object&gt;(GetEventName(region)));<br>}<br>Task replicationCompletedTask = Task.WhenAll(eventTasks);<br>await replicationCompletedTask</p></blockquote><p>By awaiting the replicationCompletedTask we won't continue with any further code until that Task has completed. Since that was created using Task.WhenAll for the Tasks for the external events, that corresponds to all the external events having been raised.<p>The last step is to take some action at this point, so we call into an activity function:<blockquote><p>await context.CallActivityAsync&lt;string&gt;("FirePushNotification", notification);</p></blockquote><p>The activity function is just a placeholder function in the sample code, but you could use this function to make an HTTP call to notify another system, post to teams/slack, ...<blockquote><p>[FunctionName("FirePushNotification")]<br>public static string FirePushNotification([ActivityTrigger] WebHookNotification notification, TraceWriter log)<br>{<br>&nbsp;&nbsp;&nbsp; log.Info($"TODO: All regions are sync'd - add whatever onward notification you want here! Repository: {notification.Target.Repository}, Tag: {notification.Target.Tag}, Id: {notification.Request.Id}");<br>&nbsp;&nbsp;&nbsp; return $"All regions are sync'd!";<br>}</p></blockquote><h2>What's with all the Tasks?</h2><p>I really like how the Durable Functions runtime exposes Tasks as the interface to the units of work (calling activity functions, waiting for external events) as it means that we can bring in experience of working with Tasks from other contexts. We can use await and Task.WhenAll that are familiar from other async programming in C#. <h2>SIDE NOTE:</h2><p>It is important to note that while these give the illusion that the orchestration function will keep running and wait for the potentially long-running Tasks to complete, that's not actually the case. When the orchestrator reaches an idle point where it is blocked waiting on Tasks, the underlying runtime suspends it, which is particularly cool for the consumption billing plan of Azure Functions - if it's not running then you're not paying! With this coolness, you do need to be aware that the orchestrator will be replayed when a new notification has come in and it needs to resume. The documentation covers <a href="https://docs.microsoft.com/en-gb/azure/azure-functions/durable-functions-checkpointing-and-replay">how replay works</a> and the <a href="https://docs.microsoft.com/en-gb/azure/azure-functions/durable-functions-checkpointing-and-replay#orchestrator-code-constraints">constraints this puts on orchestration functions</a>.<h2>Adding another layer</h2><p>In my experience with the ACR geo-replication it has been rock-solid. However, in the interests of exploring Durable Functions a little further, let's add in a requirement to be notified if we don't get all of the notifications within a specified time period. Let's use 1 minute for this, but we could have picked 10 seconds or 3 days :-)<p>The code we have so far uses the orchestration context to get Tasks for various external event notifications, and then uses Task.WhenAll to join multiple notifications together to create a single Task that represents all the notifications completing. Let's call this the "completion Task".<p>One of the other things we can do with the orchestration context is to create a timer, and hopefully it won't come as a surprise that this returns a Task that completes when the timer fires. Now we have the completion Task and the timer Task, and we can use the Task.WhenAny method to combine these two Tasks into a new Task that completes when *either* of the input tasks completes, i.e. Either when the timer fires, or when the notifications have all completed. Hey presto, we have now implemented the timeout!<p>In code, we create the timeout Task by using the orchestration context. We use the CurrentUtcDateTime property to calculate the timer expiry as it will give us a consistent DateTime value even if the orchestration function is being replayed.<blockquote><p>Task timeoutTask = context.CreateTimer(context.CurrentUtcDateTime + timeOutInterval, cts.Token);</p></blockquote><p>Then we combine the timeoutTask with the replicationCompletedTask we had before:<blockquote><p>var winningTask = await Task.WhenAny(timeoutTask, replicationCompletedTask);</p></blockquote><p>Once we've returned from this await, winningTask will be set to whichever task has completed. We can then test whether this is the timeoutTask or the replicationCompletedTask to determine which action to take.<h1>Trying it for yourself</h1><p>All of the code for this post is available on github (<a href="https://github.com/stuartleeks/acr-global-webhook">https://github.com/stuartleeks/acr-global-webhook</a>). There are instructions in the repo README for deploying and configuring.<h1>Find out more</h1><p>If you want to find out more about Durable Functions there is some great documentation:<ul><li>Overview <a href="https://docs.microsoft.com/en-gb/azure/azure-functions/durable-functions-overview">https://docs.microsoft.com/en-gb/azure/azure-functions/durable-functions-overview</a><li>Timers <a href="https://docs.microsoft.com/en-gb/azure/azure-functions/durable-functions-timers">https://docs.microsoft.com/en-gb/azure/azure-functions/durable-functions-timers</a><li>External Events <a href="https://docs.microsoft.com/en-gb/azure/azure-functions/durable-functions-external-events">https://docs.microsoft.com/en-gb/azure/azure-functions/durable-functions-external-events</a></li></ul><p>For more information on Azure Container Registry see<ul><li>Overview <a href="https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-intro">https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-intro</a><li>Webhooks <a href="https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-webhook">https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-webhook</a><li>Geo-replication <a href="https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-geo-replication">https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-geo-replication</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>posh-HumpCompletion in Azure Cloud Shell</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/posh-humpcompletion-in-azure-cloud-shell</link>
      <pubDate>Tue, 01 May 2018 09:59:56 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/?p=1355</guid>
      <description><![CDATA[Azure Cloud Shell is an in-browser shell experience that you can launch from the Azure portal or on...]]></description>
      <content:encoded><![CDATA[<p><sub></sub>Azure Cloud Shell is an in-browser shell experience that you can launch from the <a href="https://portal.azure.com">Azure portal</a> or on its own at <a href="https://shell.azure.com">shell.azure.com</a>. You can choose between <a href="https://docs.microsoft.com/en-us/azure/cloud-shell/quickstart">bash</a> and <a href="https://docs.microsoft.com/en-us/azure/cloud-shell/quickstart-powershell">PowerShell</a>, and both come with a nice range of installed tools (<a href="https://docs.microsoft.com/en-us/azure/cloud-shell/features">bash</a>, <a href="https://docs.microsoft.com/en-us/azure/cloud-shell/features-powershell">PowerShell</a>). Oh, and you can also use this inside the <a href="https://code.visualstudio.com/">Visual Studio Code</a> editor as <a href="https://www.hanselman.com/blog/AzureCloudShellYourOwnBashShellAndContainerRightInsideVisualStudioCode.aspx">Scott Hanselman shows</a>!</p><p>In this short post I’m going to be looking at the PowerShell experience and will walk through setting up Cloud Shell to work with <a href="https://github.com/stuartleeks/posh-humpcompletion">posh-HumpCompletion</a> (a module that adds tab completion richness to PowerShell and which I was inspired to write after working with the <strike>verbose</strike> clear naming of the Azure cmdlets). You can see a GIF of it in action on the <a href="https://github.com/stuartleeks/posh-humpcompletion#instructions">GitHub page</a>.</p><h1>Launch Azure Cloud Shell</h1><p>The first step of this is to launch the Cloud Shell: <a href="https://shell.azure.com/PowerShell">https://shell.azure.com/PowerShell</a>.</p><p>Currently the PowerShell experience is in preview and it can take a while to start and connect – hang in there!</p><p>If this is your first time using Cloud Shell then it will walk you through configuring a file share. This is then automatically mounted for you in each Cloud Shell session to allow you to save files across sessions. You can even mount it on your local machine to share content from your local machine with Cloud Shell (docs for <a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-how-to-use-files-windows">Windows</a>, <a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-how-to-use-files-linux">Linux</a>, <a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-how-to-use-files-mac">Mac</a>).</p><h1>Install posh-HumpCompletion</h1><p>Now that you have Cloud Shell running you can install posh-HumpCompletion from PowerShell Gallery</p><blockquote><p><font face="Consolas">Install-Module posh-HumpCompletion</font></p></blockquote><p>Once you have installed the module simply import it to bring posh-HumpCompletion to life</p><blockquote><p><font face="Consolas">Import-Module posh-HumpCompletion</font></p></blockquote><h1>Add to your $profile</h1><p>If you want posh-HumpCompletion to be active automatically when you start a new instance of Cloud Shell then simply add an Import-Module to your PowerShell profile. Since this is stored on the cloud drive that you set up when you first started Cloud Shell it will be invoked for each new instance. The following command appends the import to the profile</p><blockquote><p><font face="Consolas">echo "`nImport-Module posh-HumpCompletion`n" &gt;&gt; $profile</font></p></blockquote><h1>NOTES</h1><p>One thing to mention is that the PowerShell Cloud Shell has both the Desktop PowerShell (powershell) and PowerShell Core (pwsh) installed, and they share the $profile. So if you use both and add posh-HumpCompletion to your profile you should install it in both environments to avoid errors!</p><p>Update: This post originally said that you needed to specify “-Scope CurrentUser” on the Install-Module command, but thanks go to <a title="https://twitter.com/alexandair" href="https://twitter.com/alexandair">Aleksandar Nikolić</a> for setting me straight and teaching me about <a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameters_default_values?view=powershell-6">$PSDefaultParameterValues</a>. In short, the Cloud Shell team have set you up for success by defaulting to the CurrentUser scope when installing modules <img class="wlEmoticon wlEmoticon-smile" alt="Smile" src="https://msdnshared.blob.core.windows.net/media/2018/05/wlEmoticon-smile.png"></p>]]></content:encoded>
    </item>
    <item>
      <title>Azure Functions and App Service Authentication</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/azure-functions-and-app-service-authentication</link>
      <pubDate>Mon, 19 Feb 2018 19:24:12 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/?p=1315</guid>
      <description><![CDATA[Azure App Service has a handy authentication integration that takes away the work of integrating...]]></description>
      <content:encoded><![CDATA[<a href="https://azure.microsoft.com/services/app-service/">Azure App Service</a> has a handy authentication integration that takes away the work of integrating with various identity providers (currently: Azure Active Directory, Facebook, Google, Twitter and Microsoft Accounts). <a href="https://azure.microsoft.com/services/functions/">Azure Functions</a> are built on the same underlying core components as Azure App Service and in this post we will show how to integrate http-based Azure Functions with <a href="https://docs.microsoft.com/azure/app-service/app-service-authentication-overview">Azure App Service Authentication</a> (aka EasyAuth).

When working with a Web App, you can easily set up <a href="https://docs.microsoft.com/azure/app-service/app-service-authentication-overview#authorization">EasyAuth</a> to redirect unauthenticated users to the identity provider of your choice and thanks to the magic of the implicit flow (i.e. various browser redirections) the user ends up returning to your web app as an authenticated user with a cookie from EasyAuth. With this server-directed flow EasyAuth really is particularly easy! For APIs (either hosted as Web Apps, or in Azure Functions) you need to follow a slightly different flow where the initial authentication is driven by the client, and there are some gaps in the documentation right now, so hopefully this blog post can help you through the steps to make this work until the docs are updated :-)

Before we start digging in to how it all works it is worth mentioning that there are <a href="https://github.com/search?utf8=%E2%9C%93&amp;q=org%3AAzure+mobile-apps+client&amp;type=">various SDKs</a> for Mobile Apps (another part of App Service) which have support for EasyAuth amongst other things. These cover JavaScript, Android, iOS etc but I want to keep this post as general as possible so won’t be using an SDK here. (The sample code does have an <a href="https://github.com/stuartleeks/AzureFunctionsEasyAuth/blob/master/src/SimpleWebClient/Pages/Zumo.cshtml">example of using the Mobile Apps JavaScript SDK </a>if you’re interested in seeing how that helps!)
<h2>The Goal</h2>
So, what exactly is my aim? I want to be able to secure an Azure Function using providers such as Facebook, Google etc. The customer that I was working with on this plan to build out a Unity Application, but for ease of putting the sample together (based on my background) I created a simple web client to test the function.
<h2>The Code</h2>
If you want to skip ahead to the end, the code for this article is <a href="https://github.com/stuartleeks/AzureFunctionsEasyAuth">up on Github</a>. There is an ARM template with some instructions for how you can deploy it to test it. The template will deploy the Azure Function, set up EasyAuth on the Azure Function, deploy the client, and the set up the configuration that the web app needs. At the time of writing I also have a <a href="https://easyauthweb.azurewebsites.net/">live demo</a> if you want to just see the result in action.
<h2>Creating a Function with EasyAuth</h2>
The first thing we need is an Azure Function. I created this in Visual Studio in the same way as is described in <a href="https://docs.microsoft.com/azure/azure-functions/functions-create-your-first-function-visual-studio">these instructions</a>.

Once you have deployed the function, we need to configure EasyAuth. This can be done in the portal by navigating to your function, and then choosing Authentication/Authorization under Platform Features

<a href="https://msdnshared.blob.core.windows.net/media/2018/02/image285.png"><img title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2018/02/image_thumb244.png" width="1326" height="490" border="0" /></a>

From there you can enable App Service Authentication, i.e. EasyAuth, and configure the providers that you want to:

<a href="https://msdnshared.blob.core.windows.net/media/2018/02/clip_image00161.png"><img title="clip_image001[6]" alt="clip_image001[6]" src="https://msdnshared.blob.core.windows.net/media/2018/02/clip_image0016_thumb.png" width="296" height="484" border="0" /></a>

To configure a provider you will need to enter the relevant details for that provider. When you click on a provider you will get a link to the documentation for setting up that provider and getting the information that you need.

For Facebook, at this point I have the following in the Facebook portal (I'll come back and add more settings later, once I have the client web app):

<a href="https://msdnshared.blob.core.windows.net/media/2018/02/clip_image00181.png"><img title="clip_image001[8]" alt="clip_image001[8]" src="https://msdnshared.blob.core.windows.net/media/2018/02/clip_image0018_thumb.png" width="1028" height="526" border="0" /></a>

And then I enter these settings this in the EasyAuth configuration:

<a href="https://msdnshared.blob.core.windows.net/media/2018/02/clip_image001101.png"><img title="clip_image001[10]" alt="clip_image001[10]" src="https://msdnshared.blob.core.windows.net/media/2018/02/clip_image00110_thumb.png" width="644" height="349" border="0" /></a>

Once you've done this then we have an Azure Function ready for EasyAuth, but we need to call it passing a token…
<h2>Creating a Client</h2>
For this post let's create a web app - in the sample project I deploy this as an Azure Web App, but you can host it wherever, or create a different type of client app (iOS, Android, Windows, Unity, ….). For the rest of the post I'm going to talk about a web client, but I'll do as much as possible in the browser (rather than the web server) so that it is easy to see how to port to another client type.

For the actual Facebook/Google sign-in, we will use the JavaScript SDKs. Once the Web App is deployed we need to revisit the Facebook/Google developer portals to configure them to accept logins from our Web App

Back in the Facebook app settings, I can now set the App Domain and add a Website platform:

<a href="https://msdnshared.blob.core.windows.net/media/2018/02/image286.png"><img title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2018/02/image_thumb245.png" width="1028" height="721" border="0" /></a>

In case you're interested, this is what the Google app settings look like:

<a href="https://msdnshared.blob.core.windows.net/media/2018/02/image287.png"><img title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2018/02/image_thumb246.png" width="1028" height="554" border="0" /></a>

Note the URLs in each case for easyauthtestweb.azurewebsites.net (which was a disposable test site I created for taking screenshots). And yes, I've reset the keys for the apps and will most likely delete them soon!

Because I opted for a web app as the client there is one final tweak to make is to enable CORS on the Function so that our web app can call the Function. Again, under Platform Features for the Function we can select CORS

<a href="https://msdnshared.blob.core.windows.net/media/2018/02/image288.png"><img title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2018/02/image_thumb247.png" width="1326" height="490" border="0" /></a>

And then enter the URL to our web app <strong>(without a trailing slash)</strong>

<a href="https://msdnshared.blob.core.windows.net/media/2018/02/clip_image001121.png"><img title="clip_image001[12]" alt="clip_image001[12]" src="https://msdnshared.blob.core.windows.net/media/2018/02/clip_image00112_thumb.png" width="461" height="356" border="0" /></a>
<h2>Logging In</h2>
Now that we have a web app, we need to put some content in it and the sample code can be found <a href="https://github.com/stuartleeks/AzureFunctionsEasyAuth/blob/master/src/SimpleWebClient/Pages/vanilla-js.cshtml">here</a>.

In the sample code, I've used <a href="https://docs.microsoft.com/aspnet/core/mvc/razor-pages/?tabs=visual-studio">ASP.NET Core Razor Pages</a>. These are server-rendered HTML pages that can contain server-side C# code. I've taken advantage of this by injecting the <span style="font-family: Consolas">IConfiguration</span> dependency. This is part of the ASP.NET Core configuration system and pulls in configuration values from various sources including environment variables. This is particularly convenient as App Settings in Azure Web Apps are exposed as environment variables, so this gives a clean way to pick up the config.

The sample code also has some <span style="font-family: Consolas">@if</span> sections to only include the Facebook/Google scripts if we have the IDs for them set. This allows the same code to work for either or both provider, but you don't have to do that for your client!

The documentation for Facebook and Google both show how to use their SDKs to obtain a token for the user. The key part from there is knowing how to use that to call the Azure Function via EasyAuth, and the steps for that are outlined below.

For Facebook we get an access token, and we need to make an HTTP POST to <span style="font-family: Consolas">&lt;functionapp&gt;/.auth/login/facebook</span> with the application/json body <span style="font-family: Consolas">{ 'access_token' : &lt;accesstoken&gt; }</span>

For Google we get an id token, and we need to make an HTTP POST to <span style="font-family: Consolas">&lt;functionapp&gt;/.auth/login/googl</span>e with the application/json body <span style="font-family: Consolas">{ 'id_token': &lt;idtoken&gt; }</span>

These calls translate the provider token into an EasyAuth token, which is returned in the <span style="font-family: Consolas">authenticationToken</span> property of the returned JSON object.

Finally, once we have the EasyAuth token we can call the Azure Function passing the EasyAuth token in the <span style="font-family: Consolas">X-ZUMO-AUTH</span> header on the HTTP request.

These steps are all implemented with vanilla JavaScript in the <a href="https://github.com/stuartleeks/AzureFunctionsEasyAuth/blob/master/src/SimpleWebClient/Pages/vanilla-js.cshtml">sample page</a> so that they can easily be translated to other client types.
<h2>Working with Authentication in the Function</h2>
We have the Function App configured for EasyAuth, and the client sending up the correct token which leaves one final question: how do we access the identity in the Function App? The approach you take here depends on what you want to do.

If you simply want to know whether the request is for an authenticated user then you can test <span style="font-family: Consolas">Thread.CurrentPrincipal.Identity.IsAuthenticated</span>. This will be <span style="font-family: Consolas">true</span> if a valid token was included on the incoming request.

Alternatively, if you want to get a user identifier that you can use to store information for the authenticated user then you can cast <span style="font-family: Consolas">Thread.CurrentPrincipal</span> to a <span style="font-family: Consolas">ClaimsPrincipal</span>, and then retrieve the claim of type "<span style="font-family: Consolas">stable_sid</span>". The combination of provider (supplied in the "<span style="font-family: Consolas">https://schemas.microsoft.com/identity/claims/identityprovider</span>" claim) and the <span style="font-family: Consolas">stable_sid</span> gives you a unique user id. Also, while it may be tempting to use other properties (see below) as the user identifier, you need to be careful which properties you pick, for example a user can change the email address associated with their Facebook account. For further reading, see <a href="https://github.com/Azure/azure-mobile-apps-net-server/wiki/Understanding-User-Ids">Understanding User Ids</a>.

Finally, if you want to get profile information from the provider then you get retrieve that via EasyAuth. To do this we need to call the<span style="font-family: Consolas"> .auth/me</span> endpoint passing the <span style="font-family: Consolas">X-ZUMO-AUTH</span> header along. I've packaged this in an extension method on <span style="font-family: Consolas">HttpRequestMessage</span> called <a href="https://github.com/stuartleeks/AzureFunctionsEasyAuth/blob/master/src/FunctionWithAuth/AuthInfoExtensions.cs"><span style="font-family: Consolas">GetAuthInfoAsync</span></a> for ease of use.

The raw response from <span style="font-family: Consolas">.auth/me</span> is of the form:

<span style="font-family: Consolas">[{
"provider_name":"&lt;provider&gt;",
"user_id": "&lt;user_id&gt;",
"user_claims":[{"typ": "&lt;claim-type&gt;","val": "&lt;claim-value&gt;"}, ...],
"access_token":"&lt;access_token&gt;",
"access_token_secret":"&lt;access_token_secret&gt;",
"authentication_token":"&lt;authentication_token&gt;",
"expires_on":"&lt;iso8601_datetime&gt;",
"id_token":"&lt;id_token&gt;",
"refresh_token":"&lt;refresh_token&gt;"
}]</span>

The extension method parses this into an instance of the <span style="font-family: Consolas">AuthInfo</span> class for easier use.

In the Function project there are a number of Functions that demonstrate accessing the data for each of the scenarios above: <a href="https://github.com/stuartleeks/AzureFunctionsEasyAuth/blob/master/src/FunctionWithAuth/AuthFunctions.cs">https://github.com/stuartleeks/AzureFunctionsEasyAuth/blob/master/src/FunctionWithAuth/AuthFunctions.cs</a>
<h2>Putting it All Together</h2>
When we put it all together we have an Azure Function that can support logins from a variety of methods via configuration. The beauty of EasyAuth in Azure Functions/AppService is that we don't have to worry about integrating with each provider, we can just call the standard .auth/me endpoint to get the profile information that the provider supplied.

The code for this article is on github <a href="https://github.com/stuartleeks/AzureFunctionsEasyAuth/">here</a>, and there are instructions for deploying this to your Azure subscription (if you don't have one then <a href="https://azure.microsoft.com/free/">get a free subscription here</a>. When you deploy the template it will create an Azure Function (with a whole stack of <a href="https://azure.microsoft.com/pricing/details/functions/">free executions each month</a>), an Azure Web App on the <a href="https://azure.microsoft.com/pricing/details/app-service/">Free Plan</a> and a <a href="https://azure.microsoft.com/pricing/details/storage/">storage account</a> (for Function logging).

In short, testing this will hardly cost you anything. So what are you waiting for? <a href="https://github.com/stuartleeks/AzureFunctionsEasyAuth/">Give it a try</a>!
<h2>Further Reading</h2>
If you want to find out more about EasyAuth and Azure Functions then here are some recommended articles:
<ul>
 	<li><a href="https://docs.microsoft.com/azure/app-service/app-service-authentication-overview">EasyAuth Docs</a></li>
 	<li><a href="https://cgillum.tech/2016/02/01/architecture-of-azure-app-service-authentication-authorization/">Chris Gillum on EasyAuth</a></li>
 	<li>Tsuyoshi Ushio on <a href="https://medium.com/@tsuyoshiushio/configuring-microsoft-graph-bindings-for-azure-functions-with-b2c-60fe0b63e81a">Configuring Microsoft Graph bindings for Azure Functions with B2C</a></li>
 	<li><a href="https://cgillum.tech/2016/03/07/app-service-token-store/">Chris Gillum on Token store</a> (details of refreshing tokens etc)</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Including Headers for Request Events with Application Insights</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/including-headers-for-request-events-with-application-insights</link>
      <pubDate>Thu, 03 Nov 2016 20:58:41 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/?p=1125</guid>
      <description><![CDATA[When working with Application Insights recently in an ASP.NET application, I suddenly realised that...]]></description>
      <content:encoded><![CDATA[When working with <a href="https://azure.microsoft.com/en-us/services/application-insights/">Application Insights</a> recently in an ASP.NET application, I suddenly realised that the HTTP request and response headers weren’t included in the request data that is automatically captured. Fortunately, Application Insights has a few handy extensibility points, and this post looks at how to use one of them to include selected request and response headers along with the request events.

Application Insights has an extension point using an <a href="https://azure.microsoft.com/en-us/documentation/articles/app-insights-api-filtering-sampling/#add-properties">ITelemetryInitializer</a> interface. By implementing this interface, you can create a class that plugs into Application Insights and is called to initialise the telemetry data before it is sent to the service.

For this scenario I created the HeaderTelemetryInitializer class as shown below. This class has a couple of properties to allow you to specify which request/response headers you want to include. In the Initialize method, it then gets the specified request and response headers (with the appropriate null checks) and adds them as custom properties for the telemetry.

&nbsp;
<pre>
    public class HeaderTelemetryInitializer : ITelemetryInitializer
    {
        public List&lt;string&gt; RequestHeaders { get; set; }
        public List&lt;string&gt; ResponseHeaders { get; set; }

        public HeaderTelemetryInitializer()
        {
            RequestHeaders = new List&lt;string&gt;();
            ResponseHeaders = new List&lt;string&gt;();
        }

        public void Initialize(ITelemetry telemetry)
        {
            var context = HttpContext.Current;
            if (context == null)
            {
                return;
            }
            if (context.Request != null)
            {
                foreach (var headerName in RequestHeaders)
                {
                    var header = context.Request.Headers[headerName];
                    if (header != null)
                    {
                        telemetry.Context.Properties.Add($"request-{headerName}", header);
                    }
                }
            }
            if (context.Response != null)
            {
                foreach (var headerName in ResponseHeaders)
                {
                    var header = context.Response.Headers[headerName];
                    if (header != null)
                    {
                        telemetry.Context.Properties.Add($"response-{headerName}", header);
                    }
                }
            }
        }
    }
</pre>

Now that we have an ITelemetryInitializer, we need to register it with Application Insights when the application starts up (e.g. in Global.asax or our Startup class etc depending on which frameworks we’re using):
<pre>
            TelemetryConfiguration.Active.TelemetryInitializers.Add(
                new HeaderTelemetryInitializer
                {
                    RequestHeaders =
                    {
                        "Accept"
                    },
                    ResponseHeaders =
                    {
                        "Content-Type"
                    }
                });
</pre>
&nbsp;

With that in place, we can run the site again and we will see the custom properties emitted for request that include the header values we asked for.

The code above is also included in a <a href="https://gist.github.com/stuartleeks/620aa7858f54f864b27803febc176811">gist</a> for easy consumption.

Enjoy!]]></content:encoded>
    </item>
    <item>
      <title>IntelliSense for Marathon Application and Group JSON in Visual Studio Code</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/intellisense-for-marathon-application-and-group-json-in-visual-studio-code</link>
      <pubDate>Wed, 19 Oct 2016 21:29:08 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/?p=1115</guid>
      <description><![CDATA[tl;dr – You can get IntelliSense for Marathon applications and groups in Visual Studio Code by...]]></description>
      <content:encoded><![CDATA[tl;dr – You can get IntelliSense for Marathon applications and groups in Visual Studio Code by adding a $schema property
<h1>The Problem</h1>
I’ve been having quite a lot of fun with Docker Containers recently, including presenting at various conferences! For ease and speed of demoing, I’ve tended to show <a href="https://docs.docker.com/swarm/">Docker Swarm</a> (with <a href="https://www.docker.com/products/docker-compose">Docker Compose</a>) when deploying an application to a cluster because there are fewer new concepts to introduce. You can get IntelliSense for Dockerfile and docker-compose.yml files in both <a href="https://visualstudiogallery.msdn.microsoft.com/0f5b2caa-ea00-41c8-b8a2-058c7da0b3e4">Visual Studio</a> and <a href="https://marketplace.visualstudio.com/items?itemName=PeterJausovec.vscode-docker">Visual Studio Code</a> (I often use the latter simply because I often demo from a non-Windows machine). I’ve spent some time with <a href="https://dcos.io/">DC/OS</a> recently, too. With DC/OS, you can use Marathon to run your containers, and these can be described in <a href="https://mesosphere.github.io/marathon/docs/rest-api.html#apps">Application JSON</a> or <a href="https://mesosphere.github.io/marathon/docs/application-groups.html">Application Group JSON</a>. The Marathon UI gives you an interactive way to define this:

&nbsp;

<a href="https://msdnshared.blob.core.windows.net/media/2016/10/image749.png"><img title="image" style="padding-top: 0px;padding-left: 0px;padding-right: 0px;border: 0px" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/10/image_thumb651.png" width="460" height="242" /></a>

And it even shows you the JSON behind it and allows you to edit it for scenarios that the UI doesn’t support:

<a href="https://msdnshared.blob.core.windows.net/media/2016/10/image750.png"><img title="image" style="padding-top: 0px;padding-left: 0px;padding-right: 0px;border: 0px" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/10/image_thumb652.png" width="458" height="271" /></a>

If you work with the definition in JSON files then you can use the <a href="https://dcos.io/docs/1.7/usage/cli/">DC/OS CLI</a> to create applications from the command line. Call me old-fashioned, but I like that this approach allows me to version-control my definitions. However, I wasn’t getting any help from Visual Studio Code with editing the files and that bothered me!
<h1>The Solution</h1>
It turned out that there was a pretty quick fix for this, which was to specify the <a href="https://json-schema.org/">JSON Schema</a> for the file I was editing. If you’re familiar with XML, you can kind of think of JSON Schema as XSDs for JSON.

After a quick bit of searching I found schemas for both the <a href="https://github.com/mesosphere/marathon/tree/1.1.1/docs/docs/rest-api/public/api/v2/schema">application and group JSON</a>. Visual Studio Code has built-in support for JSON Schema, so all I needed to do was add the $schema property to my JSON file.

For application JSON use:
<blockquote>"$schema": "<a href="https://raw.githubusercontent.com/mesosphere/marathon/master/docs/docs/rest-api/public/api/v2/schema/AppDefinition.json">https://raw.githubusercontent.com/mesosphere/marathon/master/docs/docs/rest-api/public/api/v2/schema/AppDefinition.json</a>",</blockquote>
For group JSON use:
<blockquote>"$schema": "<a href="https://raw.githubusercontent.com/mesosphere/marathon/master/docs/docs/rest-api/public/api/v2/schema/Group.json">https://raw.githubusercontent.com/mesosphere/marathon/master/docs/docs/rest-api/public/api/v2/schema/Group.json</a>",</blockquote>
Once that’s done you can enjoy IntelliSense (and naturally run your Swarm or DCOS workloads on <a href="https://azure.microsoft.com/en-us/documentation/articles/container-service-intro/">Container Service</a> <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none" alt="Winking smile" src="https://msdnshared.blob.core.windows.net/media/2016/10/wlEmoticon-winkingsmile3.png" />)

<a href="https://msdnshared.blob.core.windows.net/media/2016/10/marathon-code.gif"><img title="marathon-code" alt="marathon-code" src="https://msdnshared.blob.core.windows.net/media/2016/10/marathon-code_thumb.gif" width="520" height="208" /></a>]]></content:encoded>
    </item>
    <item>
      <title>Tweaking your PowerShell profile - Part 2: conditionally loading modules</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/tweaking-your-powershell-profile-part-2-conditionally-loading-modules</link>
      <pubDate>Tue, 24 May 2016 20:48:23 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/?p=1025</guid>
      <description><![CDATA[Introduction In the previous post we saw how to show the progress as PowerShell loads your profile....]]></description>
      <content:encoded><![CDATA[<h1>Introduction</h1> <p>In the <a href="https://blogs.msdn.microsoft.com/stuartleeks/2016/05/24/tweaking-your-powershell-profile-part-1-showing-loading-progress/">previous post</a> we saw how to show the progress as PowerShell loads your profile. </p> <p>I spend a lot of time working with the Azure PowerShell cmdlets so I had <a href="https://blogs.msdn.microsoft.com/stuartleeks/2015/12/11/persisting-azure-powershell-logins/">added them to my profile</a>. However, it turned out that they can be a little slow to load (yes, I know I’m impatient!). Since I frequently start PowerShell I wanted a way to be able to load the Azure cmdlets only when I needed them,. Since my computer isn’t yet psychic, I opted for a simple approach where I hold down the Shift key while PowerShell loads to signal that I want the Azure cmdlets loaded. The rest of the post will show how this can be achieved</p> <h1>The building blocks</h1> <p>Windows exposes a <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301(v=vs.85).aspx">GetKeyState</a> function that can be used to query the state of a key (e.g. whether it is currently pressed). If we were using this from C#, we would use <a href="https://msdn.microsoft.com/en-us/library/26thfadc.aspx">P/Invoke</a> via a DllImport. Since PowerShell is built on top of .NET we can take advantage of the <a href="https://blogs.technet.microsoft.com/heyscriptingguy/2013/10/19/weekend-scripter-use-powershell-and-pinvoke-to-remove-stubborn-files/">same functionality</a> (with a shout out for a <a href="https://rubli.info/t-blog/2011/06/29/querying-key-states-in-powershell/">helpful example</a>). </p> <p>Paste the following code into a PowerShell window to create the Get-KeyState function</p> <blockquote> <p><font face="Consolas">function Get-KeyState([uint16]$keyCode)<br>{<br>&nbsp; $signature = '[DllImport("user32.dll")]public static extern short GetKeyState(int nVirtKey);'<br>&nbsp; $type = Add-Type -MemberDefinition $signature -Name User32 -Namespace GetKeyState -PassThru<br>&nbsp; return [bool]($type::GetKeyState($keyCode) -band 0x80)<br>}<br>$VK_SHIFT = 0x10</font></p></blockquote> <p>Now we can execute <font face="Consolas">Get-KeyState $VK_SHIFT </font><font face="Segoe UI">to test the current state of the Shift key. Naturally it will return false. Instead, paste the following code into a PowerShell window and try holding down the shift key and releasing it:</font></p> <blockquote> <p><font face="Consolas">while($true) { Get-KeyState $VK_SHIFT; Start-Sleep -Milliseconds 500 }</font></p></blockquote> <p>Now we have the starting point for the conditional loading, the only thing that remains is to use this to test the state of the Shift key and then conditionally load the Azure module accordingly.</p> <h1>Show me the code</h1> <p>To see an example of this, check out <a href="https://gist.github.com/stuartleeks/9b3c8434cf86a1714b504247c945135b">this gist</a> that incorporates it into a profile script. It also includes the module loading messages from the <a href="https://blogs.msdn.microsoft.com/stuartleeks/2016/05/24/tweaking-your-powershell-profile-part-1-showing-loading-progress/">previous post</a> to make it easy to see what is going on.</p>]]></content:encoded>
    </item>
    <item>
      <title>Tweaking your PowerShell profile - Part 1: showing loading progress</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/tweaking-your-powershell-profile-part-1-showing-loading-progress</link>
      <pubDate>Tue, 24 May 2016 20:33:25 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/?p=1015</guid>
      <description><![CDATA[Tl;dr  In this post we look at adding rotating output at the top of the PowerShell window as shown...]]></description>
      <content:encoded><![CDATA[<h1>Tl;dr </h1> <p>In this post we look at adding rotating output at the top of the PowerShell window as shown here:</p> <p><a href="https://msdnshared.blob.core.windows.net/media/2016/05/PsLoadProfile.gif"><img title="PsLoadProfile" alt="PsLoadProfile" src="https://msdnshared.blob.core.windows.net/media/2016/05/PsLoadProfile_thumb.gif" width="383" height="177"></a></p> <h1>Introduction</h1> <p>Recently I realised that PowerShell was taking a while to load on my machine. I'd been adding more and more things to my profile and wanted a way to easily see what was taking the time (although I had a pretty good idea).</p> <h1>Thoughts</h1> <p>A couple of ideas came to mind pretty quickly. First was good old Write-<font face="Consolas">Host</font>, so I peppered these calls throughout my profile but wasn’t happy with the result as it felt a bit verbose.</p> <p><a href="https://msdnshared.blob.core.windows.net/media/2016/05/image736.png"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/05/image_thumb603.png" width="551" height="104"></a></p> <p>Next was the idea of using <font face="Consolas">System.Diagnostics.Debug.WriteLine</font>. Since PowerShell is built on .NET, this is pretty easy to do, and I’ve used this <a href="https://github.com/stuartleeks/posh-HumpCompletion/blob/master/posh-HumpCompletion.ps1#L4">in other places</a> to good effect <img class="wlEmoticon wlEmoticon-smile" style="border-top-style: none;border-left-style: none;border-bottom-style: none;border-right-style: none" alt="Smile" src="https://msdnshared.blob.core.windows.net/media/2016/05/wlEmoticon-smile9.png">. You can use <a href="https://technet.microsoft.com/en-us/sysinternals/debugview.aspx">DebugView</a> from SysInternals to view the output, and in terms of the console window it is pretty unobtrusive. In fact, it is maybe a little too unobtrusive as you only get an indication of progress if you have something like DebugView open.</p> <p>Then I came back to the fact that PowerShell is built on .NET and had an idea for how to implement the rotating text…</p> <h1>Implementing the rotating text</h1> <p>So, as I’ve mentioned, PowerShell is built on .NET. And in .NET, console applications use System.Console to interact with the console (to read/write text etc). To test this you can enter <font face="Consolas">[Console]::WriteLine(“Test”)</font> <img class="wlEmoticon wlEmoticon-smile" style="border-top-style: none;border-left-style: none;border-bottom-style: none;border-right-style: none" alt="Smile" src="https://msdnshared.blob.core.windows.net/media/2016/05/wlEmoticon-smile9.png"></p> <p><a href="https://msdnshared.blob.core.windows.net/media/2016/05/image737.png"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/05/image_thumb604.png" width="528" height="54"></a></p> <p>At this point an idea was definitely forming, as <font face="Consolas">Console</font> has another method: <font face="Consolas">SetCursorPosition</font></p> <p><font face="Consolas"><a href="https://msdnshared.blob.core.windows.net/media/2016/05/image738.png"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/2016/05/image_thumb605.png" width="538" height="138"></a></font></p> <blockquote> <p><em>Aside: As shown above, if you don’t include parameters and try executing a function in PowerShell it returns the type info for the function – handy way to check parameters and overloads</em></p></blockquote> <p>We can put this function to work by setting the location to 0,0 (top left) and then immediately writing some output:</p> <p><a href="https://msdnshared.blob.core.windows.net/media/2016/05/pssetcursorposition.gif"><img title="pssetcursorposition" alt="pssetcursorposition" src="https://msdnshared.blob.core.windows.net/media/2016/05/pssetcursorposition_thumb.gif" width="459" height="176"></a></p> <p>Now we can simply wrap that in a function. Note that we’re padding the output to the full width to erase any previous messages that were written.</p> <blockquote> <p><font face="Consolas">function OutputStatus($message){ <br>&nbsp;&nbsp;&nbsp; </font><font face="Consolas">[Console]::SetCursorPosition(0,0) <br>&nbsp;&nbsp;&nbsp; </font><font face="Consolas">Write-Host $message.PadRight([Console]::BufferWidth) <br></font><font face="Consolas">}</font></p></blockquote> <p>And then we can use <font face="Consolas">OutputStatus “Loading something”</font> in our profile and we get output like this:</p> <p>&nbsp;</p> <p><a href="https://msdnshared.blob.core.windows.net/media/2016/05/PsLoadProfile1.gif"><img title="PsLoadProfile[1]" alt="PsLoadProfile[1]" src="https://msdnshared.blob.core.windows.net/media/2016/05/PsLoadProfile1_thumb.gif" width="333" height="154"></a></p> <h1>Show me the code</h1> <p>The code for this is in <a href="https://gist.github.com/stuartleeks/2bc6709c6e023d18986a82f54cda6e08">this gist</a>. The gist also includes tracking messages to display at the end of loading, but hopefully that code doesn’t need an explanation <img class="wlEmoticon wlEmoticon-smile" style="border-top-style: none;border-left-style: none;border-bottom-style: none;border-right-style: none" alt="Smile" src="https://msdnshared.blob.core.windows.net/media/2016/05/wlEmoticon-smile9.png"></p>]]></content:encoded>
    </item>
    <item>
      <title>Posh-HumpCompletion–from the ground up</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/posh-humpcompletionfrom-the-ground-up</link>
      <pubDate>Tue, 10 May 2016 20:15:56 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/?p=895</guid>
      <description><![CDATA[Earlier this year I spent some time with Seth at Channel 9 and we recorded a couple of videos.  I’m...]]></description>
      <content:encoded><![CDATA[<p>Earlier this year I spent some time with <a href="https://sethjuarez.com/">Seth</a> at <a href="https://channel9.msdn.com/">Channel 9</a> and we recorded a couple of videos. </p> <p>I’m a little behind on things, but the <a href="https://channel9.msdn.com/Blogs/cloud-with-a-silver-lining/Fun-with-PowerShell-Creating-posh-HumpCompletion">first video is now up</a>, and covers building <a href="https://github.com/stuartleeks/posh-humpcompletion">posh-HumpCompletion</a> from scratch. It skips over some of the optimisations, but covers the main functionality. </p>]]></content:encoded>
    </item>
    <item>
      <title>Persisting Azure PowerShell logins</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/persisting-azure-powershell-logins</link>
      <pubDate>Fri, 11 Dec 2015 04:40:56 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/2015/12/11/persisting-azure-powershell-logins/</guid>
      <description><![CDATA[With the pre-1.0 Azure PowerShell cmdlets, my Azure login credentials were cached. Since making the...]]></description>
      <content:encoded><![CDATA[<p>With the pre-1.0 Azure PowerShell cmdlets, my Azure login credentials were cached. Since making the switch to the 1.x release I’ve found that I need to execute Login-AzureRmAccount each new PowerShell session. This has been bugging me for a while and today I finally foudnm the time to figure out a way round it. I’m blogging it here mostly as a way to find it later so that I don’t have to figure it out again, but if it helps anyone else then that’s a nice added bonus ;-)</p>  <p>After a bit of searching I found this issue which steered me in the right direction. </p>  <p>To set up persistence, start a PowerShell session and authenticate (e.g. run <font face="Consolas">Login-AzureRmAccount</font>).</p>  <p>From that session, run </p>  <blockquote>   <p><font face="Consolas">Save-AzureRmProfile –Path C:\your-path-here\AzureRmProfile.json</font></p> </blockquote>  <p>Then update your profile (I like to run “<font face="Consolas">ise $profile</font>”) to include </p>  <blockquote>   <p><font face="Consolas">Select-AzureRmProfile –Path C:\your-path-here\AzureRmProfile.json | out-null</font></p> </blockquote>  <p>Et voila! Now when you create a new PowerShell session it will import the saved profile.</p>  <p>NOTE: YMMV: this is working for me so far – if it works for you too, that’s great! I’ve also only been running like this for less than a day, so don’t know how long I’ve got until the token expires, or whether it gets refreshed! Use at your own risk ;-)</p>]]></content:encoded>
    </item>
    <item>
      <title>Working with docker output in PowerShell</title>
      <link>https://docs.microsoft.com/archive/blogs/stuartleeks/working-with-docker-output-in-powershell</link>
      <pubDate>Tue, 01 Dec 2015 22:24:27 GMT</pubDate>
      <dc:creator><![CDATA[stuartle]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/stuartleeks/2015/12/01/working-with-docker-output-in-powershell/</guid>
      <description><![CDATA[Just a quick post today :-)  These days I find myself working in both PowerShell and bash, and when...]]></description>
      <content:encoded><![CDATA[<p>Just a quick post today :-)</p>  <p>These days I find myself working in both PowerShell and bash, and when I’m in PowerShell, I like to have objects that I can work with. With the <a href="https://azure.microsoft.com/en-us/documentation/articles/xplat-cli/">Azure CLI</a> I can use the <font face="Consolas">--json</font> switch and then use something like <a href="https://stedolan.github.io/jq/">jq</a> to process the output, or in PowerShell I can use <a href="https://technet.microsoft.com/en-us/library/hh849898.aspx">ConvertFrom-Json</a> to parse the JSON into objects that can be piped/filtered/projected in the normal way.</p>  <p>When working with the docker command line, things are slightly different. The query commands (e.g. <font face="Consolas">ps</font>, <font face="Consolas">images</font>) support filtering but only the <font face="Consolas">ps</font> command seems to support <a href="https://docs.docker.com/engine/reference/commandline/ps/">formatting</a>. </p>  <p>To enable me to work with docker more easily in PowerShell, I wrote a little <a href="https://gist.github.com/stuartleeks/4661c3c05678eec822bc">helper</a>: ConvertFrom-Docker</p>  <h1>Installing ConvertFrom-Docker</h1>  <p>To get started, grab the script from <a title="https://gist.github.com/stuartleeks/4661c3c05678eec822bc" href="https://gist.github.com/stuartleeks/4661c3c05678eec822bc">https://gist.github.com/stuartleeks/4661c3c05678eec822bc</a> and save as <font face="Consolas">ConvertFromDocker.ps1</font></p>  <p>Then you need to dot source it, simply because I’ve not found time to wrap it up in a module yet – I’ll update this post if I do :-)</p>  <blockquote>   <p><font face="Consolas">. ./ConvertFromDocker.ps1</font></p> </blockquote>  <h1>Using ConvertFrom-Docker</h1>  <p>With this done you can run the following command:</p>  <blockquote>   <p><font face="Consolas">docker ps --no-trunc | ConvertFrom-Docker</font></p> </blockquote>  <p>The output will be similar to</p>  <blockquote>   <p><font face="Consolas">Image&#160;&#160;&#160;&#160;&#160;&#160; : containersched       <br />Ports&#160;&#160;&#160;&#160;&#160;&#160; : 0.0.0.0:5123-&gt;5000/tcp        <br />Names&#160;&#160;&#160;&#160;&#160;&#160; : desperate_jang        <br />Command&#160;&#160;&#160;&#160; : &quot;dnx -p project.json web&quot;        <br />Created&#160;&#160;&#160;&#160; : 12 days ago        <br />ContainerId : 9fb9d10f6a6d6423ff3b3a7734375726cc79706038942201442e636b50fa7979        <br />Status&#160;&#160;&#160;&#160;&#160; : Up 12 days</font></p>    <p><font face="Consolas">Image&#160;&#160;&#160;&#160;&#160;&#160; : stuartleeks/vorlon       <br />Ports&#160;&#160;&#160;&#160;&#160;&#160; : 0.0.0.0:1337-&gt;1337/tcp        <br />Names&#160;&#160;&#160;&#160;&#160;&#160; : stoic_yalow        <br />Command&#160;&#160;&#160;&#160; : &quot;node /vorlon/bin/vorlon&quot;        <br />Created&#160;&#160;&#160;&#160; : 2 weeks ago        <br />ContainerId : 5e64f5a8accabd039b24bcfec6b89127f46c14eb16e2d165461071f1e557151c        <br />Status&#160;&#160;&#160;&#160;&#160; : Up 2 weeks</font></p>    <p><font face="Consolas">Image&#160;&#160;&#160;&#160;&#160;&#160; : jwilder/nginx-proxy       <br />Ports&#160;&#160;&#160;&#160;&#160;&#160; : 0.0.0.0:80-&gt;80/tcp, 443/tcp        <br />Names&#160;&#160;&#160;&#160;&#160;&#160; : angry_visvesvaraya        <br />Command&#160;&#160;&#160;&#160; : &quot;/app/docker-entrypoint.sh forego start -r&quot;        <br />Created&#160;&#160;&#160;&#160; : 2 weeks ago        <br />ContainerId : 7fb4709668946f5bdc915874b9537b5cc52ccaf7fa2c74586b93af279db6512b        <br />Status&#160;&#160;&#160;&#160;&#160; : Up 2 weeks</font></p> </blockquote>  <p>This works with docker ps, docker images, etc and uses the first line of output from the command to determine the property names for the object :-)</p>  <p>Enjoy!</p>]]></content:encoded>
    </item>
  </channel>
</rss>