<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Tom Hollander's blog</title><link>http://blogs.msdn.com/b/tomholl/</link><description>patterns, practices and pontification</description><dc:language>en-US</dc:language><generator>Telligent Evolution Platform Developer Build (Build: 5.6.50428.7875)</generator><item><title>Windows Azure in Australia: Facts and Rumours</title><link>http://blogs.msdn.com/b/tomholl/archive/2013/05/21/windows-azure-in-australia-facts-and-rumours.aspx</link><pubDate>Mon, 20 May 2013 20:58:42 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10420133</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10420133</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2013/05/21/windows-azure-in-australia-facts-and-rumours.aspx#comments</comments><description>&lt;p&gt;Today, Microsoft has made the &lt;a href="http://blogs.msdn.com/b/ausblog/archive/2013/05/16/windows-azure-expands-downunder.aspx"&gt;long-awaited announcement that Windows Azure is coming to Australia&lt;/a&gt;! Of course it’s been possible for Aussies to deploy and use applications in Windows Azure for some time, but this has always required deploying to overseas data centres. This announcement is about the upcoming availability of two new Windows Azure sub-regions in New South Wales and Victoria, complete with data geo-replication between the sub-regions. This is big news for many Australian customers, as it will mean lower latency when accessing Windows Azure infrastructure, as well as increased flexibility for customers with specific compliance and data sovereignty concerns.&lt;/p&gt;  &lt;p&gt;While we’re very excited to be able to finally confirm this news, there are a number of rumours surrounding this announcement which we are not able to confirm or deny at this time:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;We have no comment on whether these new sub-regions will be deployed in the Sydney Opera House and on a Melbourne tram&lt;/li&gt;    &lt;li&gt;We have no comment on whether we will be employing a “Star Wars” defence mechanism to protect the infrastructure against attacks from crocodiles, funnel web spiders and &lt;a href="http://en.wikipedia.org/wiki/Drop_bear"&gt;drop bears&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;We have no comment on whether the fans in the servers will spin in the opposite direction to those in our northern hemisphere servers&lt;/li&gt;    &lt;li&gt;We have no comment on whether the new servers will play a “Crikey!” sound when they boot&lt;/li&gt;    &lt;li&gt;We have no comment about whether the backup generators will be powered by beer (however, if this &lt;i&gt;were&lt;/i&gt; true, we can confirm that it would &lt;i&gt;not &lt;/i&gt;be Fosters).&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I’m sorry I can’t put any of these rumours to bed just now, but in the meantime I hope the news that Windows Azure is coming to town is exciting enough to keep you going for a while. If you’re already using Windows Azure, we look forward to seeing your apps deployed to the Aussie regions soon! And if you’re not… well what are you waiting for?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10420133" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Windows+Azure/">Windows Azure</category><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Australia/">Australia</category></item><item><title>Keep your Windows Azure applications running with custom health checks</title><link>http://blogs.msdn.com/b/tomholl/archive/2013/05/17/keep-your-windows-azure-applications-running-with-custom-health-checks.aspx</link><pubDate>Fri, 17 May 2013 13:37:30 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10419660</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10419660</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2013/05/17/keep-your-windows-azure-applications-running-with-custom-health-checks.aspx#comments</comments><description>&lt;p&gt;&lt;em&gt;Summary: Even though Windows Azure does a great job of keeping your VMs running, only you know exactly what it means for your own apps to be healthy. This post and sample code shows a pattern for implementing custom health checks that can report the health of your application, recover from failures if possible, and bring an instance offline if not.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;The big selling point of Platform as a Service (PaaS) is that managing things like the hardware, network and operating system is someone else’s problem. So if a Windows Azure server spontaneously combusts in the middle of the night, the fabric will automatically detect this and move any affected VMs onto servers not currently engulfed by flames. However keeping your &lt;em&gt;applications&lt;/em&gt; healthy is still your responsibility. While a simple web application is almost certain to keep running if the underlying OS and hardware are healthy, this isn’t necessarily true for a complex enterprise application. A complex app could depend on various Windows Services running, files and registry keys being in a certain state, and connectivity to local and remote services being in place. If any of these things break it could be disastrous for your application, yet as far as the Windows Azure fabric is concerned, everything is running perfectly.&lt;/p&gt;  &lt;p&gt;Fortunately, Windows Azure provides you with a couple of hooks that let you implement health checks into your deployments. The first of these is &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/jj151530.aspx"&gt;Load Balancer Probes&lt;/a&gt;. These can be specified in your ServiceDefinition.csdef file, and instruct the Windows Azure load balancer to regularly ping URLs of your choice to check that your service is still alive. If the response is anything but a 200 OK, your VM is deemed unhealthy and it’s removed from the load balancer. This mechanism is useful as it’s completely declarative, works on both PaaS (cloud services) and IaaS (virtual machines), and can be hooked into existing production or health check pages built into a web app. On the downside, when a Load Balancer Probe detects your instance is unhealthy it doesn’t apparently change the VM state or otherwise indicate to operations staff that something is wrong. Also, web pages are not always the best launching point for checking health of things like Windows Services.&lt;/p&gt;  &lt;p&gt;The other option is to subscribe to the &lt;strong&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/microsoft.windowsazure.serviceruntime.roleenvironment.statuscheck.aspx"&gt;RoleEnvironment.StatusCheck&lt;/a&gt; &lt;/strong&gt;event, which gets fired every time the Windows Azure Guest Agent needs to report its status to the fabric. In the event handler you can implement any logic you wish, and if you deem the instance unhealthy you can request the instance’s status be changed to Busy until the next status check, resulting in it being removed from the load balancer. Since this approach leverages the RoleEnvironment it’s PaaS only, but I found it more useful than Load Balancer Probes so it’s the approach I’ll use in this post and accompanying sample.&lt;/p&gt;  &lt;p&gt;First, the mandatory disclaimer. I’ve made &lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/0143.AzureHealthCheckSampleService.zip"&gt;some source code available&lt;/a&gt;&lt;font style="style"&gt;&lt;/font&gt; that shows the solution described in the post, but this is sample, not production quality code. It hasn’t been extensively tested and may well contain bugs. For enterprise use you should look at incorporating dependency injection and possibly a plug-in framework like MEF to provide more flexibility and testability. And the two health check classes I’ve supplied are designed as examples of what kind of thing is possible, rather than being complete implementations that will solve real problems. However I’m confident the pattern is sound, so feel free to build upon this (with appropriate testing) in your own solutions.&lt;/p&gt;  &lt;p&gt;With that out of the way, let’s talk about the solution. My code contains a project called &lt;strong&gt;AzureHealthCheck&lt;/strong&gt; which contains both the framework classes and a couple of sample health checks. This can be wired up into any web or worker roles in your PaaS cloud services. You do this by creating an instance of &lt;strong&gt;HealthCheckController&lt;/strong&gt;, starting it when the role starts and stopping it when the role stops:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WebRole : RoleEntryPoint
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; HealthCheckController _healthCheckController = &lt;span class="kwrd"&gt;new&lt;/span&gt; HealthCheckController();

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; OnStart()
    {
        _healthCheckController.Start();
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnStart();
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnStop()
    {
        _healthCheckController.Stop();
        &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnStop();
    }       
}&lt;/pre&gt;


&lt;p&gt;I won’t show all the code for &lt;strong&gt;HealthCheckController&lt;/strong&gt; here, but here’s what it does:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Retrieves the list of health checks and their settings from the ServiceConfiguration setting called “HealthCheckers”, instantiates the classes and stores them in a list&lt;/li&gt;

  &lt;li&gt;Subscribes to the RoleEnvironment.Changed and RoleEnvironment.StatusCheck events&lt;/li&gt;

  &lt;li&gt;In the RoleEnvironment_Changed event handler, reloads the configuration and refreshes the list of health checkers&lt;/li&gt;

  &lt;li&gt;In the RoleEnvironment_StatusCheck event handler:&lt;/li&gt;

  &lt;ul&gt;
    &lt;li&gt;Iterates through all configured health checks&lt;/li&gt;

    &lt;ul&gt;
      &lt;li&gt;Calls the &lt;strong&gt;CheckHealth()&lt;/strong&gt; method&lt;/li&gt;

      &lt;li&gt;If the instance is deemed unhealthy, and the health checker wasn’t configured to keep the instance running anyway, calls &lt;strong&gt;SetBusy()&lt;/strong&gt; to remove the instance from the load balancer&lt;/li&gt;

      &lt;li&gt;For any unhealthy or error conditions, logs the results to Windows Azure Diagnostics (which could be read by System Center Operations Manager or similar tools to perform further actions such as rebooting or reimaging the instance)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/ul&gt;
&lt;/ul&gt;

&lt;p&gt;The health checkers are custom classes that implement the &lt;strong&gt;IHealthChecker &lt;/strong&gt;interface:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IHealthChecker
{
    &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialize(&lt;span class="kwrd"&gt;string&lt;/span&gt; initData);
    HealthCheckResult CheckHealth();
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HealthCheckResult
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsHealthy { get; set; }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; RemediationAttempted { get; set; }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; StatusMessage { get; set; }
}&lt;/pre&gt;

&lt;p&gt;As you can see, this is a pretty simple contract. Each health checker can be initialised with a custom string, it can check health, and it can report the result: whether the check showed the instance as healthy, whether remediation was performed, and any status messages that should be logged. &lt;/p&gt;

&lt;p&gt;In my code I have two sample health checkers. The first, &lt;strong&gt;PingUrlHealthChecker&lt;/strong&gt;, is a lot like a Load Balancer Probe in that it calls a URL in your main web site and reports unhealthy if the response is anything but 200 OK. This health checker does not attempt any remediation:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PingUrlHealthChecker : IHealthChecker
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; Uri _pingUrl;

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetWebUrlBase()
    {
        var serverManager = &lt;span class="kwrd"&gt;new&lt;/span&gt; ServerManager();
        var siteName = RoleEnvironment.CurrentRoleInstance.Id + &lt;span class="str"&gt;&amp;quot;_Web&amp;quot;&lt;/span&gt;; &lt;span class="rem"&gt;// TODO: allow user to specify which site to use&lt;/span&gt;
        var site = serverManager.Sites[siteName];
        var binding = site.Bindings[0]; &lt;span class="rem"&gt;// TODO: allow user to specify which binding to use&lt;/span&gt;
        &lt;span class="kwrd"&gt;return&lt;/span&gt;  String.Format(&lt;span class="str"&gt;&amp;quot;{0}://{1}:{2}/&amp;quot;&lt;/span&gt;, binding.Protocol, binding.EndPoint.Address, binding.EndPoint.Port);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialize(&lt;span class="kwrd"&gt;string&lt;/span&gt; initData)
    {
        &lt;span class="rem"&gt;// initData is a relative URL to ping, e.g. &amp;quot;/foo/bar.aspx&amp;quot;&lt;/span&gt;
        var urlBase = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(GetWebUrlBase());
        _pingUrl =  &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(urlBase, initData);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; HealthCheckResult CheckHealth()
    {
        var result = &lt;span class="kwrd"&gt;new&lt;/span&gt; HealthCheckResult
        {
            IsHealthy = &lt;span class="kwrd"&gt;true&lt;/span&gt;,
        };

        HttpWebResponse response; 
        &lt;span class="kwrd"&gt;try&lt;/span&gt;
        {
            var client = WebRequest.Create(_pingUrl) &lt;span class="kwrd"&gt;as&lt;/span&gt; HttpWebRequest;
            response = client.GetResponse() &lt;span class="kwrd"&gt;as&lt;/span&gt; HttpWebResponse;
        }
        &lt;span class="kwrd"&gt;catch&lt;/span&gt; (WebException wex)
        {
            response = (HttpWebResponse) wex.Response;
        }
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (response.StatusCode != HttpStatusCode.OK)
        {
            result.IsHealthy = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            result.StatusMessage += String.Format(&lt;span class="str"&gt;&amp;quot;HTTP Response '{0} {1}' returned from URL {2}.&amp;quot;&lt;/span&gt;, (&lt;span class="kwrd"&gt;int&lt;/span&gt;)response.StatusCode, response.StatusDescription, _pingUrl.ToString());
        }
        
        &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
    }
}&lt;/pre&gt;


&lt;p&gt;The second sample health checker, &lt;strong&gt;WindowsServiceHealthChecker &lt;/strong&gt;does just what it says on the box: it checks if a specified Windows Service is running. However this one supports remediation, in that it will attempt to restart the service if it isn’t running. If it’s successful, the instance will still be reported as healthy (although a warning is still logged). If not, the instance will be reported as unhealthy.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WindowsServiceHealthChecker : IHealthChecker
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _serviceName;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialize(&lt;span class="kwrd"&gt;string&lt;/span&gt; initData)
    {
        _serviceName = initData;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; HealthCheckResult CheckHealth()
    {
        var result = &lt;span class="kwrd"&gt;new&lt;/span&gt; HealthCheckResult();
        var sc = &lt;span class="kwrd"&gt;new&lt;/span&gt; ServiceController(_serviceName);

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (sc.Status == ServiceControllerStatus.Stopped)
        {
            result.RemediationAttempted = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
            result.StatusMessage = String.Format(&lt;span class="str"&gt;&amp;quot;Service '{0}' was restarted.&amp;quot;&lt;/span&gt;, _serviceName);
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                sc.Start();
                DateTime start = DateTime.Now;
                &lt;span class="kwrd"&gt;while&lt;/span&gt; (sc.Status != ServiceControllerStatus.Running &amp;amp;&amp;amp; (DateTime.Now - start).TotalSeconds &amp;lt; 10)
                {
                    sc.Refresh();
                }
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                result.StatusMessage = String.Format(&lt;span class="str"&gt;&amp;quot;Service '{0}' could not be restarted: '{1}'. &amp;quot;&lt;/span&gt;, _serviceName, ex.Message);
            }

        }

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (sc.Status == ServiceControllerStatus.Running)
        {
            result.IsHealthy = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }
        &lt;span class="kwrd"&gt;else&lt;/span&gt;
        {
            result.IsHealthy = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            result.StatusMessage += String.Format(&lt;span class="str"&gt;&amp;quot;Service '{0}' is in state {1}.&amp;quot;&lt;/span&gt;, _serviceName, sc.Status);
        }

        &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
    }
}&lt;/pre&gt;


&lt;p&gt;Hopefully these two sample health checkers will give you an idea of what’s possible, so you can come up with more interesting and sophisticated ones for your own application. Once your health checkers are defined, the last step is to configure your cloud service with a setting called “HealthCheckers” in ServiceConfiguration.cscfg. The value is a JSON-formatted array of health checkers, each of which you must specify the &lt;strong&gt;typeName&lt;/strong&gt; (assembly-qualified), the &lt;strong&gt;initData&lt;/strong&gt;, and optionally a Boolean value &lt;strong&gt;keepRunningIfUnhealthy &lt;/strong&gt;(default is false). An example setting is shown below, although keep in mind that if you edit it using Visual Studio’s role configuration dialog you don’t need to escape the quotes yourself.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Setting&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;HealthCheckers&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;[{&amp;amp;quot;typeName&amp;amp;quot;: &amp;amp;quot;AzureHealthCheck.PingUrlHealthChecker, AzureHealthCheck&amp;amp;quot;, &amp;amp;quot;initData&amp;amp;quot;: &amp;amp;quot;FileProbe.txt&amp;amp;quot;},&lt;br /&gt;{&amp;amp;quot;typeName&amp;amp;quot;: &amp;amp;quot;AzureHealthCheck.WindowsServiceHealthChecker, AzureHealthCheck&amp;amp;quot;, &amp;amp;quot;initData&amp;amp;quot;: &amp;amp;quot;W3SVC&amp;amp;quot;},&lt;br /&gt;{&amp;amp;quot;typeName&amp;amp;quot;: &amp;amp;quot;AzureHealthCheck.WindowsServiceHealthChecker, AzureHealthCheck&amp;amp;quot;, &amp;amp;quot;initData&amp;amp;quot;: &amp;amp;quot;W32Time&amp;amp;quot;, &amp;amp;quot;keepRunningIfUnhealthy&amp;amp;quot; : &amp;amp;quot;true&amp;amp;quot;}]&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;




&lt;p&gt;Note that since this setting is in CloudConfiguration.cscfg, you can change it after deployment, although of course any health check assemblies you use need to be deployed with your solution. &lt;/p&gt;

&lt;h3&gt;Running the Sample&lt;/h3&gt;

&lt;p&gt;If you like the look of this and would like to try it out, please &lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/0143.AzureHealthCheckSampleService.zip"&gt;download the sample code&lt;/a&gt;&lt;font style="style"&gt;&lt;/font&gt;&lt;font style="background-color: #ffff00"&gt;&lt;/font&gt;. Here’s what you need to do to get it running and test it out:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;If you don’t already have a Windows Azure subscription, &lt;a href="http://www.windowsazure.com/en-us/pricing/free-trial/"&gt;sign up now&lt;/a&gt; and &lt;a href="http://www.windowsazure.com/en-us/downloads/"&gt;download the .NET SDK for Visual Studio 2012&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;Open the sample code solution in Visual Studio 2012&lt;/li&gt;

  &lt;li&gt;Update the diagnostics connection string for your cloud storage account&lt;/li&gt;

  &lt;li&gt;Publish the solution to the cloud, ensuring you enable remote desktop and configure your credentials&lt;/li&gt;

  &lt;li&gt;Once the solution is up and running in the cloud, remote desktop into any one of the instances and try:&lt;/li&gt;

  &lt;ol&gt;
    &lt;li&gt;Browsing to E:\sitesroot\0 and deleting/renaming the file called ProbeFile.txt. You should see the instance status change to Busy and removed from the load balancer, and error logs written to the WADLogsTable. Once you’re done, restore the file to make the instance healthy again.&lt;/li&gt;

    &lt;li&gt;Opening the Services console and stopping the “World Wide Web Publishing Service”. You should see the service automatically restart, and a warning log written to the WADLogsTable, but the instance will remain healthy as the issue was remediated.&lt;/li&gt;

    &lt;li&gt;Opening the Services console, stopping &lt;em&gt;and disabling&lt;/em&gt; the “Windows Time” service (disabling it prevents the remediation from succeeding). You should see logs in the WADLogsTable saying the instance is unhealthy, however it will not be set to Busy since this health checker has &lt;strong&gt;keepRunningIfUnhealthy &lt;/strong&gt;set to true.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/ol&gt;

&lt;p&gt;As I’ve said before, this is just a sample—but I hope that it will serve as a useful staring point that will help you build rock-solid PaaS solutions on top of Windows Azure.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10419660" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Windows+Azure/">Windows Azure</category></item><item><title>Running scripts from a Windows Azure role’s OnStart method</title><link>http://blogs.msdn.com/b/tomholl/archive/2013/05/15/running-scripts-from-a-windows-azure-role-s-onstart-method.aspx</link><pubDate>Wed, 15 May 2013 05:36:30 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10418771</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10418771</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2013/05/15/running-scripts-from-a-windows-azure-role-s-onstart-method.aspx#comments</comments><description>&lt;p&gt;&lt;em&gt;Summary: Startup scripts declared in ServiceDefinition.csdef work well in most cases, but if you need to modify IIS configuration you’ll need to run your scripts from your role’s OnStart method. This post includes some sample code that can do this using a configuration-driven declarative approach. &lt;/em&gt;&lt;/p&gt;  &lt;p&gt;In a Windows Azure cloud service, you can specify scripts that should run at role startup time using the &lt;strong&gt;&amp;lt;Startup&amp;gt; &lt;/strong&gt;element in ServiceDefinition.csdef. This works well in almost all cases, and as it’s declarative you don’t need to write any code (other than the scripts themselves, obviously). However there is one common scenario where startup scripts won’t cut it: anytime you need to query or modify your IIS configuration. Why? As Kevin Williamson depicts nicely in &lt;a href="http://blogs.msdn.com/b/kwill/archive/2011/05/05/windows-azure-role-architecture.aspx"&gt;this post&lt;/a&gt;, the IISConfigurator does not create IIS websites (step 8 in Kevin’s post) until &lt;em&gt;after&lt;/em&gt; the startup tasks have already finished (step 7). So if you want to do anything to IIS that can’t be defined declaratively in ServiceDefinition.csdef, you’ll need to do it at some point after the IISConfigurator has done its bit.&lt;/p&gt;  &lt;p&gt;The logical place do this is in your role’s &lt;strong&gt;OnStart&lt;/strong&gt; method (triggered in step 9). Normally you’ll do this via a call to &lt;strong&gt;Process.Start&lt;/strong&gt; and associated code, and this is a fine approach – however compared to the declarative simplicity of “real” startup tasks, hard-coding the details into C# code makes me feel a little dirty, especially if you want to call more than one script or you’re doing this in multiple applications. &lt;/p&gt;  &lt;p&gt;So I built a simple solution that lets you use a declarative approach to start processes and scripts from your role’s &lt;strong&gt;OnStart&lt;/strong&gt; method. The full code can be downloaded &lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/6371.RoleEntryPointScriptTest.zip"&gt;here&lt;/a&gt;; the highlights are described below.&lt;/p&gt;  &lt;p&gt;This solution lets you specify the scripts you want to run using a configuration setting defined in ServiceConfiguration.cscfg, for example:   &lt;br /&gt;    &lt;pre class="csharpcode"&gt;&amp;lt;ConfigurationSettings&amp;gt;
  &amp;lt;Setting name=&lt;span class="str"&gt;&amp;quot;RoleStartupScripts&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;=&lt;span class="str"&gt;&amp;quot;startup\test1.cmd!;startup\test2.cmd;Powershell.exe startup\test3.ps1&amp;quot;&lt;/span&gt; /&amp;gt;
    ....
&amp;lt;/ConfigurationSettings&amp;gt;&lt;/pre&gt;
  &lt;/p&gt;

&lt;p&gt;The setting value contains a semicolon-separated list of scripts to run. Note that the first script has an exclamation mark after its filename – this is my way of saying that the code needs to wait for that process to finish before starting the next script. For scripts without the exclamation mark, it won’t wait. There is no way to specify that a script needs to run as elevated; if you need this (which will generally be the case for IIS manipulation), be sure to set &amp;lt;Runtime executionContext=&amp;quot;elevated&amp;quot; /&amp;gt; in your ServiceDefinition.csdef file to force the role startup code (and all processes it launches) to be elevated.&lt;/p&gt;

&lt;p&gt;Next, I built an abstract class &lt;strong&gt;StartupScriptRoleEntryPoint &lt;/strong&gt;that extends &lt;strong&gt;RoleEntryPoint&lt;/strong&gt; to automatically launch the processes specified in configuration. My class is directly in the WebRole project, but you’d probably want to move this into a reusable library.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; StartupScriptRoleEntryPoint : RoleEntryPoint
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; OnStart()
    {
        var startupScripts = CloudConfigurationManager.GetSetting(&lt;span class="str"&gt;&amp;quot;RoleStartupScripts&amp;quot;&lt;/span&gt;);
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!String.IsNullOrEmpty(startupScripts))
        {
            var scriptList = startupScripts.Split(&lt;span class="str"&gt;';'&lt;/span&gt;);
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var script &lt;span class="kwrd"&gt;in&lt;/span&gt; scriptList)
            {
                &lt;span class="kwrd"&gt;bool&lt;/span&gt; waitForExit = &lt;span class="kwrd"&gt;false&lt;/span&gt;;

                &lt;span class="kwrd"&gt;string&lt;/span&gt; scriptCommandLine = script;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (script.EndsWith(&lt;span class="str"&gt;&amp;quot;!&amp;quot;&lt;/span&gt;))
                {
                    scriptCommandLine = script.Substring(0, script.Length - 1);
                    waitForExit = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                }

                var args = CmdLineToArgvW.SplitArgs(scriptCommandLine);

                var processStartInfo = &lt;span class="kwrd"&gt;new&lt;/span&gt; ProcessStartInfo()
                {
                    FileName = args[0],
                    Arguments = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Join(&lt;span class="str"&gt;&amp;quot; &amp;quot;&lt;/span&gt;, args.Skip(1).ToArray()),
                    WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory,
                    UseShellExecute = &lt;span class="kwrd"&gt;true&lt;/span&gt;,
                };
                var process = Process.Start(processStartInfo);
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (waitForExit)
                {
                    process.WaitForExit();
                }
            }
        }
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnStart();
    }
}&lt;/pre&gt;


&lt;p&gt;This code should be fairly self-explanatory – it loops through each specified script and launches it as a new process. The one unusual bit is the &lt;strong&gt;CmdLineToArgvW.SplitArgs&lt;/strong&gt; call; this uses P/Invoke to call a Win32 API to parse the command line arguments out of a string which is necessary when launching a process from .NET.&lt;/p&gt;

&lt;p&gt;Now all that’s left is to update the &lt;strong&gt;WebRole &lt;/strong&gt;class to derive from &lt;strong&gt;StartupScriptRoleEntryPoint &lt;/strong&gt;instead of the default &lt;strong&gt;RoleEntryPoint&lt;/strong&gt; – no other code changes are needed. You could do this for a worker role too I guess, although I’m not sure if there’s a scenario where this is useful. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WebRole : StartupScriptRoleEntryPoint
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; OnStart()
    {
        &lt;span class="rem"&gt;// For information on handling configuration changes&lt;/span&gt;
        &lt;span class="rem"&gt;// see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.&lt;/span&gt;

        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnStart();
    }
}&lt;/pre&gt;


&lt;p&gt;Since this approach uses configuration settings from ServiceConfiguration.cscfg, one interesting consequence is that you can change which scripts run in which environments – this may be particularly useful when running under the emulator on your local PC where you don’t want scripts doing weird things to your box. It’s also possible to change the configuration after deployment, but remember the settings are only used when the role starts (and any scripts you refer to need to already exist on the Windows Azure VM).&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10418771" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Windows+Azure/">Windows Azure</category></item><item><title>Using XPath to set environment variables in ServiceDefinition.csdef</title><link>http://blogs.msdn.com/b/tomholl/archive/2013/05/14/using-xpath-to-set-environment-variables-in-servicedefinition-csdef.aspx</link><pubDate>Tue, 14 May 2013 02:04:52 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10418289</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10418289</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2013/05/14/using-xpath-to-set-environment-variables-in-servicedefinition-csdef.aspx#comments</comments><description>&lt;p&gt;In my &lt;a href="http://blogs.msdn.com/b/tomholl/archive/2013/05/09/zip-your-iis-log-files-before-transferring-with-windows-azure-diagnostics.aspx"&gt;last post&lt;/a&gt; on zipping IIS log files in Windows Azure, my ServiceDefinition.csdef file included the following code to set an environment variable to the value of a local resource path:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Task&lt;/span&gt; &lt;span class="attr"&gt;commandLine&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Startup\ScheduleLogFileZipAndDeleteTask.cmd&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;executionContext&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;elevated&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;taskType&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Environment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Variable&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ZippedLogFilesPath&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RoleInstanceValue&lt;/span&gt; &lt;span class="attr"&gt;xpath&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='ZippedLogFiles']/@path&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Variable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Environment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Task&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;As you can see, an XPath query is used to retrieve the resource path. Someone asked me what this XPath query refers to. I didn’t know, so I looked into it. &lt;/p&gt;

&lt;p&gt;There is a &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/hh404006.aspx"&gt;page in the Windows Azure documentation&lt;/a&gt; which talks about this feature, and gives a whole bunch of examples of values you can pull out using different XPath queries. You can use this to set environment variables either for a specific startup task (specifying it under the &lt;strong&gt;&amp;lt;Startup&amp;gt;&lt;/strong&gt; element), or for the role entry point code (specifying it under the &lt;strong&gt;&amp;lt;Runtime&amp;gt; &lt;/strong&gt;element). However the documentation still doesn’t explain what XML document is being queried, so you can’t tell what other information may be available to you.&lt;/p&gt;

&lt;p&gt;After a bit of poking around, I found the mysterious document. It only seems to be created if you include an &lt;strong&gt;xpath&lt;/strong&gt; element somewhere in your ServiceDefinition.csdef file, so you can add a dummy environment variable like this to ensure the file is created:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Runtime&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Environment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Variable&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;TestIsEmulated&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RoleInstanceValue&lt;/span&gt; &lt;span class="attr"&gt;xpath&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;/RoleEnvironment/Deployment/@emulated&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Variable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Environment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Runtime&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;Now when you deploy the solution (either to Windows Azure or to the local compute emulator), you’ll get a file with a filename similar to &lt;strong&gt;&lt;em&gt;DeploymentId.DeploymentId.RoleInstanceName&lt;/em&gt;.RoleEnvironment.1.xml. &lt;/strong&gt;On a real Windows Azure VM, this file is in&lt;strong&gt; C:\Config&lt;/strong&gt;; in the local compute emulator it is more hidden, living at &lt;strong&gt;C:\Users\&lt;em&gt;username&lt;/em&gt;\AppData\Local\dftmp\Config&lt;/strong&gt;. (Don’t confuse this file with another one in the same folder that doesn’t end with &lt;strong&gt;RoleEnvironment.1&lt;/strong&gt;, as this file has a different schema and data, and as far as I know can’t be queried in the same way). In both Windows Azure and the emulator, the role environment XML file should have the same format – here’s an example from my IIS log zipping app:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RoleEnvironment&lt;/span&gt; &lt;span class="attr"&gt;xmlns:xsd&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;xmlns:xsi&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Deployment&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;046cfa59b8894be3b0ca5f0c6aaeb237&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;emulated&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CurrentInstance&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;WebRole1_IN_0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;roleName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;WebRole1&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;faultDomain&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;updateDomain&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ConfigurationSettings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ConfigurationSetting&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;DefaultEndpointsProtocol=https;AccountName=xxxx;AccountKey=xxxxx&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ConfigurationSetting&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountEncryptedPassword&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;xxxx&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ConfigurationSetting&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountExpiration&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;2014-05-08T23:59:59.0000000+10:00&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ConfigurationSetting&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountUsername&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;remoteuser&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ConfigurationSetting&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Microsoft.WindowsAzure.Plugins.RemoteAccess.Enabled&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ConfigurationSetting&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Microsoft.WindowsAzure.Plugins.RemoteForwarder.Enabled&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ConfigurationSettings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;LocalResources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;LocalResource&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;DiagnosticStore&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;C:\Resources\directory\046cfa59b8894be3b0ca5f0c6aaeb237.WebRole1.DiagnosticStore\&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;sizeInMB&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;4096&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;LocalResource&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ZippedLogFiles&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;C:\Resources\directory\046cfa59b8894be3b0ca5f0c6aaeb237.WebRole1.ZippedLogFiles\&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;sizeInMB&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1000&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;LocalResources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Endpoints&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Endpoint&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Endpoint1&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;address&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;10.78.196.62&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;port&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;80&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;publicPort&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;80&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;protocol&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Endpoint&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Microsoft.WindowsAzure.Plugins.RemoteAccess.Rdp&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;address&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;10.78.196.62&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;port&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;3389&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;publicPort&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;protocol&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;tcp&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Endpoint&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Microsoft.WindowsAzure.Plugins.RemoteForwarder.RdpInput&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;address&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;10.78.196.62&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;port&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;20000&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;publicPort&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;3389&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;protocol&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;tcp&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Endpoints&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CurrentInstance&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Roles&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RoleEnvironment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;There’s not a whole lot in there that isn’t alluded to in the documentation, but it’s always nice to know exactly what it is that you’re dealing with.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10418289" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Windows+Azure/">Windows Azure</category></item><item><title>Zip your IIS log files before transferring with Windows Azure Diagnostics</title><link>http://blogs.msdn.com/b/tomholl/archive/2013/05/09/zip-your-iis-log-files-before-transferring-with-windows-azure-diagnostics.aspx</link><pubDate>Thu, 09 May 2013 01:04:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10417175</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10417175</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2013/05/09/zip-your-iis-log-files-before-transferring-with-windows-azure-diagnostics.aspx#comments</comments><description>&lt;p&gt;&lt;em&gt;Summary: If your Windows Azure-hosted website is really popular, the IIS log files can start to get pretty big. To prevent them from filling up your local VM&amp;rsquo;s quota and to minimise storage size and transfer bandwidth, you can zip the log files before Windows Azure Diagnostics transfers them to blob storage.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of the many nice things about &lt;a href="http://msdn.microsoft.com/en-us/library/gg433048.aspx"&gt;Windows Azure Diagnostics&lt;/a&gt; is that it can automatically transfer your IIS log files to blob storage, read for you to pull down and analyse using your favourite log analysis tool. This capability is turned on by default in the &lt;strong&gt;diagnostics.wadcfg&lt;/strong&gt; file you get when you create a new Windows Azure Cloud Service using the .NET SDK, and for most sites the default behaviour is just fine. But if your website is really popular, those log files can start to get very large. This could have a few implications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IIS log files on Windows Azure Cloud Service VMs are written to your &amp;ldquo;local resources&amp;rdquo; area on drive C:. This area has a quota. If you go beyond the quota, your site should keep running, but you may lose log files if they are cleaned up by the diagnostics agent to keep you under the quota.&lt;/li&gt;
&lt;li&gt;Once transferred to a blob container in Windows Azure Storage, you pay per megabyte stored. Even with today&amp;rsquo;s crazy cheap storage prices, the more you store, the more you pay.&lt;/li&gt;
&lt;li&gt;Similarly, you pay to transfer files from Windows Azure Storage to your local environment &amp;ndash; both in dollars (Windows Azure bandwidth costs) and time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because IIS log files are plain text with lots of repetition, they compress very well (generally over 90% reduction). However unfortunately there&amp;rsquo;s no built-in way to compress IIS log files. But with the awesome power of PowerShell, Windows Azure startup tasks and the Windows Task Scheduler, rolling your own solution isn&amp;rsquo;t too hard. In fact it&amp;rsquo;s super easy as I&amp;rsquo;ve already written some sample code which you can &lt;span&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/5287.ZipLogFileTest.zip"&gt;download here&lt;/a&gt;&lt;/span&gt;. &lt;strong&gt;&lt;em&gt;Disclaimer: &lt;/em&gt;&lt;/strong&gt;This code is provided as-is and should be modified and tested to ensure it meets your requirements. Also, I&amp;rsquo;m actually pretty rubbish at PowerShell so I know the code could be improved a lot.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t show all of the code in this blog post, but I will summarise how it works so you can customise it as needed.&lt;/p&gt;
&lt;p&gt;First, we&amp;rsquo;ll need to declare a few things in our &lt;strong&gt;ServiceDefinition.csdef&lt;/strong&gt; file&lt;strong&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Allocate some space in our local resource areas to hold our zipped log files&lt;/li&gt;
&lt;li&gt;Run a startup task which will schedule a PowerShell script to run every hour to zip the log files&lt;/li&gt;
&lt;li&gt;Pass an environment variable to the above script that contains the path to our local resources area&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are the relevant parts of the file:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ServiceDefinition&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="ZipLogFileTest"&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition"&lt;/span&gt; &lt;span class="attr"&gt;schemaVersion&lt;/span&gt;&lt;span class="kwrd"&gt;="2013-03.2.0"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;WebRole&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="WebRole1"&lt;/span&gt; &lt;span class="attr"&gt;vmsize&lt;/span&gt;&lt;span class="kwrd"&gt;="Small"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
     ...
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;LocalResources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;LocalStorage&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="ZippedLogFiles"&lt;/span&gt; &lt;span class="attr"&gt;sizeInMB&lt;/span&gt;&lt;span class="kwrd"&gt;="1000"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;LocalResources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Startup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Task&lt;/span&gt; &lt;span class="attr"&gt;commandLine&lt;/span&gt;&lt;span class="kwrd"&gt;="Startup\ScheduleLogFileZipAndDeleteTask.cmd"&lt;/span&gt; &lt;span class="attr"&gt;executionContext&lt;/span&gt;&lt;span class="kwrd"&gt;="elevated"&lt;/span&gt; &lt;span class="attr"&gt;taskType&lt;/span&gt;&lt;span class="kwrd"&gt;="simple"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Environment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Variable&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="ZippedLogFilesPath"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RoleInstanceValue&lt;/span&gt; &lt;span class="attr"&gt;xpath&lt;/span&gt;&lt;span class="kwrd"&gt;="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='ZippedLogFiles']/@path"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Variable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Environment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Task&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Startup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;WebRole&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ServiceDefinition&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Next, we need a batch file which creates the scheduled task. Depending on your needs you may want to tweak the parameters, but in my example the task is run hourly. Note the weird quoting in the parameters to &lt;strong&gt;schtasks.exe &lt;/strong&gt;which it seems to insist on to prevent weird errors. Also note that I am passing the path to the &lt;strong&gt;ZippedLogFilesPath&lt;/strong&gt; as a parameter to the scheduled PowerShell script, as the environment variable isn&amp;rsquo;t accessible at the time the script runs.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;rem ScheduleLogFileZipAndDeleteTask.cmd
powershell.exe Set-ExecutionPolicy RemoteSigned -force
schtasks.exe /create /sc HOURLY /tn ZipAndDeleteLogFiles /tr &lt;span class="str"&gt;"\"powershell.exe\" -file \"%~dp0IISLogZipAndDelete.ps1\" %ZippedLogFilesPath%."&lt;/span&gt; /RL highest /F /RU SYSTEM &amp;gt;&amp;gt; ScheduleLogFileZipAndDeleteTask.out.log 2&amp;gt;&amp;gt; ScheduleLogFileZipAndDeleteTask.err.log&lt;/pre&gt;
&lt;p&gt;Now we need our PowerShell script. It&amp;rsquo;s a little long so if you want to go through it, &lt;span&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/5287.ZipLogFileTest.zip"&gt;download the full sample&lt;/a&gt;&lt;/span&gt;. But here&amp;rsquo;s the gist of what it does:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Uses the &lt;strong&gt;WebAdministration&lt;/strong&gt; PowerShell module to look up the IIS log path&lt;/li&gt;
&lt;li&gt;Iterate through each folder under this path (as IIS creates a second level of folders under the configured log path)&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;Create a corresponding folder under the &lt;strong&gt;ZippedLogFiles&lt;/strong&gt; resource folder (passed as a parameter to the script)&lt;/li&gt;
&lt;li&gt;Iterate through each file in the IIS log path&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;Check if the last-modified-date of the file is more than 60 minutes old&lt;/li&gt;
&lt;li&gt;If so:&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;Zip the individual log file&lt;/li&gt;
&lt;li&gt;Copy the zipped file to the corresponding subfolder under &lt;strong&gt;ZippedLogFiles&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Delete the original unzipped log file&lt;/li&gt;
&lt;/ol&gt;&lt;/ol&gt;&lt;/ol&gt;
&lt;li&gt;Iterate through each folder and file under &lt;strong&gt;ZippedLogFiles&lt;/strong&gt;&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;Check if the last-modified-date of the file is more than 1 day (1440 minutes) old&lt;/li&gt;
&lt;li&gt;If so, delete the file.&lt;/li&gt;
&lt;/ol&gt;&lt;/ol&gt;
&lt;p&gt;The PowerShell script depends on the &lt;strong&gt;System.IO.Compression.ZipFile&lt;/strong&gt; class which comes with .NET Framework 4.5. Therefore you&amp;rsquo;ll need Windows Server 2012 (Windows Azure OS Family version 3) VMs to run this script. If you&amp;rsquo;re using an older OS, you may need to use a different approach to compress the file.&lt;/p&gt;
&lt;p&gt;Finally, you need to configure Windows Azure Diagnostics to transfer files from our &lt;strong&gt;ZippedLogFiles &lt;/strong&gt;folder, but ignore the standard IIS log files folder. You can do this by modifying &lt;strong&gt;diagnostics.wadcfg&lt;/strong&gt; by removing the &lt;strong&gt;IISLogs&lt;/strong&gt; element and adding &lt;strong&gt;DirectoryConfiguration &lt;/strong&gt;element pointing to the local resource, for example:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DiagnosticMonitorConfiguration&lt;/span&gt; &lt;span class="attr"&gt;configurationChangePollInterval&lt;/span&gt;&lt;span class="kwrd"&gt;="PT1M"&lt;/span&gt; &lt;span class="attr"&gt;overallQuotaInMB&lt;/span&gt;&lt;span class="kwrd"&gt;="4096"&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DiagnosticInfrastructureLogs&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Directories&lt;/span&gt; &lt;span class="attr"&gt;bufferQuotaInMB&lt;/span&gt;&lt;span class="kwrd"&gt;="1024"&lt;/span&gt;  &lt;span class="attr"&gt;scheduledTransferPeriod&lt;/span&gt;&lt;span class="kwrd"&gt;="PT30M"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DataSources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DirectoryConfiguration&lt;/span&gt; &lt;span class="attr"&gt;container&lt;/span&gt;&lt;span class="kwrd"&gt;="wad-iis-zippedlogs"&lt;/span&gt; &lt;span class="attr"&gt;directoryQuotaInMB&lt;/span&gt;&lt;span class="kwrd"&gt;="1024"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;LocalResource&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="ZippedLogFiles"&lt;/span&gt; &lt;span class="attr"&gt;relativePath&lt;/span&gt;&lt;span class="kwrd"&gt;="."&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DirectoryConfiguration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DataSources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CrashDumps&lt;/span&gt; &lt;span class="attr"&gt;container&lt;/span&gt;&lt;span class="kwrd"&gt;="wad-crash-dumps"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Directories&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DiagnosticMonitorConfiguration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Now it&amp;rsquo;s simply a matter of using your app and waiting for the various timers to go off, and you should see your IIS log files beautifully gift-wrapped as zip files in the &lt;strong&gt;wad-iis-zippedlogs&lt;/strong&gt; container in your configured Windows Azure Diagnostics storage account. Please let me know if you find this useful.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10417175" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Windows+Azure/">Windows Azure</category></item><item><title>Using Windows Firewall to restrict access to Windows Azure instances</title><link>http://blogs.msdn.com/b/tomholl/archive/2013/05/07/using-windows-firewall-to-restrict-access-to-windows-azure-instances.aspx</link><pubDate>Tue, 07 May 2013 11:06:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10416592</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10416592</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2013/05/07/using-windows-firewall-to-restrict-access-to-windows-azure-instances.aspx#comments</comments><description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Summary&lt;/strong&gt;: If you ever have a need to restrict access to your Windows Azure deployment to known IP address ranges, you can do this by programmatically modifying the Windows Firewall. You&amp;rsquo;ll need to do this both at startup, and whenever your role topology changes, as the Windows Azure guest agent also likes to modify firewall rules. &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When you deploy your PaaS cloud service to Windows Azure, it&amp;rsquo;s on the internet. This means it can be accessed by anyone who is also on the internet, subject to your application&amp;rsquo;s authorisation logic. Normally this is a good thing&amp;mdash;we build and deploy apps so people can use them. However sometimes you may want to restrict access to certain known client machines. Some of the reasons I&amp;rsquo;ve seen for this include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You&amp;rsquo;re working on an unreleased, super-secret application that you don&amp;rsquo;t want anyone to stumble upon until you&amp;rsquo;re good and ready.&lt;/li&gt;
&lt;li&gt;You have multiple deployments for different environments (e.g. development, test, UAT) which should each only be accessed by certain people but you don&amp;rsquo;t want to change the app&amp;rsquo;s authorisation logic.&lt;/li&gt;
&lt;li&gt;Your application is only designed for internal users and you don&amp;rsquo;t want to allow remote access. In this case you should also use a federated identity solution to authorise individual users, but if you&amp;rsquo;re really paranoid you may want to prevent these users from accessing the app when away from the corporate network.&lt;/li&gt;
&lt;li&gt;Even though you&amp;rsquo;re happy for anyone to access the application&amp;rsquo;s public UI, you want some additional security (beyond standard user authentication) for admin services, such as RDP or an administrative UI running on a different port.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re only interested in blocking traffic to IIS-hosted services, one option is to use IIS&amp;rsquo;s &amp;ldquo;IP and Domain Restrictions&amp;rdquo; feature to restrict access as described in &lt;a href="http://blog.liamcavanagh.com/2011/10/how-to-block-ip-addresses-in-windows-azure/"&gt;Liam Cavanagh's Blog&lt;/a&gt;. This is a good option as the IP restrictions are configuration-based, and Windows Azure won&amp;rsquo;t do anything that interferes with your settings. However as Liam points out, this capability depends on a Windows feature that isn&amp;rsquo;t installed by default, so you&amp;rsquo;ll need to write a startup script to install the &amp;ldquo;IP and Domain Restrictions&amp;rdquo; feature.&lt;/p&gt;
&lt;p&gt;However this solution will not work if you want to restrict access to something that&amp;rsquo;s not IIS hosted, such as RDP. In this case you need to step it up a level by modifying the Windows Firewall which runs locally on each Windows Azure VM. Normally it&amp;rsquo;s pretty easy to configure Windows Firewall to only allow access to a given port to specific IP ranges: you set up a single rule for that port and set the scope to your IP ranges; any traffic from other IP addresses will be automatically blocked as there is no matching firewall rule. Unfortunately this is a bit more complex in Windows Azure, as the fabric will automatically configure a whole bunch of firewall rules (helpfully named after random GUIDs) that open certain ports to &lt;em&gt;all&lt;/em&gt; IP addresses. You can still add additional rules if you want, but due to the way that firewall rules combine, you can&amp;rsquo;t easily block access once another rule has already granted it.&lt;/p&gt;
&lt;p&gt;The most practical option I found was to modify the existing firewall rules to add the IP range restrictions. There are a few different APIs to do this, but the easiest way is to use the &lt;a href="http://technet.microsoft.com/en-us/library/jj554906(v=wps.620).aspx"&gt;Network Security PowerShell cmdlets&lt;/a&gt;. These run on Windows Server 2012, so make sure you set your Windows Azure &lt;strong&gt;osFamily&lt;/strong&gt; attribute to &amp;ldquo;3&amp;rdquo;. Here&amp;rsquo;s a simple PowerShell script that modifies all existing rules for two ports (80 and 3389) to restrict them to specific IP addresses and ranges:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;# SetFirewallRestrictions.ps1&lt;/span&gt;
$date = Get-Date
Write-Host &lt;span class="str"&gt;"Updating firewall rule restrictions at "&lt;/span&gt; $date &lt;span class="str"&gt;"`r`n"&lt;/span&gt;
$allowedRanges = (&lt;span class="str"&gt;'3.2.1.0/24'&lt;/span&gt;, &lt;span class="str"&gt;'1.2.3.4'&lt;/span&gt;) 
Get-NetFirewallPortFilter | ? LocalPort &lt;span class="preproc"&gt;-eq&lt;/span&gt; &lt;span class="str"&gt;'80'&lt;/span&gt; | Get-NetFirewallRule | Set-NetFirewallRule -RemoteAddress $allowedRanges
Get-NetFirewallPortFilter | ? LocalPort &lt;span class="preproc"&gt;-eq&lt;/span&gt; &lt;span class="str"&gt;'3389'&lt;/span&gt; | Get-NetFirewallRule | Set-NetFirewallRule -RemoteAddress $allowedRanges&lt;/pre&gt;
&lt;p&gt;To make it easier to call the script and log the output, let&amp;rsquo;s also create a .cmd file to wrap it:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;rem SetFirewallRestrictions.cmd
cd /d %~dp0
Powershell set-executionpolicy remotesigned -force
Powershell .\SetFirewallRestrictions.ps1 &amp;gt;&amp;gt; SetFirewallRestrictions.out.log 2&amp;gt;&amp;gt; SetFirewallRestrictions.err.log&lt;/pre&gt;
&lt;p&gt;So now we have our scripts, it&amp;rsquo;s just a matter of including them into our Windows Azure cloud service role and calling them at the appropriate time. The obvious place to do this is at role startup, so let&amp;rsquo;s add a startup task to the ServiceDefinition.csdef file. Remember to run it as elevated since we&amp;rsquo;re playing with security settings. Also note the &amp;lt;Runtime&amp;gt; element which I&amp;rsquo;ll get to in a moment.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ServiceDefinition&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="FirewallTest"&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition"&lt;/span&gt; &lt;span class="attr"&gt;schemaVersion&lt;/span&gt;&lt;span class="kwrd"&gt;="2013-03.2.0"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;WebRole&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="WebRole1"&lt;/span&gt; &lt;span class="attr"&gt;vmsize&lt;/span&gt;&lt;span class="kwrd"&gt;="Small"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
   ...  
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Startup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Task&lt;/span&gt; &lt;span class="attr"&gt;commandLine&lt;/span&gt;&lt;span class="kwrd"&gt;="Startup\SetFirewallRestrictions.cmd"&lt;/span&gt; &lt;span class="attr"&gt;executionContext&lt;/span&gt;&lt;span class="kwrd"&gt;="elevated"&lt;/span&gt; &lt;span class="attr"&gt;taskType&lt;/span&gt;&lt;span class="kwrd"&gt;="simple"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Startup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Runtime&lt;/span&gt; &lt;span class="attr"&gt;executionContext&lt;/span&gt;&lt;span class="kwrd"&gt;="elevated"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;WebRole&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ServiceDefinition&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;With the startup script in place, Windows Azure will automatically update the firewall settings with your IP range restrictions just as the instance starts. So we&amp;rsquo;re done, right? Actually not quite. After some testing, we found that our custom firewall rules were occasionally overwritten after the instance has been running for a while. After further investigation we discovered that the Windows Azure Guest Agent (an app which the fabric installs on your VM to carry out various cloudy tasks) recreates the firewall rules whenever the role is scaled &amp;ndash; yes, even on the instances that were already running. So in order to keep our IP address restrictions, we need to reapply our firewall script when the role&amp;rsquo;s topology changes. &lt;em&gt;&lt;strong&gt;Important: &lt;/strong&gt;This solution is based on experimentation, not insider knowledge of exactly how this part of the platform works. It&amp;rsquo;s possible that there are other times when the firewall rules are overwritten. Use this solution at your own risk and test thoroughly.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In order to reapply the firewall rules when the app is scaled, it&amp;rsquo;s necessary to subscribe to the &lt;strong&gt;RoleEnvironment.Changed&lt;/strong&gt; event in your &lt;strong&gt;RoleEntryPoint&lt;/strong&gt;-derived class. In the event handler we can launch the same script again. The &amp;lt;Runtime executionContext=&amp;rdquo;elevated&amp;rdquo; /&amp;gt; entry we put in above ensures that this code runs as admin.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WebRole : RoleEntryPoint
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; OnStart()
    {
        RoleEnvironment.Changed += RoleEnvironment_Changed;
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnStart();
    }

    &lt;span class="kwrd"&gt;void&lt;/span&gt; RoleEnvironment_Changed(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoleEnvironmentChangedEventArgs e)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (e.Changes.Any(ch =&amp;gt; ch &lt;span class="kwrd"&gt;is&lt;/span&gt; RoleEnvironmentTopologyChange))
        {
            var processStartInfo = &lt;span class="kwrd"&gt;new&lt;/span&gt; ProcessStartInfo(&lt;span class="str"&gt;@"Startup\SetFirewallRestrictions.cmd"&lt;/span&gt;);
            var process = Process.Start(processStartInfo);
        }
    }
}&lt;/pre&gt;
&lt;p&gt;So far it looks like this is a solid option for restricting access to your Windows Azure applications to specific IP addresses. If you find any issues or have any suggestions please let me know, and I&amp;rsquo;ll promise to do the same!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10416592" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Security/">Security</category><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Windows+Azure/">Windows Azure</category></item><item><title>Keeping diagnostics in sync across Windows Azure instances</title><link>http://blogs.msdn.com/b/tomholl/archive/2013/05/05/keeping-diagnostics-in-sync-across-windows-azure-instances.aspx</link><pubDate>Sun, 05 May 2013 08:36:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10416143</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10416143</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2013/05/05/keeping-diagnostics-in-sync-across-windows-azure-instances.aspx#comments</comments><description>  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg433048.aspx"&gt;Windows Azure Diagnostics&lt;/a&gt; provides a great way for operations staff, developers and testers to find out what’s going on within a Windows Azure PaaS (Cloud Service) deployment. In a nutshell, it lets you specify what types of logs you are interested in (application logs, event logs, performance counters, or log files), and at specified intervals these logs are transferred from your Windows Azure VMs to blobs and tables in your Windows Azure Storage Account. &lt;/p&gt;  &lt;p&gt;To specify what diagnostics you’re interested in, you normally include a file called &lt;strong&gt;diagnostics.wadcfg &lt;/strong&gt;within each role of your Cloud Service (or, you can also do it programmatically). This file specifies your “factory default” diagnostics settings and gets baked into your deployment package, so you can’t modify it without redeploying. However, as soon as your role instances start, the diagnostics settings are copied into a blob in the &lt;strong&gt;wad-control-container&lt;/strong&gt;, which is what Windows Azure Diagnostics uses at runtime. There’s a separate blob for each instance of each role of each deployment, and this can be changed after deployment. In fact, if you have the new &lt;a href="http://weblogs.asp.net/scottgu/archive/2013/04/30/announcing-the-release-of-windows-azure-sdk-2-0-for-net.aspx"&gt;Windows Azure SDK 2.0 for .NET&lt;/a&gt; or third party tools like &lt;a href="http://www.cerebrata.com/products/azure-diagnostics-manager/introduction"&gt;Cerebrata’s Azure Diagnostics Manager&lt;/a&gt; it’s very easy to update the live diagnostics from a GUI so you don’t need to hand-edit the control container blobs.&lt;/p&gt;  &lt;p&gt;Even though it’s possible to set different diagnostics configuration for each instance of a role, in practice it’s pretty unlikely that you’ll want this. The people who built the aforementioned tools must agree because they also provide easy ways to update the diagnostics configuration of all instances of a role at the same time. However, consider what happens in the following situation:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;2 instances of WebRole1 are deployed, and Windows Azure uses the “factory default” diagnostics configuration loaded from &lt;strong&gt;diagnostics.wadcfg&lt;/strong&gt;.&lt;/li&gt;    &lt;li&gt;To improve operations processes, the diagnostics configuration for both instances of WebRole1 are modified to “new improved” diagnostics configuration using a tool&lt;/li&gt;    &lt;li&gt;Based on high user demand, the deployment is scaled (either automatically or manually) by adding a 3rd instance of WebRole1.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So what diagnostics configuration would you expect the new 3rd instance to have? Well, the result which you’d almost certainly &lt;em&gt;want&lt;/em&gt; is for the 3rd instance’s diagnostics configuration to match the other two. However, when the new instance is deployed it will come with the “factory default” settings, and won’t get “new improved” settings unless someone explicitly applies them.&lt;/p&gt;  &lt;p&gt;If this is a concern to you, the good news it’s very easy to change the behaviour with a bit of code, and the better news is that I’ve already written the code for you. Hopefully the code is pretty self-explanatory, but basically whenever a role instance starts, if that instance isn’t the first one (instance 0), the diagnostics configuration is copied from instance 0’s current version. You may wonder what happens if instance 0 is ever reimaged or fails over – it’s actually OK as its &lt;strong&gt;wad-control-container&lt;/strong&gt; blob remains intact even when the new VM starts. &lt;/p&gt;  &lt;p&gt;My code is below; if you need to do this across multiple roles or applications, of course you should put this into a reusable library. &lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WebRole : RoleEntryPoint
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; OnStart()
    {
        &lt;span class="rem"&gt;// For information on handling configuration changes&lt;/span&gt;
        &lt;span class="rem"&gt;// see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.&lt;/span&gt;

        CopyDiagnosticsSettingsFromExistingInstance();

        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnStart();
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CopyDiagnosticsSettingsFromExistingInstance()
    {
        var trace = &lt;span class="kwrd"&gt;new&lt;/span&gt; DiagnosticMonitorTraceListener();
        &lt;span class="kwrd"&gt;try&lt;/span&gt;
        {
            var sourceInstance = RoleEnvironment.CurrentRoleInstance.Role.Instances.OrderBy(i =&amp;gt; i.Id).First();
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (RoleEnvironment.CurrentRoleInstance.Id != sourceInstance.Id)
            {
                trace.WriteLine(String.Format(&lt;span class="str"&gt;&amp;quot;Copying live diagnostics settings from instance {0}.&amp;quot;&lt;/span&gt;, sourceInstance.Id));
                var diagnosticsConnectionString = CloudConfigurationManager.GetSetting(&lt;span class="str"&gt;&amp;quot;Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString&amp;quot;&lt;/span&gt;);
                var deploymentId = RoleEnvironment.DeploymentId;
                var deploymentDiagnosticsManager = &lt;span class="kwrd"&gt;new&lt;/span&gt; DeploymentDiagnosticManager(diagnosticsConnectionString, deploymentId);

                var sourceDiagnosticsManager = deploymentDiagnosticsManager.GetRoleInstanceDiagnosticManager(sourceInstance.Role.Name, sourceInstance.Id);
                var sourceConfig = sourceDiagnosticsManager.GetCurrentConfiguration();

                &lt;span class="kwrd"&gt;if&lt;/span&gt; (sourceConfig != &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="rem"&gt;// May happen during deployment when all instances are coming online&lt;/span&gt;
                {
                    var thisDiagnosticsManager = deploymentDiagnosticsManager.GetRoleInstanceDiagnosticManager(RoleEnvironment.CurrentRoleInstance.Role.Name, RoleEnvironment.CurrentRoleInstance.Id);
                    thisDiagnosticsManager.SetCurrentConfiguration(sourceConfig);
                }
            }
        }
        &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
        {
            trace.WriteLine(String.Format(&lt;span class="str"&gt;&amp;quot;Error while copying diagnostics settings: {0}&amp;quot;&lt;/span&gt;, ex.ToString()));
        }
    }
}&lt;/pre&gt;

&lt;p&gt;It’s critical that developers “design for operations” to ensure applications they develop can be kept running smoothly over time. Diagnostics and scalability are two aspects of designing for operations, and while Windows Azure provides great platform services for both, with this code in place these two concerns will work even better together. Please let me know if you find this useful or have any suggestions or questions.&lt;/p&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10416143" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Windows+Azure/">Windows Azure</category></item><item><title>Integrate Lync into your intranet sites using the NameCtrl plug-in</title><link>http://blogs.msdn.com/b/tomholl/archive/2013/03/02/integrate-lync-into-your-intranet-sites-using-the-namectrl-plug-in.aspx</link><pubDate>Sat, 02 Mar 2013 10:57:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10398766</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10398766</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2013/03/02/integrate-lync-into-your-intranet-sites-using-the-namectrl-plug-in.aspx#comments</comments><description>&lt;h3&gt;Introduction&lt;/h3&gt;  &lt;p&gt;If you’re a regular user of both SharePoint and Lync, you’ve probably seen that SharePoint integrates with Lync by showing users’ presence on the page, and giving you a nice hover dialog allowing you to collaborate with them. But did you know that you can add the same capabilities to your own intranet sites? And did you know it can work on Firefox and Chrome as well as in Internet Explorer? Even if you knew it was possible, chances are you haven’t found it easy, since the documentation is frankly pretty awful.&lt;/p&gt;  &lt;p&gt;&lt;img title="clip_image001" style="display: inline" alt="clip_image001" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90-metablogapi/7245.clip_5F00_image001_5F00_2C18CF8B.png" width="395" height="144" /&gt;&lt;/p&gt;  &lt;p&gt;Now before I go any further, yes this approach relies on plug-ins, and yes we all know that isn’t the way of the future. Very soon it will become much easier to integrate Lync presence into web apps using the new &lt;a href="http://ucwa.lync.com/"&gt;Unified Communications Web API (UCWA)&lt;/a&gt; which will ship as an update to Lync Server 2013. However even with that coming, there is still value in client-side plug-ins, and the integration with the Lync client you get with the plug-in approach does provide a very nice experience.&lt;/p&gt;  &lt;p&gt;You can download a working sample showing everything I discuss in the post &lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/3833.LyncPlugInDemo.html"&gt;here&lt;/a&gt;. &lt;strong&gt;Important: &lt;/strong&gt;I’ve made this available as a downloadable HTML file instead of hosting it on a web server as it won’t work in the Internet zone anyway. However after downloading you’ll need to right-click the file, choose &lt;strong&gt;Properties&lt;/strong&gt; and &lt;strong&gt;Unblock&lt;/strong&gt; before your browser will launch the plug-ins and scripts.&lt;/p&gt;  &lt;p&gt;It’s not the most beautiful web code you’ll come across (nor has it been extensively tested) but I wanted to show all of the key concepts in one file without any unnecessary complexity.&lt;/p&gt;  &lt;h3&gt;Prerequisites&lt;/h3&gt;  &lt;p&gt;There are a few things required for this approach to work. If you can’t rely on all of these, make sure you do defensive coding to fall back gracefully when the plug-in isn’t available.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Your users will need Lync installed and be signed in &lt;/li&gt;    &lt;li&gt;The NameCtrl plug-in must be properly registered. This should happen automatically when Lync is installed. &lt;/li&gt;    &lt;li&gt;Your users will need to be using a supported web browser. I don’t know the official support matrix, but with Lync 2013 installed and the site coded correctly it works with Internet Explorer, Firefox and Chrome on Windows. I don’t know if it works on non-IE browsers with versions prior to Lync 2013 (let me know!). &lt;/li&gt;    &lt;li&gt;Your web site must be in Internet Explorer’s Intranet or Trusted Sites security zone (even if being accessed from a different browser). This may sound like a big restriction, but in practice you’ll probably only want to do this on intranet sites anyway. &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Initialising the Plug-In&lt;/h3&gt;  &lt;p&gt;The NameCtrl plug-in exposes the same API to all browsers, but the way you initialise it is different on different browsers.&lt;/p&gt;  &lt;p&gt;On Internet Explorer, you need to create an ActiveX object of the type NameCtrl of the class “Name.NameCtrl”:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;nameCtrl = &lt;span class="kwrd"&gt;new&lt;/span&gt; ActiveXObject(&lt;span class="str"&gt;&amp;quot;Name.NameCtrl&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

&lt;p&gt;On Chrome and Firefox you need an &amp;lt;object&amp;gt; tag to initialise the plug-in:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;object&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;application/x-sharepoint-uc&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;application/x-sharepoint-uc&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;width&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;height&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;style&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;visibility: hidden;&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;object&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;My demo code (based on a simplified version of what ships with SharePoint 2013) to initialise using the correct approach based on the browser is as follows:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; nameCtrl = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

$(document).ready(&lt;span class="kwrd"&gt;function&lt;/span&gt; () {

    &lt;span class="kwrd"&gt;try&lt;/span&gt; {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (window.ActiveXObject) {
            nameCtrl = &lt;span class="kwrd"&gt;new&lt;/span&gt; ActiveXObject(&lt;span class="str"&gt;&amp;quot;Name.NameCtrl&amp;quot;&lt;/span&gt;);

        } &lt;span class="kwrd"&gt;else&lt;/span&gt; {
            nameCtrl = CreateNPApiOnWindowsPlugin(&lt;span class="str"&gt;&amp;quot;application/x-sharepoint-uc&amp;quot;&lt;/span&gt;);
        }
        attachLyncPresenceChangeEvent();
    }
    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (ex) { }
});


&lt;span class="kwrd"&gt;function&lt;/span&gt; IsSupportedNPApiBrowserOnWin() {
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;; &lt;span class="rem"&gt;// SharePoint does this: IsSupportedChromeOnWin() || IsSupportedFirefoxOnWin()&lt;/span&gt;
}

&lt;span class="kwrd"&gt;function&lt;/span&gt; IsNPAPIOnWinPluginInstalled(a) {
    &lt;span class="kwrd"&gt;return&lt;/span&gt; Boolean(navigator.mimeTypes) &amp;amp;&amp;amp; navigator.mimeTypes[a] &amp;amp;&amp;amp; navigator.mimeTypes[a].enabledPlugin
}

&lt;span class="kwrd"&gt;function&lt;/span&gt; CreateNPApiOnWindowsPlugin(b) {
    &lt;span class="kwrd"&gt;var&lt;/span&gt; c = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsSupportedNPApiBrowserOnWin())
        &lt;span class="kwrd"&gt;try&lt;/span&gt; {
            c = document.getElementById(b);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!Boolean(c) &amp;amp;&amp;amp; IsNPAPIOnWinPluginInstalled(b)) {
                &lt;span class="kwrd"&gt;var&lt;/span&gt; a = document.createElement(&lt;span class="str"&gt;&amp;quot;object&amp;quot;&lt;/span&gt;);
                a.id = b;
                a.type = b;
                a.width = &lt;span class="str"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;;
                a.height = &lt;span class="str"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;;
                a.style.setProperty(&lt;span class="str"&gt;&amp;quot;visibility&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);
                document.body.appendChild(a);
                c = document.getElementById(b)
            }
        } &lt;span class="kwrd"&gt;catch&lt;/span&gt; (d) {
            c = &lt;span class="kwrd"&gt;null&lt;/span&gt;
        }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; c
}&lt;/pre&gt;

&lt;h3&gt;Subscribing to Presence Updates&lt;/h3&gt;

&lt;p&gt;Once you’ve initialised your plug-in, you can use it to check the presence for any number of users. Doing this properly takes a few steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Subscribe to the plug-in’s &lt;strong&gt;OnStatusChange&lt;/strong&gt; event &lt;/li&gt;

  &lt;li&gt;Call the plug-in’s &lt;strong&gt;GetStatus &lt;/strong&gt;method for each user whose presence you are interested in &lt;/li&gt;

  &lt;li&gt;In the &lt;strong&gt;OnStatusChange&lt;/strong&gt; event, update your UI (for example to change the presence icon or colour) based on the reported user’s new presence. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a few tricks here which I figured out the hard way:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When you call &lt;strong&gt;GetStatus&lt;/strong&gt; the first time, you probably won’t get the user’s actual presence back. Really this method is used to tell the plug-in you want to subscribe to a user. The correct presence value will be returned asynchronously in the &lt;strong&gt;OnStatusChange&lt;/strong&gt; event handler. &lt;/li&gt;

  &lt;li&gt;The &lt;strong&gt;GetStatus &lt;/strong&gt;method takes two parameters. The first is the SIP address (typically the same as their email address) of the user you are subscribing to. The &lt;a href="http://msdn.microsoft.com/en-us/library/bb802706(v=office.14).aspx"&gt;documentation&lt;/a&gt; says that the second parameter is “a string that identifies the HTML &amp;lt;DIV&amp;gt; tag to update with the correct pawn icon”. I’ve never got this to work, and in any event I prefer to control my own UI rather than have the plug-in decide how it should look. In my tests, you can use any value for this string in Internet Explorer however it won’t work in Chrome or Firefox if you use an empty string (but other random strings worked fine). &lt;/li&gt;

  &lt;li&gt;The &lt;strong&gt;OnStatusChange &lt;/strong&gt;event handler gives you three parameters. The &lt;a href="http://msdn.microsoft.com/en-us/library/bb862183(v=office.14).aspx"&gt;docs&lt;/a&gt; say (accurately enough): “The first parameter is the sign-in name of the user, the second parameter is the new status, and the third parameter is the same ID that is passed to the GetStatus method.” The presence value returned in the second parameter is numeric; the docs have a partial list but see my code snippet below for some other values that may be returned. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, with that out of the way, here’s my code to subscribe to users’ presence and update the UI (using CSS classes) when their presence changes:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; addUser() {
    &lt;span class="kwrd"&gt;var&lt;/span&gt; userName = $(&lt;span class="str"&gt;'#userName'&lt;/span&gt;).val();
    &lt;span class="kwrd"&gt;var&lt;/span&gt; userElementId = getId(userName);
    $(&lt;span class="str"&gt;'&amp;lt;div/&amp;gt;'&lt;/span&gt;, {
        text: userName,
        id: userElementId,
        &lt;span class="kwrd"&gt;class&lt;/span&gt;: &lt;span class="str"&gt;'user'&lt;/span&gt;,
        onmouseover: &lt;span class="str"&gt;&amp;quot;showLyncPresencePopup('&amp;quot;&lt;/span&gt; + userName + &lt;span class="str"&gt;&amp;quot;', this)&amp;quot;&lt;/span&gt;,
        onmouseout: &lt;span class="str"&gt;&amp;quot;hideLyncPresencePopup()&amp;quot;&lt;/span&gt;,
    }).appendTo(&lt;span class="str"&gt;'#users'&lt;/span&gt;);

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (nameCtrl) {
        nameCtrl.GetStatus(userName, &lt;span class="str"&gt;'users'&lt;/span&gt;);
    }
    $(&lt;span class="str"&gt;'#userName'&lt;/span&gt;).val(&lt;span class="str"&gt;''&lt;/span&gt;);
}

&lt;span class="kwrd"&gt;function&lt;/span&gt; getLyncPresenceString(status) {

    &lt;span class="kwrd"&gt;switch&lt;/span&gt; (status) {
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 0:
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;'available'&lt;/span&gt;;
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 1:
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;'offline'&lt;/span&gt;;
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 2:
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 4:
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 16:
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;'away'&lt;/span&gt;;
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 3:
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 5:
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;'inacall'&lt;/span&gt;;
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 6:
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 7:
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 8:
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 10:
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;'busy'&lt;/span&gt;;
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 9:
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 15:
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;'donotdisturb'&lt;/span&gt;;
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;default&lt;/span&gt;:
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;''&lt;/span&gt;;
    }
}

&lt;span class="kwrd"&gt;function&lt;/span&gt; attachLyncPresenceChangeEvent() {
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!nameCtrl) {
        &lt;span class="kwrd"&gt;return&lt;/span&gt;;
    }
    nameCtrl.OnStatusChange = onLyncPresenceStatusChange;
}

&lt;span class="kwrd"&gt;function&lt;/span&gt; onLyncPresenceStatusChange(userName, status, id) {
    &lt;span class="kwrd"&gt;var&lt;/span&gt; presenceClass = getLyncPresenceString(status);

    &lt;span class="kwrd"&gt;var&lt;/span&gt; userElementId = getId(userName);
    &lt;span class="kwrd"&gt;var&lt;/span&gt; userElement = $(&lt;span class="str"&gt;'#'&lt;/span&gt; + userElementId);
    removePresenceClasses(userElement);
    userElement.addClass(presenceClass);

}

&lt;span class="kwrd"&gt;function&lt;/span&gt; removePresenceClasses(jqueryObj) {
    jqueryObj.removeClass(&lt;span class="str"&gt;'available'&lt;/span&gt;);
    jqueryObj.removeClass(&lt;span class="str"&gt;'offline'&lt;/span&gt;);
    jqueryObj.removeClass(&lt;span class="str"&gt;'away'&lt;/span&gt;);
    jqueryObj.removeClass(&lt;span class="str"&gt;'busy'&lt;/span&gt;);
    jqueryObj.removeClass(&lt;span class="str"&gt;'donotdisturb'&lt;/span&gt;);
    jqueryObj.removeClass(&lt;span class="str"&gt;'inacall'&lt;/span&gt;);
}

&lt;span class="kwrd"&gt;function&lt;/span&gt; getId(userName) {
    &lt;span class="kwrd"&gt;return&lt;/span&gt; userName.replace(&lt;span class="str"&gt;'@'&lt;/span&gt;, &lt;span class="str"&gt;'_'&lt;/span&gt;).replace(&lt;span class="str"&gt;'.'&lt;/span&gt;, &lt;span class="str"&gt;'_'&lt;/span&gt;);
}&lt;/pre&gt;


&lt;h3&gt;Showing and Hiding the Lync contact card&lt;/h3&gt;

&lt;p&gt;One final thing you can do with the plug-in is have it show a Lync contact card for a given user. This is useful as the contact card shows additional information about a user (full name, location, phone number, org chart, etc), and also allows you to interact them using any Lync modality (IM, phone, video, etc).&lt;/p&gt;

&lt;p&gt;Showing and hiding the contact card is pretty straightforward: the &lt;strong&gt;ShowOOUI &lt;/strong&gt;method shows it, and the &lt;strong&gt;HideOOUI&lt;/strong&gt; method hides it. You just need to wire it up to an appropriate event (typically &lt;strong&gt;onmouseover&lt;/strong&gt; and &lt;strong&gt;onmouseout&lt;/strong&gt; respectively).&lt;/p&gt;

&lt;p&gt;The trick is getting it to display in the right place. Without going into all of the details, here is some code which I’ve found to work pretty well:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;function showLyncPresencePopup(userName, target) {
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!nameCtrl) {
        &lt;span class="kwrd"&gt;return&lt;/span&gt;;
    }

    var eLeft = $(target).offset().left;
    var x = eLeft - $(window).scrollLeft();

    var eTop = $(target).offset().top;
    var y = eTop - $(window).scrollTop();

    nameCtrl.ShowOOUI(userName, 0, x, y);
}

function hideLyncPresencePopup() {
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!nameCtrl) {
        &lt;span class="kwrd"&gt;return&lt;/span&gt;;
    }
    nameCtrl.HideOOUI();
}&lt;/pre&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;So there you have it. If your organisation uses Lync, hopefully you’ve noticed how awesome it is. But it’s even awesomer (yes, I know that isn’t a word) if you can launch it exactly when you need it, which is often when using some intranet site or line-of-business application which tells you which people you need to communicate with. Even as we slowly move toward a plug-in-free world, it’s important to keep in mind what’s possible with the technology you already have deployed, and use it to create the best experiences you can.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10398766" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Lync/">Lync</category></item><item><title>New ABC iView plug-in for TunerFreeMCE</title><link>http://blogs.msdn.com/b/tomholl/archive/2012/11/06/new-abc-iview-plug-in-for-tunerfreemce.aspx</link><pubDate>Tue, 06 Nov 2012 10:35:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10366104</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10366104</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2012/11/06/new-abc-iview-plug-in-for-tunerfreemce.aspx#comments</comments><description>&lt;p&gt;Most Australians will recognise &lt;a href="http://www.abc.net.au/iview/"&gt;ABC iView&lt;/a&gt; as the country's best online TV service. In recent years they have done a good job of expanding to multiple platforms including PS3, Xbox 360, iOS and many smart TVs. Unfortunately one platform that is close to my heart but has not received any love from the ABC is Windows Media Center. (Windows 8 is also missing out but it's early days there so hopefully things will change soon!).&lt;/p&gt;
&lt;p&gt;The only way I've found to get ABC iView through Media Center is to use the &lt;a href="http://www.tunerfree.tv/"&gt;TunerFreeMCE&lt;/a&gt; application. This is an excellent app that provides a remote control friendly interface to many popular TV services. But the app was built primarily for UK services, and while its plug-in model made it possible to support international services like ABC, the original plug-in was somewhat limited and unreliable.&lt;/p&gt;
&lt;p&gt;Recently TunerFreeMCE author Martin Millmore added some enhancements to the app which made it possible to build much more reliable plug-ins. Building on top of this and some richer metadata from the ABC, I'm pleased to announce that I've rewritten the plug-in. Users of the old version will notice more programs, grouping of episodes under series, and improved reliability when starting or ending programs. If you haven't used it before I encourage you to download &lt;a href="http://www.tunerfree.tv/"&gt;TunerFreeMCE&lt;/a&gt; and give it a go. There's no need to download my plug-in separately as it can be accessed from the app's Settings page. There's also a plug-in available for SBS Australia that I wrote a while back but haven't yet migrated to the improved plug-in model.&lt;/p&gt;
&lt;p&gt;Rumours of Windows Media Center's demise are greatly exaggerated. After a recent hardware failure of my Media Center PC I needed to decide whether to fix it or try some other path, and indeed I did experiment with a non-PC PVR. However I still think there's no better solution for combining broadcast TV with my digital media library. With TunerFreeMCE and support for services I care about, the solution is even more complete.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/3566.iview1.png"&gt;&lt;img src="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/3566.iview1.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/5023.iview2.png"&gt;&lt;img src="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/5023.iview2.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/3240.iview3.png"&gt;&lt;img src="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90/3240.iview3.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10366104" width="1" height="1"&gt;</description></item><item><title>Automated Build and Deployment with Windows Azure SDK 1.6</title><link>http://blogs.msdn.com/b/tomholl/archive/2011/12/06/automated-build-and-deployment-with-windows-azure-sdk-1-6.aspx</link><pubDate>Tue, 06 Dec 2011 00:36:37 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:10244439</guid><dc:creator>Tom Hollander</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.msdn.com/b/tomholl/rsscomments.aspx?WeblogPostID=10244439</wfw:commentRss><comments>http://blogs.msdn.com/b/tomholl/archive/2011/12/06/automated-build-and-deployment-with-windows-azure-sdk-1-6.aspx#comments</comments><description>&lt;p&gt;A few months ago I &lt;a href="http://blogs.msdn.com/b/tomholl/archive/2011/02/23/using-msbuild-to-deploy-to-multiple-windows-azure-environments.aspx"&gt;posted&lt;/a&gt; on how to automate deployment of Windows Azure projects using MSBuild. While the approach documented in that post continues to work, Windows Azure SDK 1.6 has introduced some new capabilities for managing Windows Azure credentials and publishing settings which I wanted to leverage and build upon. With this new approach, you’ll no longer need to manually manage details such as Subscription IDs, hosted service names and certificates. Because this approach relies on a few tools that are too big to share in a blog post, I’ve also created the &lt;a href="http://code.msdn.microsoft.com/Windows-Azure-Build-8cee065d"&gt;Windows Azure Build &amp;amp; Deployment Sample&lt;/a&gt; on MSDN which contains all of the tools and sample projects described in this post.&lt;/p&gt;  &lt;p&gt;Before we go into details on how the build and deployment process works, let’s look at how Windows Azure SDK 1.6 manages credentials and publishing profiles:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The Visual Studio “Publish Windows Azure Application” dialog contains a link to a &lt;a href="https://windows.azure.com/download/publishprofile.aspx"&gt;special page on the Windows Azure Portal&lt;/a&gt; that allows you to download a &lt;strong&gt;.publishsettings&lt;/strong&gt; file. This file contains all of the details of your subscription(s), including subscription IDs and certificates. &lt;/li&gt;    &lt;li&gt;The same “Publish Windows Azure Application” dialog allows you to import the &lt;strong&gt;.publishsettings&lt;/strong&gt; file, which results in the certificate being installed on your local machine, and the subscription details imported into a Visual Studio file called &lt;strong&gt;Windows Azure Connections.xml &lt;/strong&gt;(this lives in %UserProfile%\Documents\Visual Studio 2010\Settings). Note that after you import the &lt;strong&gt;.publishsettings&lt;/strong&gt; file you should delete it (or at least protect it) as it contains the full certificate and private key that grants access to your Windows Azure subscription. &lt;/li&gt;    &lt;li&gt;When you are ready to publish your Windows Azure application, you can create a new &amp;quot;publish profile” or use an existing one. A publish profile is saved in your Windows Azure project with a &lt;strong&gt;.azurePubxml&lt;/strong&gt; extension, and contains various details such as your hosted service name, storage account name and deployment slot. The &lt;strong&gt;.azurePubxml&lt;/strong&gt; file doesn’t contain your subscription details, but it does list the subscription name that must correspond to an entry in your &lt;strong&gt;Windows Azure Connections.xml&lt;/strong&gt; file. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In updating my scripts for automated build and deployment on a build server, I wanted to leverage as much as this as possible, but I needed to build some tools that mirror some of the steps done by Visual Studio’s “Publish Windows Azure Application” dialog, since you may not have Visual Studio installed on your build server.&lt;/p&gt;  &lt;p&gt;The build and deployment solution contains the following components:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The &lt;strong&gt;AzureDeploy.targets &lt;/strong&gt;file, which is installed on your build server to tell MSBuild to package and deploy your solution to Windows Azure &lt;/li&gt;    &lt;li&gt;The &lt;strong&gt;ImportPublishSettings&lt;/strong&gt; tool, to import a &lt;strong&gt;.publishsettings&lt;/strong&gt; file onto a build server &lt;/li&gt;    &lt;li&gt;The &lt;strong&gt;AzureDeploy.ps1 &lt;/strong&gt;PowerShell script, which also depends on a helper library called &lt;strong&gt;AzurePublishHelpers&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;A TFS Build Definition that passes properties to MSBuild to initiate the build and deployment process. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The following diagram shows how all the components and files come together, and I’ll describe the details of each below.&lt;/p&gt;  &lt;p&gt;&lt;img style="display: inline" title="SDK 1.6 deploy" alt="SDK 1.6 deploy" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90-metablogapi/8130.SDK_2D00_1.6_2D00_deploy_5F00_38B0B613.png" width="640" height="480" /&gt;&lt;/p&gt;  &lt;h2&gt;The AzureDeploy.targets file&lt;/h2&gt;  &lt;p&gt;In my &lt;a href="http://blogs.msdn.com/b/tomholl/archive/2011/02/23/using-msbuild-to-deploy-to-multiple-windows-azure-environments.aspx"&gt;previous post on this topic&lt;/a&gt;, I showed you how you can edit your .ccproj project file to define additional targets used in the build process. This approach is still an option, but this time I’ve change my approach by creating a custom MSBuild &lt;strong&gt;.targets&lt;/strong&gt; file which is installed on the build server. This is generally a better option as you don’t need to hand-edit .ccproj files, the custom targets run only on the build server (not on development workstations), and the targets can be reused for multiple Windows Azure projects. &lt;/p&gt;  &lt;p&gt;The code included in my &lt;strong&gt;AzureDeploy.targets&lt;/strong&gt; file is shown below. This file needs to be copied to your build server to C:\Program Files\MSBuild\Microsoft\VisualStudio\v10.0\Windows Azure Tools\1.6\ImportAfter, and it will be automatically referenced by the main Windows Azure targets file. &lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt; &lt;span class="attr"&gt;ToolsVersion&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;4.0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DefaultTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.microsoft.com/developer/msbuild/2003&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PackageName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(AssemblyName).cspkg&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PackageName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PackageForComputeEmulator&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;true&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PackageForComputeEmulator&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;AzureDeploy&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;AfterTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Publish&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AzurePublishProfile)!=''&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Executing target AzureDeploy from AzureDeploy.targets file&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Exec&lt;/span&gt; &lt;span class="attr"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildProjectDirectory)&amp;quot;&lt;/span&gt; 
         &lt;span class="attr"&gt;Command&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(windir)\system32\WindowsPowerShell\v1.0\powershell.exe -f c:\builds\AzureDeploy.ps1 $(PublishDir) $(PackageName) &amp;amp;quot;Profiles\$(AzurePublishProfile)&amp;amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;The purpose of this code is to tell MSBuild to package the project for Windows Azure (achieved with the dependency on the Windows Azure SDK’s &lt;strong&gt;Publish&lt;/strong&gt; target) and then call a PowerShell script (you need to change the path depending on how you set up your build server). Note that this target only runs when the &lt;strong&gt;AzurePublishProfile&lt;/strong&gt; MSBuild property is set, which we’ll do later on when we set up the TFS build definition. &lt;/p&gt;

&lt;p&gt;Note that you may want to make some other customisations in a .targets or .ccproj file, for example to transform configuration files. I haven’t described this in this post, but there is some information on this in my &lt;a href="http://blogs.msdn.com/b/tomholl/archive/2011/02/23/using-msbuild-to-deploy-to-multiple-windows-azure-environments.aspx"&gt;previous post on this topic&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;The ImportPublishSettings tool&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;ImportPublishSettings &lt;/strong&gt;tool (available from the &lt;a href="http://code.msdn.microsoft.com/Windows-Azure-Build-8cee065d"&gt;Windows Azure Build &amp;amp; Deployment Sample&lt;/a&gt;) can be used to import Windows Azure credentials from a &lt;strong&gt;.publishsettings&lt;/strong&gt; file into your build server. It has been designed to operate in the exact same way as the Visual Studio “Publish Windows Azure Application” dialog, so if you have Visual Studio installed on your build server you can use that instead of this tool. Whichever tool you use, this is a one-time process that is completed when you first set up your build process.&lt;/p&gt;

&lt;p&gt;This is a simple command line tool which takes 3 parameters (only one of which is required):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;publishSetingsFilename&lt;/strong&gt;: the .publishsettings file to import&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;certStoreLocation &lt;/strong&gt;(optional): the certificate store to which the certificate should be imported. Possible values are &lt;strong&gt;CurrentUser &lt;/strong&gt;(the default) or &lt;strong&gt;LocalMachine&lt;/strong&gt;. You should use &lt;strong&gt;CurrentUser&lt;/strong&gt; if your build process is running as a user account, or &lt;strong&gt;LocalMachine &lt;/strong&gt;if you are running under a system account such as NETWORK SERVICE.&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;connectionsFileName&lt;/strong&gt; (optional): the filename in which the imported settings should be stored. This defaults to “%UserProfile%\Documents\Visual Studio 2010\Settings\Windows Azure Connections.xml”. You may want to change this if your build process is running under a system account such as NETWORK SERVICE.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run the tool under the same account used for your build process, you shouldn’t need to anything more. However if you run it as a different user (for example, you run the script as yourself but your build process runs under NETWORK SERVICE), you will need to open the MMC Certificates snap-in and grant permissions for the certificate private key to the build process’s account.&lt;/p&gt;

&lt;h2&gt;The AzureDeploy.ps1 PowerShell Script&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;AzureDeploy.ps1&lt;/strong&gt; PowerShell script is responsible for taking a packaged Windows Azure application and deploying it to the cloud. The sample implementation included in the sample project is pretty simple, and you may want to extend it to perform additional steps such as installing certificates, creating storage accounts, running build verification tests or swapping staging and production slots. There are also a couple of things which you will need to customise depending on if you’re running as a normal user account or a system account. Still, hopefully this script is a useful starting point for your build and deployment process.&lt;/p&gt;

&lt;p&gt;The script takes three parameters, which will normally be passed to it by the TFS build process (but you can pass them in yourself for test purposes):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;BuildPath: &lt;/strong&gt;The folder containing the Windows Azure project on the build server, for example “C:\Builds\1\ProjectName\BuildDefinitionName\Sources\AzureProjectName”.&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;PackageName: &lt;/strong&gt;The unqualified name for the Windows Azure .cspkg name, for example AzureProjectName.cspkg&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;PublishProfile: &lt;/strong&gt;The path to the .&lt;strong&gt;azurepubxml&lt;/strong&gt; file that should be used for deploying the solution. Note that only some of the properties in this file are used for deployment, such as the subscription name, hosted service name, storage account name and deployment slot. Other settings in this file, such as EnableIntelliTrace, are not currently used by the sample scripts. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The deployment script depends on a helper library called &lt;strong&gt;AzurePublishHelpers.dll&lt;/strong&gt; (which is also used by the &lt;strong&gt;ImportPublishSettings&lt;/strong&gt; tool), which knows how to read and write from the various files used in the solution. In order to make this library available to PowerShell you will need to install it as a PowerShell module. To this, first open the folder for PowerShell modules, which is “C:\Windows\System32\WindowsPowerShell\v1.0\Modules\AzurePublishHelpers” (replace System32 with SysWOW64 if you’re running your build as 32-bit on a 64-bit system). Then create a folder called &lt;strong&gt;AzurePublishHelpers&lt;/strong&gt; and copy in the &lt;strong&gt;AzurePublishHelpers.dll&lt;/strong&gt; file. &lt;/p&gt;

&lt;h2&gt;The TFS Build Definition&lt;/h2&gt;

&lt;p&gt;The final piece of the puzzle is setting up one or more Build Definitions. I’m using Team Foundation Server for this, but if you’re using a different ALM toolset you should be able to accomplish something similar.&lt;/p&gt;

&lt;p&gt;You can configure your Build Definitions however you want, for example to use different XAML workflows, different settings for running tests, versioning assemblies, etc. You should have at least one Build Definition for each Windows Azure environment you want to deploy to, for example Test, UAT or Production. To configure a Build Definition to deploy to Windows Azure, you’ll need to choose the &lt;strong&gt;Process &lt;/strong&gt;tab and enter the name of your chosen Publish Profile (&lt;strong&gt;.azurepubxml&lt;/strong&gt; file) in the &lt;strong&gt;MSBuild Arguments &lt;/strong&gt;property as shown in the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-43-90-metablogapi/1185.image_5F00_083A319D.png" width="812" height="679" /&gt;&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I hope this post and the accompanying tools and samples help you automate most (if not all) of your Windows Azure build and deployment process. I’ll try to keep the post up-to-date as the platform continues to evolve. If you have questions or comments, please feel free to post here or on the &lt;a href="http://code.msdn.microsoft.com/Windows-Azure-Build-8cee065d"&gt;Windows Azure Build &amp;amp; Deployment Sample page&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10244439" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Visual+Studio/">Visual Studio</category><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Windows+Azure/">Windows Azure</category><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/Powershell/">Powershell</category><category domain="http://blogs.msdn.com/b/tomholl/archive/tags/ALM/">ALM</category></item></channel></rss>