Azure VM Managed Disks backup to Azure Blob Storage

I’ve recently had a requirement to backup managed disks to Azure blob storage. Rather performing this manually, I scripted this with PowerShell. I created a structure within a .CSV file as an input file, which specifies the Virtual machine names and the storage container and folder, where the disks will be copied into. The script and a sample input file is in my repository below.

Copy Azure Virtual Machine Managed Disks to Azure Blob Storage PowerShell Script

Sample Input .CSV File

You will need to update the following variables in the PowerShell script and create your own input file.

$VMNames = Import-Csv -LiteralPath “FULL-PATH-TO-CSV-FILE”
$TargetStorageAccountName = “YOUR-STORAGE-ACCOUNT-NAME”
$TargetStorageAccountKey = “YOUR-STORAGE-ACCOUNT-KEY”

Cosmos DB World Blazor Application with DevExpress UI Components and Bing Maps: Part 2

A few months ago I developed and published a post on a Blazor server project which utilises DevExpress UI Framwork components, Cosmos DB and Bing Maps with JSinterop. There are two Razor UI components, which are presented on the main index page, these display country and city selector drop down controls, a tiny javascript file to interact with the Bing Maps API and a Bing maps UI component.

To use this solution, you will need to provision a Cosmos DB account and create a single collection. You can utilise the Cosmos DB migration tool to load the dataset below, into the Cosmos DB collection. Various appsettings need to be updated to reflect your own Cosmos DB account, collection, partition key, database and cosmos db key. The _host.cshtml, will need to be updated for the Javascript link reference in relation to the Bing maps key too.

The project site is accessible on Microsoft Azure below and I have now uploaded the code to my GitHub public repo. Follow the links below.

Cosmos DB World Web Site

Cosmos DB World Source Code

Cosmos DB World Countries DataSet

My Public Code Repository on GitHub

For a while now, I have been adding code inline within my blob posts. I’ve now released a public repository on GitHub, which I will be using moving forward to publish all my community shared code, free for use with the MIT license.

I will start to publish my previous code into the public repository, for now I’ve published a recent .NET 5 console app which is a basic RSS reader that currently reads the .NET teams RSS feed. My public repository can be found below.

Tejinder Rai on GitHub

Blazor File Uploads – to Azure Blob Storage

The Intro…

You might wonder, your an Architect, why are you posting blogs about coding? Good question I would say 🙂 Well, working as an Architect is my day job, but there are many different ideas I have in my head and some of them just require a bit more thought, where I might need to build a PoC, or sometimes like this post, I like to try out new frameworks, libraries or just build samples for fun. Having already coded for well over a decade in .NET, doesn’t stop me from wanting to keep up to date with my coding skills , especially C#, or trying out different architectural patterns to understand how they can be applied in software applications, hybrid architectures, native cloud architectures or help a project I am working on at a specific point in time. From a work perspective, all things Microsoft are highly important to me, especially since I consider myself lucky enough to have spent a fair bit of time working at Microsoft Canada, Microsoft UK and in Seattle at Microsoft HQ and at Microsoft conferences being trained and kept up to date on technologies, which were not always about Microsoft Azure of course.

Now back to this post…

With the recent updates announced at the .NET 2020 Conference last week, I decided to try out the new InputFile UI component in Blazor. Steve Sanderson had already posted a blog regarding a InputFile component here previously, in September 2019. This is now included with the launch of .NET 5. I’ve also been using the DevExpress Blazor UI Components library and used the <DXUpload/> UI component, which I highly recommend also.

In this post I wanted to try out the new native InputFile Control and upload some files to Azure blob storage for testing purposes. I am working on a project which will require the basic functionality of file uploads and downloads to and from Azure blob storage, I may add a future post about one of the new exciting projects I am working on.

Note: This is a very basic implementation for the purposes of this blog post, it is not at all production ready.

Nuget Packages

With any .NET project, the first thing you may want to do is to decide your approach on how you want to build out your components, whether or not you have existing shared libraries, component libraries, NuGet packages you work with regularly, or if you just like coding and building your own supporting toolsets and templates, you may not even need to include anything from the onset and just include packages whilst you are building out your solution in an agile way.

In my sample project, a Blazor Server application, called BlazorFileUploader, I used the following NuGet packages, Microsoft Azure.Storage.Blobs client library and DevExpress.Blazor.

Note: As I mentioned earlier in this article, I have been testing the DevExpress UI components <DXUpload> UI component, but it is not used in this post.

The code…

Appsettings.json

The following configuration was added for the Azure blob storage connection string. Of course, in an enterprise scenario, if your hosting your application in Azure App Service, you could utilise Azure KeyVault, which is recommended instead.

“Storage”: {
“StorageAccountConnectionString”: “DefaultEndpointsProtocol=https;AccountName=[YourStorageAccountName;AccountKey=YourStorageAccountKey==;EndpointSuffix=core.windows.net”,
},

Startup.cs

The the default configuration provider, the connection string is set in string within a config context class.

public class Startup
{
    public IConfiguration Configuration { get; }
    readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
        Config.AzureStorageConnectionString = Configuration.GetConnectionString("StorageAccountConnectionString");
    }
....

Config.cs

The AzureStorageConnectionString is set by the code above, so this can be used when the server upload is handled server side.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Threading.Tasks;

namespace BlazorAzureStorageFileLoader.Data
{
    public class Config
    {
        public static string AzureStorageConnectionString { get; set; }

    }
}

New Razor page

A new Razor page is created to handle the file uploads, a bulk of the code, with the <InputFile/> component.

Note: I hard coded a container named “files” in the code. This is not necessary of course, you can build your own blob storage browser and even have methods to retrieve files and create containers.

@page "/fileloader"
@using System.IO
@using Azure.Storage.Blobs

<h4>Blob Storage File Loader</h4>

<InputFile OnChange="@UploadFiletoAzBlobStorage" />

<p>@status</p>

@if (fileSelected)
{
<p>
    <div class="spinner-border" /><h5>Uploading file...</h5>
</p>
}

@code {

    int count = 1;
    string status;
    bool fileSelected = false;
    private string localFileName { get; set; } = "Not Selected";

    private void UpdateStatus(ChangeEventArgs e)
    {
        status = e.Value.ToString();
        count = count +1 ;
        StateHasChanged();
    }


    async Task UploadFiletoAzBlobStorage(InputFileChangeEventArgs e)
    {
        var file = e.File;

        if (file != null)
        {

            fileSelected = true;

            string connectionString = Data.Config.AzureStorageConnectionString;

            // Nax File Size ~ 50MB
            long maxFileSize = 1024 * 1024 * 50;

            BlobContainerClient container = new BlobContainerClient(connectionString, "files");

            try
            {
                BlobClient blob = container.GetBlobClient(file.Name);
                using (Stream fs = file.OpenReadStream(maxFileSize))
                {
                    await blob.UploadAsync(fs);
                }
            }
            catch (Exception ex)
            {

            }
            finally
            {
                // Clean up after the test when we're finished
            }

            status = $"Finished loading {file.Size/1024/1024} MB from {file.Name}";
            fileSelected = false;
            StateHasChanged();
        }
        else
        {
            status = $"No file selected!";
        }
    }
}

Shared\NavMenu.razor

The navigation menu is updated to remove the default links and an update is made to the application display name. A new navigation link is added to the fileloader razor page.

div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">Azure Storage FileLoader</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        @*<li class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="fetchdata">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
            </NavLink>
        </li>*@
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="fileloader">
                <span class="oi oi-list-rich" aria-hidden="true"></span> File Loader
            </NavLink>
        </li>
        @*<li class="nav-item px-3">
            <NavLink class="nav-link" href="fileloader2">
                <span class="oi oi-list-rich" aria-hidden="true"></span> File Loader 2
            </NavLink>
        </li>*@
        @*<li class="nav-item px-3">
            <NavLink class="nav-link" href="Component Testing">
                <span class="oi oi-list-rich" aria-hidden="true"></span> File Loader 2
            </NavLink>
        </li>*@
    </ul>
</div>

@code {
    private bool collapseNavMenu = true;

    private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}

The Test

The FileInput UI component is shown in the fileloader.razor page.

I choose a local file to upload.

The spinner is shown with the filename. The code which displays this in the razor page is highlighted below.

<p>@status</p>

@if (fileSelected)
{
<p>
    <div class="spinner-border" /><h5>Uploading file...</h5>
</p>
}

The file load to Azure blob storage is completed.

The blob is shown in the Azure storage account blob container.

That’s the most simple and quickest way to utilise the new <InputFile/> UI component in Blazor with .NET 5, with Azure blob storage.

.NET Core 3.1 to .NET 5.0

Today marks the launch of .NET 5.0, the unified platform framework which executes on desktop, web, cloud, mobile, gaming, IoT and AI platforms. Catch all the updates in the sessions at the .NET conference from November 10th 2020, through to November 12 2020, here. Ensure that you keep an eye on the support policy too, which is available here.

And more news, .NET 5.0 is available in Azure App Service, from today!

Useful Links:

Resources
• .NET Documentation https://aka.ms/dotnet-docs
• SDK Documentation https://aka.ms/dotnet-sdk-docs
• Release Notes https://aka.ms/dotnet5-release-notes
• Tutorials https://aka.ms/dotnet-tutorials
• Code Mag https://aka.ms/dotnet5-codemag

In addition, I’ve ensured Visual Studio 2019 is on the latest release, 16.8.0.

Cosmos DB World Blazor Application with DevExpress UI Components and Bing Maps:Part 1

I’ve recently been working on a Blazor server side application, to integrate with Cosmos DB. The Cosmos DB holds a single collection with a list of countries and cities with coordinates for each city. I’ve had the small dataset for a while now, most of the free sources of data can be downloaded from this location: http://www.geonames.org/.

Initially the data was in .CSV format and I initially imported the dataset into an Azure SQL database. I later decided to copy the dataset into Cosmos DB and utilise the SDK within a Blazor application, added my Blazor DevExpress nuget package, for the drop down controls, then integrated a Bing Maps application with the Bing Maps SDK. Transferring the data from Azure SQL to a Cosmos DB collection was straight forward using Azure Data Factory.

I have published the basic version of the Blazor application to https://cosmosdbworld.azurewebsites.net, where you can select a country and then a city, using the DevExpress drop down controls, then the map is updated dynamically as the IJSRuntime interface is dependency injected into a Bing Maps UI component. Overall, the Bing map renders extremely quickly, as the longitude and latitude is bound to the parameters of the Bing maps component from the parent country and city drop down component. The longitude and latitude coordinates are also fetched from the CosmosDB collection, everytime a city is selected, which refreshes the map automatically. The simple javascript functions update the <div> in the UI component, with the coordinates each time the city is changed.

AADSTS Error Codes and References

I was working on an issue which seemed to be a conditional access policy issue in Azure AD today. Whilst the issue was related to a conditional access policy in the sign in logs, it actually turned out to be a user requiring SSPR security information verification. During research, I found that new Azure AD tenants from August 15th 2020, start utilising the combined experience for both MFA and SSPR. This is documented here.

Here’s a view of what was occurring, which may help someone else in the future.

Problem/Scenario

A cloud application was excluded from MFA, the user also has a password policy applied to the Azure AD account not requiring password resets (something which was required for the scenario). When the user signed into the cloud application, the user received a prompt for more security information, seeming as though from the sign in logs this was point to a conditional access policy blocking the request.

Actual Issue

The actual issue was the user needed to review their verification methods to keep the account secure, for SSPR. This is controlled through the password reset options. Upon review of the sign in logs, an AADSTS50125 was present confirming the issue.

AADSTS Error Code Reference

The actual AAD Security Token Service error message are well documented on this Microsoft docs page. You can also submit the code to the web page below:

https://login.microsoftonline.com/error

Light Bulb Moment {}

Since the above form accepts an error action with a code, as per the HTML markup:

I decided to create my own Blazor application to submit my own AADSTS error codes for troubleshooting. I used the HtmlAgilityPack to pull out the response in the Blazor component to display the details of error codes. This makes it easier to parse the response html and embed the response into a razor page with a reference to ((MarkupString)[HTMLValue])

I have deployed the Blazor AADErrorChecker SPA here, using Azure App service.

Azure AD Outage Sept 28, 2020; Tracking ID SM79-F88

Microsoft Azure suffered an outage with Azure AD authentication (Americas) on Monday, September 28th 2020, due to a software change in the service, which Microsoft reported was rolled back. As with other service health issues in cloud services, Microsoft constantly ensure customers are kept up to date with service issues and remediation activities. Azure Status, is main place to visit when reviewing cloud service health across all regions. For any historical status issues, the status history is also available for view.

I’ve seen a number of articles on several websites clearly reporting the issues incorrectly and making wide assumptions on how Microsoft handles software code updates. But, it’s important to understand a few basic things before making wide assumptions…

Lets talk about outages…

This isn’t the first and last outage we will see in any cloud platform.

Azure AD has an SLA, it’s important to understand what the SLA is and why it is stated; don’t expect every cloud service to be up 100% all the time. This happened in traditional data centers, there are things that happen, the things that cause outages are investigated, they are remediated, lessons are learned and the affected service, or process which affected the service, has an opportunity to be improved as part of continual service improvement phases.

Failures occur in every industry

Unfortunately, there are failures and service outages across different industries that affect consumers on a daily basis. We can always remember things like:

The time power was lost in our houses

The time the car had a fault or a recall

The time when the internet connection dropped

How does this help?

Well, technically for the outage it doesn’t, but the one of the key takeaways from a service outage is the remediation plan. The postmortem which Microsoft provide as part of the response to the issue experienced is key to improving the service availability and governance around how the specific outage occurred can be rectified to stop similar issues occurring again.

How does this help you?

As I mentioned earlier, it can be frustrating when outages occur, but in the long run, you can expect that similar outages should not occur in the way that the previous outage manifested itself previously. You can be sure that every outage is taken seriously, remediated and you can only expect that there will be innovative phases and releases to improve upon the service in the near future, to ensure outages are kept to a minimum. I can clearly imagine that publicly, we only see a very small percentage of the communication that occurs with such incidents. To Microsoft, such incidents are a matter of paramount importance.

Whilst, customers can’t specifically design for an Azure AD outage, where many Microsoft services rely on Azure AD, one of the key points of cloud computing is to not expect everything to be up and running 100% all of the time. That said, every enterprise solution deployed to a public cloud platform should be designed for availability, with redundancy in mind utilising the correct architectural patterns for each service component.

Closing thoughts

This has all reminded me of a quote by Tom Peters;

“Almost all quality improvement comes via simplification of design, manufacturing… layout, processes, and procedures.”
Tom Peters

Microsoft officially announce support end dates for ADAL and the Azure AD Graph API

I still have some old projects I’ve worked on in my own personal code repository, which still utilise ADAL and the Azure AD Graph API. Without question, there most definitely software solutions on the market which still use the the same nuget packages or endpoints via REST API’s to authenticate users and pull back/update user profile information in a multitude of ways as required by the application.

Just incase you missed this, Microsoft have now provided official guidance on the end of support timelines for both the Active Directory Authentication Library and the Azure Active Directory Graph API.

I’ve been using the Microsoft Authentication Library and MS Graph for a few years now, as the guidance from Microsoft has always been to urge developers to use MSAL and MS Graph for all new development projects. So, now it’s official and time to move over and start migrating over and work with the Microsoft Identity Platform v2.0 endpoint and v2.0 tokens.

Blazor Apps: The Login Display – Part 2

This is part two of two, on Blazor Apps and the Login Display.

In my first post I discussed some basics around the LoginDisplay Razor component in Blazor server-side applications. In this post I will expand out the sample, to link the user display name value to navigate to another Razor component as a page to call MS Graph and return a basic set of user properties.

Updating your Blazor App Dependencies

You will need to update your application dependencies and introduce a new service, in this case a TokenProvider, to return the access token and refresh token, with additional scopes to call MS Graph. For simplicity of this article, this is well defined in the following article already by Microsoft.

ASP.NET Core Blazor Server additional security scenarios

MS Graph Client

Whilst you can build your own HTTP client to call the MS Graph REST APIs, Microsoft provide the Graph Client library for .Net, so in my sample I installed the nuget package in my project.

Azure AD Permissions

I already have the Azure AD permissions in place for the application to read user profiles in the tenant, but I’ve provided a sample below.

New UserProfile.cs Class

A new class is created for each profile property I was interested in displaying on the profile page. The code for the class is below. For simplicity, the types are all strings.

namespace BlazorProfile.Data
{
    public class UserProfile
    {
        public string ObjectId { get; set; }
        public string DisplayName { get; set; }
        public string Office { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string UPN  { get; set; }
        public string JobTitle { get; set; }
        public string Department { get; set; }
        public string MobilePhone { get; set; }
        public string CompanyName { get; set; }
        public string EmployeeId { get; set; }
    }
}

New LCProfile Component

I then created a new Razor page “LCProfile” to host the code required to utilise the TokenProvider service. The code for the component is below.

@page "/lcprofile"
@using BlazorProfile.Data
@inject AuthenticationStateProvider AuthenticationStateProvider
@using Microsoft.Identity.Client
@inject Microsoft.Extensions.Configuration.IConfiguration config
@using Microsoft.Graph
@using Microsoft.AspNetCore.Components.Authorization
@using System.Net.Http.Headers
@using Microsoft.AspNetCore.Http
@inject IHttpContextAccessor httpContextAccessor
@using BlazorProfile.Auth
@inject TokenProvider TokenProvider

<AuthorizeView>
    <Authorized>
        <h3>Profile</h3>
        <table class="table" width="500px">
            <tr>
                <td>First Name: @prof.FirstName</td>
            </tr>
            <tr>
                <td>Last Name: @prof.LastName</td>
            </tr>
            <tr>
                <td>ObjectId: @prof.ObjectId</td>
            </tr>
            <tr>
                <td>Display Name: @prof.DisplayName</td>
            </tr>
            <tr>
                <td>Company: @prof.CompanyName</td>
            </tr>
            <tr>
                <td>Job Title: @prof.JobTitle</td>
            </tr>
            <tr>
                <td>Department: @prof.Department</td>
            </tr>
            <tr>
                <td>Office: @prof.Office</td>
            </tr>
            <tr>
                <td>UPN: @prof.UPN</td>
            </tr>
            <tr>
                <td>Office Phone: @prof.MobilePhone</td>
            </tr>
        </table>
@ErrorMessage
</Authorized>
        <NotAuthorized>
            You have not authenticated!
        </NotAuthorized>
    </AuthorizeView>

@code {

        private string ErrorMessage;

        private UserProfile prof = new UserProfile();

        protected override async Task OnInitializedAsync()
        {
                ErrorMessage = "No exceptions on page load";
            try
            {

                var accesstoken = TokenProvider.AccessToken;

                var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
                var authenticateduser = authState.User.Claims.First(c => c.Type == "preferred_username");




                var graphClient = new GraphServiceClient(
                new DelegateAuthenticationProvider(requestMessage =>
                {
                    requestMessage.Headers.Authorization =
                        new AuthenticationHeaderValue("bearer", accesstoken);
                    return Task.FromResult(0);
                }));


                User graphuser = await graphClient.Users[authenticateduser.Value]
                   .Request()
                   .Select(u => new
                   {
                       u.GivenName,
                       u.Surname,
                       u.Id,
                       u.UserPrincipalName,
                       u.OfficeLocation,
                       u.Department,
                       u.JobTitle,
                       u.MobilePhone,
                       u.DisplayName,
                       u.EmployeeId,
                       u.CompanyName,
                       u.City
                   })
           .GetAsync();

                prof.FirstName = graphuser.GivenName;
                prof.LastName = graphuser.Surname;
                prof.ObjectId = graphuser.Id;
                prof.UPN = graphuser.UserPrincipalName;
                prof.Office = graphuser.OfficeLocation;
                prof.Department = graphuser.Department;
                prof.JobTitle = graphuser.JobTitle;
                prof.MobilePhone = graphuser.MobilePhone;
                prof.DisplayName = graphuser.DisplayName;
                prof.EmployeeId = graphuser.EmployeeId;
                prof.CompanyName = graphuser.CompanyName;

            }
            catch (Exception e)
            {
                //throw new Exception (e.Message);
                ErrorMessage = e.Message;
            }
        }
    }

The TokenProvider is injected into the component and then referenced in the GraphClient. I also use the AuthenticationStateProvider to pull back the users principal name, in order to query MS Graph for the users Azure AD profile data.

Since the default users profile data is limited, an explicit selection for the properties in the user profile are selected and returned as part of the request. The Razor component should contain an authorised view.

Note: This is sample code, so you should check for Nulls in your own implementation. In fact, you would want to ensure that you check each property and likely store the values i.e. in a container that can be then referenced by the application. Typically, you could implement the scope offline_access for the application to retrieve refresh tokens as this is explicitly required for the v2.0 token endpoint i.e. you don’t want your application to fail based on the fact it doesn’t have the necessary structure to utilise refresh tokens to request new access tokens, otherwise you will end up receiving the an error similar to the one below.

Kungfu Developer 
Profile 
First Name: 
Last Name: 
Objectld: 
Display Name: 
Company: 
Job Title: 
Department: 
Office: 
UPN: 
Office Phone: 
Log out 
About 
Code: InvalidAuthenticationToken Message: Access token has expired. Inner error: AdditionalData: date: request-id: 72849096-54fb-4199-9f17- 
d6c6a7e6bc25 ClientRequestld: 72849096-54fb-4199-9f17-d6c6a7e6bc25

Updating the LoginDisplay Razor Component

For this sample, I’ve simply updated the component to add <a href tag> around the @UserName property to access the new LCprofile Razor Component.

@inject AuthenticationStateProvider AuthNStateProvider

<AuthorizeView>
    <Authorized>
        <a href="/lcprofile" >@UserName</a>
        <a href="AzureAD/Account/SignOut">Log out</a>
    </Authorized>
    <NotAuthorized>
        <a href="AzureAD/Account/SignIn">Log in</a>
    </NotAuthorized>
</AuthorizeView>

The Result

When the user name is clicked in the header, the user navigates to the lcprofile razor component and the profile properties are displayed .

This reminds me of the days when I developed custom controls for SharePoint several years ago, for users to edit their own profiles.

This ends the sample on the update to the LoginDisplay component in Blazor server-side applications.