Deploy storage account and output connection string with SAS token using ARM template

I found my self in a situation where I needed to deploy Azure storage account with a blob container and generate connection string with SAS token and update one of the web app’s settings with generated connection strings.

For this purpose, I used linked ARM template and created Storage account and blob container and generated the connection string with SAS token and output from that template so that master template can use this value.

Table of content

  1. Craft ARM Template
  2. Output connection string with SAS token
  3. Output connection string with account key
  4. Deploy Template

Craft arm template

We need to Craft ARM template as below for our requirement.


{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"variables": {
"storageAccountApiVersion": "2018-07-01",
"storageAccountNameTidy": "[toLower(trim(parameters('storageAccountName')))]",
"blobEndPoint":"[concat('https://',variables('storageAccountNameTidy'),'.blob.core.windows.net/')]"
},
"parameters": {
"location": {
"type": "string",
"defaultValue": "southeastasia"
},
"storageAccountName": {
"type": "string",
"defaultValue": "awesomestorage"
},
"accountType": {
"type": "string",
"defaultValue": "Standard_LRS"
},
"accessTier": {
"type": "string",
"defaultValue": "Hot"
},
"supportsHttpsTrafficOnly": {
"type": "bool",
"defaultValue": true
},
"sasTokenExpiry": {
"type": "string",
"defaultValue": "2020-12-31T23:59:00Z"
},
"containerName": {
"type": "string",
"defaultValue": "test"
},
"accountSasProperties": {
"type": "object",
"defaultValue": {
"signedServices": "b",
"signedPermission": "rl",
"signedResourceTypes": "sco",
"keyToSign": "key2",
"signedExpiry": "[parameters('sasTokenExpiry')]"
}
}
},
"resources": [
{
"name": "[parameters('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "[variables('storageAccountApiVersion')]",
"location": "[parameters('location')]",
"properties": {
"accessTier": "[parameters('accessTier')]",
"supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]"
},
"dependsOn": [],
"sku": {
"name": "[parameters('accountType')]"
},
"kind": "BlobStorage",
"resources": [
{
"name": "[concat('default/', parameters('containerName'))]",
"type": "blobServices/containers",
"apiVersion": "[variables('storageAccountApiVersion')]",
"dependsOn": [
"[parameters('storageAccountName')]"
]
}
]
}
],
"outputs": {
"storageAccountConnectionString": {
"type": "string",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountNameTidy'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameTidy')), variables('storageAccountApiVersion')).keys[0].value)]"
},
"storageAccountConnectionStringWithSAS": {
"type": "string",
"value": "[concat('BlobEndpoint=',variables('blobEndPoint'),';SharedAccessSignature=', listAccountSas(variables('storageAccountNameTidy'), variables('storageAccountApiVersion'), parameters('accountSasProperties')).accountSasToken)]"
}
}
}

 

generate connection string with sas token

As per the above full ARM Template, we can see connection string is generated with full access and another is generated with SAS token.

In order to generate a connection string with SAS token, I have used listAccountSas ARM function.

Find More details on this function here

"storageAccountConnectionStringWithSAS": { "type": "string", "value": "[concat('BlobEndpoint=',variables('blobEndPoint'),';SharedAccessSignature=', listAccountSas(variables('storageAccountNameTidy'), variables('storageAccountApiVersion'), parameters('accountSasProperties')).accountSasToken)]" }

We need to pass three parameters for this function

  • resourceIdenifier

The name of the storage account within the specified resource group

  • apiVersion

The API version to use for this operation

  • requestParameters

We need to pass parameters as specified here

"accountSasProperties": {
            "type": "object",
            "defaultValue": {
                "signedServices": "b",
                "signedPermission": "rl",
                "signedResourceTypes": "sco",
                "keyToSign": "key2",
                "signedExpiry": "[parameters('sasTokenExpiry')]"
            }
        }

We can find more details about parameters specified herein above Microsoft documentation.

Generate connection string with storage account key

We can generate connection string which has full access to storage account with Storage account access keys.  We can use listKeys ARM function for this.

We can find more details on this function here.

We need to pass two parameters for this function

  • Storage account resource id
  • API version

This function gives you all keys in the storage account and we can select one key to create connection string as below.

 


listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameTidy')), variables('storageAccountApiVersion')).keys[0].value

Deploy ARM template

We can use the following PowerShell script to deploy ARM template.

Note: Fill out the required parameters. (denotes in caipatal)


$password = "SECRET"
$clientId = "CLIENTID"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential ($clientId, $securePassword)
Login-AzureRmAccount -ServicePrincipal -TenantId "TENANTID" -SubscriptionId "SUBSCRIPTIONID" -Credential $credentials 


$templateFilePath = "ARM TEMPLATE PATH"

$resourceGroupName = "RESOURCEGROUPNAME"
$resourceGroupLocation = "LOCATION"
$deploymentName = "DEPLOYMENTNAME"

#Create or check for existing resource group
$resourceGroup = Get-AzureRmResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue
if(!$resourceGroup)
{
    Write-Host "Resource group '$resourceGroupName' does not exist. To create a new resource group, please enter a location.";
    if(!$resourceGroupLocation) {
        $resourceGroupLocation = Read-Host "resourceGroupLocation";
    }
    Write-Host "Creating resource group '$resourceGroupName' in location '$resourceGroupLocation'";
    New-AzureRmResourceGroup -Name $resourceGroupName -Location $resourceGroupLocation
}
else{
    Write-Host "Using existing resource group '$resourceGroupName'";
}


# Start the deployment
Write-Host "Starting deployment...";
New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -Name $deploymentName -TemplateFile $templateFilePath;

We can see the following output once deployment is successful.

So this is how we deploy storage account and generate connection strings. 🙂

Custom functions in Azure ARM Templates

Azure provides a helpful number of functions which can be used in ARM templates. It makes our life easier.

We can see the complete list of Azure ARM function here

Apart from that in some situations, you may find your self where you need to implement custom function inside ARM templates. So we can reuse it. So it is DRY.

Typically, we use complicated logic inside the function that we don’t want to duplicate in the ARM template.

So is it possible in ARM template? Yes, ARM templates give us the opportunity to implement custom functions. 🙂

Keep in mind. There are some restrictions when we use functions as below.

  • The function can’t access variables.
  • The function can only use parameters that are defined in the function. When you use the parameters function within a user-defined function, you’re restricted to the parameters for that function.
  • The function can’t call other user-defined functions.
  • The function can’t use the reference function.
  • Parameters for the function can’t have default values

The custom function should be declared inside functions property in an ARM template.

Following is a sample function which accepts the container name as a parameter and appends resource group location to container name.


{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"functions": [
{
"namespace": "rt",
"members": {
"containerNameWithLocation": {
"parameters": [
{
"name": "containerName",
"type": "string"
}
],
"output": {
"type": "string",
"value": "[concat(parameters('containerName'), resourceGroup().location)]"
}
}
}
}
],
"parameters":{
"containerName": {
"type": "string",
"defaultValue": "blobcontainer"
}
}
}

Note that parameters used in scope of function should be declared in parameters section in ARM template.

Your functions require a namespace value to avoid naming conflicts with template functions. In above function we have used rt as namespace.

 

Then we can call the function as below

rt.containerNameWithLocation(parameters(‘containerName’))

Following snippet shows actual usage of this function.


"resources": [
{
"name": "[parameters('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "[variables('storageAccountApiVersion')]",
"location": "[parameters('location')]",
"properties": {
"accessTier": "[parameters('accessTier')]",
"supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]"
},
"dependsOn": [],
"sku": {
"name": "[parameters('accountType')]"
},
"kind": "BlobStorage",
"resources": [
{
"name": "[concat('default/', rt.containerNameWithLocation(parameters('containerName')))]",
"type": "blobServices/containers",
"apiVersion": "[variables('storageAccountApiVersion')]",
"dependsOn": [
"[parameters('storageAccountName')]"
]
}
]
}
],

 

So enjoy writing custom functions in ARM Template 🙂

msbuild copy

Copy directory recursively task in MSBuild

So I ran into a situation where I needed to copy a directory to a specific destination through MSBuild.

This is how I could achieve my goal.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<CloudArtifacts Include=".Cloud\Data\**\*.*"/>
</ItemGroup>
<Target Name="CopyFiles">
<Copy SourceFiles="@(CloudArtifacts)" DestinationFiles="@(CloudArtifacts->'c:\PackableFiles\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
</Project>

We can get more details on MS Build Copy task in this link. 

🙂

Create Service Principal using Powershell and Login to Azure with Powershell

What is Service principle?

Service principle are non-interactive Azure accounts.  Applications use Azure services should always have restricted permissions.  Azure offers Service principals allow applications to login with restricted permission Instead having full privilege in non-interactive way.

Using Service Principal we can control which resources can be accessed.

For Security reason, it’s always recommended to use service principal with automated tools rather than allowing them to log in with user identity

Create a Service Principal with PowerShell. 

Note: For this demo we are using Azure RM PowerShell module. Azure has introduced new PowerShell module called AZ. Create AD App

Create AD app

#Create Service principal
New-AzureRmADServicePrincipal ApplicationId $app.ApplicationId `
DisplayName $dummyUrl `
Password $securePassword `
Scope "/subscriptions/<SUBSCRIPTION ID>" `
Role Contributor `
StartDate ([datetime]::Now) `
EndDate $([datetime]::now.AddYears(1)) Verbose

Create a Service Principal

#Create Service principal
New-AzureRmADServicePrincipal ApplicationId $app.ApplicationId `
DisplayName $dummyUrl `
Password $securePassword `
Scope "/subscriptions/<SUBSCRIPTION ID>" `
Role Contributor `
StartDate ([datetime]::Now) `
EndDate $([datetime]::now.AddYears(1)) Verbose

This service principal is valid for one year from the created date and it has Contributor Role assigned. Further using this Service principal application can access resource under given subscription.  We can scope to resources as we wish by passing resource id as a parameter for Scope.

View created AD app in Portal

   1. Log in Portal

  • Go to Azure Active Direcoty -> App Registrations
  • We can find the created app as below
  • Once we click the app we will see app details as below

We need this information when we need to login through Service principal

Login using Service Principal with Powershell

#Login with service principal
$clientId = "<CLIENT ID>"
$credentials = New-Object System.Management.Automation.PSCredential ($clientId, $securePassword)
LoginAzureRmAccount ServicePrincipal TenantId "<TENANTID>" `
SubscriptionId "<SUBSCRIPTIONID>" `
Credential $credentials

Fill out the required parameters.

Once we run the script we can successfully log in to Azure using Service Principal

Full code: 🙂

#Create AD app
$dummyUrl = "https://dummy.dummy.com"
$passpowrd = "Qwerty@123!"
$securePassword = ConvertTo-SecureString String $passpowrd AsPlainText Force
$app = New-AzureRmADApplication DisplayName $dummyUrl `
IdentifierUris $dummyUrl `
HomePage $dummyUrl `
Password $securePassword Verbose
#Create Service principal
New-AzureRmADServicePrincipal ApplicationId $app.ApplicationId `
DisplayName $dummyUrl `
Password $securePassword `
Scope "/subscriptions/<SUBSCRIPTION ID>" `
Role Contributor `
StartDate ([datetime]::Now) `
EndDate $([datetime]::now.AddYears(1)) Verbose
#Login with service principal
$clientId = "<CLIENT ID>"
$credentials = New-Object System.Management.Automation.PSCredential ($clientId, $securePassword)
LoginAzureRmAccount ServicePrincipal TenantId "<TENANTID>" `
SubscriptionId "<SUBSCRIPTIONID>" `
Credential $credentials

 

 

Powershell Identify whether running on Administrator

In some cases, we need to run some script in administrator mode.

Sometimes we face a situation where we want to know whether the script is running on Administrator mode.

Following script says whether PowerShell script is running on Administrator mode or not.


$elevated = [bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544")
if($elevated -eq $false)
{
throw "In order to install services, please run this script elevated."
}
else {
Write-Host "You are in Administrator mode"
}

🙂

Calling POST REST API in powershell with headers

In some cases we need to call POST REST API using Powershell.

Let’s go through sample code to get to know how it is done using Powershell.

In this Article we will go through below topics.

  • Create sample Web API
  • Invoke Web API in Powershell

Create Sample Web API

  1. Create ASP.NET Core Web Application

  1. Select API option

  1. Once project created we can see default values controller as below

We need our API to accept some Data. So we will create Modal class for that

  1. Create Modals Folder

  1. Create SampleData class under Modals Folder

  1. Add Sample properties to the class. I created Value1 and Value2 as string type.

  1. Implement API method in ValuesController as below.
[Route(“TestMethod”)]
[HttpPost]
public ActionResult TestMethod(SampleData data)
{
// Do what ever with Data
var authKey = Request.Headers[“AuthKey”];return Ok();

}

Invoke Web API in Powershell

  1. Open Powershell ISE and write following codes to invoke REST API.

 

  • Api url
$apiUri = “https://localhost:44326/api/values/TestMethod&#8221;
  • POST Body Data Object

 

$data = @{
‘Value1’ = “val1”
‘Value2’ = “val2”
}
  • Convert POST BODY data to json format
$requestBody = $data | ConvertTo-Json -Compress
  • Create request headers object
$requestHeaders = @{‘AuthKey’ = ‘sampleauth’}
  • Use Powershell Invoke-RestMethod with parameter as below
Invoke-RestMethod -Method Post -Uri $apiUri -Body $requestBody -ContentType “application/json” -Headers $requestHeaders
  1. Put break point on TestMethod and Run the API project in debug mode
  2. Run the Powershell snippet in Powershell ISE

  1. Breakpoint will be hit and we can see the data we passed.

  1. Once you step over to “authkey” line we can see “AuthKey” header value

 

So this is how we call POST REST API end point in Powershell. ☺

Connect Sitecore 9 instance in Sitecore Rocks

We have found our self needing to connect Sitecore Rocks to Sitecore 9 instance.

When we try to connect to Sitecore 9 instance in Sitecore Rocks in the first time we can not connect.

In order to make it work we have to tweak web.config with following entry to system.web xml node.


<location path="sitecore/shell/WebService">
<system.web>
<authorization>
<allow users="?,*" />
</authorization>
</system.web>
</location>

view raw

tweak.xml

hosted with ❤ by GitHub

🙂

 

Reading json file and update json file in powershell

There are some cases we need to update json files using powershell.

This is how I do it.


$filePath = "C:\jeevan\sample.json"
$file = ([System.IO.File]::ReadAllText($filePath) | ConvertFrom-Json)
Write-Host $file.property1
$file.property1 = Get-Random
$file | ConvertTo-Json | Out-File FilePath $filePath Encoding utf8 Force

1

I used following json file


{
"property1": 123,
"property2": "value2"
}

view raw

sample.json

hosted with ❤ by GitHub

Done 🙂

 

 

Double tap to exit in xamarin Android

So I had to implement double tap to exit from app in Android using xamarin. This how it is implemented

  • Create blank Android App

create project

 

  • Override OnBackPressed method in MainActivity.cs

private bool doubleBackToExitPressedOnce = false;
public override void OnBackPressed()
{
if (doubleBackToExitPressedOnce)
{
base.OnBackPressed();
Java.Lang.JavaSystem.Exit(0);
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.MakeText(this, "Double tap to exit", ToastLength.Short).Show();
new Handler().PostDelayed(() =>
{
doubleBackToExitPressedOnce = false;
}, 2000);
}

view raw

MainActivity.cs

hosted with ❤ by GitHub

  • That’s it 🙂 Run the app and see the out put

double tap to exit

GIF_Maker_VideoToGif_15-3-2018_95808_PM

Thanks. 🙂

 

Toast in android using xamarin forms

 

When we want to let user know that something happening we can use Toast.

Let’s see how to create Toast in in Android in Xamarin Forms

Create xamrin foms application with Android project

project

  • In .net standard project add a Interface

public interface IToastMessageService
{
void ShowToastMessage(string message);
}

  • In Android project add ToastMessageService and implement the IToastMessageService

[assembly: Xamarin.Forms.Dependency(typeof(ToastMessageService))]
namespace ToastTestXamarin.Droid
{
public class ToastMessageService : IToastMessageService
{
public void ShowToastMessage(string message)
{
Toast.MakeText(Android.App.Application.Context, message, ToastLength.Long).Show();
}
}
}

  • In MainPage.xaml add a button

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ToastTestXamarin"
x:Class="ToastTestXamarin.MainPage">
<Button x:Name="BtnToastMessage" Text="Show Toast" Clicked="ShowToast"></Button>
</ContentPage>

view raw

MainPage.xaml

hosted with ❤ by GitHub

  • And in the code behind implement the event handler

private void ShowToast(Object sender, EventArgs args)
{
DependencyService.Get<IToastMessageService>().ShowToastMessage("Test Toast Message");
}

Finally run the project 🙂

 

toast

Get the sample project on Github