<?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>Will's UK ISV Corner</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/willeastbury/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/willeastbury/feed.xml</link>
    <description>Building software, services and solutions on the Microsoft Cloud platform, with whatever stack and toolchain you choose.</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:39:46 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Crib Sheet: Get Started with Windows Containers and Docker</title>
      <link>https://docs.microsoft.com/archive/blogs/willeastbury/crib-sheet-get-started-with-windows-containers-and-docker</link>
      <pubDate>Fri, 04 Aug 2017 09:43:14 GMT</pubDate>
      <dc:creator><![CDATA[William Eastbury]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/willeastbury/?p=205</guid>
      <description><![CDATA[A few people have been asking about where to start with containers on Windows 10 and Windows server,...]]></description>
      <content:encoded><![CDATA[<strong>A few people have been asking about where to start with containers on Windows 10 and Windows server, and with deployment to Azure (thinking about ACS and ACIs).</strong>

Before you even worry about how you host and deploy containers in Azure, it's probably best to start with a quick 101 list of reading and video resources on Containers in general and Docker, once you've read these - you can progress onto how / where to host them in Azure (our preferred platform for Windows Container orchestration in Azure is <strong>Service Fabric</strong>)

<strong>Here we go.. This is roughly the learning path that I followed to learn about Containers.</strong>

My Colleague David Gristwood also has a <a href="https://blogs.msdn.microsoft.com/david_gristwood/2017/08/04/getting-up-and-going-with-windows-containers-on-microsoft-azure/">nicely crafted blog post</a> that you should read as a primer before you start along this path which is more Azure Focused, I'm focusing on the container platform itself in Windows and Docker here.

<strong>Level 100 : Start Here</strong>

QuickStart Container 101

<a href="https://docs.microsoft.com/en-us/virtualization/windowscontainers/quick-start/index">https://docs.microsoft.com/en-us/virtualization/windowscontainers/quick-start/index</a>

Build 2015 - Containers what why and how

<a href="https://channel9.msdn.com/Events/Build/2015/2-704">https://channel9.msdn.com/Events/Build/2015/2-704</a>

Windows 10 Containers

<a href="https://docs.microsoft.com/en-us/virtualization/windowscontainers/quick-start/quick-start-windows-10">https://docs.microsoft.com/en-us/virtualization/windowscontainers/quick-start/quick-start-windows-10</a>

What is Docker?

<a href="https://www.docker.com/what-docker">https://www.docker.com/what-docker</a>

&nbsp;

<span><strong>Level 200 : More advanced containers / docker</strong> </span>

Linux vs Windows Containers

<a href="https://containerjournal.com/2016/10/28/linux-vs-windows-containers-whats-difference/">https://containerjournal.com/2016/10/28/linux-vs-windows-containers-whats-difference/</a>

Hyper-V vs Windows Containers

<a href="https://windowsitpro.com/windows-server-2016/differences-between-windows-containers-and-hyper-v-containers-windows-server-201">https://windowsitpro.com/windows-server-2016/differences-between-windows-containers-and-hyper-v-containers-windows-server-201</a>

Docker for Windows

<a href="https://docs.docker.com/docker-for-windows/">https://docs.docker.com/docker-for-windows/</a>

Docker Tutorial

<a href="https://docs.docker.com/get-started/">https://docs.docker.com/get-started/</a>

&nbsp;

<strong>Docker PowerShell Tools install</strong>
<p lang="en-US" style="padding-left: 30px">Open Powershell prompt with administrative credentials and execute</p>
<p lang="en-US" style="padding-left: 30px"><span>Register-PSRepository </span><span>-</span><span>Name DockerPS</span><span>-</span><span>Dev </span><span>-</span><span>SourceLocation </span><a href="https://ci.appveyor.com/nuget/docker-powershell-dev"><span>https:</span><span>//</span><span>ci.appveyor.com</span><span>/</span><span>nuget</span><span>/</span><span>docker</span><span>-</span><span>powershell</span><span>-</span><span>dev</span></a><span>
</span><span>Install-Module</span><span> Docker </span><span>-</span><span>Repository DockerPS</span><span>-</span><span>Dev</span></p>
<p style="padding-left: 30px"><cite lang="en-US">From <a href="https://github.com/artisticcheese/artisticcheesecontainer/wiki">https://github.com/artisticcheese/artisticcheesecontainer/wiki</a></cite></p>
<p lang="en-US"><strong>Windows Server - Install Server Providers</strong></p>
<p lang="en-US" style="padding-left: 30px"><span>Install</span><span>-</span><span>Module</span><span> -</span><span>Name</span><span> DockerMsftProvider -Repository PSGallery -</span><span>Force</span><span>
</span><span>Install</span><span>-</span><span>Package</span><span> -</span><span>Name</span><span> docker -ProviderName DockerMsftProvider</span></p>
<p style="padding-left: 30px"><cite lang="en-US">From <a href="https://docs.microsoft.com/en-us/virtualization/windowscontainers/quick-start/quick-start-windows-server">https://docs.microsoft.com/en-us/virtualization/windowscontainers/quick-start/quick-start-windows-server</a></cite></p>
&nbsp;

<strong>Building Docker Images</strong>

<a href="https://docs.docker.com/engine/reference/builder/">https://docs.docker.com/engine/reference/builder/</a>

<a href="https://docs.microsoft.com/en-gb/virtualization/windowscontainers/quick-start/quick-start-images">https://docs.microsoft.com/en-gb/virtualization/windowscontainers/quick-start/quick-start-images</a>

&nbsp;

Service Fabric and Containers

<a href="https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-containers-overview">https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-containers-overview</a>

&nbsp;

Ch9 Link Containers and Windows Server 2016

<a href="https://channel9.msdn.com/Blogs/windowsserver/Containers-in-Windows-Server-2016/">https://channel9.msdn.com/Blogs/windowsserver/Containers-in-Windows-Server-2016/</a>

&nbsp;

Connect - path to containerization

<a href="https://view.officeapps.live.com/op/view.aspx?src=https%3a%2f%2fsec.ch9.ms%2fsessions%2fignite%2f2016%2fBRK3319.pptx">https://view.officeapps.live.com/op/view.aspx?src=https%3a%2f%2fsec.ch9.ms%2fsessions%2fignite%2f2016%2fBRK3319.pptx</a>

&nbsp;

<strong>Level 300: Nanoserver, technical deep dive and command crib sheet.</strong>

&nbsp;

Repackaging apps to install headlessly on nanoserver

<a href="https://blogs.technet.microsoft.com/nanoserver/2015/11/19/hands-on-packaging-and-installing-your-first-windows-server-apps-on-nano-server/">https://blogs.technet.microsoft.com/nanoserver/2015/11/19/hands-on-packaging-and-installing-your-first-windows-server-apps-on-nano-server/</a>

&nbsp;

Technical Deep Dive further reading, why AND how + history and architecture on Windows Containers.

<a href="https://msdn.microsoft.com/en-us/magazine/mt797649.aspx">https://msdn.microsoft.com/en-us/magazine/mt797649.aspx</a>

&nbsp;

Service Fabric Container applications

<a href="https://docs.microsoft.com/en-gb/azure/service-fabric/service-fabric-get-started-containers#create-the-containerized-service-in-visual-studio">https://docs.microsoft.com/en-gb/azure/service-fabric/service-fabric-get-started-containers#create-the-containerized-service-in-visual-studio</a>

&nbsp;

<strong>+ Handy Docker Command List</strong>
<div>
<table title="" border="1" cellspacing="0" cellpadding="0" summary="">
<tbody>
<tr>
<td><span>Requirement</span></td>
<td><span>Command</span></td>
<td><span>Options</span></td>
<td><span>Handy Values</span></td>
</tr>
<tr>
<td>Download a base container image</td>
<td>docker pull &lt;publisher/image&gt;

&nbsp;</td>
<td></td>
<td>microsoft/nanoserver

microsoft/iis

microsoft/windowsservercore</td>
</tr>
<tr>
<td>List downloaded images</td>
<td>docker images</td>
<td></td>
<td></td>
</tr>
<tr>
<td>List running containers and ids</td>
<td>docker ps</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Commit a container to a new image</td>
<td>docker commit &lt;containeridfromdockerpscommand&gt; &lt;imagename&gt;</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Launch a command from a container</td>
<td>docker run &lt;imagename&gt; &lt;command&gt;</td>
<td>-rm Clean up container on exit, -it Run interactively (for command consoles will not run then exit)</td>
<td></td>
</tr>
<tr>
<td>Build a container from a dockerfile in the current path</td>
<td>docker build</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>]]></content:encoded>
    </item>
    <item>
      <title>UK ISV Technical Team in-person Events</title>
      <link>https://docs.microsoft.com/archive/blogs/willeastbury/in-person-events-program</link>
      <pubDate>Tue, 01 Aug 2017 10:40:58 GMT</pubDate>
      <dc:creator><![CDATA[William Eastbury]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/willeastbury/?p=186</guid>
      <description><![CDATA[These are the planned events through August and September that are currently open for registration....]]></description>
      <content:encoded><![CDATA[<em><strong>These are the planned events through August and September that are currently open for registration. #BuildWithAzure #Azure</strong></em>
<h2><strong><em>Briefing Roadshow: Your Journey to the Microsoft Azure Cloud – A Briefing for Software Solution Businesses </em></strong></h2>
We’re back on the road! In this multi-location technical briefing, spanning the UK, we will share the secrets from the different options to design and build apps in the cloud with Azure. Whether you are migrating existing applications “as is” to the cloud, optimising existing solutions and systems for cost on the cloud or building new applications specifically for the cloud. Join us as we show you the fastest route to the cloud and beyond with Microsoft Azure.

<strong><a href="https://blogs.msdn.microsoft.com/willeastbury/2017/08/01/briefing-roadshow-your-journey-to-the-microsoft-azure-cloud-a-briefing-for-software-solution-businesses/">Find out the schedule and Register Here</a></strong>
<h2></h2>
<h2><strong>Future Planned Events (Not yet open for registration), to be informed about when these events run and to sign up for event notifications - please email <a href="mailto:vipazure@microsoft.com?subject=Please sign me up to receive promotional emails on future FREE Microsoft UK ISV events and webinars!">vipazure@microsoft.com!</a></strong></h2>
<strong>Best Practices: Designing highly scalable and available cloud solutions</strong>

Agenda: Covers range of Azure best practices, patterns, dos and don’ts, etc around application high availability and scalability

<span>London Paddington 2KS (capacity 40) 27th Sept </span>

&nbsp;

<span><strong>Serverless and Microservices Azure Workshop</strong> </span>

Agenda: Cover the latest hot trends in Azure such as Containers, Functions, Service Fabric, microservice design patterns, etc

<span>London Paddington 2KS (capacity 40) 10th Oct</span>

&nbsp;

<strong>Best Practices: Security, Privacy and GDPR in Azure Workshop</strong>

Agenda: cover salient identity, security, privacy and GDPR aspects to Azure

<span>London Paddington 2KS (capacity 40) 17th Oct</span>

&nbsp;

<span><strong>Data and the Intelligent Cloud</strong> </span>

Agenda: Big data, ML, AI, etc

<span>London Paddington 2KS (capacity 50) 9th Nov</span>

<span> </span>

<strong>Best Practices: Deploy, Manage and Support Azure Based Services</strong>

Agenda: Best practices, patterns, dos and don’ts, etc around how to best deploy, and manage and support Azure applications

<span>London Paddington 2KS (capacity 50) 16th Nov</span>

&nbsp;

<strong>Best Practices: Architecting for cost design and managing, tracking and controlling service costs on Azure.</strong>

Agenda: Best practices, patterns, dos and don’ts, etc around how to reduce operational costs on Azure and get a better return on your cloud investment.

<span>London 2KS (capacity 50) 12th Dec</span>

&nbsp;

<strong>Note: To sign up to receive notifications on our events program when these events are confirmed to run with registration links, please email vipazure@microsoft.com.</strong>]]></content:encoded>
    </item>
    <item>
      <title>Briefing Roadshow: Your Journey to the Microsoft Azure Cloud - A Briefing for Software Solution Businesses</title>
      <link>https://docs.microsoft.com/archive/blogs/willeastbury/briefing-roadshow-your-journey-to-the-microsoft-azure-cloud-a-briefing-for-software-solution-businesses</link>
      <pubDate>Tue, 01 Aug 2017 10:28:38 GMT</pubDate>
      <dc:creator><![CDATA[William Eastbury]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/willeastbury/?p=185</guid>
      <description><![CDATA[In this technical roadshow briefing, we will share the secrets from the different options to design...]]></description>
      <content:encoded><![CDATA[In this technical roadshow briefing, we will share the secrets from the different options to design and build apps in the cloud with Azure. Whether you are migrating existing applications “as is” to the cloud, optimising existing solutions and systems for cost on the cloud or building new applications specifically for the cloud. Join us as we show you the fastest route to the cloud and beyond with Microsoft Azure.

1. <a href="https://www.microsoftevents.com/profile/form/index.cfm?PKformID=0x224148899e7">Register for Edinburgh August 30th</a>

2. <a href="https://www.microsoftevents.com/profile/form/index.cfm?PKformID=0x22411089924">Register for Birmingham September 5th </a>

3. <a href="https://www.microsoftevents.com/profile/form/index.cfm?PKformID=0x22420012858">Register for Manchester September 12th</a>

4. <a href="https://www.microsoftevents.com/profile/form/index.cfm?PKformID=0x2402893332b">Register for London September 18th</a>]]></content:encoded>
    </item>
    <item>
      <title>An Interactive Workshop: 12 Things to Consider when Moving to the Azure Cloud</title>
      <link>https://docs.microsoft.com/archive/blogs/willeastbury/an-interactive-workshop-12-things-to-consider-when-moving-to-the-azure-cloud</link>
      <pubDate>Tue, 01 Aug 2017 10:25:25 GMT</pubDate>
      <dc:creator><![CDATA[William Eastbury]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/willeastbury/?p=175</guid>
      <description><![CDATA[Have you been evaluating Azure as a possible platform for a software project? Or perhaps you have an...]]></description>
      <content:encoded><![CDATA[Have you been evaluating Azure as a possible platform for a software project? Or perhaps you have an existing application you are considering moving to Azure? If you develop software and are unsure about how to best proceed, or are going through the design process for a move to the cloud, then this interactive technical briefing could be just what you need, as we discuss the 12 most important things to consider when moving to the cloud.
<ol>
 	<li><strong>Register for London – August 8<sup>th  </sup></strong><u><a href="https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.microsoftevents.com%2Fprofile%2Fform%2Findex.cfm%3FPKformID%3D0x2232577ac1b&amp;data=02%7C01%7Cclasht%40microsoft.com%7C1924d0c99db749c9bbc608d4d5209edd%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636367783472152229&amp;sdata=QVHw9Sx6l87AxHZMGmo%2Fb9%2Fihx6AF86u6ghTACkH6Xs%3D&amp;reserved=0">https://www.microsoftevents.com/profile/form/index.cfm?PKformID=0x2232577ac1b</a></u></li>
 	<li><strong>Register for </strong><strong>Reading – August 15<sup>th </sup></strong><u><a href="https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.microsoftevents.com%2Fprofile%2Fform%2Findex.cfm%3FPKformID%3D0x2229594ee8e&amp;data=02%7C01%7Cclasht%40microsoft.com%7C1924d0c99db749c9bbc608d4d5209edd%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636367783472152229&amp;sdata=3MtxbctG%2BMCA0w%2FxL8E9%2BeJXwL9qApT4uBGBlx1C%2BD8%3D&amp;reserved=0">https://www.microsoftevents.com/profile/form/index.cfm?PKformID=0x2229594ee8e</a></u></li>
</ol>]]></content:encoded>
    </item>
    <item>
      <title>Azure Function to Authenticate Azure PowerShell into the ARM APIs</title>
      <link>https://docs.microsoft.com/archive/blogs/willeastbury/azure-function-to-authenticate-azure-powershell-into-the-arm-apis</link>
      <pubDate>Thu, 30 Mar 2017 17:15:17 GMT</pubDate>
      <dc:creator><![CDATA[William Eastbury]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/willeastbury/?p=87</guid>
      <description><![CDATA[Whilst working through a problem with a colleague I thought this would be a useful snippet to pop...]]></description>
      <content:encoded><![CDATA[Whilst working through a problem with a colleague I thought this would be a useful snippet to pop out there for ISVs who are deploying small scale tenant services or want to poll services and run Azure management processes in response to events. (This can be useful if your application design prevents you from using Autoscaling or VM Scale Sets in Azure, but you need to have some kind of flexibility in operations).

Literally copy and paste this into a powershell function, and define a service principal with the right permissions to connect to the subscription - then put SP_AppID and SP_Secret into your functionapp settings.

<hr />

<pre><span style="color: #008000"># Define an AppService setting SP_AppID to be the Azure AD Service Principal applicationid
# Define the AppService setting SP_Secret to be an Azure AD Service Principal Secret</span>
<span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$secpasswd</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">=</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">ConvertTo-SecureString</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$ENV:SP_Secret</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-AsPlainText</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-Force</span><span style="font-family: Lucida Console;font-size: xx-small"> </span>
<span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$mycreds</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">=</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">New-Object</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #8a2be2;font-family: Lucida Console;font-size: xx-small">System.Management.Automation.PSCredential</span><span style="font-family: Lucida Console;font-size: xx-small"> (</span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$ENV:SP_AppID</span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">,</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$secpasswd</span><span style="font-family: Lucida Console;font-size: xx-small">) </span>
<span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$result</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">=</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">Login-AzureRmAccount</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-ServicePrincipal</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-Tenant</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$ENV:SP_Tenant</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-Credential</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$mycreds</span><span style="font-family: Lucida Console;font-size: xx-small"> </span>
<span style="color: #008000"># Now do / deploy whatever you need to with the AzureRm Powershell cmdlets</span></pre>

<hr />

You can host this on an Azure Functions Consumption Plan so this will cost you a minimal amount for hosting administrative processes.

The use case my colleague (Mike Ormond) was interested in was dynamic deployment of an entire application tenant in response to an authenticated web request.

In this case we would have fired the New-AzureRmResourceGroupDeployment cmdlet.
<div style="color: #000000;line-height: 22px;font-family: Consolas, 'Courier New', monospace;font-size: 16px;font-weight: normal;background-color: #ffffff">
<div><span><span style="color: #0000ff">New-AzureRmResourceGroupDeployment</span> -ResourceGroupName </span><span style="color: #ff0000">$</span><span><span style="color: #ff0000">rg </span>-TemplateFile </span><span style="color: #ff0000">$</span><span><span style="color: #ff0000">templatefile</span> <span style="color: #0000ff">-Force</span> -TemplateParameterFile </span><span style="color: #ff0000">$</span><span><span style="color: #ff0000">tempparamfile</span> </span></div>
</div>
<div style="color: #000000;line-height: 22px;font-family: Consolas, 'Courier New', monospace;font-size: 16px;font-weight: normal;background-color: #ffffff">And voila, a dynamically deployed application tenant, based on a template, you can now manage that subscription fully via ARM from your Azure Functions.</div>
<div style="color: #000000;line-height: 22px;font-family: Consolas, 'Courier New', monospace;font-size: 16px;font-weight: normal;background-color: #ffffff"></div>
<div style="color: #000000;line-height: 22px;font-family: Consolas, 'Courier New', monospace;font-size: 16px;font-weight: normal;background-color: #ffffff">Now imagine if this function was bound via a storage queue to fire upon signup of a new tenant via a mgmt portal (say someone signs up with a credit card for your app).</div>
That's all for now :)]]></content:encoded>
    </item>
    <item>
      <title>How to Deploy a (Functions / Angular / Other native HTML5) App to Azure App Service from CI and CD tools.</title>
      <link>https://docs.microsoft.com/archive/blogs/willeastbury/how-to-deploy-a-functions-angular-other-native-html5-app-to-azure-app-service-from-ci-and-cd-tools</link>
      <pubDate>Thu, 22 Dec 2016 11:14:36 GMT</pubDate>
      <dc:creator><![CDATA[William Eastbury]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/willeastbury/?p=35</guid>
      <description><![CDATA[I've had a few requests recently to talk about how to run a full Continuous Integration + Continuous...]]></description>
      <content:encoded><![CDATA[<strong>I've had a few requests recently to talk about how to run a full Continuous Integration + Continuous Delivery service that can deploy non-asp.net sites (that can't be built and packaged in Visual Studio via MSBuild) to Azure App Service Web Apps.</strong>

<strong>If you have ever wanted to do one of the following, then please read on ...</strong>
<ul>
 	<li>Ever wanted to publish a site that you do not build through MS Build and MS Deploy to an Azure Functions Site ?</li>
 	<li>Ever looked at the myriad of possible options to do this and wondered where to start ?</li>
 	<li>Ever wanted to do this in a way that will work from all possible deployment scenarios (e.g. Locally, From VSTS, From TeamCity etc).</li>
</ul>
<strong>So... to do this we need to be aware of a few things.</strong>
<ol>
 	<li>There is a 'special' Zip RESTful API running behind the scenes as part of Azure App Service that you can use (The Kudu Zip API), read about it <a href="https://github.com/projectkudu/kudu/wiki/REST-API#zip">here</a>, if you GET from this API, you'll get zipped content from your site - whereas if you POST at the API Kudu will extract your Zip file.</li>
 	<li>Your deployment credentials for this API are the same as your FTP credentials to the site (just formatted differently), which are USER specific.</li>
 	<li>All of your <strong>app service deployment credentials</strong> are available to download from the Azure Resource Manager (ARM) API via scripts, once you have authenticated to the ARM API (and these are nicely wrapped in a cmdlet for us).</li>
 	<li>To trigger a 'pull CD' deployment we can use a webhook style connection to <a href="https://docs.microsoft.com/en-us/azure/app-service-web/app-service-continuous-deployment">pull directly from source control.</a> BUT in most professional / enterprise dev scenarios this is NOT appropriate for production environments. Ideally you want more fine-grained control of this and need to be able to have more explicit timing, hence you 'push' your code via a Deployment / Release agent after more thorough automated testing / load testing and approval. Whereas the standard webapp CD process will just shove whatever code is checked in onto your live site.</li>
</ol>
By combining 1-3 together, we can now deploy ANY kind of site up to Azure App Service (This should also work for a Tomcat WAR deployment, or deploying the root of a standard ASP.NET website (In fact this is the endpoint that is used when you deploy from visual studio using web deploy), deploying an Azure Functions site, or a bog standard HTML5 site such as a jQuery / JavaScript or AngularJS app.

<hr />

<strong>1. Firstly we need to zip your source code up into a zip file. </strong>

<strong>NOTE: If you don't need a zip file (if you only have one file to upload, such as a .war tomcat package) you can skip the zip stage and can use the <a href="https://github.com/projectkudu/kudu/wiki/REST-API#vfs">kudu vfs api </a>instead.</strong>

<strong>MANUALLY:</strong> So, let's zip your deployment source up using powershell, so we have a zip file to deploy over kudu (ideally you would do this in the build stage of your CI and save it as a deployment artifact, in this case I'll use the local copy of the IIS holding page on my machine to demonstrate this).

<strong><span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">     Add-Type</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-A</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #8a2be2;font-family: Lucida Console;font-size: xx-small">System.IO.Compression.FileSystem</span></strong>

<strong><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">     [</span><span style="color: #008080;font-family: Lucida Console;font-size: xx-small">IO.Compression.ZipFile</span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">]::</span><span style="font-family: Lucida Console;font-size: xx-small">CreateFromDirectory(</span><span style="color: #8b0000;font-family: Lucida Console;font-size: xx-small">"C:\inetpub\wwwroot"</span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">,</span><span style="color: #8b0000;font-family: Lucida Console;font-size: xx-small">"C:\build\web.zip"</span></strong><span style="font-family: Lucida Console;font-size: xx-small"><strong>)</strong> </span>

The output of this powershell script is simply a web.zip file in C:\build\, if you want to parameterize this in VSTS to build from the root of your project then use the VSTS environment variables in your script ... Like this.

<span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">     Add-Type</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-A</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #8a2be2;font-family: Lucida Console;font-size: xx-small">System.IO.Compression.FileSystem</span>

<span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">     [</span><span style="color: #008080;font-family: Lucida Console;font-size: xx-small">IO.Compression.ZipFile</span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">]::</span><span style="font-family: Lucida Console;font-size: xx-small">CreateFromDirectory(</span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$ENV:BUILD_REPOSITORY_LOCALPATH</span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">,</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$ENV:ARTIFACTSTAGINGDIRECTORY</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">+</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #8b0000;font-family: Lucida Console;font-size: xx-small">'\wwwroot.zip'</span><span style="font-family: Lucida Console;font-size: xx-small">) </span>

<strong>Below is an example of running something similar in a powershell script task in VSTS where I only want to zip PART of my repo (in this case the middle tier of a multi-tier application hosted on Azure Functions).</strong>

[caption id="attachment_16" align="aligncenter" width="1024"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/build-function-package.png"><img width="1024" height="265" class="size-large wp-image-16" alt="Build a function zip package" src="https://msdnshared.blob.core.windows.net/media/2016/12/build-function-package-1024x265.png" /></a> Build a function zip package[/caption]

<strong>AUTOMATED: If you are using VSTS to build then you can use the <a href="https://www.visualstudio.com/en-us/docs/build/steps/utility/archive-files">Archive files build task</a> to complete the above steps without writing powershell.</strong>

<strong>If we are using a <em>cloud hosted</em> build agent (in VSTS or elsewhere), we need to capture the output of the zip file at this point to an artifact ready for deployment (in VSTS you would simply use a 'Copy and publish artifact' or 'publish artifact' build task like the below). </strong>

&nbsp;

[caption id="attachment_65" align="aligncenter" width="300"]<a href="https://msdnshared.blob.core.windows.net/media/2016/12/site-zip-artifact.png"><img width="300" height="171" class="size-medium wp-image-65" alt="Site - Store Zip Artifact VSTS" src="https://msdnshared.blob.core.windows.net/media/2016/12/site-zip-artifact-300x171.png" /></a> Site - Store Zip Artifact VSTS[/caption]

<strong>If you are running this locally, then you will retain the output from the build anyway on your local filesystem. </strong>

<hr />

<strong>2. Next, we need to authenticate to the Azure ARM API in powershell.</strong>

<strong>AUTOMATED:</strong> If you are using VSTS to host this pipeline (and running this next script in an Azure Powershell task), <strong>then at this point you would already be authenticated to your Azure subscription via a service principal.</strong>

<strong>MANUAL: If not, then to call this locally you will need to call Add-AzureRMAccount and login your script interactively (using the <a href="https://docs.microsoft.com/en-us/azure/active-directory/active-directory-authentication-libraries">ADAL libraries</a>). </strong>

<span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">    Add-AzureRmAccount </span>

<strong>You <em>can</em> do the below and pipe the script some credentials in, <span style="text-decoration: underline">though we do not recommend this</span> for production service deployments.</strong>
<blockquote><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$inputuser</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">=</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #8b0000;font-family: Lucida Console;font-size: xx-small">'UserName'</span>

<span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$inputpass</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">=</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #8b0000;font-family: Lucida Console;font-size: xx-small">'Password'</span>

<span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$Password</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">=</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">ConvertTo-SecureString</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-AsPlainText</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$inputpass</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-Force</span>

<span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$Credential</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">=</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">New-Object</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #8a2be2;font-family: Lucida Console;font-size: xx-small">System.Management.Automation.PSCredential</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$inputuser</span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">,</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$Password</span><span style="font-family: Lucida Console;font-size: xx-small"> </span>

<span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">Login-AzureRmAccount</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-Credential</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$Credential</span></blockquote>
<em><strong>Note: If your organization enforces Multi Factor Authentication, then you MUST use a Service Principal to automate this login step via a service, Login-AzureRmAccount can only be used interactively in this situation and the above call will fail with this error message.</strong> </em>
<blockquote><span style="color: #ff0000;font-family: Lucida Console;font-size: xx-small">Login-AzureRmAccount : Federated service at https://stsaddress returned error: ID3242: The security token could not be authenticated or authorized.: </span>

The remote server returned an error: (500) Internal Server Error.

At line:1 char:1

+ Login-AzureRmAccount -Credential $creds

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : CloseError: (:) [Add-AzureRmAccount], AadAuthenticationFailedException

+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.AddAzureRMAccountCommand</blockquote>
<strong>David Ebbo has a neat post how to login through PowerShell with a Service Principal <a href="https://blog.davidebbo.com/2014/12/azure-service-principal.html">here</a> and our official docs on how to create a service principal are <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal">here</a>. Of course, VSTS also automates all of this for you nicely, which is another reason to use it. </strong>

<hr />

<strong>3.</strong> <strong>Next up, we can go fetch our web deploy credentials via the AzureRM cmdlets.</strong>

<strong>MANUAL: <span style="color: orangered;font-family: 'Lucida Console';font-size: 9pt"> </span></strong>
<blockquote><span style="color: orangered;font-family: 'Lucida Console';font-size: 9pt">$temploc</span><span style="font-family: 'Lucida Console';font-size: 9pt"><span style="color: #000000"> </span><span>=</span><span style="color: #000000"> </span><span>"test.output.txt"</span></span>

<span style="color: darkgreen;font-family: 'Lucida Console';font-size: 9pt"># For web deploy - </span><span style="color: darkgreen;font-family: 'Lucida Console';font-size: 9pt">Get the publishing data from the site.</span>

<span style="color: orangered;font-family: 'Lucida Console';font-size: 9pt">$site</span><span style="font-family: 'Lucida Console';font-size: 9pt"><span style="color: #000000"> </span><span>=</span><span style="color: #000000"> </span><span>Get-AzureRmWebAppPublishingProfile</span><span style="color: #000000"> </span><span>-Name</span><span style="color: #000000"> </span><span>$sitename</span><span style="color: #000000"> </span><span>-OutputFile</span><span style="color: #000000"> </span><span>$temploc</span><span style="color: #000000"> </span><span>-ResourceGroup</span><span style="color: #000000"> </span><span>$resgrp</span><span style="color: #000000"> </span><span>-Format</span><span style="color: #000000"> </span><span>WebDeploy</span><span> </span></span>

<span style="color: darkgreen;font-family: 'Lucida Console';font-size: 9pt"># Reload it from the disk, parse the XML and clean up</span>

<span style="color: darkgray;font-family: 'Lucida Console';font-size: 9pt">[</span><span style="color: teal;font-family: 'Lucida Console';font-size: 9pt">Xml</span><span style="color: darkgray;font-family: 'Lucida Console';font-size: 9pt">]</span><span style="font-family: 'Lucida Console';font-size: 9pt"><span style="color: #000000"> </span><span>$resourcefile</span><span style="color: #000000">  </span><span>=</span><span style="color: #000000"> </span><span>Get-Content</span><span style="color: #000000"> </span><span>$temploc</span></span>

<span style="color: blue;font-family: 'Lucida Console';font-size: 9pt">Del</span><span style="font-family: 'Lucida Console';font-size: 9pt"><span style="color: #000000"> </span><span>$temploc</span></span>

<span style="color: darkgreen;font-family: 'Lucida Console';font-size: 9pt"># Pull the user details from the first Pub profile object returned</span>

<span style="color: orangered;font-family: 'Lucida Console';font-size: 9pt">$username</span><span style="font-family: 'Lucida Console';font-size: 9pt"><span style="color: #000000"> </span><span>=</span><span style="color: #000000"> </span><span>$resourcefile</span><span>.</span><span style="color: #000000">publishData</span><span>.</span><span style="color: #000000">publishProfile</span><span>[</span><span>0</span><span>].</span><span style="color: #000000">userName </span><span># The Username</span></span>

<span style="color: orangered;font-family: 'Lucida Console';font-size: 9pt">$password</span><span style="font-family: 'Lucida Console';font-size: 9pt"><span style="color: #000000"> </span><span>=</span><span style="color: #000000"> </span><span>$resourcefile</span><span>.</span><span style="color: #000000">publishData</span><span>.</span><span style="color: #000000">publishProfile</span><span>[</span><span>0</span><span>].</span><span style="color: #000000">userPWD </span><span># The Password </span></span></blockquote>
<strong>At this point $username and $password contain your credentials to manipulate the Azure Web App.</strong>

<strong>AUTOMATED: Steps 3 and 4 are both collated together under VSTS' - 'Azure App Service Deploy' release task here, which uses Kudu's API's under the covers.</strong>

<hr />

<strong>4. Let's REST post my zip file at the webroot of the App Service Web App using the Kudu Zip API
MANUAL:
</strong>

<span style="color: darkgreen;font-family: 'Lucida Console';font-size: 9pt"># Post the file at the KUDU rest API </span>

<span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$ZipPath</span><span style="font-family: Lucida Console;font-size: xx-small"> = "path to zip file"</span>

$sitename =

<span style="color: orangered;font-family: 'Lucida Console';font-size: 9pt">$base64AuthInfo</span><span style="font-family: 'Lucida Console';font-size: 9pt"><span style="color: #000000"> </span><span>=</span><span style="color: #000000"> </span><span>[</span><span>Convert</span><span>]::</span><span style="color: #000000">ToBase64String(</span><span>[</span><span>Text.Encoding</span><span>]::</span><span style="color: #000000">ASCII</span><span>.</span><span style="color: #000000">GetBytes((</span><span>"{0}:{1}"</span><span style="color: #000000"> </span><span>-f</span><span style="color: #000000"> <span style="color: orangered;font-family: 'Lucida Console';font-size: 9pt">$username</span></span><span>, <span style="color: orangered;font-family: 'Lucida Console';font-size: 9pt">$password</span></span><span style="color: #000000">)))</span></span>

<span style="color: orangered;font-family: 'Lucida Console';font-size: 9pt">$apiRM</span><span style="font-family: 'Lucida Console';font-size: 9pt"><span style="color: #000000"> </span><span>=</span><span style="color: #000000"> </span><span>"<a href="https://$sitename.scm.azurewebsites.net/api/zip/site/wwwroot/"><span style="color: #0563c1">https://$sitename.scm.azurewebsites.net/api/zip/site/wwwroot/</span></a>"</span></span>

<span style="color: #0000ff;font-family: Lucida Console;font-size: xx-small">Invoke-RestMethod</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-Uri</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$apiRM</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-Headers</span><span style="font-family: Lucida Console;font-size: xx-small"> @{Authorization</span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">=</span><span style="font-family: Lucida Console;font-size: xx-small">(</span><span style="color: #8b0000;font-family: Lucida Console;font-size: xx-small">"Basic {0}"</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #a9a9a9;font-family: Lucida Console;font-size: xx-small">-f</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$base64AuthInfo</span><span style="font-family: Lucida Console;font-size: xx-small">)} </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-Method</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #8a2be2;font-family: Lucida Console;font-size: xx-small">PUT</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #000080;font-family: Lucida Console;font-size: xx-small">-InFile</span><span style="font-family: Lucida Console;font-size: xx-small"> </span><span style="color: #ff4500;font-family: Lucida Console;font-size: xx-small">$ZipPath</span><span style="font-family: Lucida Console;font-size: xx-small"> </span>

<strong>AUTOMATED: Steps 3 and 4 are both collated together under VSTS' - 'Azure App Service Deploy' release task here, which uses Kudu's API's under the covers.</strong>

<strong>And we're done !</strong> <strong>The site should have been uploaded.</strong>

<hr />

<em>I hope this gives you a feel for how to package, authenticate to the App Service APIs and upload both ASP.NET sites and standard HTML sites directly to Azure App Service using powershell scripting from your choice of deployment tool in place of xcopy deployment. </em>

<em>Please use any and or all of these pieces to deploy your sites.</em>

<em>Other things for you to consider might include :-</em>
<ul>
 	<li>Check out the <a href="https://www.visualstudio.com/en-gb/docs/release/examples/azure/deployment-slots-webapps">App Service deployment slot swapping </a>task from VSTS.</li>
 	<li>Don't forget to automate the creation of your infrastructure using the VSTS 'Azure Resource Group Deployment' task to deploy an <a href="https://github.com/Microsoft/vsts-tasks/tree/master/Tasks/DeployAzureResourceGroup">Azure Resource Manager template </a>to build your App Service Plan and Site + deploy config.</li>
 	<li>Deploying a <a href="https://www.visualstudio.com/en-gb/docs/release/examples/nodejs/node-to-azure-webapps">node.js app to App Service from VSTS</a></li>
</ul>
<strong>Thanks,</strong>

Will Eastbury]]></content:encoded>
    </item>
  </channel>
</rss>