It has become increasingly important to have your site secured via some kind of certificate. Even your Google ranking is affected by it.

The main problem with SSL/TLS certificates is the fact most of them cost money. Now, I don’t have any problem with paying some money for something like a certificate, but it will cost quite a lot if I want to set this up for all of my sites & domains. In theory it’s possible to create a self-signed certificate and publish your site with it, but that’s not a very good idea as there’s no one who trusts your self-signed certificate besides yourself.

Luckily Mozilla is helping us, poor content-creators, out with their service called Let’s Encrypt. Let’s Encrypt is a rather new Certificate Authority which is offering a free, open and automated service to create certificates. Their Getting Started guide contains some details on how to set this up for your website or hosting provider.

This is all fun and games, but when hosting your site(s) in the Azure App Service ecosystem you can’t do much with the steps defined in the Getting Started guide. At least, I couldn’t make any sense off it.

There’s a developer who has been so kind to create a so called Site extension for an Azure App Service called Azure Let’s Encrypt. It comes in two flavors for both x86 and x64 systems. Depending on which platform you have deployed your site to, you need to activate one corresponding this platform.

image

In order to access these site extensions you’ll have to log in to the Kudu environment of your site (https://yourAzureSite.scm.azurewebsites.net/SiteExtensions/#gallery).

Once it’s installed you can launch the extension and will navigate to the configuration area of this extension. This screen will show you a number of fields for which most of them have to be filled with correct data.

image

This form can look quite impressive if you are not familiar with these things. I’m not very familiar with these terms also, but Nik Molnar has a nice post with some details on the matter.

He mentions you should first create two new application settings within the Azure Portal for the App Service you want to enable SSL. The name/key of these settings are AzureWebJobsStorage and AzureWebJobsDashboard. Both should contain a connectionstring to your Azure Storage account, which will look something like the following DefaultEndpointsProtocol=https;AccountName=[storage account name];AccountKey=[storage account key]. The storage account is necessary for the WebJobs, which will be created by the site extension in order to refresh the SSL certificate.

Next up is the hardest part, creating a Server Principal and retrieving a Client Id and Client Secret from it. In this context, a Server Principal can be seen as some kind of authentication server.
If you already have a Server Principal, you can skip the step of creating one. I still had to add one to my subscription. The following script will create one for you.

$uri = 'http://mysubdomain.mydomain.nl'
$password = 'SomeStrongPassword'

$app = New-AzureRmADApplication -DisplayName 'MySNP' -HomePage $uri -IdentifierUris $uri -Password $password

Needles to say, your PowerShell context needs to be logged in into your Azure subscription before you are able to run this command.

You are now ready to add your application to the server principal with the following commands.

New-AzureRmADServicePrincipal -ApplicationId $app.ApplicationId

New-AzureRmRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $app.ApplicationId

These commands will add the application and make sure it has the Contributor role, so it will have enough permissions to install and configure certificates.
Make sure you write down the $app.ApplicationId which will be used as the Client Id in the site extension later on.

Now that we have all the information to configure the Let’s Encrypt site extension, we are ready to install it on our App Service. In order to make this even easier, please configure the following Application Settings in your App Service.

KeyValue

letsencrypt:Tenant

Your AAD domain
(yoursubscription.onmicrosoft.com)

letsencrypt:SubscriptionId

Your Azure Subscription Id
Can be found on the Overview page of an App Service

letsencrypt:ClientId

The $app.ApplicationId we saved from before

letsencrypt:ClientSecret

The $password value used in the earlier script

letsencrypt:ResourceGroupName

The resource group name your App Service is created on

After installing the site extension, navigate to the configuration page. If all is set up correctly, the fields will all be prefilled with the correct information.

image

Check the settings and adjust them if necessary. When you are sure everything is set up correct, proceed to the next page.

This next page isn’t very interesting at this time, so we can continue to the final page of the wizard.

image

Nothing very special over here, just make sure to fill out your e-mail address so you are able to receive notifications from Let’s Encrypt when necessary.

Also good to note, don’t check the Use Staging option. By checking this box the extension will use the test API of Let’s Encrypt and will not create a certificate for you.

Press the big blue button and your site will be available with the certificate after a few moments. The extension uses the challenge-response system of Let’s Encrypt to create a certificate for you. This means it will create a couple of directories in the wwwroot folder of your App Service. This folder structure will look like .well-known\acme-challenge.

image

If this succeeds, Let’s Encrypt is able to create your certificate.

The challenge-response system folders are hard-coded in the extension. If you run your site in subfolder, like public, website, build, etc. you have to specify this via a special variable. You can add the letsencrypt:WebRootPath key in the application settings and specify the site folder in the value, for example site\wwwroot\public. This is very important to remember. I had forgotten about this on one of my sites and couldn’t figure out why the creation of the SSL certificate didn’t work.

Now that you know how to secure your sites with a free certificate, go set this up right away!

As of late, there are a couple of Store apps which just won’t install on any of my Windows 10 machines (One Commander and Open Live Writer in case you are interested).

The message shown is:

The error code is 0x80073CF9, in case you need it.

If you do a search on the error number you’ll find numerous posts and articles explaining on how this error might be solved. As it happens, the error also occurs on Windows Phone/Mobile systems.

One of the suggestions I came across is re-installing the Store app.

Uninstalling a Modern App is quite easy with tools like CCleaner. If you don’t have tools like this, it’s also possible to do this via the PowerShell Remove-AppxPackage cmdlet of course.

However, once uninstalled, how will you install the Store, without having a Store.

A System Restore might help, but I didn’t have any usable restore points.

An easier solution is to re-install the Store app via PowerShell. With the following command you will see all the applications which still reside on your system.

Get-AppxPackage -allusers | Select Name, PackageFullName

One of these should have a name similar to Microsoft.WindowsStore.

You can re-install this app by using the Add-AppxPackage cmdlet.

Add-AppxPackage -register "C:\Program Files\WindowsApps\Microsoft.WindowsStore_11610.1001.25.0_x64__[uniqueId]\appxmanifest.xml" -DisableDevelopmentMode

Invoking this command, mind the [uniqueId] which differs on every system, installs the Windows Store again. You will be able to find the Store again in your start menu/screen and start it again.

The error still occurs when trying to install these specific apps, so re-installing didn’t solve my issue.

I’ve just started setting up some continuous deployment for my personal websites. All of the sites are hosted within Azure App Services and the sources are located on either GitHub or BitBucket. By having the source code located on a public accessible repository (be it private or public), it’s rather easy to connect Azure to these locations.

On my day-job I come across a lot of web- and desktop applications which also need continuous integration and deployment steps in order for them to go live. For some of these projects I’ve used Octopus Deploy and currently looking towards Azure Release Management. These are all great systems, but they offer quite a lot of overhead for my personal sites. Currently my, most important, personal sites are so called static websites using MiniBlog (this site) and Hugo (for keto.jan-v.nl). Some of the other websites I have aren’t set up with a continuous deployment path yet.

I don’t really want to set up an Octopus Deploy server or a path in Azure Release Management for these two sites. Lucky for me, the Azure team has come up with some great addition in order to provide some custom deployment steps of your Azure App Service. In order to set this up, you need to enable the automatic deployments via the `Deployment Options` blade in the Azure portal.

image

Normally, when you have set up your site to be deployed every time some change occurs in a specific branch of your repository the Azure App Service deployment system tries to build your site and place the output to the `wwwroot` folder on the file system. Because I don’t need any msbuild steps whatsoever, I need to override this step and create my own, custom, deployment step.

Setting up such a thing is quite easy, you just have to create a `.deployment` file in the root of your repository and specify the build/deployment script which should be executed. This functionality is provided by Kudu, which Azure uses in order to deploy Git repositories to the Azure App Service.

You can specify a custom script in this deployment file, this can either be a ‘normal’ command script (cmd or bat) or a PowerShell script. I have chosen for PowerShell as it offers me a bit more flexibility compared to a normal command script.

The contents of the deployment file aren’t very exciting. For my scenario it looks like the following:

[config]
command = powershell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -Command "& "$pwd\deploy.ps1" 2>&1 | echo"

This will activate the custom deployment step within the Azure App Service as you can see in the following picture (Running custom deployment command…).

image

 

The contents of my PowerShell script, deploy.ps1, aren’t very exciting either. The MiniBlog project is just a normal ASP.NET Website, so I just have to copy the contents from the repository folder to the folder of the website.

robocopy "$Env:DEPLOYMENT_SOURCE\Website" "$Env:DEPLOYMENT_TARGET" /E

You can do some more advanced stuff in your deployment script. For my Hugo website I had to tell the Hugo assembly to build my website. So the contents of this deploy.ps1 script are similar to this.

# 1. Variable substitutions
if ($env:HTTP_HOST -ne "") {
    echo "doing substitutions on $Env:DEPLOYMENT_SOURCE\config.toml"
    gc "$Env:DEPLOYMENT_SOURCE\config.toml" | %{ $_ -replace '%%HTTP_HOST%%', $env:WEBSITE_HOSTNAME } | out-file -encoding ascii "$Env:DEPLOYMENT_SOURCE\config.new.toml"
    mv "$Env:DEPLOYMENT_SOURCE\config.toml" "$Env:DEPLOYMENT_SOURCE\config.old.toml"
    mv "$Env:DEPLOYMENT_SOURCE\config.new.toml" "$Env:DEPLOYMENT_SOURCE\config.toml"
    rm "$Env:DEPLOYMENT_SOURCE\config.old.toml"
} else {
    echo "not doing any substitutions"
}

# 2. Hugo in temporary path
& "$Env:DEPLOYMENT_SOURCE/bin/hugo.exe" -s "$Env:DEPLOYMENT_SOURCE/" -d "$Env:DEPLOYMENT_TARGET/public" --log -v

# 3. Move the web.config to the root
mv "$Env:DEPLOYMENT_SOURCE/web.config" "$Env:DEPLOYMENT_TARGET/public/web.config"

Still not very exciting of course, but it shows a little what can be achieved. I’m not aware of any limitations for these deployment scripts, so anything can be placed inside it. If you need to do something with specific assemblys, like the hugo.exe, you will need to put them in your repository, or some other location which can be accessed by the script.

You can also view the output of your script in the Azure Portal. All data which is outputted by the script (Write-Host, echo, etc.) is shown in this Activity Log.

image

Useful when debugging your script.

If you have any secrets in your web application/site (like connection strings, private keys, passwords, etc.), it might be a good idea to use this custom deployment step to substitute the committed values to the actual values. If these values are stored in the Azure Key Vault, you can just access the key vault and make sure the correct values are placed within your application before it’s deployed.

Using these deployment scripts can help you out when you have some simple scenarios. If your system is a bit more complex or are working in a professional environment, I’d advise to check out one of the more sophisticated deployment systems, like Octopus Deploy or Azure Release Management. These systems offer a quite a bit more options out of the box and it’s easier to manage the steps, security and insights of a deployment.

Next I’ll try to update an Umbraco site of mine to make use of this continuous deployment scenario. This should be rather easy also as it only needs to call msbuild, which is the default action the Azure App Service deployment option invokes.

When doing modern web development you will probably have to start using NPM sooner, rather than later. Not a big deal of course, since it’s a great addition to the frontend development environment.

However, most NPM packages have quite a bit of dependencies to other packages. All of these dependencies get pulled towards your system also. Still not a big problem as you want a working solution.

The problem arises when you are on a Windows environment, there are a lot of dependencies and you want to delete a project folder on your system. You will stumble across the fact that Windows has a rather low limit on how long a path can be. When all dependencies are loaded, you will probably have some paths which are too long for Windows to handle properly.

This will give you quite a bit of a problem as you can’t delete the folder(s) anymore. One way of solving this is by using PowerShell. By executing the following script you will be able to delete the NPM modules in your project.

ls node_modules | foreach {
	echo $("Deleting module..." + $_.Name)
	& npm rm $_.Name
}

This will iterate through the `node_modules` folder and remove each module inside it.

The output will be something like this:

Deleting module...grunt-contrib-uglify
Deleting module...karma

Do note, this only works for NPM folders. If your path is too long because of some other reason, you’ll have to think of something else.

For our automated deployments we have several Azure Organizational accounts in place. These are created within the Azure Active Directory.

Because these accounts are meant for services, we don’t want them to inherit the default password policy for renewing their passwords every X days. Lucky for us, you can configure this via PowerShell. A short how-to is written on MSDN.

The thing that isn’t written (or referenced) over there is how to run the MSOL cmdlets.

I kept getting the messages `The term 'Set-MsolUser' is not recognized`. By searching a bit on this error I found a thread on the Office365 community forums where someone mentioned the “Microsoft Online Service Module for Windows PowerShell”. This set me off to searching in the right direction. Apparently you need to install a (new/extra) PowerShell module on your system in order to use the MSOL cmdlets. These cmdlets are part of the Office365 and Exchange Online services. A page with download links is provided by Microsoft Support. They provide a link to the Microsoft Online Service Sign-in Assistant for IT Professionals and the Azure Active Directory Module for Windows PowerShell (32-bit and 64-bit).

Once installed, you are finally able to use the MSOL cmdlets. Keep in mind though, you have to connect to the MSOL services first using the connection cmdlet.

Connect-MsolService -Credential $azureADCredentials

After connecting to the service, you can change the service account it’s password behavior to `Password Never Expires`.

For reference, this is the script I’ve used when changing the service account password policies:

function Set-CustomerAzureSubscription($subscriptionName)
{
    $azureSubscriptionSecurePassword  = ConvertTo-SecureString -String $azureSubscriptionPassword -AsPlainText -Force
    $azureCredentials = New-Object System.Management.Automation.PSCredential($azureSubscriptionUsername, $azureSubscriptionSecurePassword)

    Get-AzureAccount
    Add-AzureAccount -Credential $azureCredentials
    Get-AzureSubscription | % { Write-Host "Customer subscription: $($_.SubscriptionName)."}
    
    Write-Host "Selecting $($subscriptionName) as default Customer subscription."
    Select-AzureSubscription -SubscriptionName "$($subscriptionName)"
}

function Set-PasswordNeverExpiresForServiceAccounts($serviceAccountUsername, $serviceAccountPassword)
{
    $azureADCredentialsSecurePassword  = ConvertTo-SecureString -String $serviceAccountPassword -AsPlainText -Force
    $azureADCredentials = New-Object System.Management.Automation.PSCredential($serviceAccountUsername, $azureADCredentialsSecurePassword)
    Write-Host "Connecting to MSOL"
    Connect-MsolService -Credential $azureADCredentials

    Write-Host "Password never expires status of $($serviceAccountUsername)"
    Get-MSOLUser -UserPrincipalName $serviceAccountUsername | Select PasswordNeverExpires
    Write-Host "Setting password never expires status of $($serviceAccountUsername) to 'true'"
    Set-MsolUser -UserPrincipalName $serviceAccountUsername -PasswordNeverExpires $true
    Write-Host "Password never expires status of $($serviceAccountUsername)"
    Get-MSOLUser -UserPrincipalName $serviceAccountUsername | Select PasswordNeverExpires
}

Set-CustomerAzureSubscription $devSubscription
Set-PasswordNeverExpiresForServiceAccounts $devServiceAccount $devPassword

Set-CustomerAzureSubscription $accSubscription
Set-PasswordNeverExpiresForServiceAccounts $accServiceAccount $accPassword

Set-CustomerAzureSubscription $prodSubscription
Set-PasswordNeverExpiresForServiceAccounts $prodServiceAccount $prodPassword