# Code is a highway > Some thoughts & code samples from my everyday ups and downs playing with code... Public Ghost content for AI and LLM tooling. This file includes a bounded export of public pages first, then recent public posts. Append `.md` to any post or page URL to get the content in Markdown (for example, `/example-post.md`). ## Pages _No public content available._ ## Posts ### Exploring Azure Management APIs with az rest and az resource URL: https://codeisahighway.com/exploring-azure-management-apis-with-az-rest-and-az-resource/ Last updated: 2026-09-04T13:17:40.000Z For years, the [resources.azure.com](https://resources.azure.com/?ref=codeisahighway.com) website provided a convenient way to explore and interact with Azure resources through raw HTTP calls to the Azure Management APIs. It was particularly useful for performing custom REST operations directly against Azure resources. Sadly, this tool has been retired, leaving many of us searching for alternatives. Microsoft has introduced a new Resource Explorer view in the Azure Portal. While this new view allows for some exploration, it lacks the robust "raw" HTTP interaction capabilities of its predecessor I loved so much. In this article, I’ll share how you can use Azure CLI commands—`az rest` and `az resource`—to replicate the functionality of resources.azure.com and perform raw REST API calls to the Azure Management APIs. --- ## The New Resource Explorer in Azure Portal The Azure Portal now includes a Resource Explorer view that allows you to navigate the Azure resource hierarchy. While it’s a step forward, it doesn’t fully replicate the simplicity of performing raw REST API calls directly from the browser. You can access the Resource Explorer here: [Resource Explorer React View](https://portal.azure.com/?ref=codeisahighway.com#view/Microsoft%5FAzure%5FResources/ResourceExplorer.ReactView) --- ## Using `az rest` for Raw REST API Calls The `az rest` command is a versatile Azure CLI tool that allows you to perform raw REST API operations. It supports all HTTP verbs (`GET`, `POST`, `PUT`, `DELETE`, etc.) and lets you specify headers, query parameters, and request payloads. ### Performing a Simple GET Request If you want to perform a `GET` request on a specific resource, you can use `az rest`. For example, below is how you retrieve a managed certificate resource: ```bash az rest --method GET --url '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test/providers/Microsoft.App/managedEnvironments/test-cae/managedCertificates/mydomain.com-cert?api-version=2026-01-01' ``` #### Key Points: - `**--method**`: Specifies the HTTP verb (`GET` in this case). - **`--url`**: The full REST API endpoint for the resource, including the subscription ID, resource group, provider namespace, resource type, resource name, and API version. --- ### Simplifying GET Requests with `az resource` For simple GET operations, you can also use `az resource show`. This command is specifically designed for retrieving resource details and requires only the resource ID. ```bash az resource show --ids '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test/providers/Microsoft.App/managedEnvironments/test-cae/managedCertificates/mydomain.com-cert' ``` #### Why Use `az resource`? - **Ease of Use**: No need to specify the HTTP verb or API version; `az resource` automatically handles it for you. - **Resource-centric**: Ideal for users who want to query resource specifics without dealing with REST API intricacies. --- ## Performing Other HTTP Verbs with `az rest` For operations like `PUT`, `POST`, or `DELETE`, `az rest` provides flexibility to send custom payloads directly in the command or from a file. ### Example: Creating a Public IP Address Using a JSON file (`body.json`) to specify the request payload: ```bash az rest --method PUT --url https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/publicIPAddresses/{publicIpAddressName}?api-version=2019-09-01 --body @body.json ``` Alternatively, you can specify the payload directly in the command: ```bash az rest --method PUT --url https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/publicIPAddresses/{publicIpAddressName}?api-version=2019-09-01 --body '{"yourjson": "object"}' ``` #### Key Points: - `**--method**`: Specifies the HTTP verb (`PUT` in this case). - `**--body**`: The request payload, either as a JSON file (`@body.json`) or inline JSON. --- ## Common Use Cases for `az rest` Here are a few scenarios where `az rest` shines: 1. **Testing Azure Management API Calls**: Ideal for developers building applications that integrate with Azure APIs. 2. **Custom Operations**: Perform actions not directly supported by your tool of choice. 3. **Automation**: Use `az rest` in scripts to automate custom operations on Azure resources. --- ## Comparing `az rest` and `az resource` | Feature | az rest | az resource | | ------------------- | ------------------------------------------- | ---------------------------- | | **HTTP Verbs** | Supports all verbs (GET, POST, PUT, DELETE) | Easier for GET operations | | **Payload Support** | Allows sending JSON payloads | Not applicable | | **API Version** | Requires manual specification | Automatically inferred | | **Ease of Use** | Flexible but requires detailed inputs | Simplified for basic queries | --- ## Summary While resources.azure.com is no longer available, Azure CLI provides excellent alternatives in `az rest` and `az resource`. These tools enable raw interaction with Azure Management APIs, empowering you to perform custom operations directly from your terminal. ### When to Use `az rest` - For complex operations requiring HTTP verbs other than `GET`. - When sending custom payloads as part of the request. ### When to Use `az resource` - For simple `GET` operations to retrieve resource details. --- ## References 1. [Azure CLI Reference - az rest](https://learn.microsoft.com/en-us/cli/azure/rest?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) 2. [Azure CLI Reference - az resource](https://learn.microsoft.com/en-us/cli/azure/resource?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) 3. [Azure REST API Reference](https://learn.microsoft.com/en-us/rest/api/azure/?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) --- Happy REST API testing and resource exploration! Let me know if you need further articles with Azure CLI or REST API integrations. ### Automating the extraction of Azure Regions resiliency information URL: https://codeisahighway.com/automating-the-extraction-of-azure-regions-resiliency-information/ Last updated: 2026-07-30T19:45:03.000Z Azure paired regions and zone compatible regions are fundamental for ensuring redundancy and high availability of your applications in the cloud. Understanding the geography, physical regions, and their pairings can help you make informed decisions when architecting solutions on Azure. In this guide, we'll walk through how you can automate the extraction of Azure regions information using PowerShell and Azure CLI and format them as you like. ## Prerequisites - Azure CLI installed on your machine. You can download it from [here](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com). - PowerShell installed on your machine. You can download it from [here](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com). - You need to be logged in to your Azure account using `az login`. ## PowerShell Script to Extract Azure Paired Regions Below is a PowerShell script that uses Azure CLI to list all the regions, filters them to get physical regions, and formats the output to display the geography group, geography, region name, and paired region. ```powershell # Retrieve all Azure regions $results = az account list-locations | ConvertFrom-Json # Filter only physical regions $physicalResults = $results | Where-Object { $_.metadata.regionType -eq 'Physical' } # Select and format the desired properties $formattedResults = $physicalResults | Select-Object ` @{name="GeographyGroup"; Expression = {$_.metadata.geographyGroup}}, ` @{name="Geography"; Expression = {$_.metadata.geography}}, ` @{name="Region"; Expression = {$_.name}}, ` @{name="PairedRegion"; Expression = {$_.metadata.pairedRegion[0].name}} # Convert to JSON format with depth for nested objects $jsonOutput = $formattedResults | ConvertTo-Json -Depth 5 # Output the JSON result $jsonOutput ``` ## Explanation - **Retrieve Regions**: The command `az account list-locations` retrieves all the Azure regions available for your subscription. We use `ConvertFrom-Json` to convert the output into a PowerShell object for easier manipulation. - **Filter Physical Regions**: We filter the regions to include only those with a `regionType` of 'Physical'. - **Select and Format Properties**: We use `Select-Object` to extract specific properties and rename them for clarity. This includes the geography group, geography, region name, and the name of the paired region. - **Convert to JSON**: Finally, we convert the filtered and formatted data back into JSON format using `ConvertTo-Json`, allowing for easy consumption in other tools or systems. Using that kind of information, we can automate and ease all type of decisions. Here is an example where we could use that strategy to produce Azure Resource Graph statements and augment queries with resiliency information. ```powershell $results = az account list-locations | ConvertFrom-Json $physicalResults = $results | Where-Object { $_.metadata.regionType -eq 'Physical' } $results = $physicalResults ` | Select-Object @{ name = "GeographyGroup"; Expression = { $_.metadata.geographyGroup } }, ` @{ name = "Geography"; Expression = { $_.metadata.geography } }, ` @{ name = "region"; Expression = { $_.name } }, ` @{ name = "paired_region"; Expression = { $_.metadata.pairedRegion[0].name } }, ` @{ name = "zones"; Expression = { $_.availabilityZoneMappings } } ` | Where-Object GeographyGroup -in ('US', 'Canada') # extract regions that have a paired region $PairedRegions = $results ` | Where-Object paired_region -ne $null ` | Sort-Object Region ` | Select-Object -ExpandProperty region $joinedStringValues = "'$($PairedRegions -join "','")'" # Produce a ARG statement for identifying resources in paired regions "| extend drp_in_paired_region = case(location in ($joinedStringValues), true, false)" # extract regions that have a zones support $RegionsWithZones = $results ` | Where-Object zones -ne $null ` | Sort-Object Region ` | Select-Object -ExpandProperty region $joinedStringValues = "'$($RegionsWithZones -join "','")'" # Produce a ARG statement for identifying resources in regions with zones support "| extend drp_region_support_az = case(location in ($joinedStringValues), true, false)" ``` This script will produce the following outputs: ```powershell | extend drp_in_paired_region = case(location in ('canadacentral','canadaeast','centralus','centraluseuap','eastus','eastus2','eastus2euap','eastusstg','northcentralus','southcentralus','southcentralusstg','westcentralus','westus','westus2','westus3'), true, false) | extend drp_region_support_az = case(location in ('canadacentral','centralus','eastus','eastus2','eastus2euap','southcentralus','westus2','westus3'), true, false) ``` ## Conclusion This provides an automated way to extract and use Azure's regional resiliency information, which can be crucial for planning and deploying resilient and high-available applications. By leveraging Azure CLI and PowerShell, you can easily integrate this process into your existing automation workflows. ## References - [Azure CLI - Install and Setup](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) - [PowerShell - Install and Setup](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) - [Azure Paired Regions Documentation](https://learn.microsoft.com/en-us/azure/best-practices-availability-paired-regions?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) Feel free to modify the script to suit your specific needs, such as outputting the results to a file or integrating with other systems like Azure Resource Graph (ARG) for further processing. Happy automating! ### TIFU by Forgetting to Turn Off Microsoft Defender for Storage During a Massive Data Migration URL: https://codeisahighway.com/tifu-by-forgetting-to-turn-off-microsoft-defender-for-storage-during-a-massive-data-migration/ Last updated: 2026-08-10T07:13:00.000Z Not long ago, I experienced a classic "Today I Fucked Up" moment while working on a data migration at work. We needed to sync data between Azure storage accounts to set up infrastructure in a new region. Source accounts were cluttered with good and stale data, in the case of the latest, accumulated over the years without a proper cleaning routine. The task was daunting: over 1 billion blobs awaited migration. Given the scale, traditional migration options like AzCopy were sidelined due to the anticipated manual effort for syncing and monitoring. Instead, I proposed leveraging Azure's "Object Replication" feature for storage accounts, which promised to replicate containers in the background with minimal manual intervention. ### Cost Estimation Misstep Before kicking off the process, and without enough caffeine in my body, I used the Azure cost calculator to estimate the migration cost. However, I mistakenly input 10,000 instead of the correct 100,000 multiplier for write transactions, leading to a gross underestimation. The initial cost seemed reasonable at $1,300 for writes operations, but in reality, I was off by a factor of 10\. Nevertheless, the data had to be migrated or purged, nothing much we could do about that cost. ### The Migration Process The migration began smoothly. By Friday morning, a significant portion of the data was synced, and the cost metrics seemed to align with my (flawed) calculations. By Monday, the metrics indicated that the replication was complete, and I proudly shared the news with my colleagues, pleased with the minimal effort required. ### The Bitter Victory However, the sense of accomplishment was short-lived. Upon checking Azure Cost Management, my heart did a few hiccups as I met with a staggering figure: over $40,000 spent over two days. This was my oversight—I had forgotten to account for Microsoft Defender for Storage, which also bills by the transaction volume you perform and can become exorbitantly expensive. ### Damage Control After the initial shock subsided, I promptly informed the SRE, Technology, and Finance teams of the error. I then reached out to Azure support, explaining the oversight and asking if any credit for the unintended costs could be given. Thankfully, Azure's finance department was kind enough to grant a one-time credit for the costs of Defender. ### Learnings and Takeaways This incident served as a potent reminder that anyone can make mistakes, regardless of seniority. It's vital to maintain data hygiene, prioritize data lifecycle management, and be aware of additional cost factors like Microsoft Defender for Storage. There is a way to disable Microsoft Defender for Storage (Classic) from scanning storage accounts using a special tag. Before undertaking substantial data transactions, temporarily disabling Defender on target storage accounts, for the time of the migration could help prevent such a costly error. ### Migration Stats The migration resulted in over 10 billion storage transactions and 15.5TB of data movement—a testament to the scale of the operation and the importance of meticulous planning and oversight. ## Conclusion I chose to share this story to highlight that mistakes are part of the learning process. Owning up to them, sharing the experience, and implementing improvements are crucial steps. As a result, my team is now committed to developing better data management & lifecycle practices to ensure such an oversight does not happen again. Remember, always double-check your calculations, consider all cost factors, and maintain clear communication with all relevant parties during significant operations like data migrations. Happy coding, and may your migrations always be cost-effective and incident-free! ## References - [Object replication overview - Azure Storage | Microsoft Learn](https://learn.microsoft.com/en-us/azure/storage/blobs/object-replication-overview?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) - [Microsoft Defender for Storage](https://learn.microsoft.com/en-us/azure/defender-for-cloud/defender-for-storage-introduction?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) - [Configure object replication - Azure Storage | Microsoft Learn](https://learn.microsoft.com/en-us/azure/storage/blobs/object-replication-configure?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) - [Monitor Object Replication Azure Blob Storage](https://techcommunity.microsoft.com/t5/azure-paas-blog/monitor-object-replication-status-for-storage-account/ba-p/3766540?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) ### How to delete an Azure storage account with an unlocked Immutability policy URL: https://codeisahighway.com/how-to-delete-an-azure-storage-account-with-an-unlocked-immutability-policy/ Last updated: 2026-07-30T19:45:05.000Z Recently, I encountered a situation with Azure Storage. We were playing with immutability policy in a storage account in a test environment. We've set a policy for tests, we did what we wanted to do, when the time came to delete the environment, I hit a roadblock. ## Locked by an immutability policy The immutability policy on the storage account was preventing deletion. And thinking it back, it is what it is supposed to do. Azure's immutability policies are a powerful feature for compliance scenarios, where preventing data from being altered or deleted is crucial. These policies, when locked, enforce retention periods and legal holds which can't be bypassed easily. ## Understanding immutability policies Immutability policies in Azure Blob storage allow users to store business-critical data objects in a WORM (Write Once, Read Many) state. This means that once written, the data cannot be modified or deleted for a specified retention period. These policies are crucial for scenarios where data needs to be preserved in an unaltered state for compliance with industry regulations or company policies. ## The Mitigation: Removing immutability policies ! This works only if your policy is in an `Unlocked` state. If `Locked`, you'll need to wait until the period you set expires. There is nothing to do in a `Locked` state other than wait. Luckily for us, we expected that for tests and left the policy `Unlocked`. But still, I couldn't just delete the storage account, nor the container in a one-shot operation. The solution involved programmatically removing the immutability policy from each blob within the storage account's container. By leveraging Azure CLI, specifically the `az storage blob immutability-policy delete` command, I was able to loop over all the blobs and remove their respective immutability policies. Here is an example of the Azure CLI command I used to remove the immutability policy from a blob: ```bash az storage blob immutability-policy delete --account-name --container-name --name ``` This command requires the storage account name, container name, and blob name to identify the blob for which the policy should be removed. ## Scripting time To expedite the process, I wrote a script that iterated through all blobs under the target container and executed the command to remove the immutability policy for each one. Once the policies were cleared, I was able to delete the container, then the storage account without any further issues. Here's a simplified example of how such a script might look: ```powershell # Set variables $accountName="" $containerName="" # List all blobs in the container $blobList = az storage blob list --container-name $containerName --account-name $accountName --query "[].name" --output tsv # Loop through each blob and remove the access policy foreach ($blob in $blobList) { az storage blob immutability-policy delete --container-name $containerName --name $blob --account-name $accountName } ``` Remember to replace ``, `` with your actual resource names. ## Conclusion It is important to understand Azure's data protection features such as immutability policies, and how they can impact resource management. While these features are excellent for ensuring data integrity and compliance in production, they require additional steps if you play with it in an ephemeral fashion or test environment. ## References - [Overview of immutable storage for Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-immutability-policies-manage?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) - [Azure CLI - Storage Blob Immutability-Policy](https://docs.microsoft.com/en-us/cli/azure/storage/blob/immutability-policy?view=azure-cli-latest?wt.mc%5Fid=AZ-MVP-5001613&ref=codeisahighway.com) Happy cloud computing! ### Suggestion: Read GSoft journey tech blog URL: https://codeisahighway.com/suggestion-read-gsoft-journey-tech-blog/ Last updated: 2026-07-31T19:44:13.000Z The articles you find here are more around technical guidance, how-to's and errors I encountered throughout the year. It's only been recent for me to write up about decisions & what happens at work. ## GSoft's tech blog Some of my colleagues and I have been writing articles to discuss our journey at GSoft. Sometimes it's from a technical writer standpoint, sometimes from a software architect standpoint, it varies. Quite diverse in the content that lands there. Lately, we've been opening up more on what we do because we wanted to share with others our experiences and our journey. It materializes in the form of blog articles and we write about what happens in our team, the technology team, and at GSoft in general. We share decisions we made and why we ended up going there. It is the kind of content I personally enjoy, more about a process than a "Here's the answer to your question". Sometimes it can trigger ideas or reflections about a particular technology. Sometimes just about how we ended up taking a decision itself, helping you in your reality and context. I invite you to read us out :) [GSoft Tech – MediumGSoft Tech Blog.![](https://cdn-images-1.medium.com/fit/c/304/304/1*8qQYy-6LuUvjqDpl3YdLiA.jpeg)MediumEric De Carufel![](https://cdn-images-1.medium.com/max/1200/1*8qQYy-6LuUvjqDpl3YdLiA.jpeg)](https://medium.com/gsoft-tech?ref=codeisahighway.com) Happy reading! ### How to dynamically set last month date range in KQL query and Log Analytics URL: https://codeisahighway.com/how-to-dynamically-set-last-month-date-range-in-kql-query-and-log-analytics/ Last updated: 2026-07-17T08:25:48.000Z I wanted to improve an audit query we are running every month because I hate doing things manually over and over again. Before today, we were setting the date range for the previous month manually and I was searching a way to automate this instead. I found a way... ## Manually setting query date range in Log Analytics There are a few ways that you can set a date range for your query in Log Analytics. 1. Set the date range using the time range control in the UI ![](https://codeisahighway.com/content/images/2022/02/image.png) 2\. Set the date range manually in the query ```KQL AzureActivity | where TimeGenerated between (datetime('2022-01-01') .. datetime('2022-01-31')) ``` But they all imply manual intervention to update the query (every month) in our case. There must be a better way I asked myself, and there is! ## Automatically determine last month's date range I was searching for a way, in the query itself to set the date to last month relative to the date the query execute. Let's say I am February 1st and I execute the query, I want the date range to be 2022-01-01 .. 2022-01-31. Searching the web sent me directly to [StackOverflow](https://stackoverflow.com/questions/69164108/how-to-write-a-kusto-query-to-get-previous-month-logs-in-sentinel?ref=codeisahighway.com). There was my solution! ```KQL // StackOverflow code I found at https://stackoverflow.com/questions/69164108/how-to-write-a-kusto-query-to-get-previous-month-logs-in-sentinel // The Easy 'Manual' Way AuditLogs | where TimeGenerated >= datetime('2021-08-01') and TimeGenerated <= datetime('2021-08-31') // Automated Way let lastmonth = getmonth(datetime(now)) -1; let year = getyear(datetime(now)); let monthEnd = endofmonth(datetime(now),-1); AuditLogs | where TimeGenerated >= make_datetime(year,lastmonth,01) and TimeGenerated <= monthEnd ``` Not so fast... it is working, sometimes, but not exactly fit my needs. If you run this in January, we want it to shift the range to December of last year and a few small fixes like this. The solution in StackOverflow was a great starting point though. ## Let's do this! First we determine `lastMonthNumber`, we determine the current month and subtract `1` from the number. ```KQL let lastmonthNumber = getmonth(datetime(now)) - 1; ``` This will work for all of the months, except January. In January, `getmonth()` will return `1` and we cannot magically switch it to `12` by subtracting `1`. We need the help of the `iff()` function here. If `lastMonthNumber == 0`, it means we are *currently* in January, we need to change it to `12` ourselves to point to December instead. ```KQL let lastmonth = iff(lastmonthNumber == 0, 12, lastmonthNumber); ``` For `year` we get the current year as of today and subtract `1` if lastMonth is `12`, otherwise we subtract nothing, sending it `0`. ```KQL let year = getyear(datetime(now)) - iff(lastmonth == 12, 1, 0); ``` From there we have all the information we need to set `dateStart` and `dateEnd`. ```KQL let dateStart = make_datetime(year, lastmonth, 01); let dateEnd = endofmonth(dateStart); ``` We just need to use them against `TimeGenerate` in our case as follows: `| where TimeGenerated between(dateStart .. dateEnd)` Here is what I ended up with. ```KQL // Automatic date calc to get full month let lastmonthNumber = getmonth(datetime(now)) - 1; let lastmonth = iff(lastmonthNumber == 0, 12, lastmonthNumber); let year = getyear(datetime(now)) - iff(lastmonth == 12, 1, 0); let dateStart = make_datetime(year, lastmonth, 01); let dateEnd = endofmonth(dateStart); AzureActivity | where TimeGenerated between(dateStart .. dateEnd) ``` Hope it helps! Happy KQL! ### Looking for activities triggered only by humans in Azure Activities in Kusto or Log Analytics URL: https://codeisahighway.com/looking-for-activities-triggered-only-by-humans-in-azure-activities-in-kusto-or-log-analytics/ Last updated: 2026-07-31T19:44:15.000Z We wanted to know which actions where done by a human and not a service principal when looking at Azure Activities in Log Analytics queries. We thought of a nice quick way to do it! ## Email vs GUID Our assumption is that all humans that trigger something in Azure will have an email instead of a guid for service principals in the `Caller` field. My first thought was to do something with regex validation to check if it's a guid format or not. I started to look at the documentation for `matches regex` and said to myself that they're might be already something to convert a string to a guid scalar. There is something! it's called `toguid()`. In the documentation, `toguid()` will return a guid if the value is really in the proper format, otherwise `null`. Bingo! We now just have to check if the value does not convert properly, remember, only service principals have a guid as value, otherwise it's an email. We can combine functions together and write `| where isnull(toguid(Caller))` to perform this check. The query will look something like this: ```kusto AzureActivity | where Category has "Administrative" | where OperationName has "Firewall Rule" | where ActivityStatus has "Succeeded" | where isnull(toguid(Caller)) | project OperationName, OperationNameValue, Caller, _ResourceId, TimeGenerated ``` Hope it helps! Happy Kusto log query! ### List all subscriptions under a management group with Azure Resource Graph URL: https://codeisahighway.com/list-all-subscriptions-under-a-management-group-with-azure-resource-graph/ Last updated: 2026-07-23T03:04:43.000Z It is not a secret anymore that I really like Azure Resource Graph. Today I wanted to list all the subscriptions under a management group and had to adjust because I was leveraging hidden tags before on subscriptions. This data is now gone in ARG, let see how I now do it. ## Meet managementGroupAncestorsChain For the `subscriptions` and `managementgroups` under `resourcecontainers` you have access to a property called `managementGroupAncestorsChain`. This array will give you a list of the parent management groups in reversed order, from the immediate parent to the root. This is exactly what I need to filter subscriptions for a certain parent management group. Since we cannot search into indexed properties directly, we need to expand it using `mv-expand`. Doing this will create a new row in the ARG results for each item in `managementGroupAncestorsChain`. From there we can filter on the `name` property which correspond to the management group id of that ancestor. Here is the query I ended up with: ```azureresourcegraph resourcecontainers | where type == 'microsoft.resources/subscriptions' | mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ 'moamg' | project name, id | sort by name asc ``` This is useful in the portal but like mentioned in the past, the advantage with ARG is that it is well integrated with Azure CLI & Azure PowerShell. **!** make sure you replace `moag` in the segment `where managementGroupParent.name =~ 'moamg'` to target the right management group id. You can position yourself at any place in the management group hierarchy by providing the management group scope at the command line. In the example below, I target the root management group using `$tenantId`. The management group id for the root management is the id of your AAD tenant. ## Azure CLI & Az PowerShell examples ```powershell $query = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ 'moamg' | project name, id | sort by name asc" # Azure CLI $tenantId = az account show --query tenantId -o tsv az graph query -q $query --management-groups $tenantId | ConvertFrom-Json # Azure PowerShell $tenantId = (Get-AzContext).Tenant.Id Search-AzGraph -Query $query -ManagementGroup $tenantId ``` Happy coding! ### Workaround for error 'utf-8' codec can't decode byte 0x82 using Azure CLI deployment and Bicep URL: https://codeisahighway.com/workaround-for-error-utf-8-codec-cant-decode-byte-0x82-using-azure-cli-deployment-and-bicep/ Last updated: 2026-07-31T19:44:16.000Z We migrated most of our automation from ARM Templates to Bicep in the recent months and things have been good so far. We ran into an issue deploying a bicep file containing French characters using Azure CLI. The message was: `'utf-8' codec can't decode byte 0x82 in position 1197: invalid start byte` ## The problem I usually write things in English when I code so this was a non-issue for us until... We wanted to write non-compliant messages in French in our Azure Policy. Here is an example that contains the French character **é** and reproduce my error: ```bicep targetScope = 'managementGroup' var policyAssignmentName = substring(replace(guid('testassignment-#01'), '-', ''), 0, 23) resource policyAssignment 'Microsoft.Authorization/policyAssignments@2020-09-01' = { name: policyAssignmentName properties: { policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/0473574d-2d43-4217-aefe-941fcdf7e684' displayName: 'AzCLI and Bicep encoding bug' description: 'AzCLI and Bicep encoding bug' enforcementMode: 'Default' parameters: { listOfAllowedLocations: { value: [ 'canadaeast' 'canadacentral' ] } } nonComplianceMessages:[ { message: 'La région qui a été choisi n\'est pas valide...' } ] } } ``` As you can see, I get the error mentioned at the top when invoking the following command: ```powershell az deployment mg create --management-group-id experimental --location canadaeast -f .\azcli-bicep-bug.bicep 'utf-8' codec can't decode byte 0x82 in position 1179: invalid start byte ``` The error is that the character **é** is badly handled. UTF-8 is used instead of Unicode in the Bicep wrapper \_bicep.py. An issue has been filled on the GitHub repo of Azure CLI [#18029](https://github.com/Azure/azure-cli/issues/18029?ref=codeisahighway.com) ## The workaround So... this is not working as a one-time operation, calling `az deployment`. Bicep can convert to and from ARM Templates. What I ended up doing until this issue is fixed is: Generate an ARM template from my bicep file and deploy that ARM template. Two steps instead of one. ```powershell az bicep build -f .\azcli-bicep-bug.bicep az deployment mg create --management-group-id experimental --location canadaeast -f .\azcli-bicep-bug.json ``` Hope it can help some of you! ## References - [Microsoft Azure CLI](https://github.com/Azure/azure-cli?ref=codeisahighway.com) - [Azure deployment using Bicep and French characters: 'utf-8' codec can't decode byte 0x82](https://github.com/Azure/azure-cli/issues/18029?ref=codeisahighway.com) - [Bicep](https://github.com/Azure/bicep?ref=codeisahighway.com) - [Bicep Playground](https://bicepdemo.z22.web.core.windows.net/?ref=codeisahighway.com) ### Effective ways to delete resources in a resource group on Azure in 2021 URL: https://codeisahighway.com/effective-ways-to-delete-resources-in-a-resource-group-on-azure-in-2021/ Last updated: 2026-07-31T19:44:18.000Z In Azure, resource groups are very helpful to logically hold together a set of resources. For many reasons, at some point, you'll want to get rid of these resources but how can you achieve this and what are the pros and cons of each? **This is an actualized version of my popular post:** [*Effective ways to delete resources in a resource group on Azure*](https://codeisahighway.com/effective-ways-to-delete-resources-in-a-resource-group-on-azure) We'll cover Az PowerShell modules, Azure CLI, ARM template and Bicep. In my previous article I was speaking about three ways of doing this, in this article I'll stick with two, I dropped custom scripting. You have the link above, feel free to go check it if you're after a custom way to delete resources within a resource group. You have basically two options depending on the end result you want. Both are effortless, it simply comes to: Do you want to delete it? Or only purge the resources inside? ## Delete the resource group It is the simplest, it deletes everything. **Advantages** - No custom logic is required **To consider** - All resources inside the resource group will be deleted - The resource group will be deleted (losing RBAC & Tags) ```powershell Remove-AzResourceGroup -Name MyResourceGroup -Verbose ``` After a few minutes, your resources and their container will be deleted. ![](https://codeisahighway.com/content/images/2021/04/Remove-AzResourceGroup-1.png) ## Wait... What if I don't want to delete the resource group? Deleting the resource group directly is the quickest way to remove all the resources inside it but you'll also delete the container itself. What are your options if you want to preserve the resource group ? ## Purge the resource group If you are looking for a way to keep the resource group but want all the resources inside it deleted, this last option is for you. **Advantages** - No custom logic or dependency walking is required - Keep the resource group intact (including RBAC & Tags) - Native parallel delete support of non-dependent resources **To consider** - All resources inside the resource group will be deleted In Azure, you have the option of deploying resources using a template. You have two modes available when initiating a deployment: **Incremental**: You can see this mode as "Additive". What I mean is that non-existing resources declared in your template will be added. Existing resources will be modified only if there is a difference between the actual version and what is declared in your template. Finally, if there's a resource in the resource group that is not present in the template, it will be ignored and left untouched. **Complete**: You can see this mode as "Exact match". What I mean is that after your deployment is done, only the resources declared in your template will exist in the resource group. If there are existing resources in the resource group that are not present in the template, they will be deleted automatically. Now that we understand what happens in "Complete" mode, we can use that to our advantage. We are looking for a way to purge all the resources in a resource group, without having to handle the complexity of resolving dependencies and parallel delete of resources. The trick, simple when you think about it, just ask the ARM engine to deploy an empty template (no resources) in an existing resource group in "Complete" mode. You'll end up exactly with the behavior we want. We can do this with an ARM template containing no resources or an empty Bicep file. ### Empty ARM template ```json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { }, "variables": { }, "resources": [ ], "outputs": { } } ``` Now, let's pretend the name of the ARM template is "ResourceGroupCleanup.template.jsonc". A JSONC file is just a JSON file format that supports comments. Azure and Visual Studio code support this. ### Empty Bicep file Bicep is a DSL that is easier and compact to author than ARM templates (they are now considered more as an intermediate language - IL). Knowing this, you don't have to remember the empty format of the ARM template. We just need to create an empty file, give it a bicep extension and you now have a lightweight ARM template. ```powershell $null > ResourceGroupCleanup.bicep ``` > In order to deploy bicep files thru PowerShell or Azure CLI, you'll need a recent, 2021 version of them. In this article I've used [Az 5.8.0](https://github.com/Azure/azure-powershell/releases/tag/v5.8.0-April2021?ref=codeisahighway.com) and [Azure CLI 2.22.1](https://github.com/Azure/azure-cli/releases/tag/azure-cli-2.22.1?ref=codeisahighway.com) ### Powershell Here is how to invoke the deployment in "Complete" mode in PowerShell. ```powershell # ARM template New-AzResourceGroupDeployment -ResourceGroupName MyResourceGroup -Mode Complete -TemplateFile .\ResourceGroupCleanup.template.json -Force -Verbose # Bicep New-AzResourceGroupDeployment -ResourceGroupName MyResourceGroup -Mode Complete -TemplateFile .\ResourceGroupCleanup.bicep -Force -Verbose ``` After you run this command, you should have something similar to the following: ![](https://codeisahighway.com/content/images/2021/04/Empty-ResourceGroup-With-Deployment-1.png) ### Azure-CLI Here is how to invoke the deployment in "Complete" mode on a resource group in Azure CLI v2.22.1 or later. ```powershell az deployment group create -g MyResourceGroup -f .\ResourceGroupCleanup.bicep --mode Complete ``` After you run this command, you should have something similar to the following: ![](https://codeisahighway.com/content/images/2021/04/Empty-ResourceGroup-With-Deployment-AzureCLI.png) Hope you have fun with Azure Resource Manager and automation! ## References - [Authoring Azure Resource Manager templates](https://azure.microsoft.com/en-us/documentation/articles/resource-group-authoring-templates/?ref=codeisahighway.com) - [What is Bicep?](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/bicep-overview?ref=codeisahighway.com) - [Azure Resource Manager deployment modes](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/deployment-modes?ref=codeisahighway.com) - [Latest Microsoft Azure PowerShell release](https://github.com/Azure/azure-powershell/releases/latest?ref=codeisahighway.com) - [Latest Azure-CLI release](https://github.com/Azure/azure-cli/releases?ref=codeisahighway.com) ### Stop wasting money in Azure - ShareGate webinar URL: https://codeisahighway.com/stop-wasting-money-in-azure-sharegate-webinar/ Last updated: 2026-07-31T19:44:19.000Z One of the main issues facing IT management in 2020 is uncontrolled cloud spending. Learn how to gain the visibility and insights you need to take control of your cloud environment, and implement a team-wide Azure cost management strategy. During this ShareGate webinar on **December 8, 1:30pm EST**, I will cover: - **Why cloud cost management is so important—and so difficult.** According to our data, approximately 30% of money spent in Azure is on resources and services that could be optimized. We’ll explain why so many people are wasting so much of their money in the cloud. - **Actionable steps to creating an effective Azure cost management strategy.** We can take you through the steps that will help you gain visibility over your Azure spending so that you know what to optimize. - **Automated solutions that can help with ongoing Azure management.** Manual monitoring of spending, identifying changes, and analyzing your Azure costs is time consuming and probably not why you and your team got into cloud engineering. We’ll discuss some tools that allow you to spend your time where it counts—leading a team in building better products and services. You can register here, it is free: [https://sharegate.com/resource/azure-cost-management-webinar](https://sharegate.com/resource/azure-cost-management-webinar?ref=codeisahighway.com) ### My ScriptCenter's Azure scripts has moved to Github URL: https://codeisahighway.com/my-scriptcenters-azure-scripts-has-moved-to-github/ Last updated: 2026-07-17T08:26:55.000Z Over the years I posted a few scripts that have been useful for me in Azure on ScriptCenter. Time has come to move them on a newer platform since ScriptCenter is now obsolete and is retiring. ### Bye Bye ScriptCenter ScriptCenter will continue to operate in read-only mode, no new contributions but existing one can be updated from what I know. Still it has been a useful platform for the last 10 years or so. Here are the scripts I posted over the years: [Powershell, VB Script, SQL and JavaScript - TechNet IT Pro’s and Scripting GuysDownload resources and applications for Windows 8, Windows 7, Windows Server 2012, Windows Server 2008 R2, Windows Server 2008, SharePoint, System Center, Office, and other products.![](https://i1.gallery.technet.s-msft.com/scriptcenter/GlobalResources/images/Technet/favicon.ico)Script Center](https://gallery.technet.microsoft.com/scriptcenter/site/search?f%5B0%5D.Type=User&f%5B0%5D.Value=s%5Flapointe&ref=codeisahighway.com) Some has been very popular over the years, like: ### [Easily obtain AccessToken(Bearer) from an existing Az/AzureRM PowerShell session](https://gallery.technet.microsoft.com/scriptcenter/Easily-obtain-AccessToken-3ba6e593?redir=0&ref=codeisahighway.com) > You'll find in this function an easy way to extract the information required for you to build a Bearer token and all this from YOUR credentials within an authenticated PowerShell Azure session. You can then use this token to talk to Azure Resource Manager REST API It got almost 8K downloads at the time of writing this. Several others were downloaded in the thousands also. Knowing that these script helped and continue to help people, I decided to move them before they are no longer accessible at all. ### Hello GitHub! I decided to move all these scripts to a repository in GitHub. I made a first release with what is exactly on ScriptCenter. You can download the release here: [Release Snapshot from ScriptCenter · slapointe/azure-scriptsSame as downloading all of my scripts from ScriptCenter and starting point for their evolution on Github: Easily obtain AccessToken(Bearer) from an existing Az/AzureRM PowerShell session List all ...![](https://github.githubassets.com/favicons/favicon.svg)GitHubslapointe![](https://avatars2.githubusercontent.com/u/1054412?s=400&v=4)](https://github.com/slapointe/azure-scripts/releases/tag/v1.0?ref=codeisahighway.com) Hope it helps, if you want to contribute on this repo, you are more than welcome :) ### Reference - [Stephane Lapointe's Azure Scripts on GitHub](https://github.com/slapointe/azure-scripts?ref=codeisahighway.com) ### How-to use customer-managed keys with Azure Key Vault and Azure Storage encryption using ARM Template URL: https://codeisahighway.com/how-to-use-customer-managed-keys-with-azure-key-vault-and-azure-storage-encryption-using-arm-template/ Last updated: 2026-07-23T03:03:12.000Z I got a question from a reader asking how to use the Managed Identity of a storage account against Azure Key Vault to enable storage encryption using [customer-managed keys](https://docs.microsoft.com/en-us/azure/storage/common/encryption-customer-managed-keys?ref=codeisahighway.com). The documentation doesn't say storage accounts can have an identity. Testing a solution made me realize I was wrong, today I learned! ### Genesis It all started with this article on my blog for the best way to reference Managed Identity using ARM templates - [there-is-a-new-way-to-reference-managed-identity-in-arm-template/](https://codeisahighway.com/there-is-a-new-way-to-reference-managed-identity-in-arm-template/) I always say that others' problems can make you grow in knowledge and it's exactly what happened with Soniya's [question](https://codeisahighway.com/there-is-a-new-way-to-reference-managed-identity-in-arm-template/#comment-5010449677) yesterday. > Hi Stephane, I am trying to use this method to get storage account Managed Identity and pass it to existing Keyvault's Access policy in the same template where Storage account needs to be provisioned. In the same template this storage account needs to access the keyvault to get key for user managed Storage encryption and hence the need to add the Manage identity to Keyvault access policy. I am trying to deploy it the way you have referenced the Managed Identity. But its failing. Any idea? I wasn't aware that storage accounts could have a Managed Identity, I double-checked the documentation before answering her that it was not supported. It is available for Azure Data Lake so I was kinda intrigued. She replied that she was doing it in PowerShell but wanted a way to do it via ARM templates. Nothing more was required to trigger me and try to find the answer myself. ### Managed Identity on Storage Account After a quick test in with an ARM template, it turns out it IS possible to assign a Managed Identity to a storage account and it is fairly easy. If you need more background on Managed Identity and how to use them in ARM templates, I have an article for you here: [There is a new way to reference managed identity in ARM template](https://codeisahighway.com/there-is-a-new-way-to-reference-managed-identity-in-arm-template/) Like for any other resources, I only had to add the identity property to my resource like this: ```json "identity": { "type": "SystemAssigned" } ``` It worked, the deployment was successful! Now my storage account has a Managed Identity, awesome! ### Updating Key Vault Access I wrote another article recently, [How to incrementally update KeyVault access policies with ARM templates](https://codeisahighway.com/how-to-incrementally-update-keyvault-access-policies-with-arm-templates/). Go read it if you weren't aware, it is a good trick to have in your toolbox. There are 2 properties that you need to set on your vault if you want to use customer-managed keys with Azure Key Vault to manage Azure Storage encryption. Microsoft documentation says: > Using customer-managed keys with Azure Storage encryption requires that two properties be set on the key vault, **Soft Delete** and **Do Not Purge**. These properties are not enabled by default, but can be enabled using either PowerShell or Azure CLI on a new or existing key vault. You can also do it in the Portal if you want. That being said, you need to update Key Vault to set those two properties. If you don't want to mess around with retrieving access policy via a script and injecting them into an ARM template, use PowerShell, Azure CLI or the Azure Portal. If you still want to update this via template, here are the two properties. ```json { "type": "Microsoft.KeyVault/vaults", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "properties": { "sku": { "family": "A", "name": "standard" }, "tenantId": "[subscription().tenantid]", "accessPolicies": [...], "enableSoftDelete": true, "enablePurgeProtection": true } } ``` We now have a properly configured Key Vault to support storage encryption, we still need a key for that encryption. There's several ways to do this, the simpliest is via the portal. It is not possible "natively" via template without going through a complicated plumbing. Still interested to create keys via template? I found this [little gem from Jorge Cotillo](https://medium.com/@jorge.cotillo/create-key-vault-keys-using-arm-templates-and-azure-blueprints-77086ae02b3e?ref=codeisahighway.com) Let stick to the portal for simplicity ![](https://codeisahighway.com/content/images/2020/07/generate-keyvault-key.png) ![](https://codeisahighway.com/content/images/2020/07/create-keyvault-key.png) ![](https://codeisahighway.com/content/images/2020/07/keyvault-key-created.png) ### Add the new access policy The storage account needs access to Key Vault. Let's add a new access policy, the access need to be `wrapkey`, `unwrapkey` and `get` permissions on `keys`. ```json { "type": "Microsoft.KeyVault/vaults/accessPolicies", "name": "[concat(variables('uniqueResourceNameBase'), '/add')]", "apiVersion": "2019-09-01", "properties": { "accessPolicies": [ { "tenantId": "[subscription().tenantid]", "objectId": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('uniqueResourceNameBase')),'2019-06-01', 'full').identity.principalId]", "permissions": { "keys": [ "wrapkey", "unwrapkey", "get" ], "secrets": [], "certificates": [] } } ] } } ``` ### Configuring the encryption key on the storage account Now that we have our key and appropriate permission in Key Vault. We need to reference and configure the key to use on the storage account. We need to set the `keySource` to `Microsoft.Keyvault` and fill Key Vault and key details. If `keyVersion` is left blank, it will use the latest version of the key. You can also set it to a specific version if you prefer that. ```json { "type": "Microsoft.Storage/storageAccounts", "sku": { "name": "Standard_LRS", "tier": "Standard" }, "kind": "Storage", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2019-06-01", "location": "[parameters('location')]", "identity": { "type": "SystemAssigned" }, "properties": { "encryption": { "services": { "file": { "enabled": true }, "blob": { "enabled": true } }, "keySource": "Microsoft.Keyvault", "keyvaultproperties": { "keyvaulturi": "[reference(resourceId('Microsoft.KeyVault/vaults', variables('uniqueResourceNameBase')),'2016-10-01', 'full').properties.vaultUri]", "keyname": "[parameters('keyName')]", "keyversion": "[parameters('keyversion')]" } } } } ``` ## Complete example Here is a complete and functional ARM template that you need to deploy 2 times to fully configure it all. The first run will create the Key Vault and storage account. You then need to manually create the key in Key Vault and run the deployment again to let it do the rest of the work. This template use a nested deployment to seperate the configuration of the storage account with key information from the creation of the 2 resources to have a complete example. ```json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "keyName": { "type": "string", "defaultValue": "storage-enc-test" }, "keyVersion": { "type": "string", "defaultValue": "" }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]" }, "configureEncryptionKey": { "type": "bool", "defaultValue": false } }, "variables": { "uniqueResourceNameBase": "[uniqueString(resourceGroup().id, parameters('location'), deployment().name)]" }, "resources": [ { "condition": "[not(parameters('configureEncryptionKey'))]", "type": "Microsoft.KeyVault/vaults", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "properties": { "sku": { "family": "A", "name": "standard" }, "tenantId": "[subscription().tenantid]", // !BEWARE! Running this property with an empty bracket will remove all your existing access policies // If you need to update the required properties for storage encryption, // you can fetch existing access policies via script and pass them as template parameter "accessPolicies": [], "enableSoftDelete": true, "enablePurgeProtection": true }, "dependsOn": [ "[resourceId('Microsoft.Storage/storageAccounts', variables('uniqueResourceNameBase'))]" ] }, { "type": "Microsoft.Storage/storageAccounts", "sku": { "name": "Standard_LRS", "tier": "Standard" }, "kind": "Storage", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2019-06-01", "location": "[parameters('location')]", "identity": { "type": "SystemAssigned" }, "properties": { "supportsHttpsTrafficOnly": true }, "dependsOn": [] }, { "condition": "[parameters('configureEncryptionKey')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2019-07-01", "name": "updateStorageAccount", "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults', variables('uniqueResourceNameBase'))]" ], "properties": { "mode": "Incremental", "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "0.1.0.0", "resources": [ { "type": "Microsoft.KeyVault/vaults/accessPolicies", "name": "[concat(variables('uniqueResourceNameBase'), '/add')]", "apiVersion": "2019-09-01", "properties": { "accessPolicies": [ { "tenantId": "[subscription().tenantid]", "objectId": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('uniqueResourceNameBase')),'2019-06-01', 'full').identity.principalId]", "permissions": { "keys": [ "wrapkey", "unwrapkey", "get" ], "secrets": [], "certificates": [] } } ] } }, { "type": "Microsoft.Storage/storageAccounts", "sku": { "name": "Standard_LRS", "tier": "Standard" }, "kind": "Storage", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2019-06-01", "location": "[parameters('location')]", "identity": { "type": "SystemAssigned" }, "properties": { "encryption": { "services": { "file": { "enabled": true }, "blob": { "enabled": true } }, "keySource": "Microsoft.Keyvault", "keyvaultproperties": { "keyvaulturi": "[reference(resourceId('Microsoft.KeyVault/vaults', variables('uniqueResourceNameBase')),'2016-10-01', 'full').properties.vaultUri]", "keyname": "[parameters('keyName')]", "keyversion": "[parameters('keyversion')]" } } }, "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', variables('uniqueResourceNameBase'), 'add')]" ] } ] } } } ] } ``` 1 - First run ```powershell Connect-AzAccount New-AzResourceGroup -name mi-storage -location eastus New-AzResourceGroupDeployment -ResourceGroupName mi-storage -TemplateFile C:\temp\deploy.json -Verbose VERBOSE: Performing the operation "Creating Deployment" on target "mi-storage". VERBOSE: 11:30:12 AM - Template is valid. VERBOSE: 11:30:14 AM - Create template deployment 'deploy' VERBOSE: 11:30:14 AM - Checking deployment status in 5 seconds VERBOSE: 11:30:19 AM - Resource Microsoft.Storage/storageAccounts 'ic626scfz2hba' provisioning status is running VERBOSE: 11:30:19 AM - Checking deployment status in 17 seconds VERBOSE: 11:30:37 AM - Checking deployment status in 5 seconds VERBOSE: 11:30:42 AM - Resource Microsoft.KeyVault/vaults 'ic626scfz2hba' provisioning status is running VERBOSE: 11:30:42 AM - Resource Microsoft.Storage/storageAccounts 'ic626scfz2hba' provisioning status is succeeded VERBOSE: 11:30:42 AM - Resource Microsoft.Storage/storageAccounts 'ic626scfz2hba' provisioning status is succeeded VERBOSE: 11:30:42 AM - Checking deployment status in 15 seconds VERBOSE: 11:30:57 AM - Resource Microsoft.KeyVault/vaults 'ic626scfz2hba' provisioning status is succeeded VERBOSE: 11:30:57 AM - Resource Microsoft.KeyVault/vaults 'ic626scfz2hba' provisioning status is succeeded DeploymentName : deploy ResourceGroupName : mi-storage ProvisioningState : Succeeded Timestamp : 7/30/2020 3:30:55 PM Mode : Incremental TemplateLink : Parameters : Name Type Value ======================== ========================= ========== keyName String storage-enc-test keyVersion String location String eastus configureEncryptionKey Bool False Outputs : DeploymentDebugLogLevel : ``` 2 - Create your key manually. 3 - Last, run with the special flag `configureEncryptionKey` set to true to run the configuration step on the storage account. There is a condition on the nested deployment that will only execute if that template parameter is set to true. See below ```json { "condition": "[parameters('configureEncryptionKey')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2019-07-01", "name": "updateStorageAccount", ... } ``` Trigger the second deployment like this: ```powershell New-AzResourceGroupDeployment -ResourceGroupName mi-storage -TemplateFile C:\temp\deploy.json -configureEncryptionKey $true -Verbose VERBOSE: Performing the operation "Creating Deployment" on target "mi-storage". VERBOSE: 11:34:10 AM - Template is valid. VERBOSE: 11:34:11 AM - Create template deployment 'deploy' VERBOSE: 11:34:11 AM - Checking deployment status in 5 seconds VERBOSE: 11:34:17 AM - Resource Microsoft.Resources/deployments 'updateStorageAccount' provisioning status is running VERBOSE: 11:34:17 AM - Resource Microsoft.KeyVault/vaults/accessPolicies 'ic626scfz2hba/add' provisioning status is succeeded VERBOSE: 11:34:17 AM - Resource Microsoft.KeyVault/vaults 'ic626scfz2hba' provisioning status is succeeded VERBOSE: 11:34:17 AM - Resource Microsoft.KeyVault/vaults 'ic626scfz2hba' provisioning status is succeeded VERBOSE: 11:34:17 AM - Resource Microsoft.Storage/storageAccounts 'ic626scfz2hba' provisioning status is succeeded VERBOSE: 11:34:17 AM - Resource Microsoft.Storage/storageAccounts 'ic626scfz2hba' provisioning status is succeeded VERBOSE: 11:34:17 AM - Checking deployment status in 5 seconds VERBOSE: 11:34:22 AM - Checking deployment status in 5 seconds VERBOSE: 11:34:28 AM - Checking deployment status in 6 seconds VERBOSE: 11:34:34 AM - Checking deployment status in 6 seconds DeploymentName : deploy ResourceGroupName : mi-storage ProvisioningState : Succeeded Timestamp : 7/30/2020 3:34:39 PM Mode : Incremental TemplateLink : Parameters : Name Type Value ======================== ========================= ========== keyName String storage-enc-test keyVersion String location String eastus configureEncryptionKey Bool True Outputs : DeploymentDebugLogLevel : ``` If I take a look in the Azure portal, we can see that the key has been correctly configured. ![](https://codeisahighway.com/content/images/2020/07/encryption-configured.png) Hope you liked this article, again, thank you [Soniya](https://www.linkedin.com/in/soniya-sutar/?ref=codeisahighway.com), today you made me learned something new, storage can have an identity :) Happy ARM template! ### References - [Configure customer-managed keys with Azure Key Vault by using the Azure portal](https://docs.microsoft.com/en-us/azure/storage/common/storage-encryption-keys-portal?ref=codeisahighway.com) - [Configure customer-managed keys with Azure Key Vault by using PowerShell](https://docs.microsoft.com/en-us/azure/storage/common/storage-encryption-keys-powershell?ref=codeisahighway.com) - [Storage Account KeyVault KeyType reference documentation](https://docs.microsoft.com/en-us/rest/api/storagerp/storageaccounts/create?ref=codeisahighway.com#keytype) - [Create Key Vault keys using ARM templates and Azure Blueprints](https://medium.com/@jorge.cotillo/create-key-vault-keys-using-arm-templates-and-azure-blueprints-77086ae02b3e?ref=codeisahighway.com) ### How to incrementally update KeyVault access policies with ARM templates URL: https://codeisahighway.com/how-to-incrementally-update-keyvault-access-policies-with-arm-templates/ Last updated: 2026-08-10T07:12:59.000Z I was recently asked how to give access to an existing KeyVault to a managed identity that already have access policies configured. It's not a secret but not all know about this little trick that will enable you to incrementally process permissions to KeyVault over time using ARM templates. ### Genesis It all started with this article on the best way to reference Managed Identity using ARM templates - [there-is-a-new-way-to-reference-managed-identity-in-arm-template/](https://codeisahighway.com/there-is-a-new-way-to-reference-managed-identity-in-arm-template/) One of my readers ([Sam](https://disqus.com/by/disqus%5FXuNXkX4KEU/?ref=codeisahighway.com) not to name it :)) reached out with a question I got asked several times over the years. So I decided to write an article about it. The question was: > Thanks for the article. I'm trying to assign keyvault access policies to the system-assigned identity of my webapp. However in your example a new keyvault is created. How can do that for an existing keyvault ? My understading with this question is that he wants to update his existing KeyVault without messing with the existing acess policies. The good news is there's a way to do this, let's see how. ### Incremental Access Policy update The way to perform an incremental update of KeyVault AccessPolicies is by using a resource type named `Microsoft.KeyVault/vaults/accessPolicies` You have three choice of name for the resource: `add`, `replace` or `remove`. As you can guess they will perform different actions on the access policy you are defining. I used `add` in the example below but let me summarize them rapidly. - `add` will add a new set of permission or merge them with existing if any exists for the pair objectId and tenantId. In the case of `add` if the principal had the `list` permission and you call `add` with the `get` permission, the end result will be `list, get`. - `replace` will create or override any existing permission with what is expressed in the template for the pair objectId and tenantId. In the case of `replace` if the principal had `list, get` permissions and you call `replace` with the `get` permission, the end result will be `get`. - `delete` will delete the access policyfor the pair objectId and tenantId. ### Complete example Here is a complete and functional ARM template that use `vaulName`, `principalId`and optional `tenantId` parameters to populate add/merge (1) access policy because of the resource name `add` on KeyVault `vaulName`. ```json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "vaultName": { "type": "string" }, "principalId": { "type": "string" }, "tenantId": { "type": "string", "defaultValue": "[subscription().tenantId]" } }, "resources": [ { "type": "Microsoft.KeyVault/vaults/accessPolicies", "name": "[concat(parameters('vaultName'), '/add')]", "apiVersion": "2019-09-01", "properties": { "accessPolicies": [ { "tenantId": "[parameters('tenantId')]", "objectId": "[parameters('principalId')]", "permissions": { "keys": ["all"], "secrets": ["all"], "certificates": ["all"], "storage": ["all"] } } ] } } ], "outputs": { } } ``` Hope you like this article, and Sam, that it answer your question! Happy ARM template! ### References - [Microsoft.KeyVault vaults/accessPolicies template reference](https://docs.microsoft.com/en-us/azure/templates/microsoft.keyvault/2019-09-01/vaults/accesspolicies?ref=codeisahighway.com) - [There is a new way to reference managed identity in ARM template](https://codeisahighway.com/there-is-a-new-way-to-reference-managed-identity-in-arm-template) ### 2020-05-07: ShareGate Deploy Azure online event URL: https://codeisahighway.com/2020-05-07-sharegate-deploy-azure-online-event/ Last updated: 2026-07-17T08:27:29.000Z Before COVID-19 started to force a global shutdown everywhere, we were already thinking about this event. The long term goal? Help cloud engineers being more successful with Microsoft Azure. ShareGate Deploy is a free event, one of the several to come onto this journey! ## A full day focused on Microsoft Azure governance and best practices ShareGate Deploy is a free event will take place online on *Thursday, May 7 from 9am-5pm ET*. There will be 8 sessions total given by Microsoft Most Valuable Professionals (MVPs) and Microsoft employees. From the event page: > Deploy is a virtual event in which Azure experts share their experiences and insights to help you identify best practices to increase efficiency and visibility in the cloud. **The idea behind this event is to share other people's experiences, best practices and governance tips to enable you to be more successful with Microsoft Azure.** Register here: [Deploy: An expert-led online event focused on Microsoft Azure governance - ShareGateDeploy is a virtual event where experts share their experiences and insights to help you optimize your Azure environment. Join us to learn Azure governance best practices.![](https://sharegate.com/app/themes/sharegate/img/favicons/ShareGate_Favicon_192X192.png)ShareGate![](https://sharegate.com/app/uploads/2020/03/deploy-og2x-1024x536.png)](https://sharegate.com/deploy-event?ref=codeisahighway.com) ## Speakers and session lineup Here is the list of speakers and session details - **Bulletproofing your Azure subscriptions** \- [Jussi Roine](https://twitter.com/JussiRoine?ref=codeisahighway.com) - **Governance: The forgotten key to managing the cloud** \- [Rik Hepworth](https://twitter.com/rikhepworth?ref=codeisahighway.com) - **Securing Serverless Applications in Azure** \- [Sjoukje Zaal](https://twitter.com/SjoukjeZaal?ref=codeisahighway.com) - **Manage and govern your hybrid servers using Azure Arc** \- [Thomas Maurer](https://twitter.com/ThomasMaurer?ref=codeisahighway.com) - **Azure Resource Manager templates tips, tricks, and advanced techniques** \- [Sam Cogan](https://twitter.com/samcogan?ref=codeisahighway.com) - **Exploring Azure with Resource Graph** \- [Aleksandar Nikolic](https://twitter.com/alexandair?ref=codeisahighway.com) - **Lessons learned: Improving visibility, accountability and cost in Azure** \- [Stephane Lapointe](https://twitter.com/s%5Flapointe?ref=codeisahighway.com) - **Implementing control and governance at-scale using Azure Policy and Azure governance** \- [Liz Kim](https://twitter.com/lizkim101?ref=codeisahighway.com) and [Joseph Chan](https://twitter.com/jochan%5Fmsft?ref=codeisahighway.com) All the details below: ### Bulletproofing your Azure subscriptions In this session we'll do a lap around Microsoft Azure to understand how to best monitor what's happening within your Azure subscriptions, how to manage these subscriptions, and how best to configure security for your services. ![Jussi Roine](https://sharegate.com/app/uploads/2020/03/jussi.png) **Jussi Roine** Azure Developer Audience Lead at Microsoft ### Governance: The forgotten key to managing the cloud We all want to use the cloud in our projects, and every customer I talk to has developers that want to pioneer their company's adoption of the latest and coolest stuff. But for every success story there is a painful admission: Crazy costs from unconstrained adoption, sensitive data suddenly stored somewhere it shouldn't be, technology gone wild as every project tries something new. The solution is governance, and making sure you, the developers and IT pros who are advocating cloud in you organizations, understand the management needed for successful adoption is key: When you convince your team to move to Azure you can get extra credit for helping your organization move to the cloud without the pain. Whilst governance does not need tooling per se, Microsoft has a range of great tools in the Azure arsenal to help you. In this session I'll talk about the kinds of things that can go wrong, the simple things you can do to avoid them, and I'll show you the Azure tooling, some of it brand new, that will help you. ![Rik Hepworth](https://sharegate.com/app/uploads/2020/03/rik.png) **Rik Hepworth** Chief Consulting Officer at Black Marble ### Securing Serverless Applications in Azure Serverless is all about unleashing developer productivity by reducing the management burden and allowing you to focus on the application logic. But even for serverless applications, security is key! In this session Sjoukje will guide you on how to secure your serverless applications. We are going to take a look at the different options for securing your serverless apps, such as using Azure Key Vault, ClaimsPrincipal binding data for Azure Functions and much more. ![Sjoukje Zaal](https://sharegate.com/app/uploads/2020/03/sjoukje.png) **Sjoukje Zaal** CTO Microsoft at Capgemini ### Manage and govern your hybrid servers using Azure Arc Thomas Maurer shows you how you can manage and govern your Windows and Linux machines hosted outside of Azure on your corporate network or other cloud provider, similarly to how you manage native Azure virtual machines. When a hybrid machine is connected to Azure, it becomes a connected machine and is treated as a resource in Azure. Azure Arc provides you with the familiar cloud-native Azure management experience, like RBAC, Tags, Azure Policy, Log Analytics and more. ![Thomas Maurer](https://sharegate.com/app/uploads/2020/03/thomas.png) **Thomas Maurer** Senior Cloud Advocate at Microsoft ### Azure Resource Manager templates tips, tricks, and advanced techniques A technical discussion of some more advanced techniques to take your Azure Resource Manager templates to the next level. Covering techniques such as T-Shirt sizes, functions and testing as well as some brand new tools fresh into preview. Intended for those who have used basic ARM templates to deploy Azure resources but now want to learn more advanced techniques and overcome problems they may be facing. ![Sam Cogan](https://sharegate.com/app/uploads/2020/03/sam.png) **Sam Cogan** Solution Architect at Willis Towers Watson ### Exploring Azure with Resource Graph Azure Resource Graph is a service that is designed to enable us to explore all of our Azure resources and effectively manage our cloud inventory at scale. There is no better way to learn about powerful querying capabilities to get deeper insights from our resources than analyzing various query examples. We use Azure Resource Graph Explorer to run queries, and build inventory dashboards and Azure Monitor workbooks to visualize our Azure resources or take advantage of the scripting and automate queries using Azure PowerShell and Azure CLI. ![Aleksandar Nikolic](https://sharegate.com/app/uploads/2020/03/aleksandar.png) **Aleksandar Nikolic** Co-founder of PowerShellMagazine.com ### Lessons learned: Improving visibility, accountability and cost in Azure The cloud promises many great things, but they won't magically happen without any adjustment on your part. In a democratized model, giving more power to more users comes at a price. Visibility, accountability, and cost control now become crucial aspects of a good cloud governance. Maybe are you already asking yourself if your resource usage and cost are optimal or if you could do better? Are you able to tell who owns what very easily? Are your resources configured the way you require them across your organization? In all cases, being proactive regarding resource configuration, categorization, usage, and cost in Azure will bring you great benefits. In a very transparent way, learn about our cloud journey at ShareGate. Our good—and less good—moves regarding all the topics above as we continue to adapt and evolve in an ever-changing cloud world.\[read less\] ![Stephane Lapointe](https://sharegate.com/app/uploads/2020/03/slap.png) **Stephane Lapointe** Cloud Solutions Architect at ShareGate ### Implementing control and governance at-scale using Azure Policy and Azure governance In this session, we will go over how Azure makes it easy to get better visibility and control into your environment using Azure Governance. This will be an in-depth session on Azure Governance capabilities, Azure Policy architecture, and best practices on implementing governance. ![Liz Kim and Joseph Chan](https://sharegate.com/app/uploads/2020/03/joseph_liz.gif) **Liz Kim and Joseph Chan** Liz is Product manager, Azure Policy and ARM RBAC at Microsoft Joseph is Head of Products, Azure ARM Control Plane & Governance team at Microsoft ## Conclusion If you want to be proactive, learn new tips and growth your expertise, this is a great (did I mention free?!) event to attend to. [Deploy: An expert-led online event focused on Microsoft Azure governance - ShareGateDeploy is a virtual event where experts share their experiences and insights to help you optimize your Azure environment. Join us to learn Azure governance best practices.![](https://sharegate.com/app/themes/sharegate/img/favicons/ShareGate_Favicon_192X192.png)ShareGate![](https://sharegate.com/app/uploads/2020/03/deploy-og2x-1024x536.png)](https://sharegate.com/deploy-event?ref=codeisahighway.com) ### Azure Policy essentials webinar resources URL: https://codeisahighway.com/azure-policy-essentials-webinar-resources/ Last updated: 2026-07-17T08:27:41.000Z I had the pleasure to co-host a webinar with Jussi Roine around Azure Policy and governance in Azure at the end of March 2020 for ShareGate. It was a good event and we had a lot of registrations but if you missed it, or would like a chance to listen to it again or get the highlights of this event, follow me. ## Video and recap of highlights If you missed or want to watch the webinar again, you can do so by going here: [https://sharegate.com/resource/webinar-azure-policy-governance-best-practices](https://sharegate.com/resource/webinar-azure-policy-governance-best-practices?ref=codeisahighway.com) If you want a recap of highlights of this webinar in a 10-15 minutes readable format, Elle Crosby at ShareGate got you covered here: > [Azure Policy essentials: Highlights from our expert-led webinar](https://sharegate.com/blog/azure-policy-essentials-highlights?ref=codeisahighway.com) ## Interested by Governance in Azure? We'll hold a full day online conference THURSDAY, MAY 7 2020 | 9AM-5PM ET around governance and best practices in Azure for a total of 8 great sessions. It is called **Deploy**, it's a free event and you can reserve your seat here: [https://sharegate.com/deploy-event](https://sharegate.com/deploy-event?ref=codeisahighway.com) ### There is a new way to reference managed identity in ARM template URL: https://codeisahighway.com/there-is-a-new-way-to-reference-managed-identity-in-arm-template/ Last updated: 2026-07-31T19:44:21.000Z I have been using managed identity (aka Managed Service Identity - MSI) in Azure for several years now. It's a best practice and a very convenient way to assign an identity (Service Principal) to an Azure resource. A new way to reference managed identities in ARM templates has been introduced recently and its not very well documented, read through for more details. ## What is Managed Identity? Here is the description from Microsoft's documentation: > The managed identities for Azure resources feature in Azure Active Directory (Azure AD) solves this problem. The feature provides Azure services with an automatically managed identity in Azure AD. You can use the identity to authenticate to any service that supports Azure AD authentication, including Key Vault, without any credentials in your code. There are two types of managed identities: - A **system-assigned managed identity** is enabled directly on an Azure service instance. When the identity is enabled, Azure creates an identity for the instance in the Azure AD tenant that's trusted by the subscription of the identity instance. After the identity is created, the credentials are provisioned onto the instance. The lifecycle of a system-assigned identity is directly tied to the Azure service instance that it's enabled on. If the instance is deleted, Azure automatically cleans up the credentials and the identity in Azure AD. - A **user-assigned managed identity** is created as a standalone Azure resource. Through a create process, Azure creates an identity in the Azure AD tenant that's trusted by the subscription in use. After the identity is created, the identity can be assigned to one or more Azure service instances. The lifecycle of a user-assigned identity is managed separately from the lifecycle of the Azure service instances to which it's assigned. ## Assigning a managed identity to a resource in ARM template First, you need to tell ARM that you want a managed identity for an Azure resource. It can be a Web site, Azure Function, Virtual Machine, AKS, etc. To do so, you add the `identity` section on your resource definition in your template. Here is an example of a system-assigned managed identity on a Azure Function. ```json { "type": "Microsoft.Web/sites", "kind": "functionapp", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2016-08-01", "location": "[resourceGroup().location]", "identity": { "type": "SystemAssigned" }, "properties": { ... } } ``` This part is fairly easy to achieve. Now imagine you want, in or outside your template, to use the managed identity information for permission and role assignments, how would you do that? Since the change in fairly recent, not all the documentation is up to date and it will take some time to be updated everywhere. Let's imagine that we want to grant our managed identity access to a Key Vault via its access policies. ## Referencing, the old way What you'll find around on the internet is to grab the information this way: ```json { "type": "Microsoft.KeyVault/vaults", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2016-10-01", "location": "[resourceGroup().location]", "properties": { "sku": { "family": "A", "name": "standard" }, "tenantId": "[subscription().tenantid]", "accessPolicies": [ { "tenantId": "[subscription().tenantid]", "objectId": "[reference(concat(resourceId('Microsoft.Web/sites', variables('uniqueResourceNameBase')), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]", "permissions": { "keys": [], "secrets": [ "get" ], "certificates": [] } } ], "enabledForDeployment": false, "enabledForDiskEncryption": false, "enabledForTemplateDeployment": false }, "dependsOn": [ "[resourceId('Microsoft.Web/sites', variables('uniqueResourceNameBase'))]" ] } ``` The template expression that is responsible to fetch the managed identity information and expose the objectId (via the principalId property) is this one: ``` [reference(concat(resourceId('Microsoft.Web/sites', variables('uniqueResourceNameBase')), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId] ``` This work today (at the time of this writing) and will continue for some time but is not the recommended approach anymore. ## Referencing, the new way The identity information is now available directly from a resource that support managed identity when you fetch its full set of data. You can obtain the full definition by using the `reference` function. For the new approach to work, you need to pass the string value `full` as the last parameter of the `reference` template function. Here is a documentation extract for the `reference` template function: **Usage** `reference(resourceName or resourceIdentifier, [apiVersion], ['Full'])` For the last parameter, which is optional: > Value that specifies whether to return the full resource object. If you don't specify `'Full'`, only the properties object of the resource is returned. The full object includes values such as the resource ID and location. Here is the new construct targeting the same identity that we saw a little bit earlier ```json [reference(resourceId('Microsoft.Web/sites', variables('uniqueResourceNameBase')), '2019-08-01', 'full').identity.principalId] ``` First, we need to build a resource identifier using the `resourceId` template function. We then provide the apiVersion to use for that resource type (here: `Microsoft.Web/sites`). Finally we provide the `full` parameter to indicate we want the full object, not just the base properties. Personally I like it better this way, it is more concise. It is the way to get that sort of information from now on. ## Complete example Here is a complete and functional ARM template that use the new construct to populate the access policy of a Key Vault with the system managed identity information of an Azure Function. ```json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "location": { "type": "string", "defaultValue": "[resourceGroup().location]" } }, "variables": { "uniqueResourceNameBase": "[uniqueString(resourceGroup().id, parameters('location'), deployment().name)]" }, "resources": [ { "type": "Microsoft.KeyVault/vaults", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "properties": { "sku": { "family": "A", "name": "standard" }, "tenantId": "[subscription().tenantid]", "accessPolicies": [ { "tenantId": "[subscription().tenantid]", "objectId": "[reference(resourceId('Microsoft.Web/sites', variables('uniqueResourceNameBase')),'2019-08-01', 'full').identity.principalId]", "permissions": { "keys": [], "secrets": [ "get" ], "certificates": [] } } ], "enabledForDeployment": false, "enabledForDiskEncryption": false, "enabledForTemplateDeployment": false }, "dependsOn": [ "[resourceId('Microsoft.Web/sites', variables('uniqueResourceNameBase'))]" ] }, { "type": "Microsoft.Storage/storageAccounts", "sku": { "name": "Standard_LRS", "tier": "Standard" }, "kind": "Storage", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2019-06-01", "location": "[parameters('location')]", "scale": null, "properties": { "supportsHttpsTrafficOnly": false, "encryption": { "services": { "file": { "enabled": true }, "blob": { "enabled": true } }, "keySource": "Microsoft.Storage" } }, "dependsOn": [] }, { "type": "Microsoft.Web/serverfarms", "apiVersion": "2018-02-01", "name": "[variables('uniqueResourceNameBase')]", "location": "[parameters('location')]", "sku": { "name": "Y1", "tier": "Dynamic" }, "properties": { "name": "[variables('uniqueResourceNameBase')]", "computeMode": "Dynamic" } }, { "type": "Microsoft.Web/sites", "kind": "functionapp", "name": "[variables('uniqueResourceNameBase')]", "apiVersion": "2016-08-01", "location": "[parameters('location')]", "identity": { "type": "SystemAssigned" }, "properties": { "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('uniqueResourceNameBase'))]", "siteConfig": { "appSettings": [ { "name": "AzureWebJobsStorage", "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('uniqueResourceNameBase'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('uniqueResourceNameBase')),'2015-05-01-preview').key1)]" }, { "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('uniqueResourceNameBase'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('uniqueResourceNameBase')),'2015-05-01-preview').key1)]" }, { "name": "WEBSITE_CONTENTSHARE", "value": "[toLower(variables('uniqueResourceNameBase'))]" }, { "name": "FUNCTIONS_EXTENSION_VERSION", "value": "~2" }, { "name": "WEBSITE_NODE_DEFAULT_VERSION", "value": "~10" }, { "name": "FUNCTIONS_WORKER_RUNTIME", "value": "dotnet" } ] } }, "dependsOn": [ "[resourceId('Microsoft.Web/serverfarms', variables('uniqueResourceNameBase'))]" ] } ] } ``` Hope you like this update Happy ARM template! ## References - [Reference ARM template function documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource?ref=codeisahighway.com#reference) - [What are managed identities for Azure resources?](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview?ref=codeisahighway.com) - [Services that support managed identities for Azure resources](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/services-support-managed-identities?ref=codeisahighway.com) - [Create, list and delete a user-assigned managed identity using Azure Resource Manager](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-manage-ua-identity-arm?ref=codeisahighway.com) ### Speaking at Microsoft Ignite about our journey to the cloud URL: https://codeisahighway.com/speaking-at-microsoft-ignite-about-our-journey-to-the-cloud/ Last updated: 2026-07-23T03:04:53.000Z I started getting involved in the community for my love of sharing what passionate my in technology and at work. I never thought this would bring me to speak at an event like Microsoft Ignite, thus it's exactly what I'll be doing in a few days. This year Microsoft Ignite is again in Orlando, FL between November 4-8. ### What Is Microsoft Ignite? It is the biggest Microsoft event of the year with roughly 26K people gathering for the event. It offers opportunities to meet with Microsoft experts, product groups, [MVPs](https://en.wikipedia.org/wiki/Microsoft%5FMost%5FValuable%5FProfessional?ref=codeisahighway.com) and community members. There are tons of networking opportunities, enhanced through parties, community areas and "Ask the Expert" sessions. ### Our Cloud Journey I'll be speaking about the visibility & cost optimization aspect of our journey to the cloud at GSoft & ShareGate. I wrote a 10000-foot blog about it a couple of weeks ago: [https://sharegate.com/blog/our-journey-on-prem-to-azure](https://sharegate.com/blog/our-journey-on-prem-to-azure?ref=codeisahighway.com) When I joined GSoft, they were already using Microsoft Azure. It grew organically over the years; Starting as experiments, running client development environments, then production environments. Even if it was already the case, the company made it official in 2016, all new project/products would go directly to the cloud. ### Lessons learned in gaining visibility and lowering cost in our Azure environments I'll speak about what we did good, bad and what we learned in the process. I think that speaking about our experience can help others in their own cloud adoption journey. **Tuesday, November 5** The Hub: Partner Solution Zone - Theater 2 12:40 PM - 1:00 PM > Do you ask yourself if your Azure spending is optimal or how you can do better? Staying on top of your consumption brings great benefits as it is an important aspect of a healthy governance plan. Learn how to determine if you misuse your resources and how cost monitoring helps detect bugs and defects early, preventing cost bleeding. Here is the link to add it to your schedule if you are there in person or view it offline after the event, session code THR2220: [THR2220 - Lessons learned in gaining visibility and lowering cost in our Azure environments](https://myignite.techcommunity.microsoft.com/sessions/84326?ref=codeisahighway.com) ### How to detect expiring certificates in Azure Application Gateway URL: https://codeisahighway.com/how-to-detect-expiring-certificates-in-azure-application-gateway/ Last updated: 2026-07-17T08:28:14.000Z We've been on a mission lately at work to find expiring credentials and certificates in our Azure environments. One of the resources we had on our radar is Azure Application Gateway. Here's what I did to solve this problem and to enable us to be more proactive. Updated: 2021-06-14 - Refreshed modules & script references ### Requirements - PowerShell Az module - Az.ResourceGraph module v 0.10.0+ ### The problem It is always stressful to have people landing at your desk, panic in their eyes because some HTTPS certificate just expired in a critical environment. Some resources in Azure are more easily detected than others. Expiring certificates in App Services can be easily detected using only Azure Resource Graph, here's the [recipe](https://github.com/slapointe/azure-quickstart-resource-graph/tree/master/queries/appServices/certificates-expiring-in-90days?ref=codeisahighway.com) if you want it. Others, like Application Gateway cannot be checked only using Resource Graph (at the moment of writing this). ### The Assumption My first reflex was to use PowerShell to call Azure Resource Graph to automate this. Basically, I want to extract all certificate information from Azure, decode it from Base64, create the certificate (X509Certificate2) in memory and check the `NotAfter` property against the date I wanted. Well, in the case of Application Gateway, it turned out to be a bit more complicated than I thought. ### The Twist I tried, and tried for an hour to decode the certificate `publicCertData` property without success. I turned to the internet and found the following PowerShell module: [AzureRMAppGWCert](https://www.powershellgallery.com/packages/AzureRMAppGWCert?ref=codeisahighway.com). A big thank you by the way to **Victor Santana** for this gem. When I examined the code, I understood why it didn't work like I was always doing elsewhere. In the case of Application Gateway, we need to remove some of the data after the base64 conversion. ### The solution After the tricky truncate part. I created a PowerShell script with Azure Resource Graph to scan all subscriptions you have access to. Here is how to use it: ``` # Default is in the next 90 days .\Get-AzureAppGatewayExpiringCertificates.ps1 # To look further, i.e. 180 days .\Get-AzureAppGatewayExpiringCertificates.ps1 -ExpiresInDay 180 ``` If you have any expired or soon expiring certificates, you'll have one or more of the following output: ``` Name Value ---- ----- SubscriptionId 00000000-0000-0000-0000-000000000000 Thumbprint 4956BCC058BCA4BCB1349357AB474CCDBB37C28AB ResourceGroup poc-prod-common SubscriptionName my-company-subscription NotAfter 3/4/2019 4:51:03 PM Cert [Subject]... Name poc-prod-common-ag ``` ### Conclusion Again, the truncate thing was a nice pitfall, but very glad I finally worked it out with the help of Azure Resource Graph. In my case I scan 30+ subscriptions and check all of them in under 3 seconds which is blazing fast! You can download the script from my azure-scripts repo on GitHub [here](https://github.com/slapointe/azure-scripts/tree/master/application-gateway?ref=codeisahighway.com). Enjoy! Hope it help! ### Tenant and Subscription display names now available in Azure Resource Graph command lines URL: https://codeisahighway.com/tenant-and-subscription-display-names-now-available-in-azure-resource-graph-command-lines/ Last updated: 2026-07-17T08:28:27.000Z I love Azure Resource Graph but one of the things I deeply wanted since its launch is a native way to get the subscription or tenant names, not just the id. Good news! It's now possible if you use Azure CLI or Azure PowerShell. ## Prerequisites The following article has been tested with: - Azure CLI: `resource-graph` extension v1.0.0 - PowerShell: `Az.ResourceGraph` module v0.7.6 ## Before the include Here's a simple query that returns only one result ``` #Azure CLI az graph query -q "where type =~ 'Microsoft.Network/dnsZones' | limit 1" # PowerShell Search-AzGraph -Query "where type =~ 'Microsoft.Network/dnsZones' | limit 1" ``` Both will return the same data, let's convert it to JSON, we end up with the following output: ``` [ { "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/ciah-shared-all/providers/Microsoft.Network/dnszones/poc.ciah.dev", "identity": null, "kind": "", "location": "global", "managedBy": "", "name": "poc.ciah.dev", "plan": null, "properties": { "maxNumberOfRecordSets": 10000, "maxNumberOfRecordsPerRecordSet": null, "nameServers": [ "ns1-03.azure-dns.com.", "ns2-03.azure-dns.net.", "ns3-03.azure-dns.org.", "ns4-03.azure-dns.info." ], "numberOfRecordSets": 5, "zoneType": "Public" }, "resourceGroup": "ciah-shared-all", "sku": null, "subscriptionId": "00000000-0000-0000-0000-000000000000", "tags": {}, "tenantId": "00000000-0000-0000-0000-000000000000", "type": "microsoft.network/dnszones", "zones": null } ] ``` As you can see, we get a member `subscriptionId` and `tenantId` but no names. ## Welcome the include parameter In the latest versions of Azure Resource Graph PowerShell module (PS)/extension (CLI), you now have the option to include this information automatically. If you DON'T use projection in your query using the `project` operator, you can do something like this: ``` #Azure CLI az graph query -q "where type =~ 'Microsoft.Network/dnsZones' | limit 1" --include displayNames # PowerShell Search-AzGraph -Query "where type =~ 'Microsoft.Network/dnsZones' | limit 1" -Include displayNames ``` Will result in: ``` [ { "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/ciah-shared-all/providers/Microsoft.Network/dnszones/poc.ciah.dev", "identity": null, "kind": "", "location": "global", "managedBy": "", "name": "poc.ciah.dev", "plan": null, "properties": { "maxNumberOfRecordSets": 10000, "maxNumberOfRecordsPerRecordSet": null, "nameServers": [ "ns1-03.azure-dns.com.", "ns2-03.azure-dns.net.", "ns3-03.azure-dns.org.", "ns4-03.azure-dns.info." ], "numberOfRecordSets": 5, "zoneType": "Public" }, "resourceGroup": "ciah-shared-all", "sku": null, "subscriptionDisplayName": "MSDN Subscription", "subscriptionId": "00000000-0000-0000-0000-000000000000", "tags": {}, "tenantDisplayName": "POC", "tenantId": "00000000-0000-0000-0000-000000000000", "type": "microsoft.network/dnszones", "zones": null } ] ``` If you DO use projection, ensure you specify which display name you want returned, i.e.: ``` #Azure CLI az graph query -q "where type =~ 'Microsoft.Network/dnsZones' | limit 1 | project name, resourceGroup, subscriptionDisplayName, tenantDisplayName" --include displayNames # PowerShell Search-AzGraph -Query "where type =~ 'Microsoft.Network/dnsZones' | limit 1 | project name, resourceGroup, subscriptionDisplayName, tenantDisplayName" -Include displayNames ``` Will result in: ``` [ { "name": "poc.ciah.dev", "resourceGroup": "ciah-shared-all", "subscriptionDisplayName": "MSDN Subscription", "tenantDisplayName": "POC" } ] ``` Hope it helps you if you use the command line to query Azure Resource Graph. ## References - [Azure Resource Graph](https://docs.microsoft.com/en-us/azure/governance/resource-graph/?ref=codeisahighway.com) - Run your first Resource Graph query using Azure CLI - [Run your first Resource Graph query using Azure PowerShell](https://docs.microsoft.com/en-us/azure/governance/resource-graph/first-query-powershell?ref=codeisahighway.com) - [Kusto Project operator](https://docs.microsoft.com/en-us/azure/kusto/query/projectoperator?ref=codeisahighway.com) ### How to use Office 365 Exchange PowerShell module in Azure Automation URL: https://codeisahighway.com/how-to-use-office-365-exchange-powershell-module-in-azure-automation/ Last updated: 2026-07-31T19:44:22.000Z We had to do automation around Office 365 mailboxes a couple of days ago and struggled to do it. We looked around and found the solution in a sea of non working articles. Let this save you time if you want to do this yourself. ## Why running in Azure Automation Instead of executing a script in Windows task scheduler that requires a virtual machine (VM), we wanted to execute our mailbox script in Azure Automation. Mainly to get rid of the dependence on a VM and to benefit of a secure way to save the credentials for the script. We thought this would just work out of the box, but there is a gotcha we encountered with the Exchange PowerShell module in Azure automation. ## Problem In almost all articles, you'll find the code similar to this one: ``` $credential = Get-AutomationPSCredential -Name 'O365ServiceAccount' $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri 'https://outlook.office365.com/powershell-liveid/ -Credential $credential -Authentication Basic -AllowRedirection Import-PSSession -Session $session -DisableNameChecking -AllowClobber -DisableNameChecking ``` When run, we encountered an error trying to use one of the cmdlet in the module, e.g.: `Get-Mailbox`, the cmdlet was not found, like if `Import-PSSession` didn't work loading the cmdlets in the Azure Automation session. ``` Get-Mailbox : The term 'Get-Mailbox' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:1 char:1 + Get-Mailbox + ~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (get-mailbox2:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException ``` ## Solution In a good blog from [undocumented-feature.com](https://www.undocumented-features.com/2019/01/31/getting-around-the-basics-of-azure-automation-for-office-365/?ref=codeisahighway.com), one of the comments has the answer that solved our issue. You need to import the module like this: ``` Import-Module (Import-PSSession -Session $session -DisableNameChecking -AllowClobber -DisableNameChecking) -Global ``` After doing this, we were able to call `Get-Mailbox` cmdlet successfully in Azure Automation. ## References - [Azure Automation Documentation](https://docs.microsoft.com/en-us/azure/automation/?ref=codeisahighway.com) ### Native Azure REST API calls now available in Azure CLI 2.0.67+ URL: https://codeisahighway.com/native-azure-rest-api-calls-now-available-in-azure-cli-2-0-67/ Last updated: 2026-07-31T19:44:25.000Z I wrote a few PowerShell functions a couple of years ago to build a bearer token out of an active session. I needed to make calls in scripts here and there and nothing native was available. This is now things of the past if you are open to use Azure CLI. ### There is finally something! Searching for a *new* way to perform native calls at the command line to Azure Management REST APIs, I stumble upon an issue on GitHub. To discover at the end of the issue that it is now implemented and in preview in Azure CLI! ### Requirements You'll need to update to Azure CLI version 2.0.67+ ### Usage From the Azure CLI help you'll get the following if you type `az rest --help`. ``` Command az rest : Invoke a custom request. This command is in preview. It may be changed/removed in a future release. Arguments --method -m [Required] : HTTP request method. Allowed values: delete, get, head, options, patch, post, put. Default: get. --uri -u [Required] : Request uri. For uri without host, CLI will assume "https://management.azure.com/". Common tokens will also be replaced with real values including "{subscriptionId}". --body -b : Request body. --headers : Space-separated headers in KEY=VALUE format or JSON string. Use @{file} to load from a file. --output-file : Save response payload to a file. --resource : Resource url for which CLI should acquire a token in order to access the service. The token will be placed in the "Authorization" header. By default, CLI can figure this out based on "--url" argument, unless you use ones not in the list of "az cloud show --query endpoints". --skip-authorization-header : Do not auto append "Authorization" header. --uri-parameters : Space-separated queries in KEY=VALUE format or JSON string. Use @{file} to load from a file. Global Arguments --debug : Increase logging verbosity to show all debug logs. --help -h : Show this help message and exit. --output -o : Output format. Allowed values: json, jsonc, none, table, tsv, yaml. Default: json. --query : JMESPath query string. See http://jmespath.org/ for more information and examples. --subscription : Name or ID of subscription. You can configure the default subscription using `az account set -s NAME_OR_ID`. --verbose : Increase logging verbosity. Use --debug for full debug logs. Examples Get Audit log through Microsoft Graph az rest --method get --uri https://graph.microsoft.com/beta/auditLogs/directoryAudits Update a Azure Active Directory Graph User's display name az rest --method patch --uri "https://graph.microsoft.com/v1.0/users/johndoe@azuresdkteam.onmicrosoft.com" --body "{\"displayName\": \"jondoe2\"}" ``` Here is an invocation I made using `az rest` to call the Azure Policy REST API to extract non-compliant data: ``` az rest --method post --uri "https://management.azure.com/providers/Microsoft.Management/managementGroups/{managementGroupName}/providers/Microsoft.PolicyInsights/policyStates/latest/queryResults?api-version=2018-04-04&$filter=policyAssignmentId eq '/providers/Microsoft.Management/managementGroups/{managementGroupName}/providers/Microsoft.Authorization/policyAssignments/3132643538114acc900af638'" ``` ### Conclusion The days of having to extract and manipulate bearer tokens are pretty much gone if you are willing to use a little bit of Azure CLI. ### Resources - [How to easily and silently obtain AccessToken (Bearer) from an existing Azure PowerShell session](https://codeisahighway.com/how-to-easily-and-silently-obtain-accesstoken-bearer-from-an-existing-azure-powershell-session/) - [\`az curl\` or \`az rest\` for custom REST support (coverage)](https://github.com/Azure/azure-cli/issues/7618?ref=codeisahighway.com) ### How to audit Key Vault Access Policy using Azure Resource Graph URL: https://codeisahighway.com/how-to-audit-key-vault-accesspolicies-using-azure-resource-graph/ Last updated: 2026-08-10T07:12:57.000Z If you didn't know it yet, I am a big fan of Azure Resource Graph. It gives me the ability to quickly answer business inquiries / people showing at my desk with questions regarding Azure resources. I got one last week: "What is all the Key Vault where "UserX" has access". Seems complicated? Not at all, follow me. If you need a quick intro or refresh about what is Azure Resource Graph, [jump here](https://codeisahighway.com/how-azure-resource-graph-is-gonna-change-the-way-you-search-and-script). ### The requirement Like stated above, the need was, please tell me all the Azure Key Vault instances where "UserX" (who is an admin) forgot to clean his access/remove itself after his maintenance ticket. ### How I solved it What I first did is query Azure Resource Graph to see the definition/properties I get for an Azure Key Vault instance, just to see if its definition contains the information I needed (in this case Access Policy) ``` where type =~ "Microsoft.KeyVault/vaults" | limit 1 ``` it returned me the following properties: ``` { "provisioningState": "RegisteringDns", "tenantId": "4f9ff0ff-bbb7-4cd0-ac4d-f8aea3f93bf6", "sku": { "name": "Standard", "family": "A" }, "enabledForTemplateDeployment": false, "enabledForDiskEncryption": false, "enabledForDeployment": false, "accessPolicies": [ { "permissions": { "secrets": [ "Get", "List", "Set", "Delete", "Recover", "Backup", "Restore" ], "certificates": [ "Get", "List", "Update", "Create", "Import", "Delete", "Recover", "Backup", "Restore", "ManageContacts", "ManageIssuers", "GetIssuers", "ListIssuers", "SetIssuers", "DeleteIssuers" ], "keys": [ "Get", "List", "Update", "Create", "Import", "Delete", "Recover", "Backup", "Restore" ] }, "tenantId": "4f9ff0ff-bbb7-4cd0-ac4d-f8aea3f93bf6", "objectId": "5eaecd00-b76e-47ab-8645-16d9a75f5757" }, { "permissions": { "secrets": [ "Get", "List", "Set", "Delete", "Recover", "Backup", "Restore" ], "certificates": [], "keys": [] }, "tenantId": "4f9ff0ff-bbb7-4cd0-ac4d-f8aea3f93bf6", "objectId": "5a99e6db-4ec7-43ac-9585-25eee5b479df" } ], "vaultUri": "https://key-vault-resource-graph.vault.azure.net/" } ``` I found the information I need under the property `accessPolicies`. Now I needed to find the `objectId` of "UserX", this is easy, using PowerShell or Azure CLI, I can look it up. ``` # Azure CLI az ad user show --upn "userx@mycompany.com" --query objectId #PowerShell Get-AzADUser -UserPrincipalName 'userx@mycompany.com' | Select-Object -ExpandProperty Id ``` Once I have this information, I can now build up the Resource Graph query to ask about all Key Vault where this `objectId` is present in the `accessPolicies`. ``` where type =~ "Microsoft.KeyVault/vaults" | mvexpand policy = properties.accessPolicies | where policy.objectId == '5a99e6db-4ec7-43ac-9585-25eee5b479df' | project name, resourceGroup ``` ### Let's Understand What This Query Does The secret sauce here is `mvexpand`. It will expand a multi-value array or property bag into separate results, allowing you to query each item in the `accessPolicies` array. 1. It will first filter to only return types `Microsoft.KeyVault/vaults` (Key Vault). 2. It will extend the result set by creating a separate row for each accessPolicies in that Key Vault. 3. It will filter results to the `objectId` we looked up earlier. ### Use it as often as possible I invite you to play more and more with Azure Resource Graph, it is a very valuable tool in your tool belt. In all transparency, this is the original query I use to lookup the information I needed last week: ``` where type =~ "Microsoft.Keyvault/vaults" | extend p=todynamic(properties) | extend policies=todynamic(tostring(p.accessPolicies)) | mvexpand policy = policies | where tostring(policy.objectId) == '5a99e6db-4ec7-43ac-9585-25eee5b479df' | project name, resourceGroup ``` I originally took pieces here and there from Log Analytics query I had for policies and compliance . Taking a step back after, I was able to trim it to be more effective. We learn every day! ### Resources - [Azure Data Explorer Query Language reference](https://docs.microsoft.com/en-us/azure/kusto/query/?ref=codeisahighway.com) - [mvexpand documentation](https://docs.microsoft.com/en-us/azure/kusto/query/mvexpandoperator?ref=codeisahighway.com) ### Azure Resource Change History is here URL: https://codeisahighway.com/azure-resource-change-history-is-here/ Last updated: 2026-08-10T07:12:55.000Z I wrote not long ago about Azure Resource Graph and how it would change the way you script. It now enables us to track changes over time. Ever wanted to know what was the state of a resource 1 week before the laschange. It is now possible. ### Before the Change History era It was possible to keep track of resource changes in Azure, but you had to do it yourself. It was possible also to get notified via Azure Log Activity when an operation other than \*/read happens on a resource, but you don't really get the details of what is changing exactly, i.e. which properties. ### Why Is It Important Configuration drift (change) detection is important in several situations, let's imagine you are in a middle of an incident and need to understand quickly if something has changed or not since last deployment to help you troubleshoot. Using Change History in the portal or the Rest API, you can dig into these configuration drift to help you compare what has changed. ### How can I use Change History? In the portal, you can access Change History in Azure Policy's [Change history](https://docs.microsoft.com/en-us/azure/governance/policy/how-to/determine-non-compliance?ref=codeisahighway.com#change-history-preview) or Azure Activity Logs [Change history](https://docs.microsoft.com/en-us/azure/azure-monitor/platform/activity-log-view?ref=codeisahighway.com#azure-portal). Using the Rest API, with the public preview (at the time of writing), Resource Change History API gives you access to the last 14 days of ARM resource's property changes. Very neat! For a start, two (2) APIs are available: > **resourceChanges**: returns a list of change events for a resource and time interval. > > **resourceChangeDetails**: returns the before and after resource content for a given resource and change event There is a great article around the Change History API Microsoft documentation. I won't repeat the code samples here but in a nutshell: You make an API call to **resourceChanges** to get the list of changes available to consult, then call the **resourceChangeDetails** to get a *beforeSnapshot* and *afterSnapshot* to help you compare. Here is an example of the return of a **resourceChangeDetails** call: ```json { "changeId": "{\"beforeId\":\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\"beforeTime\":'2019-05-09T00:00:00.000Z\",\"afterId\":\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\"beforeTime\":'2019-05-10T00:00:00.000Z\"}", "beforeSnapshot": { "timestamp": "2019-03-29T01:32:05.993Z", "content": { "sku": { "name": "Standard_LRS", "tier": "Standard" }, "kind": "Storage", "id": "/subscriptions/{subscriptionId}/resourceGroups/MyResourceGroup/providers/Microsoft.Storage/storageAccounts/mystorageaccount", "name": "mystorageaccount", "type": "Microsoft.Storage/storageAccounts", "location": "westus", "tags": {}, "properties": { "networkAcls": { "bypass": "AzureServices", "virtualNetworkRules": [], "ipRules": [], "defaultAction": "Allow" }, "supportsHttpsTrafficOnly": false, "encryption": { "services": { "file": { "enabled": true, "lastEnabledTime": "2018-07-27T18:37:21.8333895Z" }, "blob": { "enabled": true, "lastEnabledTime": "2018-07-27T18:37:21.8333895Z" } }, "keySource": "Microsoft.Storage" }, "provisioningState": "Succeeded", "creationTime": "2018-07-27T18:37:21.7708872Z", "primaryEndpoints": { "blob": "https://mystorageaccount.blob.core.windows.net/", "queue": "https://mystorageaccount.queue.core.windows.net/", "table": "https://mystorageaccount.table.core.windows.net/", "file": "https://mystorageaccount.file.core.windows.net/" }, "primaryLocation": "westus", "statusOfPrimary": "available" } } }, "afterSnapshot": { "timestamp": "2019-03-29T01:54:24.42Z", "content": { "sku": { "name": "Standard_LRS", "tier": "Standard" }, "kind": "Storage", "id": "/subscriptions/{subscriptionId}/resourceGroups/MyResourceGroup/providers/Microsoft.Storage/storageAccounts/mystorageaccount", "name": "mystorageaccount", "type": "Microsoft.Storage/storageAccounts", "location": "westus", "tags": {}, "properties": { "networkAcls": { "bypass": "AzureServices", "virtualNetworkRules": [], "ipRules": [], "defaultAction": "Allow" }, "supportsHttpsTrafficOnly": true, "encryption": { "services": { "file": { "enabled": true, "lastEnabledTime": "2018-07-27T18:37:21.8333895Z" }, "blob": { "enabled": true, "lastEnabledTime": "2018-07-27T18:37:21.8333895Z" } }, "keySource": "Microsoft.Storage" }, "provisioningState": "Succeeded", "creationTime": "2018-07-27T18:37:21.7708872Z", "primaryEndpoints": { "blob": "https://mystorageaccount.blob.core.windows.net/", "queue": "https://mystorageaccount.queue.core.windows.net/", "table": "https://mystorageaccount.table.core.windows.net/", "file": "https://mystorageaccount.file.core.windows.net/" }, "primaryLocation": "westus", "statusOfPrimary": "available" } } } } ``` ### Conclusion There is great potential in being able to extract and consult configuration drift for troubleshooting or compliance need, give it a try and let me know what you think of it! ### Resources - [Get resource changes](https://aka.ms/changehistoryapi?ref=codeisahighway.com) ### How Azure Resource Graph is gonna change the way you search and script URL: https://codeisahighway.com/how-azure-resource-graph-is-gonna-change-the-way-you-search-and-script/ Last updated: 2026-07-17T08:29:26.000Z Azure Resource Graph has been announced a while ago (Ignite 2018) and I immediately understood this would be a game changer in terms of querying and data digging for the Azure resources I need to manage. ## What is Azure Resource Graph From the Microsoft documentation: > Azure Resource Graph is a service in Azure that is designed to extend Azure Resource Management by providing efficient and performant resource exploration with the ability to query at scale across all subscriptions and management groups so that you can effectively govern your environment. ## The old way... I created a lot a script over the years and when it comes the time to list or search for resources across all subscriptions, the usage pattern is pretty much always the same: Connect to a subscription, fetch what you need, switch to the next subscription, *rinse and repeat*. Example in PowerShell: ```powershell $results = Get-AzSubscription | % { Write-Host ('Processing subscription {0}' -f $_.Name) $null = Set-AzContext -Subscription $_.Id Get-AzResource -ResourceType 'Microsoft.Web/sites' ... } $results.Count ``` Time to execute something like this over my \~30 subscriptions: **131 sec** (2m11s) This approach was the only way possible until the graph was made available. It is very slow, but hey, it served me well. ## How to use Azure Resource Graph You can use the REST API directly, Azure CLI or Azure PowerShell (Az module) to use Azure Resource Graph. Here is an example in PowerShell: ```powershell $results = Search-AzGraph -Query "where type =~ 'Microsoft.Web/sites'" -First 5000 $results.Count ``` Time to execute something like this over my \~30 subscriptions: **2.5 sec** \-- which is over 50x faster! ## Working with large datasets There is one catch though, by default the behavior for `-First` parameter is 100 results. At the time of writing this, **First** currently has a maximum allowed value of *5000*. Beyond that you need to page your results. From the Microsoft documentation: > The control that is *most restrictive* will win. For example, if your query uses the `top` or `limit` operators and would result in more records than `First`, the maximum records returned would be equal to First. Likewise, if top or limit is smaller than First, the record set returned would be the smaller value configured by top or limit. ## Paging your results If you really want paging, at the moment of writing this, you'll need to call the REST API directly. The REST API `QueryResponse` provides values to indicate of a result set has been broken up: resultTruncated and $skipToken. There is good documentation on how to handle paging with the REST API, but if you use PowerShell for example, you will need to put a little bit more effort to page properly until the native support is implemented. First, you need to sort your results, otherwise they will be outputted randomly and you'll never be able to page. You can sort in your query by using the following construct: `order by [field1], [field2] asc|desc` Here is an example how you can implement paging in PowerShell until native support is there: ```powershell $pageSize = 1000 $iteration = 0 $searchParams = @{ Query = "where type =~ 'Microsoft.Web/sites' | project id, name, resourceGroup | order by id, resourceGroup desc" First = $pageSize } $results = do { $iteration += 1 Write-Verbose "Iteration #$iteration" -Verbose $pageResults = Search-AzGraph @searchParams $searchParams.Skip += $pageResults.Count $pageResults } while ($pageResults.Count -eq $pageSize) $results.Count ``` ## Conclusion There is no good reason not to use Azure Resource Graph from now on, it is very fast and enable you to dig into resources in a brand new way. Psst, it is a subset of Kusto, the same query language behind Application Insights, Azure Log Analytics & Azure Data Explorer. Mastering this query language will be an asset for sure going forward in Azure. ## References - [Azure Resource Graph - Overview](https://docs.microsoft.com/en-us/azure/governance/resource-graph/overview?ref=codeisahighway.com) - [Azure Resource Graph - Explore your Azure resources](https://docs.microsoft.com/en-us/azure/governance/resource-graph/concepts/explore-resources?ref=codeisahighway.com) - [Azure Resource Graph - Query language reference](https://docs.microsoft.com/en-us/azure/governance/resource-graph/concepts/query-language?ref=codeisahighway.com) - [Azure Resource Graph - Working with large Azure resource data sets](https://docs.microsoft.com/en-us/azure/governance/resource-graph/concepts/work-with-data?ref=codeisahighway.com) - [Azure Resource Graph - REST API reference](https://docs.microsoft.com/en-us/rest/api/azureresourcegraph/resources/resources?ref=codeisahighway.com) ### How to audit expiring soon Azure AD application credentials (keys/passwords/certificates) URL: https://codeisahighway.com/how-to-audit-expiring-soon-azure-ad-application-credentials-keys-passwords-certificates/ Last updated: 2026-07-17T08:29:38.000Z How bad the feeling is when someone comes rush onto your desk because something in production stopped working overnight. This can happen if you don't take seriously the rollover of credentials for your Azure AD application. Be the hero here, be proactive instead of reactive! ## Context There is 2 types of credentials that can be used for an Azure AD application: passwords (keys) and certificates. Both could (and should) have a realistic end date, and for the sake of good practices, they should not be configured to never end. Update: 2021-02-06 - Script reference to GitHub instead of ScriptCenter ## Setup information You'll need Azure Az PowerShell in order to use the script of this article. - Azure PowerShell module (Az) v1.x - *Audit expiring soon Azure AD application credentials (keys/certificates)* script from ScriptCenter ## Prepare for the audit Open a PowerShell shell, log into Azure and position yourself on the desired subscription, here is an example on how to do so: ```powershell Connect-AzAccount ``` ## Perform a 120 days audit ```powershell $audit = .\Get-AzADAppExpiringCredentials.ps1 -ExpiresInDays 120 -Verbose Gathering necessary information... VERBOSE: Fetching information for application ADAuditPlus Reporting VERBOSE: Fetching information for application app registration ... Validating expiration data... Done. #output the result as is $audit DisplayName : ADAuditPlus Reporting ObjectId : ApplicationId : 00000000-0000-0000-0000-000000000000 KeyId : 00000000-0000-0000-0000-000000000000 Type : Password StartDate : 4/9/2018 6:34:52 PM EndDate : 12/31/2299 5:00:00 AM Status : Valid DisplayName : ARM Test app ObjectId : ApplicationId : 00000000-0000-0000-0000-000000000000 KeyId : 00000000-0000-0000-0000-000000000000 Type : Password StartDate : 2/12/2019 8:19:38 PM EndDate : 3/12/2019 8:19:38 PM Status : ExpiringSoon ``` ## \[Optional\] Perform a grouped audit ```powershell $audit | Group-Object -Property Status # you'll end up with an output looking like this Count Name Group ----- ---- ----- 54 Expired {@{DisplayName=AutomationAccount_E+6heptOMzz8vX9ooTYFZq8DJYKweTDdIFrQmOo3BXs=; Objec... 11 ExpiringSoon {@{DisplayName=AutomationAccountQwerty_e1yHxjl45+GwXIxG/mwqMnARwn5i6C5zSMAAIxZyzw... 173 Valid {@{DisplayName=ADAuditPlus Reporting; ObjectId=; ApplicationId=9db46068-49a0-45ae-b2... ``` ## \[Optional\] Output the result as JSON and save it to disk for later use ```powershell $audit | ConvertTo-Json -Depth 5 | Out-File .\audit.json # you'll end up with a JSON file in this format [ { "DisplayName": "AutomationAccountQwerty_e1yHxjl45", "ObjectId": null, "ApplicationId": { "value": "00000000-0000-0000-0000-000000000000", "Guid": "00000000-0000-0000-0000-000000000000" }, "KeyId": "00000000-0000-0000-0000-000000000000", "Type": "Password", "StartDate": { "value": "2016-05-11T14:55:30", "DateTime": "Wednesday, May 11, 2016 2:55:30 PM" }, "EndDate": { "value": "2019-05-11T14:55:30", "DateTime": "Thursday, May 11, 2019 2:55:30 PM" }, "Status": "ExpiringSoon" }, ... ] ``` ## Conclusion If you want to be proactive and know in advance what application will have trouble because of expiring credentials, you now have another tool in your tool belt! You can download the *Audit expiring soon Azure AD application credentials (keys/certificates)* script (for free) on [Github](https://github.com/slapointe/azure-scripts/tree/master/azure-ad/expiring-app-credentials?ref=codeisahighway.com) ## References - [Install Azure PowerShell](https://docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-1.3.0&ref=codeisahighway.com) ### Get Hygge with it – Your 5 Step Guide to ESPC18 URL: https://codeisahighway.com/get-hygge-with-it-your-5-step-guide-to-espc18/ Last updated: 2026-08-10T07:12:53.000Z # 1\. PLAN YOUR SESSIONS Explore the [ESPC18 SCHEDULE](https://www.sharepointeurope.com/conference/schedule/?ref=codeisahighway.com) to identify what sessions you’d like to attend. Create your own schedule suited to you. If you are travelling with colleagues, divide and conquer by attending different sessions. Afterwards swap notes to increase your learning. Don’t have time to delve through our 120+ conference schedule? We have created dedicated pages to save you time. Check out the ESPC conference schedule based on [IT PRO](https://www.sharepointeurope.com/pros-attend-espc18/?ref=codeisahighway.com), [DEV](https://www.sharepointeurope.com/developers-attend-espc18/?ref=codeisahighway.com), [BDM](https://www.sharepointeurope.com/business-decision-makers-attend-espc/?ref=codeisahighway.com), [AZURE](https://www.sharepointeurope.com/azure-at-espc18/?ref=codeisahighway.com) or [MICROSOFT SESSIONS](https://www.sharepointeurope.com/microsoft-sessions-espc18/?ref=codeisahighway.com). # 2\. CONNECT WITH YOUR PEERS Join the ESPC18 App (Login details announced in the coming weeks) & follow the hashtag [#ESPC18](https://twitter.com/search?q=%23ESPC18&src=typd&ref=codeisahighway.com) to find out whose attending. Why not make your presence known by sending out a tweet introducing yourself. Arrange to meet new individuals at ESPC – you never know what you might discover! Helpful tip: Carry some business cards with you to share with the new people you meet. # 3\. LEARN, LEARN, LEARN Before arriving at ESPC, take some time to identify what questions you want answered. Prepare them advance to ask during a session Q&A. Why not take a break from sessions and advance your skills at the ESPC labs or check out the Ask the Experts session. Remember, it’s good practice to note three important key takeaways from each session. # 4\. HAVE FUN With 2,000 delegates expected to attend, ESPC offers a host of exciting day and night experiences. Check out the [WOMEN IN TECHNOLOGY LUNCH](https://www.sharepointeurope.com/events/spin-tale-fiction-writers-guide-telling-story/?ref=codeisahighway.com), a jam packed [EXPO HALL](https://www.sharepointeurope.com/conference/sponsors/?ref=codeisahighway.com) or challenge other delegates and the ESPC team to some fun games in the Community Area. Not enough? Be sure to join the EXPO drinks on Tuesday evening or enjoy a magical night at the sell-out [ESPC18 PARTY: A NIGHT AT THE CIRCUS](https://www.sharepointeurope.com/espc18-party-night/?ref=codeisahighway.com). # 5\. SHARE WITH YOUR TEAM Schedule a meeting post conference to share your key learnings with your fellow co-workers. Impress colleagues with your advanced knowledge while maximizing value for your company. Share your inspiration and make plans to implement what you learned. Still undecided about attending The leading European SharePoint, Office 365 & Azure Conference? Visit [10 REASONS TO ATTEND ESPC18](https://www.sharepointeurope.com/reasons-attend-espc18/?ref=codeisahighway.com) to see why you need to be there. [BOOK YOUR TICKET](https://www.sharepointeurope.com/pricing/?ref=codeisahighway.com) today and use coupon code ESPC18SPK to receive a €100 discount. ![ESPC18](https://codeisahighway.com/content/images/2018/10/ESPC18.jpg) ### How to audit an Azure subscription Role Based Access Control (RBAC) assignments URL: https://codeisahighway.com/how-to-audit-an-azure-subscription-role-based-access-control-rbac-assignments/ Last updated: 2026-07-30T19:45:16.000Z In the last year it occurred several times that I needed to audit and validate Role Based Access Control (RBAC) assignments for an Azure subscription. Using what is available in the portal doesn't help much. You can view assignments in the portal but it is not exportable, neither you'll be able to expand group membership. You'll need a lot of clicks here and there to fulfill this kind of quest. ## Setup information You'll need Azure PowerShell in order to use the script of this article. - AzureRM.Resources module v5.x or v6.x - *Audit Azure subscription RBAC assignments* script from ScriptCenter ## Prepare for the audit Open a PowerShell shell, log into Azure and position yourself on the desired subscription, here is an example on how to do so: ```powershell Login-AzureRmAccount Set-AzureRmContext -Subscription 'Your Subscription' ``` ## Perform a non-grouped audit ```powershell $rbacAudit = .\Invoke-AzureRmSubscriptionRBACAudit.ps1 #output the result as is $rbacAudit Id : 4506482f-23a0-4820-850b-06219f704739 DisplayName : FirstName1 LastName1 ParentGroup : {Id, DisplayName} RoleDefinitionName : Reader Scope : /subscriptions/11111111-1111-1111-1111-111111111111 CanDelegate : False Id : dc37e4bd-1811-4b5e-ba5e-1322ff5ac29d DisplayName : FirstName2 LastName2 ParentGroup : {Id, DisplayName} RoleDefinitionName : Owner Scope : /subscriptions/11111111-1111-1111-1111-111111111111 CanDelegate : False Id : 8a173eb5-52a4-4a5b-b6ae-aefc3dac7489 DisplayName : FirstName3 LastName3 ParentGroup : {Id, DisplayName} RoleDefinitionName : Reader Scope : /subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/stg CanDelegate : False Id : 4e13ae9c-7e3b-49e4-a49e-e81c2dd21151 DisplayName : FirstName4 LastName4 ParentGroup : {Id, DisplayName} RoleDefinitionName : Contributor Scope : /subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/stg/providers/Microsoft.Insights/components/stg-ai-app-qjkgqezdtfjr4 CanDelegate : False ``` ## \[Optional\] Output the result as JSON and save it to disk for later use ```powershell $rbacAudit | ConvertTo-Json -Depth 5 | Out-File .\rbacAudit.json # you'll end up with a JSON file in this format [ { "Id": "4506482f-23a0-4820-850b-06219f704739", "DisplayName": "FirstName1 LastName1", "ParentGroup": { "Id": "9cb7e0c1-0513-441b-b484-8b55761694fe", "DisplayName": "SecurityGroupName1" }, "RoleDefinitionName": "Reader", "Scope": "/subscriptions/11111111-1111-1111-1111-111111111111", "CanDelegate": false }, ... ] ``` ## Perform an audit grouped by users Another way to invoke the script is with the `-GroupRolesByUser`, it will group all assignments for each user to give you a view like below: ```powershell $rbacAuditGroupedByUser = .\Invoke-AzureRmSubscriptionRBACAudit.ps1 -GroupRolesByUser #output the result as is $rbacAuditGroupedByUser Count Name RoleDefinitions ParentGroup ----- ---- --------------- ----------- 2 FirstName1 LastName1 Contributor, Reader 1 azure-test@mycompany.com AccountAdministrator 1 FirstName2 LastName2 Owner 4 FirstName3 LastName3 Contributor, Reader, Owner, Owner ``` ## Conclusion If you need to perform an audit in the future, you now have another tool in your tool belt! You can download the *Audit Azure subscription RBAC assignments* script (for free) on [Microsoft Script Center](https://gallery.technet.microsoft.com/scriptcenter/Audit-Azure-subscription-f57d114e?ref=codeisahighway.com) ## References - [Install Azure PowerShell](https://docs.microsoft.com/en-us/powershell/azure/install-azurerm-ps?view=azurermps-6.9.0&ref=codeisahighway.com) - [What is role-based access control (RBAC)?](https://docs.microsoft.com/en-us/azure/role-based-access-control/overview?ref=codeisahighway.com) ### How to safely replace Find-AzureRmResource -ResourceType calls in Azure PowerShell 6.x+ URL: https://codeisahighway.com/how-to-safely-replace-find-azurermresource-resourcetype-calls-in-azure-powershell-6-x/ Last updated: 2026-07-31T19:44:27.000Z UPDATE: 2018-06-28 - Added resourcegroup ODataFilter example. Starting with version 6.0 of Azure PowerShell, `Find-AzureRmResource` have been removed and `Get-AzureRmResource` is supposed to be the workaround. My first reflex was to just convert `Find-AzureRmResource -ResourceType` to `Get-AzureRmResource -ResourceType` but I was unlucky and hit a regression and an error saying I could not only provide the `ResourceType` parameter. On my machine, with version 5.2.0 of *AzureRM.Resources* module, I get the following error if trying the following command: ```powershell Get-AzureRmResource -ResourceType Microsoft.Storage/storageAccounts Get-AzureRmResource : Parameter set cannot be resolved using the specified named parameters. At line:1 char:1 + Get-AzureRmResource -ResourceType Microsoft.Storage/storageAccounts + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [Get-AzureRmResource], ParameterBindingException + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation .GetAzureResourceCmdlet ``` I found a safer way to replace a search by resource type, we can use the OData parameter like so: ```powershell Get-AzureRmResource -ODataQuery "`$filter=resourcetype eq 'Microsoft.Storage/storageAccounts'" ``` You can be more restrictive and filter by resource type & resource group : ```powershell Get-AzureRmResource -ODataQuery "`$filter=resourcetype eq 'Microsoft.Storage/storageAccounts' and resourcegroup eq 'myrg'" ``` This worked for me in AzureRM 5.x and AzureRM 6.x Happy script rewrite! ## Resources - [Azure PowerShell v6.0.0-May2018](https://github.com/Azure/azure-powershell/releases/tag/v6.0.0-May2018?ref=codeisahighway.com) ### Prepare data disks for stability & consistency in Azure throughout virtual machines and scale sets lifecycle URL: https://codeisahighway.com/prepare-data-disks-for-stability-and-consistency-in-azure-throughout-virtual-machines-and-scale-sets-lifecycle/ Last updated: 2026-08-10T07:12:51.000Z When dealing with Windows virtual machines from the marketplace on Azure, sometimes a CD-ROM will temporarily be present in the first moments in the lifetime of a virtual machine or virtual machine scale set instances. Microsoft needs this drive to perform various actions like preparing and licensing the VM. If present, this drive will eventually go away, leaving you with a drive letter reassignment that might cause you trouble... at last, it did for me. ## The problem In my scenario, I was creating a virtual machine scale sets and was starting to assign my first data disk drive letter as F. I used an initialization script I took from the Azure documentation. It worked very well until I needed to re-image instances or perform an OS upgrade in the scale sets. When I did this, the instances were back running but with my data disk with letter E instead of F. It goes without saying that this made my application crash because it was referring to a data location of F:... in its configuration. ## Why is this happening After some troubleshooting and gathering information here and there, I realized it was a CD-ROM drive used by Microsoft that was causing this behavior. When dealing with some Azure marketplace images (Generalized), Microsoft will use this drive as a bootstrap point to properly license Windows & configure the OS. When the virtual machine agent enter a ready state and everything is fine, this drive is no longer needed and will be purged eventually, therefore vanishing at some point in the lifecycle of the virtual machine. ## The Solution I started to think about how to be consistent across the lifecycle of my instances and got an idea. I'd start from the initializing script I was previously using and chage it a bit. What if I change the CD-ROM drive letter to Z and prepare my data disks right after the D drive (temporary VM drive on Azure), starting from E instead of F. This way it would always be the same letter sequence whatever happen. It worked like a charm and after several tests, I now have my virtual machine scale sets instances very stable across reboot, de-allocate, re-image & host relocation on Azure. Here is what my data disk preparation script now does: It will move (if present) the CD-ROM drive to letter Z and perform initialization, formatting and assignation of drive letters for all un-initialized disks from letter E to Y. I am using it with a custom script extension that runs in an ARM template but you could use it directly on the VM yourself in a PowerShell console if you'd like. ```powershell # snippet of what's inside Get-WmiObject -Class Win32_volume -Filter 'DriveType=5'... ... $disks = Get-Disk | Where-Object partitionstyle -eq 'raw' | Sort-Object number ... foreach ($disk in $disks) { ... Initialize-Disk -PartitionStyle MBR -PassThru | New-Partition -UseMaximumSize -DriveLetter $driveLetter | Format-Volume -FileSystem NTFS -NewFileSystemLabel "$label.$count" -Confirm:$false -Force ... } ``` ## Conclusion You can download the full version (for free) on [Microsoft Script Center](https://gallery.technet.microsoft.com/scriptcenter/Consistent-Azure-VM-data-45e19f14?ref=codeisahighway.com) ## References - [Attach a data disk to a Windows VM using PowerShell](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/attach-disk-ps?ref=codeisahighway.com) ### Gain better control over your Microsoft Azure costs and governance using Overcast URL: https://codeisahighway.com/gain-better-control-over-your-microsoft-azure-costs-and-governance-using-overcast/ Last updated: 2026-07-30T19:45:21.000Z True is to say that it's a hard job to stay on top and remain in control of cloud computing spending. There is a tool I recently used, it didn't only provide us with awesome visibility over our Azure spending but also recommendations to trim/eliminate waste spending. Let me introduce you Overcast. > Disclosure: Before going further, I must come forward and say that I work for the company that created Overcast. We created this tool because we weren't happy with the market offering and wanted to make a cloud spending and governance tool that will educate people, is efficient, and just damn simple to use. # Cloud adoption is great, but... In most companies I've seen, there is almost always a recurring pattern in the first years. First they are very excited about the cloud benefits: *greater agility*, *pay by consumption*, etc. People then start to create resources here and there like in an open buffet. Doing so without having a good governance around resource ownership, expiration, naming, tagging, etc. Sooner or later, a lot of resources become obsolete for all the good reasons in the world: - They are less and less used to being no longer used at some point. - A new initiative is set up to replace the old resources but the latter is never deleted - Only a subset of the resources used in an initiative is deleted, leaving some artifacts behind - Misunderstanding of pricing for certain resources - The list can go on and on... After sometimes, often a year or two, someone will wake up and realize that their cloud spending is a bit out of control and definitely not cheap at all. To be frank, in a lot of situations, the cloud does not end up being cheaper than OnPremise resources but the advantage in the cloud is that you pay for what you use, and only when you use it. # There must be a way Now that they realize that they are not that much in control and need better visibility over their spending, comes the period to lookup for tools to help. At GSOFT, we tested a LOT of tools, from custom deployed tools in our Azure subscriptions, to SaaS products, we even used Power BI (we used it a lot actually). I will not make the trial for any of them here, but, let's just say we tested pretty much all of them and they usually fall within at least one of these: - Really expensive - Slow - Complicated to setup - Poor UX and navigation This is why are decided a couple of months ago to create our own tool, and we believe we did a great job. # Here is Overcast At the moment, there are two main functionalities in Overcast: *Costs* and *Savings*. In *Costs*, you can in a glimpse, see all your spending over time and if you are doing better and worse than previous months. ![overcast-costs](https://codeisahighway.com/content/images/2018/02/overcast-costs.png) And *Savings*, this is where you'll find our recommendations about potential savings you can make. ![overcast-savings](https://codeisahighway.com/content/images/2018/02/overcast-savings.png) There is a free trial so you can checkout [Overcast](https://overcast.cloud/?ref=codeisahighway.com) by yourself if you are curious or very interested in being more in control over your Azure\`s spending and governance. Have a great day! ### Migrate your classic storage account to Azure Resource Manager using PowerShell Azure v5.0.x URL: https://codeisahighway.com/migrate-your-classic-storage-account-to-azure-resource-manager-using-powershell-azure-v5-0-x/ Last updated: 2026-07-23T03:03:18.000Z I've been working to convert a lot of classic resources on Azure lately, a lot of fun I assure you! Many of the scenarios I faced implied virtual machines & virtual networks but here I will present a simple case I did recently, migration of a simple Classic storage used for blobs, tables & queues. If you want to migrate one or many classic storage accounts that are used for everything else than hosting VHDs and images, this is the recipe for you. What you'll need is Azure & AzureRM PowerShell modules installed, I used version 5.0.0 for this article, to install them you can type the following in a PowerShell (administrator) console: ```powershell Install-Module -Name AzureRm -RequiredVersion 5.0 Install-Module -Name Azure -RequiredVersion 5.0 ``` > Note: you need to make sure you don't have VM images and disks as Azure Resource Manager storage accounts don't support Classic images & disks. First thing first, you'll need to login into your account and select the right subscription. ```powershell Add-AzureAccount # enter your credentials Select-AzureSubscription -SubscriptionId 00000000-0000-0000-0000-000000000000 # replace with yours ``` In order to use any migration cmdlets, you need to register the `Microsoft.ClassicInfrastructureMigrate` resource provider using this command (make sure you have the privileged permissions on the Azure subscription): ```powershell Register-AzureRmResourceProvider -ProviderNamespace Microsoft.ClassicInfrastructureMigrate ``` ![Register-AzureRmResourceProvider](https://codeisahighway.com/content/images/2018/01/Register-AzureRmResourceProvider.png) Wait a bit and you'll see that the registration is completed. ```powershell Get-AzureRmResourceProvider -ProviderNamespace Microsoft.ClassicInfrastructureMigrate ``` ![Get-AzureRmResourceProvider](https://codeisahighway.com/content/images/2018/01/Get-AzureRmResourceProvider.png) Now that you are in the right subscription and all the requirements are met, make sure you can get the desired storage account by fetching it: ```powershell Get-AzureStorageAccount -StorageAccountName 'Your storage account name' # replace with yours ``` ![Get-AzureStorageAccount](https://codeisahighway.com/content/images/2018/01/Get-AzureStorageAccount.png) We are all good now, let's migrate this the Classic storage account to Azure Resource Manager in 3 little steps: first validate, then prepare the migration and finally, commit changes. ```powershell Move-AzureStorageAccount -Validate -StorageAccountName 'Your storage account name' # replace with yours Move-AzureStorageAccount -Prepare -StorageAccountName 'Your storage account name' # replace with yours ## IF at any point here you changed your mind, you can revert the migration using the following : # Move-AzureStorageAccount -Abort -StorageAccountName 'Your storage account name' # replace with yours Move-AzureStorageAccount -Commit -StorageAccountName 'Your storage account name' # replace with yours ``` ![Move-AzureStorageAccount](https://codeisahighway.com/content/images/2018/01/Move-AzureStorageAccount.png) You can confirm that your storage account is now under the resource provider Microsoft.Storage instead of Microsoft.ClassicStorage ```powershell Add-AzureRmAccount # enter your credentials Select-AzureRmSubscription -SubscriptionId 00000000-0000-0000-0000-000000000000 # replace with yours Find-AzureRmResource -ResourceNameContains 'Your storage account name' # replace with yours ``` ![Find-AzureRmResource](https://codeisahighway.com/content/images/2018/01/Find-AzureRmResource.png) > You'll notice that your storage account is under a new resource group, the name of your storage account + '-Migrated'. The good news with ARM resources is that you can move them in a new or existing resource group without a problem, on the contrary of when it was a classic resource. Have a good one! ## References - [AzureRm PowerShell v5.0.0](https://www.powershellgallery.com/packages/AzureRm/5.0.0?ref=codeisahighway.com) - [Azure PowerShell v5.0.0](https://www.powershellgallery.com/packages/Azure/5.0.0?ref=codeisahighway.com) - [Platform-supported migration of IaaS resources from classic to Azure Resource Manager](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/migration-classic-resource-manager-overview?ref=codeisahighway.com) ### List all App Service web apps outbound IP addresses used in a subscription URL: https://codeisahighway.com/list-all-app-service-web-apps-outbound-ip-addresses-used-in-a-subscription/ Last updated: 2026-08-10T07:12:49.000Z If you want to perform IP whitelisting against an App Service, you'll discover that on public instances of App Service (not App Service Environment) you have 4 or more outbound IP addresses. I was in a situation where I needed to get all outbound IP addresses over multiple subscriptions for IP whitelisting purposes. With the help of PowerShell I created a little script that will do just that here is an example of the output: ` .\Get-AppServiceWebAppsOutboundIpAddresses.ps1' -SubscriptionName 'mysub1','mysub2` ```powershell Switching to subscription mysub1 Switching to subscription mysub2 Count IpAddress Sites ----- ---- ----- 2 13.85.17.60 {sub1-bi-dev-as-webapp, sub2-bi-prod-as-webapp} 2 13.85.20.144 {sub1-bi-prod-as-webapp, sub1-bi-dev-as-webapp} 2 13.85.22.206 {sub2-bi-prod-as-webapp, sub1-bi-dev-as-webapp} 2 13.85.23.148 {sub1-bi-dev-as-webapp, sub2-bi-prod-as-webapp} 2 13.85.23.243 {sub1-bi-dev-as-webapp, sub2-bi-prod-as-webapp} 1 23.96.184.12 {sub1-dev-functions-mmckydd} 1 23.96.184.209 {sub1-dev-functions-mmckydd} 1 23.96.186.252 {sub1-dev-functions-mmckydd} 1 23.96.187.50 {sub1-dev-functions-mmckydd} 5 23.96.244.71 {sub1-stg-webapp-web-n7wfdda, sub1-stg-functions-n7wfdda, sub1-stg-webapp-admin-n7wfdda, sub1-dev-ops-functions-stl4tn5...} ``` If you are interested to have a sorted, unique list of IPs used in your App Services, this script is for you. You can get it on the Script Center: [https://gallery.technet.microsoft.com/scriptcenter/List-all-App-Service-web-4d563f14](https://gallery.technet.microsoft.com/scriptcenter/List-all-App-Service-web-4d563f14?ref=codeisahighway.com) ### MSDEVMTL - Azure : Let’s talk Hybrid Cloud with Clemens Vasters URL: https://codeisahighway.com/msdevmtl-azure-lets-talk-hybrid-cloud-with-clemens-vasters/ Last updated: 2026-07-31T19:44:29.000Z The summer is mostly here, and that usually mean a break for the community group, but the MSDEVMTL Azure Group still have one more surprise for you. When: **Friday morning on June 9th 2017** Speaker: **Clemens Vasters** Clemens is Microsoft's "Principal Messenger", driving global technical strategy for Microsoft's Azure Messaging platform services: Azure Service Bus, Azure Event Hubs, and Azure Relay. Title: **Systems Federation and Integration across Cloud, Fog, and Edge** > “Hybrid cloud” commonly describes how systems can be run with a combination of on-premises and public cloud assets, and how those systems can be integrated. This perspective is, however, largely constrained to data-center like assets, and typically to the scope of one organization. > > We will discuss how Microsoft sees this concept evolving into broadly federated systems that span different participating organizations, span private and public datacenters, and include intelligence at the system edge, inside traditional IT equipment as well as in consumer and industrial equipment. To illustrate the concept, we will lean on examples from the industrial automation realm, where this transformation is in full swing. > > The OPC Foundation's Unified Architecture has emerged as the clear winner for horizontal integration of production environments and vertical integration of such environments with their attached IT systems. We will discuss the next set of challenges that lie ahead given this common foundation: Each production line may have dozens of different stakeholders, from sensor to system, who each want to provide predictive-maintenance, remote-management, or X-as-a-service within that one production line as their “Industry 4.0” business objective. How does a sensor manufacturer get access to what telemetry from their product inside a component that is part of a machine installed in a production line? And through what path might they make a machine-learned optimizing correction? For this special event, we decided to remove the usual fee, so it's a FREE event! Get more detail and register quickly on the meetup page, seats are limited. Register here: [https://www.meetup.com/msdevmtl/events/239731426/](https://www.meetup.com/msdevmtl/events/239731426/?ref=codeisahighway.com) - [Clemens Vasters on Twitter](https://twitter.com/clemensv?ref=codeisahighway.com) - [Clemens Vasters on the web](https://vasters.com/?ref=codeisahighway.com) ### How to easily and silently obtain AccessToken (Bearer) from an existing Azure PowerShell session URL: https://codeisahighway.com/how-to-easily-and-silently-obtain-accesstoken-bearer-from-an-existing-azure-powershell-session/ Last updated: 2026-07-31T19:44:30.000Z More than often I need to call the Azure RM REST API to perform a variety of thing. Pretty much the only way you'll find to do it on the Internet in PowerShell is to authenticate a second time against the REST API to obtain a bearer token. I always thought that there must be another way because of there is a TokenCache... There it is... Here's a recipe that I have now included in my own PowerShell user profile that make obtaining an AccessToken from an authenticated Azure session a piece of cake... ### Updated on 2019-01-14 Added support for both AzureRM & Az modules. ### Updated on 2018-01-31 Tested code with AzureRM.Profile module v4.x. ## Setup information There is a very complex matrix of Windows/Azure PowerShell/Visual Studio versions out there, I cannot guarantee 100% this will work on your system but it should if you are not to far behind with Azure PowerShell. Here is what my system look like: Az modules - Windows 10 Version 1703 - PowerShell core 6.1.0 - Az.Accounts Version 1.x - Visual Studio 2015/2017 AzureRM modules - Windows 10 Version 1703 - PowerShell Version 5.1.15063.296 - AzureRM.Profile Version 2.x up tp 4.x - Visual Studio 2015/2017 ## The complicated ways you'll find everywhere What you'll see on the Internet as a solution for this is creating an Application in your AAD with a ServicePrincipal, then use the ServicePrincipal credentials to obtain the AccessToken. Then problem is that this is very dependant on what RBAC permissions you give to your application, this is not what I really want, manage another entity permission just to get AccessTokens. You also have a version that'll use the well-known PowerShell clientId & redirectUrl, preventing you from creating a new app in Azure AD but you'll still need to provide a username & password or clientId/password ``` # Set well-known client ID for Azure PowerShell $clientId = "1950a258-227b-4e31-a9cf-717495945fc2" # Set redirect URI for Azure PowerShell $redirectUri = "urn:ietf:wg:oauth:2.0:oob" ``` Better, but again, I still need to provide credentials to make it work. ## An easier way to obtain your AccessToken I have included this little function in my PowerShell user profile `$Home\[My ]Documents\WindowsPowerShell\Profile.ps1` ```PowerShell function Get-AzureRmCachedAccessToken() { $ErrorActionPreference = 'Stop' if(-not (Get-Module AzureRm.Profile)) { Import-Module AzureRm.Profile } $azureRmProfileModuleVersion = (Get-Module AzureRm.Profile).Version ... $currentAzureContext = Get-AzureRmContext ... Write-Debug ("Getting access token for tenant" + $currentAzureContext.Subscription.TenantId) $token = $profileClient.AcquireAccessToken($currentAzureContext.Subscription.TenantId) $token.AccessToken } ``` > You can download the full version (for free) on [Microsoft Script Center](https://gallery.technet.microsoft.com/scriptcenter/Easily-obtain-AccessToken-3ba6e593?ref=codeisahighway.com) What this code do is that it will use your session instance profile and use the TokenCache under the hood and return you an access token without having to authentication a second time. From there, simply call the function and pipe it in the clip.exe utility to put the AccessToken in Windows clipboard. ```PowerShell # Considering you have previously called # Add-AzureRmAccount || Login-AzureRmAccount ('Bearer {0}' -f (Get-AzureRmCachedAccessToken)) | Set-Clipboard ``` With this value in the clipboard I can now go in Postman, create a Header with the key `Authorization` and paste the value from the clipboard. > If you use `clip.exe` instead of `Set-Clipboard` you'll end up with an unwanted carriage return at the end of your token when pasting, hit the backspace key 1 time in order to remove it. I then have something like this in Postman ![Authorization Bearer Token](https://codeisahighway.com/content/images/2017/05/BearerTokenInPostman.png) ## Conclusion If you use the Azure RM REST API from time to time, this will likely change your life for the better ;) ## References - [Install Azure PowerShell](https://docs.microsoft.com/en-us/powershell/azure/install-azurerm-ps?view=azurermps-4.0.0&ref=codeisahighway.com) - [Understand the six PowerShell profiles](https://blogs.technet.microsoft.com/heyscriptingguy/2012/05/21/understanding-the-six-powershell-profiles/?ref=codeisahighway.com) ### Azure automation runbook invocation error when declaring array, Unable to cast object of type... to System.Object[] URL: https://codeisahighway.com/azure-automation-runbook-invocation-error-when-declaring-array-unable-to-cast-object-of-type-to-system-object-array/ Last updated: 2026-07-30T19:45:22.000Z Today I was implementing a snapshot/restore mechanism for virtual machines with the help of Azure Automation. After importing my script in Azure Automation, I encountered an error while invoking it. The message was: `Unable to cast object of type 'System.String' to type 'System.Object[]'`. ## The problem The script was running great from my workstation (I know, it works on my machine!). The problem started to occur when invoking the script from Azure Automation. I started by upgrading the Azure modules in the assets, which didn't help. I commented stuff out until I only got the parameters block declared, nothing else... Still failing, strange... I started to search for this message error online, nothing. I realized that the problem was with my `[string[]] $AzureVM` parameter declared like below: ```powershell param ( [Parameter(Mandatory)] [string]$ConnectionAssetName, [Parameter(Mandatory)] [string]$ServiceName, [Parameter(Mandatory)] [string[]]$AzureVM, [string]$VmExportConfigFolderPath = 'C:\ExportedVMs' ) ``` ## The solution I stumble upon an article on the web (see References) that was saying the following: > If you want to be able to start your runbooks from the Azure Automation portal using the Start Runbook wizard UI then keep these things in mind about input parameters: > > - The wizard UI allows you to input values for runbook parameters that can be represented by number, string, datetime, switch, boolean, Azure Automation credential asset name, JSON array, or JSON object. > - If a runbook has a parameter with a default value, this default value will appear in the UI; you can choose to use this value or change it. > - **If a runbook parameter takes an \[array\] or \[object\] type, then these must be passed in JSON format in the start runbook dialog.** For example: > - A parameter of type \[object\] that expects a property bag can be passed in the UI with a JSON string formatted like this: {"StringParam":"Joe","IntParam":42,"BoolParam":true}. > - A parameter of type \[array\] can be input with a JSON string formatted like this: \["Joe",42,true\]. That's it, that was my error. I was writing my string value as a regular string and not in a JSON notation. I changed the value for this parameter in the UI from `vmName` to `['vmName']` and it started to work. Hope it helps you save some debugging time. ## References - [Azure Automation: Runbook Input, Output, and Nested Runbooks](https://azure.microsoft.com/en-us/blog/azure-automation-runbook-input-output-and-nested-runbooks/?ref=codeisahighway.com) ### How to easily deploy Azure Hybrid Use Benefit (BYOL) virtual machines from marketplace images and Azure Resource Manager Template URL: https://codeisahighway.com/how-to-easily-deploy-bring-your-own-license-byol-virtual-machines-from-marketplace-images-and-azure-resource-manager-template/ Last updated: 2026-07-30T19:45:24.000Z Not so long ago it was possible (but painful) to deploy Windows Server virtual machines with the Azure Hybrid Use Benefit. I am glad to let you know that it's not a pain anymore! Let me walk you through how to do this in way fewer steps and using only Azure Resource Manager templates and marketplace images (also possible in pure PowerShell) ## Why Azure Hybrid Use Benefit? One of the major benefits of using Azure Hybrid Use Benefit is saving, up to 40% in some cases. Basically you pay the price of the virtual machine without the Windows licenses cost, think of it as paying the same price as a Linux virtual machine in Azure. > Use your on-premises Windows Server licenses that include Software Assurance to save big on Windows Server VMs in Azure. By using your existing licenses, you pay the base compute rate and save up to 40 percent. ## Why is it simpler now? Azure now have Bring Your Own Licenses (BYOL) images of Windows Server and Windows 10 directly in the marketplace. This is what you needed to do before: - Install Windows 10 or Windows Server on an On-Premise machine - Sysprep the installation - Upload the vhd to a storage account - Create a VM (by template or script) using the custom image This is what you need to do now to achieve the same thing: - Create a VM (by template or script) using the new marketplace BYOL image ## How to get the image names Using PowerShell you can call the following ```powershell Get-AzureRmVMImagesku -Location westus -PublisherName MicrosoftWindowsServer -Offer WindowsServer ``` ![](https://codeisahighway.com/content/images/2017/04/Get-AzureRmVmImageSku.png) You can see the some now contains the **BYOL** suffix, simply select one of theses instead of your regular image and that's it! Advertised available images: 2016-Datacenter version 2016.127.20170406 or above 2012-R2-Datacenter version 4.127.20170406 or above 2012-Datacenter version 3.127.20170406 or above 2008-R2-SP1 version 2.127.20170406 or above For Windows Client: ```powershell Get-AzureRMVMImageSku -Location "West US" -Publisher "MicrosoftWindowsServer" -Offer "Windows-HUB" ``` ## Use this image inside your ARM template To use the BYOL/HUB image sku in your deployment, put the image sku you want in the `sku` property on the `imageReference` object under the `storageProfile` of your virtual machine `"sku": "2012-R2-Datacenter-BYOL"` like in this: (note: this is only a subset of a virtual machine resource) ```json "storageProfile": { "imageReference": { "publisher": "MicrosoftWindowsServer", "offer": "WindowsServer", "sku": "2012-R2-Datacenter-BYOL", "version": "latest" }, "osDisk": { "name": "[parameters('virtualMachineName')]", "createOption": "fromImage", "managedDisk": { "storageAccountType": "Premium_LRS" } }, "dataDisks": [] } ``` Once your virtual machine is created, remote desktop into it and you'll see that it is not registered and you'll be able to enter your product key. ![](https://codeisahighway.com/content/images/2017/04/Enter-ProductKey.png) Happy saving in Azure! ## References - [Azure Hybrid Use Benefit for Windows Server and Windows Client](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/hybrid-use-benefit-licensing?ref=codeisahighway.com#deploy-a-vm-using-the-azure-marketplace) - [Save up to 40 percent on Windows Server virtual machines with the Azure Hybrid Use Benefit](https://azure.microsoft.com/en-us/pricing/hybrid-use-benefit/?ref=codeisahighway.com) ### Creating Azure Key Vault with logging using Azure Resource Manager ARM templates URL: https://codeisahighway.com/creating-azure-key-vault-with-logging-using-azure-resource-manager-arm-templates/ Last updated: 2026-07-17T08:31:55.000Z If you are looking to create an Azure Key Vault, have full visibility/traceability over who access it and what they did while preventing accidental deletes of your vault, you are at the right place. Let me show you how to achieve this using well-known best practices and patterns like template linking in Azure Resource Manager templates. ## What this solution do? - Create Key vault - Create Storage Account - Enable Key Vault logging on storage account - Optionally creates resource locks on Key Vault and Storage Account to protect them. ## What Is Azure Key Vault? Key Vault help you safeguard cryptographic keys and other secrets used by your applications whenever they are On-Premise or in the cloud. More and more services on Azure are now integrating Azure Key Vault as their secret/key source for things like deployments, data or even disk encryption. **Assumptions** This article assumes you have basic knowledge and experience with ARM templates. That you know how to configure a resource type in the Resource section of a template. If you don't and need more information about ARM templates, please take a look here before going further: [Authoring Azure Resource Manager templates](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authoring-templates?ref=codeisahighway.com) ## Why do all this in templates when we can script it? A huge benefit of ARM templates is that they are idempotent. So if something fails, you can re-run them without having to worry about cleaning up first. They are mostly optimized for what the state *should* be, rather than how to get there... Also because I love challenges ;) It's true that you can do all of this in PowerShell or Azure-CLI but I wanted to prove myself that I could do it all using an ARM template without much existing documentation. After a lot of trials & errors, I found out how to do it about a year ago. For many good and less good reasons, I didn't take the time to format and share that knowledge. This week I finally took the time to clean the recipe I had, pimp it a bit & share it on the Azure Resource Manager QuickStart Templates repository on GitHub. It is an incredible source of knowledge about Azure Resource Manager templates. You will find the templates under **201-key-vault-with-logging-create**. ## What is Template linking? This was taken from Microsoft documentation: > From within one Azure Resource Manager template, you can link to another template, which enables you to decompose your deployment into a set of targeted, purpose-specific templates. As with decomposing an application into several code classes, decomposition provides benefits in terms of testing, reuse, and readability. > > You can pass parameters from a main template to a linked template, and those parameters can directly map to parameters or variables exposed by the calling template. The linked template can also pass an output variable back to the source template, enabling a two-way data exchange between templates. You can see from this description that template linking is pretty useful when we want to decompose your deployment into a set of targeted, purpose-specific templates. It helps us with testing, reuse, and readability... but I will also add to the list: **mimic conditional logic** in your templates. ## What is Resources locking? This was taken from Microsoft documentation: > As an administrator, you may need to lock a subscription, resource group, or resource to prevent other users in your organization from accidentally deleting or modifying critical resources. You can set the lock level to CanNotDelete or ReadOnly. It is important to understand that the lock levels are in the management(control) plane as explained below: > Resource Manager locks apply only to operations that happen in the management plane, which consists of operations sent to [https://management.azure.com](https://management.azure.com/?ref=codeisahighway.com). The locks do not restrict how resources perform their own functions. Resource changes are restricted, but resource operations are not restricted. For example, a ReadOnly lock on a SQL Database prevents you from deleting or modifying the database, but it does not prevent you from creating, updating, or deleting data in the database. Data transactions are permitted because those operations are not sent to [https://management.azure.com](https://management.azure.com/?ref=codeisahighway.com). ## Digging into 201-key-vault-with-logging-create The solution consists of 3 templates, one master that creates all the resources and two other templates for the conditional logic around resources locking. Only one of them will get called depending on if you want to protect your resources with locks or not. ### Master template parameters Here are the parameters you will find in the master template: ```json "parameters": { "keyVaultName": { "type": "string", "minLength": 1, "metadata": { "description": "KeyVault name" } }, "accessPolicies": { "type": "array", "defaultValue": "{}", "metadata": { "description": "Access policies object {\"tenantId\":\"\",\"objectId\":\"\",\"permissions\":{\"keys\":[\"\"],\"secrets\":[\"\"]}}" } }, "diagnosticStorageAccountName": { "type": "string", "metadata": { "description": "Specifies the name of the storage account where diagnostics logs will be written" } }, "logsRetentionInDays": { "type": "int", "defaultValue": 0, "minValue": 0, "maxValue": 365, "metadata": { "description": "Specifies the number of days that logs are gonna be kept. If you do not want to apply any retention policy and retain data forever, set value to 0." } }, "enableVaultForDeployment": { "type": "bool", "defaultValue": false, "allowedValues": [ true, false ], "metadata": { "description": "Specifies if the vault is enabled for deployment by script or compute (VM, Service Fabric, ...)" } }, "enableVaultForTemplateDeployment": { "type": "bool", "defaultValue": false, "allowedValues": [ true, false ], "metadata": { "description": "Specifies if the vault is enabled for a template deployment" } }, "enableVaultForDiskEncryption": { "type": "bool", "defaultValue": false, "allowedValues": [ true, false ], "metadata": { "description": "Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." } }, "vaultSku": { "type": "string", "defaultValue": "Standard", "allowedValues": [ "Standard", "Premium" ], "metadata": { "description": "Specifies the SKU for the vault" } }, "protectWithLocks": { "type": "string", "allowedValues": [ "enabled", "disabled" ], "defaultValue": "disabled" } } ``` The parameters are pretty straightforward. What is interesting here is how we declare the `protectWithLocks` parameter and how we use it in the template. It is of type `string` and we allow only a restricted set of values, `enabled` and `disabled`. We need to have a parameter of type string & allowed values to achieve our goal, which is to mimic conditional logic (otherwise not possible out of the box) in templates. ### Master template variables We assemble a complex variable object named `template`. The `base` member is a static variable that contain the base URI of our templates on GitHub. The `protectWithLocks` member is a dynamic variable that use the `concat` template function to build the linked template name to call from the master template. 1. 'nestedtemplates/protectwithlocks' 2. 'enabled'|'disabled' 3. '.json' ```json "variables": { "template": { "base": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-key-vault-with-logging-create/", "protectWithLocks": "[concat('nestedtemplates/protectwithlocks', parameters('protectWithLocks'), '.json')]" }, "uniqueString": "[uniqueString(subscription().id, resourceGroup().id)]", "diagnosticStorageAccountName": "[toLower( substring( replace( concat( parameters('keyVaultName'), variables('uniqueString'), variables('uniqueString') ), '-', ''), 0, 23) )]" } ``` If we set the `protectWithLocks` parameter to value `enabled`, the `template` variable will end up with the value `nestedtemplates/protectwithlocksenabled.json` for member `protectWithLocks`. We also generate 24 unique characters value for the `diagnosticStorageAccountName` variable based on the `keyVaultName` parameter and unique values generated using the 'uniqueString' template function. ### Master template resources #### Key Vault We define the Key Vault resource and also (this is where the magic hookup happens) the Key Vault logging using the resource type `Microsoft.KeyVault/vaults/providers/diagnosticsettings`. ```json { "type": "Microsoft.KeyVault/vaults", "name": "[parameters('keyVaultName')]", "apiVersion": "2016-10-01", "Location": "[resourceGroup().location]", "tags": { "displayName": "Key Vault with logging" }, "properties": { "enabledForDeployment": "[parameters('enableVaultForDeployment')]", "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", "tenantId": "[subscription().tenantId]", "accessPolicies": "[parameters('AccessPolicies')]", "sku": { "name": "[parameters('vaultSku')]", "family": "A" } }, "resources": [ { "type": "Microsoft.KeyVault/vaults/providers/diagnosticsettings", "name": "[concat(parameters('keyVaultName'), '/Microsoft.Insights/service')]", "apiVersion": "2016-09-01", "Location": "[resourceGroup().location]", "dependsOn": [ "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]", "[concat('Microsoft.Storage/storageAccounts/', variables('diagnosticStorageAccountName'))]" ], "properties": { "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('diagnosticStorageAccountName'))]", "logs": [ { "category": "AuditEvent", "enabled": true, "retentionPolicy": { "enabled": true, "days": "[parameters('LogsRetentionInDays')]" } } ] } } ] } ``` The name of the Key Vault logging resource needs to be the name of your vault appended with `/Microsoft.Insights/service`. We link to the desired storage account using the `storageAccountId` property. Using the parameter `LogsRetentionInDays` we control how long we want the logs to be kept. Allowed values are from 0 to 365, if you choose 0, logs will be kept indefinitely. #### Storage Account Nothing fancy here, we define the storage account that is used exclusively for Key Vault logging. It is a good practice to keep it isolated so you can restrict to a maximum who can access the information stored in there using RBAC & Shared Access Signatures (SAS tokens). ```json { "type": "Microsoft.Storage/storageAccounts", "name": "[variables('diagnosticStorageAccountName')]", "apiVersion": "2016-12-01", "Location": "[resourceGroup().location]", "sku": { "name": "Standard_LRS" }, "kind": "Storage", "tags": { "displayName": "concat('Key Vault ', parameters('keyVaultName'), ' diagnostics storage account')" }, "properties": {} } ``` #### Master template linked template This is where we call the resources locking template. ```json { "type": "Microsoft.Resources/deployments", "name": "protectWithLocks", "apiVersion": "2016-09-01", "properties": { "mode": "Incremental", "templateLink": { "uri": "[concat(variables('template').base, variables('template').protectWithLocks)]", "contentVersion": "1.0.0.0" }, "parameters": { "keyVaultName": { "value": "[parameters('keyVaultName')]" }, "diagnosticStorageAccountName": { "value": "[variables('diagnosticStorageAccountName')]" } } }, "dependsOn": [ "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]", "[concat('Microsoft.Storage/storageAccounts/', variables('diagnosticStorageAccountName'))]" ] } ``` ### ProtectWithLocksDisabled template This is an empty template that does nothing. As the name states, if we ended up calling this template it's because we don't want resource locks. Note: If there are locks already present on the resources because of a previous deployment or manual intervention, we cannot undo this using a template without impacting all other resources in the resource group. In short, it will not remove locks once applied, you will need to do it yourself. ```json { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { "type": "string", "minLength": 1, "metadata": { "description": "Specifies the name of the Key Vault to lock" } }, "diagnosticStorageAccountName": { "type": "string", "metadata": { "description": "Specifies the name of the storage account to lock" } } }, "variables": {}, "resources": [], "outputs": {} } ``` ### ProtectWithLocksEnabled template This template creates 2 resources locks. One for the vault and one for the vault logging storage account. ```json { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { "type": "string", "minLength": 1, "metadata": { "description": "Specifies the name of the Key Vault to lock" } }, "diagnosticStorageAccountName": { "type": "string", "metadata": { "description": "Specifies the name of the storage account to lock" } } }, "variables": {}, "resources": [ { "comments": "Resource lock on Key Vault", "type": "Microsoft.KeyVault/vaults/providers/locks", "name": "[concat(parameters('keyVaultName'), '/Microsoft.Authorization/keyVaultDoNotDelete')]", "apiVersion": "2016-09-01", "properties": { "level": "CannotDelete" } }, { "comments": "Resource lock on diagnostics storage account", "type": "Microsoft.Storage/storageAccounts/providers/locks", "name": "[concat(parameters('diagnosticStorageAccountName'), '/Microsoft.Authorization/storageDoNotDelete')]", "apiVersion": "2016-09-01", "properties": { "level": "CannotDelete" } } ], "outputs": {} } ``` Hope this helps you in your journey for a safer use of sensitive information in the cloud! *A special thank you to Sumedh Barde of the Azure Key Vault team for his help reviewing this blog post.* ### Resources - [Azure Resource Manager QuickStart Templates](https://github.com/Azure/azure-quickstart-templates?ref=codeisahighway.com) - [201-key-vault-with-logging-create](https://github.com/azure/azure-quickstart-templates/tree/master/201-key-vault-with-logging-create?ref=codeisahighway.com) - [Using linked templates when deploying Azure resources](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-linked-templates?ref=codeisahighway.com) - [Lock resources to prevent unexpected changes](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-lock-resources?ref=codeisahighway.com) - [Azure Resource Manager template functions](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions?ref=codeisahighway.com) ### Free Training! Azure Day is coming to Montreal January 17th 2017 URL: https://codeisahighway.com/free-training-azure-day-is-coming-to-montreal-january-17th-2017/ Last updated: 2026-07-31T19:44:32.000Z Microsoft will hold a free full day of training around data and DevOps. Register soon as seats are limited! There is two tracks in the day: ## Data Cortana Intelligence – Internet of Things Lab **Objective:** Enable users with the ability to customize Azure IoT Suite solutions and their integrated components. Users should be able to create a solution, add devices and manipulate rules and outputs. Finally, users will be shown how to integrate device data and outputs to see their use in line of business applications and workflows. **Audience:** Database, data warehouse, and Business Intelligence practice leads and architects **Agenda:** Module 1: Overview of Microsoft Azure IoT Suite, Lab 1: Provision an IoT Suite solution and add devices. Module 3: Advanced solutions and integration, Lab 3: Integrate device and alert data into business workflows. ### Schedule 9am-12pm - Track: Internet of Things 1pm-4pm - Track: Machine Learning 6pm-9pm - Track: Machine Learning ## DevOps - Open Source & .NET Parts Unlimited MRP is a fictional outsourced Manufacturing Resource Planning (MRP) application for training purposes based on the description in chapters 31-35 of The Phoenix Projectby Gene Kim, Kevin Behr and George Spafford. © 2013 IT Revolution Press LLC, Portland, OR. Resemblance to “Project Unicorn” in the novel is intentional; resemblance to any real company is purely coincidental. The application uses entirely open source software including Linux, Java, Apache, and MongoDB which creates a web front end, an order service, and an integration service. Click here for the related [Parts Unlimited Website application](http://github.com/microsoft/partsunlimited?ref=codeisahighway.com). To read more about this project, please visit the [documentation website](https://microsoft.github.io/PartsUnlimitedMRP/aka.ms/pumrplabs?ref=codeisahighway.com). You may watch a demo in [Channel 9](https://channel9.msdn.com/Blogs/TalkDevOps/TalkDevOps--Deploying-a-Java-application-with-VSTS?ref=codeisahighway.com) that walks through many of the steps in the document. **Fundamentals** Continuous Integration – C.I Continuous Deployment – C.D Infrastructure as Code – IaC Configuration Management – ConfMgnt **Advanced** Microservices using Azure Container Service or Docker Swarm Automated Security Testing in production A/B Testing ### Schedule 9am-12pm - Track: Open Source (Parts Unlimited MRP) OR .NET (Parts Unlimited) 1pm-4pm - Track: Open Source (Parts Unlimited MRP) OR .NET (Parts Unlimited) 6pm-9pm - Track: Open Source (Parts Unlimited MRP) OR .NET (Parts Unlimited) ### How to enable the public preview of IaaS backups with Recovery Services in Canada using PowerShell URL: https://codeisahighway.com/how-to-enable-backups-with-recovery-services-in-canada-in-powershell/ Last updated: 2026-07-17T08:32:18.000Z We have a lot of customers that want to use Canadian regions on Azure. Azure Recovery Services in Canada is not available in the portal as the moment of writing this article. A solution without a solid backup strategy is not really serious and cannot even be considered IMO. What can we do from here if you really need to be in a Canadian region? There is a way to create Recovery Services resources in Canada but there is a little twist to enable it. ## Problem Recovery Services is available in a lot of Azure regions but not all features are yet ready for the Canadian regions (Hybrid backup is an example) so it is not publicly available in Canada. ## There is a way! You can activate the preview of ASR in Canada using PowerShell in a matter of seconds, to do so, you can use the following script: ``` #requires -Version 2.0 -Modules AzureRM.Profile, AzureRM.Resources param( [Parameter(Mandatory = $true)][string]$SubscriptionName ) $ErrorActionPreference = 'Stop' Add-AzureRmAccount Set-AzureRmContext -SubscriptionName $SubscriptionName Register-AzureRmResourceProvider -ProviderNamespace Microsoft.RecoveryServices Register-AzureRmProviderFeature -FeatureName RecoveryServicesCanada -ProviderNamespace Microsoft.RecoveryServices ``` The registration state should indicate *Registering* to not long after change to *Registered*. If you want, you can get the status of the registration state using the following command: ``` Get-AzureRmProviderFeature -FeatureName RecoveryServicesCanada –ProviderNamespace Microsoft.RecoveryServices ``` It might take a couple of minutes for the change to be effective in the portal. You can sign out and sign in again into the Azure portal to ensure the desired option is visible to you. ## Wait did you say "Preview" ? What about SLA ? Even if it's available in preview for Canadian regions, you'll get the same SLA that applies to ASR in other regions, meaning it is considered safe for your production workloads. ### References - [Azure Search and Backup available in Canada](https://azure.microsoft.com/en-us/blog/azure-search-and-backup-available-in-canada/?ref=codeisahighway.com) ### Error when deploying App Service Plan using template, 'Required property 'name' not found in JSON. Path ''.' URL: https://codeisahighway.com/error-when-deploying-app-service-plan-using-template-required-property-name-not-found-in-json-path/ Last updated: 2026-07-31T19:44:33.000Z Just a quick article to save you the time it took me to realize what exactly was the problem in my template because the error message was not of much help here ;) I exported an Azure template from an existing resource group in the portal. The resulting template had a lot of resources and properties that are not necessary IMO and that honestly mix me up more than it should but this is another debate for the Azure team ;) So after a lot of refactoring in my template to remove a lot of "noise" from it, I ended up with the following error while deploying this particular resource: ``` { "type": "Microsoft.Web/serverfarms", "name": "unique-name-of-my-app-service", "apiVersion": "2015-08-01", "location": "Canada East", "sku": { "tier": "Basic", "size": "B2", "family": "B", "capacity": 1 }, "properties": { "numberOfWorkers": 1 } } ``` New-AzureRmResourceGroupDeployment : 7:48:44 AM - Error: Code=InvalidTemplate; Message=Deployment template parse failed: 'Required property 'name' not found in JSON. Path ''.'. At J:\\wkspc\\Invoke-AzureProvisioning.ps1:19 char:1 - New-AzureRmResourceGroupDeployment -ResourceGroupName $rg.ResourceGro ... - ``` + CategoryInfo : NotSpecified: (:) [New-AzureRmResourceGroupDeployment], Exception + FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDeploymentCmdlet ``` New-AzureRmResourceGroupDeployment : The deployment validation failed At J:\\wkspc\\Invoke-AzureProvisioning.ps1:19 char:1 - New-AzureRmResourceGroupDeployment -ResourceGroupName $rg.ResourceGro ... - ``` + CategoryInfo : CloseError: (:) [New-AzureRmResourceGroupDeployment], InvalidOperationException + FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDeploymentCmdlet ``` The problem was that in my refactoring I ended up removing the **sku/name** member among other things and it was that *name* the error message was referring to . ```json { "type": "Microsoft.Web/serverfarms", "name": "unique-name-of-my-app-service", "apiVersion": "2015-08-01", "location": "Canada East", "sku": { "name": "B2", "tier": "Basic", "size": "B2", "family": "B", "capacity": 1 }, "properties": { "numberOfWorkers": 1 } } ``` After working a bit more with the app service plan resource I ended up with the following slimmed version: ```json { "type": "Microsoft.Web/serverfarms", "name": "unique-name-of-my-app-service", "apiVersion": "2015-08-01", "location": "Canada East", "sku": { "name": "S1", "tier": "Standard", "capacity": 1 }, "properties": {} } ``` Have a good gay deploying template in Azure!! ### Breaking change with Get-AzureRmStorageAccountKey in AzureRM.Storage v1.1.0 - AzureRM v1.4.0 URL: https://codeisahighway.com/breaking-change-with-get-azurermstorageaccountkey-in-azurerm-storage-v1-1-0-azurerm-v1-4-0/ Last updated: 2026-08-10T07:12:48.000Z A nasty breaking change has slipped into version 1.1.0 of AzureRM.Storage which coincide with the release v1.4.0 of AzureRM module. If you use the return object of the `Get-AzureRmStorageAccountKey` command you are impacted. This is because the object that was coming out of Get-AzureRmStorageAccountKey was `Microsoft.Azure.Management.Storage.Models.StorageAccountKeys` and it is now a list of `Microsoft.Azure.Management.Storage.Models.StorageAccountKey` objects. ## The old output In your code you probably have a code like this... You get the storage account keys to then create a storage context. ```powershell $keys = Get-AzureRmStorageAccountKey -ResourceGroupName $ResourceGroupName -Name $StorageAccountName $context = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $keys.Key1 ``` Before, each key was stored as a string in `Key1` and `Key2` properties. - $keys.Key1 - $keys.Key2 ## The new output The new type is a `List`. Each object in the list has 3 members: `KeyName`, `Value` & `Permissions`. ![New output object of Get-AzureRmStorageAccountKey](https://codeisahighway.com/content/images/2016/05/Get-AzureRmStorageAccountKey-NewOutput.png) To get the keys you now need to do this: - $keys\[0\].Value - $keys\[1\].Value ## Anothe, simplier way to obtain an AzureStorageContext If you need to get the keys only to create an `Microsoft.WindowsAzure.Commands.Common.Storage.AzureStorageContext` object you can use the `.Context` member of a `Microsoft.Azure.Commands.Management.Storage.Models.PSStorageAccount` object like this: ```powershell $storage = Get-AzureRmStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName $storage.Context ``` ![Another way to obtain a storage account context](https://codeisahighway.com/content/images/2016/05/StorageAccount-Context.png) ![Microsoft.Azure.Commands.Management.Storage.Models.PSStorageAccount.Context](https://codeisahighway.com/content/images/2016/05/Storage-Context.png) ## Conclusion This is a breaking change and should not have ended up in a minor version upgrade like it did. Microsoft need to be more cautious and build checks to prevent this from happening again. This will impact a LOT of scripts out there. ### HowTo: Purge an Azure CDN endpoint using Azure PowerShell v1.x URL: https://codeisahighway.com/howto-purge-an-azure-cdn-endpoint-using-azure-powershell-v1-x/ Last updated: 2026-08-10T07:12:46.000Z Not long ago, one of my colleagues asked me how he could automate the purge of an Azure CDN endpoint. I browsed around a bit with him and the only documentation we've found talked about calling the Azure CDN REST API, meaning acquiring a bearer token and all. I said to myself, there must be something simpler out there but what? For those who know me, I prefer to use PowerShell or Azure-CLI whenever possible and in this article, I'll show you how to achieve the very same result using **native** Azure PowerShell v1.x commands. UPDATE 2016-05-11: This article has been updated following discussions with Kuangwei Zhang & Cam Soper from Microsoft, thank you guys. ## Why purge? Here is an extract from the Azure documentation that explains well why you would want to purge your CDN endpoint. > Sometimes you may wish to purge cached content from all edge nodes and force them all to retrieve new updated assets. This might be due to updates to your web application, or to quickly update assets that contain incorrect information. ## Let's dig into the AzureRM.Cdn module If we look at what is available in v1.0.1 of the AzureRM.Cdn module, you'll see that there's no native commands with the *Purge* keyword in there. This is because purge is not an approved verb in PowerShell. The team decided to go with the Publish/Unpublish combinaison. ```powershell Get-Command -Module AzureRM.Cdn ``` ![List of available commands in v1.0.1 of AzureRM.Cdn](https://codeisahighway.com/content/images/2016/05/AzureRm-Cdn-v1-0-1-Commands.png) ## The Solution If you need to determine your CDN profile and endpoint name, you can use the [Azure Portal](https://portal.azure.com/?ref=codeisahighway.com) or [Azure Resource Explorer](https://resources.azure.com/?ref=codeisahighway.com). Here is how you can determine the required values in Resource Explorer: ![CDN profiles and endpoints in Azure Resource Explorer](https://codeisahighway.com/content/images/2016/05/CDN-ProfileName-EndpointName.png) And finally how to invoke the purge command using `Unpublish-AzureRmCdnEndpointContent`: ```powershell Unpublish-AzureRmCdnEndpointContent ` -ResourceGroupName $ResourceGroupName ` -ProfileName $ProfileName ` -EndpointName $EndpointName ` -PurgeContent '/*' ``` or if you already have your endpoint object in hand ```powershell $endpoint = Get-AzureRmCdnEndpoint -ResourceGroupName $ResourceGroupName ` -ResourceGroupName $ResourceGroupName ` -ProfileName $ProfileName ` -EndpointName $EndpointName $endpoint | Unpublish-AzureRmCdnEndpointContent -PurgeContent = '/*' ``` Happy automation with the Azure CDN! ## Reference - [MSDN - Unpublish-AzureRmCdnEndpointContent command reference](https://msdn.microsoft.com/en-us/library/mt703237.aspx?f=255&MSPPError=-2147217396&ref=codeisahighway.com) - [Purge an Azure CDN endpoint](https://azure.microsoft.com/en-us/documentation/articles/cdn-purge-endpoint/?ref=codeisahighway.com) ### Azure DSC Extension error - A previous attempt to install Win8.1AndW2K12R2-KB3066437-x64.msu failed URL: https://codeisahighway.com/azure-vm-dsc-extension-error-a-previous-attempt-to-install-win8-1andw2k12r2-kb3066437-x64-msu-failed/ Last updated: 2026-07-31T19:44:37.000Z Sometimes you make stupid mistakes that cost you a lot of time and today was a day like this. ## The context We wanted to use a fixed version of the *Microsoft.Powershell.DSC* VM extension for our Windows virtual machines in our ARM template. We were using version 2.8 of the extension and had enabled the *autoUpgradeMinorVersion*. We had an error that started to occur only recently with our DSC configuration and we wanted to use a static version of the DSC extension to help us troubleshoot. We decided to go back a couple of versions and selected 2.6 as it was not that far behind 2.8. This is where we started to receive the errors when the VM was installing the DSC extension agent. **A previous attempt to install Win8.1AndW2K12R2-KB3066437-x64.msu failed; please check the logs on the VM (C:\\WindowsAzure\\Logs\\Plugins\\Microsoft.Powershell.DSC\\2.6.0.0)** We uninstalled the DSC extension from the VM, increased the version to 2.7, same thing... **A previous attempt to install Win8.1AndW2K12R2-KB3066437-x64.msu failed; please check the logs on the VM (C:\\WindowsAzure\\Logs\\Plugins\\Microsoft.Powershell.DSC\\2.7.0.0)** We came back to the version that was in our template, 2.8, same error again... **A previous attempt to install Win8.1AndW2K12R2-KB3066437-x64.msu failed; please check the logs on the VM (C:\\WindowsAzure\\Logs\\Plugins\\Microsoft.Powershell.DSC\\2.8.0.0)** Damn... ## The Solution Probably due to a lack of sleep last night and the fact that we were having another error before but we overlooked what was the current version of the handler out there. At the time of writing this article, the current version is 2.17. We removed the DSC extension from our VMs, updated the type handler version to the latest version available and it started to work again. We still encountered the first error but at least we were running on a fixed version of the extension and form here we will be able to go back a couple of version back. ## Conlusion What is to retain of all that? First sleep well and the other thing, be cautious if you want to disable the *autoUpgradeMinorVersion* option, it might bite you back after a few weeks or months because the VM image you are using contains updates that are incompatible with the DSC extension you are referring. ## References - [Release history for the Azure DSC Extension](https://blogs.msdn.microsoft.com/powershell/2014/11/20/release-history-for-the-azure-dsc-extension/?ref=codeisahighway.com) ### HowTo: Perform POST call to Azure REST API using Invoke-AzureRmResourceAction PowerShell command URL: https://codeisahighway.com/howto-perform-post-call-to-azure-rest-api-using-invoke-azurermresourceaction-powershell-command/ Last updated: 2026-07-17T08:33:13.000Z Not long ago, one of my colleagues asked me how we could automate an action that was not quite available in the Azure PowerShell cmdlets. Sure we can use Azure REST API, meaning acquiring a bearer token and all, but if I have the choice, I prefer to stay away from this. I'll show you how to perform POST action on resources on Azure using **native** Azure PowerShell v1.x commands. ## Update 2019-09-24: You can use Invoke-AzResourceAction on `Az` Azure PowerShell Module. 2019-09-24: Fixed Cdn purge code `@{ ContentPaths = @('/*') }`. Thanks Roland Le Franc for reporting the error. # A little hidden gem There is a hidden gem in the AzureRM.Resources commands named `Invoke-AzureRmResourceAction` and I use it from time to time to perform POST call against Azure REST APIs for functionalities that are not yet surfaced as native commands in PowerShell. ![Invoke-AzureRmResourceAction command in Azure.RM.Resources module](https://codeisahighway.com/content/images/2016/05/AzureRm-Resources-Commands.png) ## How to use it First, you need to determine what action you want to perform. To obtain the list of all available action you can execute the following command: ```powershell Get-AzureRmProviderOperation -OperationSearchString * | Where { $_.Operation -like '*action' } | Format-Table ``` Let's say you are after the purge action of the Microsoft.Cdn resource provider, you can always do ```powershell Get-AzureRmProviderOperation -OperationSearchString Microsoft.Cdn/* | Where { $_.Operation -like '*action' } | Format-Table ``` ![List of available actions for Microsoft.Cdn resource provider](https://codeisahighway.com/content/images/2016/05/Get-AzureRmProviderOperation-Microsoft-Cdn.png) You need to locate the desired action, and note what is the OperationName for it. Finally how to invoke the purge command using `Invoke-AzureRmResourceAction`: ```powershell Invoke-AzureRmResourceAction ` -ResourceGroupName $ResourceGroupName ` -ResourceType 'Microsoft.Cdn/profiles/endpoints' ` -ResourceName $ProfileName/$EndpointName ` -ApiVersion '2017-10-12' ` -Action 'Purge' ` -Parameters @{ ContentPaths = @('/*') } ` -Force ``` Happy automation! ## Reference - [MSDN - Get-AzureRmProviderOperation command reference](https://msdn.microsoft.com/en-us/library/mt603720.aspx?ref=codeisahighway.com) - [MSDN - Invoke-AzureRmResourceAction command reference](https://msdn.microsoft.com/en-us/library/mt652481.aspx?ref=codeisahighway.com) ### Global Azure Bootcamp 2016 - Montreal (Samedi 16 avril 2016) URL: https://codeisahighway.com/global-azure-bootcamp-2016-montreal-samedi-16-avril-2016/ Last updated: 2026-08-10T07:12:45.000Z Cette année encore, on remet ça pour le Global Azure BootCamp à Montréal et toute la journée sera consacré à Service Fabric! ## Quand et où? Samedi 16 Avril 2016 9:00 à 16:00 Microsoft Montréal (5e) 2000 McGill College, 5e étage, Montréal, QC, Montréal, QC [Global Azure Bootcamp 2016 Montréal](http://www.meetup.com/msdevmtl/events/223840152/?ref=codeisahighway.com) ## Les micro-services et Azure Service Fabric Conférenciers: - Alexandre Brisebois, Microsoft - Stéphane Lapointe, Orckestra - François Boucher, Lixar Durée: 9h00 à 16h00 Nous vous proposons une journée complète sur les micro-services et Azure Service Fabric, le but étant d'appendre la théorie avec une série de présentations pour ensuite concrétiser le tout avec une partie pratique "hands-on" et des labs. Pour participer, vous devrez obligatoirement apporter votre ordinateur portable, avoir installé Visual Studio 2015 et avoir un compte Azure. Le compte Azure doit avoir créé été créé AVANT le début de la journée. Requis pour votre laptop Windows 7, 8, 8.1, 10 Visual Studio 2015 Update 1 ou Update 2 Service Fabric SDK v2.0.135 Bouffe Les beignes seront offerts le matin. Pensez à apporter votre café (Starbucks et Second Cup à proximité). Pizza et boisson gazeuse le midi. Coût Merci à nos commanditaires qui nous permettent de vous présenter cette journée tout à fait gratuitement. Pas besoin d'avoir payé le membership annuel pour assister. ### How to refer an Azure Key Vault secret in an Azure Resource Manager deployment template URL: https://codeisahighway.com/how-to-refer-an-azure-key-vault-secret-in-an-azure-resource-manager-deployment-template/ Last updated: 2026-08-10T07:12:38.000Z We live in a world where data and security is not to be taken lightly. Having to create or maintain a system that enable you to keep secrets and/or certificates safe is a challenge in itself. In this particular article we'll see how to refer and inject the value of a secret kept in Azure Key Vault in an ARM template. ## Prerequisites - Azure PowerShell cmdlets **v1.0.4** or later - an existing Azure Key Vault with at least one secret with proper permissions. If you need help creating an Azure Key Vault, see the [In this series](#InThisSeries) section for related information. # Referencing secrets in an ARM template The first thing you need is the ID of your key vault. In the previous article we created a Key Vault named *MyUniqueKeyVaultName* and a secret with the name *MyAdminPassword*, we'll continue to use these values in this article. To get the ID of your vault, you can do something like this in PowerShell (replace the value for the VaultName parameter with yours) ```powershell (Get-AzureRmKeyVault -VaultName MyUniqueKeyVaultName).ResourceId ``` If should return a string with a format like this: `/subscriptions/edf192ff-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/AzureKeyVaultDemo/providers/Microsoft.KeyVault/va ults/MyUniqueKeyVaultName` Now we need to instruct the engine that we want to refer a key vault secret. The following syntax will enable us to do so: ```javascript "reference": { "keyVault": { "id": "/subscriptions/edf192ff-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/AzureKeyVaultDemo/providers/Microsoft.KeyVault/vaults/MyUniqueKeyVaultName" }, "secretName": "MyAdminPassword" } ``` Using this syntax, you specify the id of the key vault to use and which secret value you're after. > At runtime, ARM will replace all the key vault references with the actual secret values. ## Parameters If you want the value of a secret to be passed to a template parameter, you can either create a new one or use an existing one but declare it as `securestring`. It is a secret after all and this is the proper way to to let Azure know that this is sensitive information. Special care are took by the platform when handling securestrings. In short, they will not travel as plain text and won't be shown in the portal and deployment logs. Here is a very basic example for a template, it do not create anything but you'll see how to declare your parameter as `securestring`. ```javascript { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "myAdminUsername": { "type": "string", "minLength": 4 }, "myAdminPassword": { "type": "securestring" } }, "resources": [ ], "outputs": { "password": { "type": "securestring", "value": "[parameters('myAdminPassword')]" } } } ``` I have also created an output named `password` to show you that you can use your parameter like any others in your template. In your parameters file, use the reference syntax we saw earlier: ``` { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "myAdminUsername": { "value": "MyAdministrator" }, "myAdminPassword": { "reference": { "keyVault": { "id": "/subscriptions/edf192ff-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/AzureKeyVaultDemo/providers/Microsoft.KeyVault/vaults/MyUniqueKeyVaultName" }, "secretName": "MyAdminPassword" } } } } ``` Here is the output when I deploy this parameter ![After Key Vault reference in parameters deployment execution](https://codeisahighway.com/content/images/2016/01/ReferKeyVaultSecretInTemplateParameter.png) **Debugging tips**: Changing the type `securestring` to `string` in the output section, it will enable you to see the value in clear text. If you do this, switch it back to a `securestring` immediately after. You put that information in a secure vault in the first time, it is certainly not to let exposed in the wild later on ;) ## Variables Referring key vault in a variable is not supported at the moment, let's cross our fingers this is coming soon. ## In this series - [Best practices: How to handle sensitive data in Azure Resource Manager templates using Key Vault](https://codeisahighway.com/best-practices-how-to-handle-sensitive-data-in-azure-resource-manager-templates-using-keyvault) - [Create an Azure Key Vault using an ARM template (api version 2015-06-01) and Azure PowerShell v1.0.4](https://codeisahighway.com/create-an-azure-key-vault-using-an-arm-template-api-version-2015-06-01-and-azure-powershell-v1-0-4) - **How to refer an Azure Key Vault secret in an Azure Resource Manager deployment template** ## References - [Authoring Azure Resource Manager templates](https://azure.microsoft.com/en-us/documentation/articles/resource-group-authoring-templates/?ref=codeisahighway.com) - [Key Vault documentation](https://azure.microsoft.com/en-us/documentation/services/key-vault/?ref=codeisahighway.com) ### Effective ways to delete resources in a resource group on Azure URL: https://codeisahighway.com/effective-ways-to-delete-resources-in-a-resource-group-on-azure/ Last updated: 2026-08-10T07:12:43.000Z Under Azure Resource Manager, resource groups are very helpful to logically hold together a set of resources. For many reasons, at some point, you'll want to get rid of these resources but how can you achieve this and what are the pros and cons of each? You have basically three options depending on the end result you want. Some will require more effort than others but will give you more granular control over what is deleted or not. UPDATE: 2018-06-28 - Replaced Find-AzureRmResource usage it do not exist anymore in Azure PowerShell 6.x+ UPDATE: 2016-06-01 - Azure CLI now support *Complete* mode ## Delete the resource group This one is the simplest, it deletes everything. **Advantages** - No custom logic is required **To consider** - All resources inside the resource group will be deleted - The resource group will be deleted ```powershell Remove-AzureRmResourceGroup -Name MyResourceGroup -Verbose ``` After a few minutes, your resources and their container will be deleted ![Remove-AzureRmResourceGroup](https://codeisahighway.com/content/images/2016/03/Remove-AzureRmResourceGroup.png) ## Wait... What if I don't want to delete the resource group? Deleting the resource group directly is the quickest way to remove all the resources inside it but you'll also delete the container itself. What are your options if you want to preserve the resource group or want granular control over which resources will be deleted? ## Enumerate and delete all the resources yourself **Advantages** - Keep the resource group intact (including RBAC & Tags) - Ability to control which resources to keep (if required) **To consider** - Requires custom logic to handle resources dependencies - Requires custom logic to handle parallel delete *Some coding skill is required here because you'll need to:* - Enumerate all the resources under the resource group - \[Optional\] Filter out some resource types - \[Optional\] Handle resources dependencies - Delete the resources In most cases your resources will have dependencies on others. When that happen, you'll need a dependency graph discovery mechanism or you can go with a simpler approach: an ordered list of resource types to perform the deletion properly. A good example of resources depending on others to be the following: you cannot delete a storage account hosting the VHD of a virtual machine before deleting the VM itself. Below is a sample script that will find and delete VM related resources in a resource group using a hard-coded resource type list. If you are dealing with other resource types, you can adjust the types in the array to control the deletion order of types. At the end of the array, there is a '\*' that will remove any other resources not caught by the previous types, whenever they have a dependency or not. This is just a sample to give you an idea, you can start from here or go your own way. ;) ```powershell param( [Parameter(Position = 0, Mandatory = $true)] [string] $SubscriptionId, [Parameter(Position = 1, Mandatory = $true)] [string] $ResourceGroupName ) $ErrorAction = 'Stop' $null = Set-AzureRmContext -SubscriptionId $SubscriptionId @( 'Microsoft.Compute/virtualMachineScaleSets' 'Microsoft.Compute/virtualMachines' 'Microsoft.Storage/storageAccounts' 'Microsoft.Compute/availabilitySets' 'Microsoft.ServiceBus/namespaces' 'Microsoft.Network/connections' 'Microsoft.Network/virtualNetworkGateways' 'Microsoft.Network/loadBalancers' 'Microsoft.Network/networkInterfaces' 'Microsoft.Network/publicIPAddresses' 'Microsoft.Network/networkSecurityGroups' 'Microsoft.Network/virtualNetworks' '*' # this will remove everything else in the resource group regarding of resource type ) | % { $odataQuery = "`$filter=resourcegroup eq '$ResourceGroupName'" if ($_ -ne '*') { $odataQuery += " and resourcetype eq '$_'" } $resources = Get-AzureRmResource -ODataQuery $odataQuery $resources | Where-Object { $_.ResourceGroupName -eq $ResourceGroupName } | % { Write-Host ('Processing {0}/{1}' -f $_.ResourceType, $_.ResourceName) $_ | Remove-AzureRmResource -Verbose -Force } } ``` ## Purge the resource group In the previous option you got all the flexibility you want but it comes with a price, complexity and maintenance. If you are looking for a way to keep the resource group but want all the resources inside it deleted, this last option is for you. **Advantages** - No custom logic or dependency walking is required - Keep the resource group intact (including RBAC & Tags) - Native parallel delete support of non-dependent resources **To consider** - All resources inside the resource group will be deleted Under Azure Resource Manager you have the option of deploying resources using a template. You have two modes available when initiating a deployment: - **Incremental**: You can see this mode as "Additive". What I mean is that non-existing resources declared in your template will be added. Existing resources will be modified only if there is a difference between the actual version and what is declared in your template. Finally, if there's a resource in the resource group that is not present in the template, it will be ignored and left untouched. - **Complete**: You can see this mode as "Exact match". What I mean is that after your deployment is done, only the resources declared in your template will exist in the resource group. If there are existing resources in the resource group that are not present in the template, they will be deleted automatically. Now that we understand what happens in "Complete" mode, we can use that to our advantage. We are looking for a way to purge all the resources in a resource group, without having to handle the complexity of resolving dependencies and parallel delete of resources. The trick, simple when you think about it, just ask the ARM engine to deploy an empty template (no resources) in an existing resource group in "Complete" mode. You'll end up exactly with the behavior we want. ```json { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { }, "variables": { }, "resources": [ ], "outputs": { } } ``` Now, let's pretend the name of the template is "ResourceGroupCleanup.template.json". ### Powershell Here is how to invoke the deployment in "Complete" mode in PowerShell. ```powershell New-AzureRmResourceGroupDeployment -ResourceGroupName MyResourceGroup -Mode Complete -TemplateFile .\ResourceGroupCleanup.template.json -Force -Verbose ``` After you run this command, you should have something similar to the following: ![Purge all resources in a resource group using PowerShell](https://codeisahighway.com/content/images/2016/03/New-AzureRmResourceGroupDeployment_PurgeAllResources.png) ### Azure-CLI Here is how to invoke the deployment in "Complete" mode in Azure CLI v0.10.0 or later. ``` azure group deployment create -g MyResourceGroup -f .\ResourceGroupCleanup.template.json -m Complete ``` After you run this command, you should have something similar to the following: ![Purge all resources in a resource group using Azure-CLI](https://codeisahighway.com/content/images/2016/06/Azure-Group-Deployment-Create_PurgeAllResources.png) Hope you have fun with Azure Resource Manager and automation! ## References - [Authoring Azure Resource Manager templates](https://azure.microsoft.com/en-us/documentation/articles/resource-group-authoring-templates/?ref=codeisahighway.com) - [Incremental and complete deployments](https://azure.microsoft.com/en-us/documentation/articles/resource-group-template-deploy/?ref=codeisahighway.com#incremental-and-complete-deployments) - [Latest Microsoft Azure PowerShell release](https://github.com/Azure/azure-powershell/releases/latest?ref=codeisahighway.com) - [Latest Azure-CLI release](https://github.com/Azure/azure-xplat-cli/releases/latest?ref=codeisahighway.com) ### WMF 5.0 (PowerShell 5.0) RTM is back and available! URL: https://codeisahighway.com/wmf-5-0-powershell-5-0-rtm-is-back-and-available/ Last updated: 2026-07-23T03:03:31.000Z After being temporarily removed in December 2015 due to a nasty bug that could resets your PowerShell module environment during installation, the Windows Management Framework 5.0 (PowerShell 5.0) installation have been fixed and it is now available for download. > Today, we have republished the Windows Management Framework (WMF) 5.0 RTM packages for Windows Server 2012 R2, Windows Server 2012, Windows 2008 R2 SP1, Windows 8.1, and Windows 7 SP1 to Microsoft’s Download Center. More details here: [https://blogs.msdn.microsoft.com/powershell/2015/12/23/windows-management-framework-wmf-5-0-currently-removed-from-download-center/](https://blogs.msdn.microsoft.com/powershell/2015/12/23/windows-management-framework-wmf-5-0-currently-removed-from-download-center/?ref=codeisahighway.com) Direct link to the download page: [https://www.microsoft.com/en-us/download/details.aspx?id=50395](https://www.microsoft.com/en-us/download/details.aspx?id=50395&ref=codeisahighway.com) ### I am presenting: Deployment with Azure Resource Management templates and GIT on March 3rd 2016 URL: https://codeisahighway.com/i-am-presenting-deployment-with-azure-resource-management-templates-and-git/ Last updated: 2026-07-30T19:45:32.000Z I am glad to present a session on March 3rd 2016 for MITPro (Montreal IT Professional Community) at the Delta Hotel in Montreal. Here is the detail of my session that start at 5h30PM: **Deployment with Azure Resource Management templates and GIT** Maximize current resources while improving your datacenter flexibility and ability to deploy new technologies—without sacrificing security, control, reliability and scalability. Attend “Deployment with Azure Resource Management templates and GIT” and learn how to use tools like GIT, Visual Studio CODE & Azure Quickstart Templates to help you with Infrastructure as code and Azure while maximizing productivity across platforms. Speaker: Stephane Lapointe - Microsodt Azure MVP / Cloud Solutions Architect at Orckestra Here is also the detail of the other session after mine: Topic 2: **DevOps** Abstract: DevOps practices have become a vital part of agile development and continuous delivery. Be ready to evolve your traditional application lifecycle management (ALM) approach to help your business deliver higher value in less time. In this session, you’ll discover: The cultural challenges, processes, and tools involved with DevOps DevOps practices such as Infrastructure as a Code and continuous delivery and testing in production DevOps techniques that can deliver higher quality software on a shorter timeline and with better compliance Speakers: Dave Kawula – MVP – Founder / Managing Principal Consultant Sean Kearney - Cloud and Datacenter Management MVP / Senior Solutions Architect at Cistel Technology Register here if you want to attend to event: [ https://www.eventbrite.ca/e/devops-and-deployment-with-azure-resource-management-templates-and-git-tickets-21633252641](https://www.eventbrite.ca/e/devops-and-deployment-with-azure-resource-management-templates-and-git-tickets-21633252641?ref=codeisahighway.com) More information about MITPro: [http://mitpro.ca/](http://mitpro.ca/?ref=codeisahighway.com) ### I am giving two Azure sessions at DevTeach Montreal DevCon 2016 URL: https://codeisahighway.com/i-am-giving-two-azure-sessions-at-devteach-montreal-devcon-2016/ Last updated: 2026-07-31T19:44:39.000Z It's with great pleasure that I will present 2 sessions at DevTeach Montreal this year (2016) DevTeach Montreal DevCon July 4-8, 2016 [http://www.devteach.com/](http://www.devteach.com/?ref=codeisahighway.com) I will speak about ARM and automation on Azure (No surprises here!) Here is the detail of my sessions: **Advanced Azure deployments using templates** \- CLD345 This session is all about best practices and how to create advanced Azure ARM templates. How to use proven patterns for ARM templates to deploy topologies and their workloads consistently on Azure. Learn about the decomposed template approach and complex objects to properly implement and reference collections of data. Secure your resources using role-based access control (RBAC) by granting appropriate access to users, groups, and services. See how to handle sensitive information like credentials inside your templates. **Automation and environments on Azure** \- CLD241 Automation and environments on Azure - Where to start? There is a lot of options when come the time to create resources and manage environments on Azure. You'll learn about the various options available for automation whenever it's imperative via scripts or declarative via templates. Why to choose one approach versus the other, what are the pros and cons of each? We'll share tips & tricks so you can be successful with automation on Azure and explore patterns to help you reduce the cost of running these environments on Azure. Don't hesitate to come and say hi if you attend DevTeach this year ### Create an Azure Key Vault using an ARM template (api version 2015-06-01) and Azure PowerShell v1.0.4 URL: https://codeisahighway.com/create-an-azure-key-vault-using-an-arm-template-api-version-2015-06-01-and-azure-powershell-v1-0-4/ Last updated: 2026-07-30T19:45:35.000Z We live in a world where data and security is not to be taken lightly. Having to create or maintain a system that enable you to keep secrets and/or certificates safe is a challenge in itself. In this particular article we'll see how to create an Azure Key Vault resource using the resource provider *Microsoft.KeyVault* and API version *2015-06-01* in an ARM template. ## Prerequisites - Azure PowerShell cmdlets **v1.0.4** or later # What Is Azure Key Vault? Key Vault help you safeguard cryptographic keys and other secrets used by your applications whenever they are On-Premise or in the cloud. More and more services on Azure are now integrating Azure Key Vault as their secret/key source for things like deployments, data or even disk encryption. **Assumptions** This article assumes you have basic knowledge and experience with ARM templates. That you know how to configure a resource type in the Resource section of a template. If you don't and need more information about ARM templates, please take a look here before going further: [Authoring Azure Resource Manager templates](https://azure.microsoft.com/en-us/documentation/articles/resource-group-authoring-templates/?ref=codeisahighway.com) ## Microsoft.KeyVault/vaults properties The type *Microsoft.KeyVault/vaults* is not that complex but we'll take a look at some the most important properties together. **enabledForDeployment** \- Specifies if the vault is enabled for deployment from tools and resources providers in Azure or from command lines likes PowerShell or Azure CLI. An example of this is when you create a virtual machine, the Microsoft.Compute resource provider could retrieve secrets from this key vault when the key vault is referenced in resource creation. **enabledForTemplateDeployment** \- Specifies if the vault is enabled for ARM template deployments. You need to enable this if you want the ARM template engine to retrieve secrets (on behalf of the user/service principal performing the deployment) from this key vault when the key vault is referenced in ARM deployment template or parameter files. **enabledForVolumeEncryption** \- Specifies if the vault is enabled for volume encryption. The Azure disk encryption solution lets you encrypt your IaaS virtual machine disks, including boot and data disks. The solution is integrated with Key Vault to help you control and manage the disk encryption keys in your Key Vault subscription. **tenantId** \- Specifies the Azure AD (tenant) unique identifier (GUID) associated with the subscription where the vault will be created. **accessPolicies** \- Specifies one or many permission on the vault. If you use the vault for deployment, the person or service principal launching the deployment will need permission on that vault. In the following example I'm going to give myself permission to the vault since I'll be performing future deployments. I'll need to know the tenantId (unique identifier of the Azure Active Directory that owns my account) and my objectId (unique identifier of my user). We can get those values using Azure PowerShell cmdlets and then pass them in as parameters to the template. To get the tenantId of the subscription, we'll use Azure PowerShell cmdlets v1.0.4 or later. Remember, we want the tenantId for the subscription our vault will reside in. The `Get-AzureRmSubscription` cmdlet will list one or more subscription if you have access to many. Simply pick the one you want like in this example : ```powershell PS C:\> Get-AzureRmSubscription SubscriptionName : Visual Studio Enterprise with MSDN SubscriptionId : edf192ff-xxxx-xxxx-xxxx-xxxxxxxxxxxx TenantId : a87b073b-xxxx-xxxx-xxxx-xxxxxxxxxxxx ``` ![Get TenantId using Get-AzureRmSubscription](https://codeisahighway.com/content/images/2015/12/Get-AzureRmSubscription.png) There is also a *tenantId* property on the *accessPolicies* for the vault. This is the unique identifier of the Azure Active Directory tenant owning the desired user you want to give access. Speaking of that user, we also need the *objectId* which represents the unique identifier of the user account in that tenant. In our example, I can do something like... ```powershell PS C:\> Get-AzureRmADUser -Mail DisplayName Type ObjectId ----------- ---- -------- Stephane Lapointe 5eaecd00-xxxx-xxxx-xxxx-xxxxxxxxxxxx ``` ![Getting the current user objectId using Get-AzureRmADUser](https://codeisahighway.com/content/images/2015/12/Get-AzureRmADUser.png) Note that if you have a lot of users in your tenant or if you are looking for the objectId of someone else, you can also do the following: ```powershell PS C:\> Get-AzureRmADUser -Mail '{TheUserEmailAddress}' ``` The next step is to set the permission on the vault that allows Azure Resource Manager to access the vault on our behalf. This is done by setting the **enabledForTemlateDeployment** property on the resource. ## Parameters and template files Here are the json files we'll need for our deployment. ### KeyVaultSetup.parameters.json ```json { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { "value": "MyUniqueKeyVaultName" }, "tenantId": { "value": "a87b073b-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }, "objectId": { "value": "5eaecd00-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }, "secretName": { "value": "MyAdminPassword" }, "enabledForTemplateDeployment": { "value": true } } } ``` And the template itself: ### KeyVaultSetup.json ```json { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { "type": "string", "metadata": { "description": "Name of the vault" } }, "tenantId": { "type": "string", "metadata": { "description": "Tenant Id for the subscription and use assigned access to the vault. Available from the Get-AzureRMSubscription PowerShell cmdlet" } }, "objectId": { "type": "string", "metadata": { "description": "Object Id of the AAD user or service principal that will have access to the vault. Available from the Get-AzureRMADUser or the Get-AzureRMADServicePrincipal cmdlets" } }, "keysPermissions": { "type": "array", "defaultValue": [ "all" ], "metadata": { "description": "Permissions to grant user to keys in the vault. Valid values are: all, create, import, update, get, list, delete, backup, restore, encrypt, decrypt, wrapkey, unwrapkey, sign, and verify." } }, "secretsPermissions": { "type": "array", "defaultValue": [ "all" ], "metadata": { "description": "Permissions to grant user to secrets in the vault. Valid values are: all, get, set, list, and delete." } }, "vaultSku": { "type": "string", "defaultValue": "Standard", "allowedValues": [ "Standard", "Premium" ], "metadata": { "description": "SKU for the vault" } }, "enabledForDeployment": { "type": "bool", "defaultValue": false, "metadata": { "description": "Specifies if the vault is enabled for VM or Service Fabric deployment" } }, "enabledForTemplateDeployment": { "type": "bool", "defaultValue": false, "metadata": { "description": "Specifies if the vault is enabled for ARM template deployment" } }, "enableVaultForVolumeEncryption": { "type": "bool", "defaultValue": false, "metadata": { "description": "Specifies if the vault is enabled for volume encryption" } }, "secretName": { "type": "string", "metadata": { "description": "Name of the secret to store in the vault" } }, "secretValue": { "type": "securestring", "metadata": { "description": "Value of the secret to store in the vault" } } }, "resources": [ { "type": "Microsoft.KeyVault/vaults", "name": "[parameters('keyVaultName')]", "apiVersion": "2015-06-01", "location": "[resourceGroup().location]", "tags": { "displayName": "KeyVault" }, "properties": { "enabledForDeployment": "[parameters('enabledForDeployment')]", "enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]", "enabledForVolumeEncryption": "[parameters('enableVaultForVolumeEncryption')]", "tenantId": "[parameters('tenantId')]", "accessPolicies": [ { "tenantId": "[parameters('tenantId')]", "objectId": "[parameters('objectId')]", "permissions": { "keys": "[parameters('keysPermissions')]", "secrets": "[parameters('secretsPermissions')]" } } ], "sku": { "name": "[parameters('vaultSku')]", "family": "A" } }, "resources": [ { "type": "secrets", "name": "[parameters('secretName')]", "apiVersion": "2015-06-01", "tags": { "displayName": "secret" }, "properties": { "value": "[parameters('secretValue')]" }, "dependsOn": [ "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]" ] } ] } ] } ``` ## What about a little secret? A vault without any secret is not really useful. Let's take a closer look at the child resource *Microsoft.KeyVault/vaults/secrets* that will help us with that. Since it is a child resource of our vault, we can use *secrets* for the type name and ARM will automatically resolve the full type name for us. ```json { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", ... "resources": [ { "type": "Microsoft.KeyVault/vaults", "name": "[parameters('keyVaultName')]", ... }, "properties": { ... }, "resources": [ { "type": "secrets", "name": "[parameters('secretName')]", "apiVersion": "2015-06-01", "tags": { "displayName": "secret" }, "properties": { "value": "[parameters('secretValue')]" }, "dependsOn": [ "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]" ] } ] } ] } ``` Since it's an array, we can declare one or many secrets. In our template we only create one secret and it uses the `secretName` and `secretValue` template parameters. ## Time to Create That Vault Ensure you replace the values with your own in the parameter file listed in this article. To perform our deployment, let's open a new PowerShell session and execute the following commands... **Note**: As you did with the parameter file values, replace the `-SubscriptionId` value with yours below. ```powershell Login-AzureRmAccount Select-AzureRmSubscription -SubscriptionId 'edf192ff-xxxx-xxxx-xxxx-xxxxxxxxxxxx' New-AzureRmResourceGroup -Name 'AzureKeyVaultDemo' -Location 'West US' -Force New-AzureRmResourceGroupDeployment -ResourceGroupName 'AzureKeyVaultDemo' -TemplateFile .\KeyVaultSetup.json -TemplateParameterFile .\KeyVaultSetup.parameters.json -Force -Verbose ``` Since we have omitted the *secretValue* parameter in our parameters file, the `New-AzureRmResourceGroupDeployment` cmdlet will detect that it's missing and prompt us to enter it. Enter any the value you want for this. At the end you should have a `Succeeded` provisioning state if you provided a unique name for your Key Vault and valid info for your tenant & object Ids in your parameter file. ![Successful Azure Key Vault deployment](https://codeisahighway.com/content/images/2015/12/CreateAzureKeyVault.png) ## In this series - [Best practices: How to handle sensitive data in Azure Resource Manager templates using Key Vault](https://codeisahighway.com/best-practices-how-to-handle-sensitive-data-in-azure-resource-manager-templates-using-keyvault) - **Create an Azure Key Vault using an ARM template (api version 2015-06-01) and Azure PowerShell v1.0.4** - [How to refer an Azure Key Vault secret in an Azure Resource Manager deployment template](https://codeisahighway.com/how-to-refer-an-azure-key-vault-secret-in-an-azure-resource-manager-deployment-template) ## References - [Authoring Azure Resource Manager templates](https://azure.microsoft.com/en-us/documentation/articles/resource-group-authoring-templates/?ref=codeisahighway.com) - [Key Vault documentation](https://azure.microsoft.com/en-us/documentation/services/key-vault/?ref=codeisahighway.com) - [Key Vault template schema](https://azure.microsoft.com/en-in/documentation/articles/resource-manager-template-keyvault/?ref=codeisahighway.com) - [Key Vault secret template schema](https://azure.microsoft.com/en-in/documentation/articles/resource-manager-template-keyvault-secret/?ref=codeisahighway.com) - [Azure PowerShell cmdlets v1.0.4](https://github.com/Azure/azure-powershell/releases/tag/AzureRMv1.0.4-December2015?ref=codeisahighway.com) - [Authenticating a service principal with Azure Resource Manager](https://azure.microsoft.com/en-us/documentation/articles/resource-group-authenticate-service-principal/?ref=codeisahighway.com) ### Best practices: How to handle sensitive data in Azure Resource Manager templates using Key Vault URL: https://codeisahighway.com/best-practices-how-to-handle-sensitive-data-in-azure-resource-manager-templates-using-keyvault/ Last updated: 2026-07-17T08:34:40.000Z Have you ever wondered how you could land in the DevOps world of Config-as-Code without storing configuration secrets (e.g. passwords) as plain text in source control? In this series of articles you'll learn how you can work with Azure Resource Manager (ARM) templates and Key Vault to protect your sensitive secrets. ## Don't put secrets in source control! We all know that we shouldn't keep sensitive information like credentials, authentication and software license keys in source control, especially those of production environments. The threat for your OnPremise environments is real if you do this but take a step back and think about what could happen if you expose cloud authentication keys or credentials. One of the biggest advantages of cloud computing is going to come back to bite you. ## Cloud agility can only be positive right? Agility of cloud environments like AWS and Microsoft Azure enables you to create a lot of resources like virtual machines very quickly. Now imagine someone with bad intentions with these informations in hand, he could easily spawn many VMs and leave you with a big invoice by the time you start to realize what is happening. You don't think this is real? Take a look at this story ([Developers, Check Your Amazon Bills For Bitcoin Miners](http://readwrite.com/2014/04/15/amazon-web-services-hack-bitcoin-miners-github?ref=codeisahighway.com)), there are hundreds of stories like theses every month! That being said, it is not only your wallet that can suffer from an error like this, it also opens the door for others to access and disrupt your servers, data, APIs, etc. I think you can easily image the consequences here. ## Say hello to Azure Key Vault If we could resume in a simplistic manner what Key Vault is, it would be something like this (taken from Azure documentation) : > Azure Key Vault helps safeguard cryptographic keys and secrets used by cloud applications and services. By using Key Vault, you can encrypt keys and secrets (such as authentication keys, storage account keys, data encryption keys, .PFX files, and passwords) by using keys that are protected by hardware security modules (HSMs). For added assurance, you can import or generate keys in HSMs. If you choose to do this, Microsoft will process your keys in FIPS 140-2 Level 2 validated HSMs (hardware and firmware). Key points: - Increase security and control over keys and passwords - Create and import encryption keys in minutes - Applications have no direct access to keys - Use FIPS 140-2 Level 2 validated HSMs - Reduce latency with cloud scale and global redundancy ## Key Vault is not that new but... Azure Key Vault integration and tooling in the platform evolve more and more but at the time I am writing this, there is no UI to create/modify a Key Vault from the Azure Portal neither is it integrated in tools like Visual Studio. Expect to spend some time at the command line (PowerShell or Azure CLI) or in ARM templates to create and modify your vault. Since we will focus on ARM templates in this series, we'll use a template to deal with the Key Vault creation. ## Scenarios Now let see how we can combine ARM templates and Key Vault to build more secure templates. - **Best practices: How to handle sensitive data in Azure Resource Manager templates using Key Vault** - First thing first... [Create an Azure Key Vault using an ARM template (api version 2015-06-01) and Azure PowerShell v1.0.4](https://codeisahighway.com/create-an-azure-key-vault-using-an-arm-template-api-version-2015-06-01-and-azure-powershell-v1-0-4) - [How to refer an Azure Key Vault secret in an Azure Resource Manager deployment template](https://codeisahighway.com/how-to-refer-an-azure-key-vault-secret-in-an-azure-resource-manager-deployment-template) \* Future - Never hardcode credentials in PowerShell DSC extension again ## Credits A special thanks to Brian Moore at Microsoft for helping me with this series. ### How to use ARM Explorer to capture your own custom virtual machine image under Azure Resource Manager URL: https://codeisahighway.com/how-to-use-arm-explorer-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager/ Last updated: 2026-07-30T19:45:37.000Z You have a v2 Azure Virtual Machine that has been generalized and are ready to capture it using ARM Explorer? All right, buckle your seat belt and follow this guide, at the end you should have your captured VHD in your storage account. > This post assume you already have a virtual machine on Azure that have been generalized and you want to capture it. You can find out how to generalize your VM and other alternatives for your capture in this article: [Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager](https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api) # Capture VM image with ARM Explorer Start by opening the [ARM Explorer](https://resources.azure.com/?ref=codeisahighway.com) website. We'll do more than GET operations in ARM Explorer so we need to allow PUT and POST verbs by enabling write mode (it is Read Only\* by default). At the top right of the site, ensure **Read/Write** is selected. ![Read/Write mode in ARM Explorer](https://codeisahighway.com/content/images/2015/08/EnableWriteMode.png) At the top you'll find a search box, type the name of your virtual machine and select it from the drop down. In my case, my VM is named *CaptureVMImage*, yours will probably be different. ![Search Your VM in ARM Explorer](https://codeisahighway.com/content/images/2015/08/SearchVmToCapture.png) You should now see your virtual machine in the right section of the site. ![Virtual machine information in ARM Explorer](https://codeisahighway.com/content/images/2015/08/VirtualMachineInARMExplorer.png) Click **Actions (POST, DELETE)**, you'll see a lot of action that you can perform on your virtual machine... ![Actions (POST, DELETE) for VM view In ARMExplorer](https://codeisahighway.com/content/images/2015/08/ActionsPostDeleteForVMInARMExplorer.png) - Click the **Deallocate** button ![Deallocate button](https://codeisahighway.com/content/images/2015/08/DeallocateButton.png) - The status of the VM should go from `Stopped` to `Updating` to `Stopped (deallocated)`. - Now that your VM is deallocated, Click the **Generalize** button ![Generalize button](https://codeisahighway.com/content/images/2015/08/GeneralizeButton.png) Your VM OSState should now be marked as `OSState/generalized`. ![Virtual Machine OSState in ARM Explorer](https://codeisahighway.com/content/images/2015/08/VirtualMachineOsStateInARMExplorer.png) ```json { "code": "OSState/generalized", "level": "Info", "displayStatus": "VM generalized" } ``` - Still in the *Actions (POST, DELETE)* section, scroll to the capture operation and fill the required information: ```json { "vhdPrefix": "template", "destinationContainerName": "mytemplates", "overwriteVhds": "false" } ``` - Click the **Capture** button ![Capture button](https://codeisahighway.com/content/images/2015/08/CaptureButton-1.png) ## Capture is done, what's next? Your image will now be ready in a minute or two! Jump to [Capture is done, what's next?](https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api#AfterCapture) ### How to get the status of a Virtual Machine under the v2 compute model in Azure PowerShell v1.0.x URL: https://codeisahighway.com/how-to-get-the-status-of-a-virtual-machine-under-the-v2-compute-model-in-azure-powershell-v1-0/ Last updated: 2026-08-10T07:12:39.000Z Getting the status of a virtual machine is really handy because once you have that information you can then take decisions and perform several actions on your virtual machines like starting it, stopping it, etc. ## List all virtual machines in a subscription To list all the virtual machines in a specific subscription you can execute the following: ```powershell Login-AzureRmAccount Select-AzureRmSubscription -SubscriptionName $mySubscriptionName Get-AzureRmVM ``` ## List all virtual machines in a specific resource group To list all the virtual machines of a specific resource group you can execute the following: ```powershell Login-AzureRmAccount Select-AzureRmSubscription -SubscriptionName $mySubscriptionName Get-AzureRmVM -ResourceGroupName $myResourceGroupName ``` # Get the status of a specific virtual machine All the examples above, regardless of the scope to list will give you the base definition of a virtual machine. To get the status of it, you need to provide the `-Status` switch. It will take a bit more time, but this time you'll have a completely different response than the previous calls we made. It will contain the information you are looking for in the `Statuses` member. ``` Login-AzureRmAccount Select-AzureRmSubscription -SubscriptionName $mySubscriptionName $vm = Get-AzureRmVM -ResourceGroupName $myResourceGroupName -Name 'MyVMName' -Status $vm.Statuses ``` You will have all the VM information you need to automate your scale up/down and automation scenarios... Enjoy! ### References - [Resource Group introduction](https://azure.microsoft.com/en-us/documentation/articles/resource-group-overview/?ref=codeisahighway.com#resource-groups) - [Azure PowerShell 1.0 Cmdlets Reference](https://msdn.microsoft.com/en-us/library/azure/mt619274.aspx?ref=codeisahighway.com) - [Azure PowerShell v1.0.4 - December 2015](https://github.com/Azure/azure-powershell/releases/tag/AzureRMv1.0.4-December2015?ref=codeisahighway.com) ### How to create a virtual machine from a custom image using ARM and Azure PowerShell v1.0.x URL: https://codeisahighway.com/how-to-create-a-virtual-machine-from-a-custom-image-using-arm-and-azure-powershell-v1-0-x/ Last updated: 2026-07-17T08:35:10.000Z You love PowerShell, have a custom VM image (specialized or generalized) and you want to create a new virtual machine from it under Azure Resource Manager API? You're at the right place... ## Prerequisites - Microsoft Azure PowerShell v1.0.2 or later, I used 1.0.4 - A custom VM image captured using the Azure Resource Manager API (more detail just below) ## Things to know before you get started Here is few items you need to be aware before you continue... ### The custom VM image needs to have been captured using a v2 Compute resource provider VM images captured from a v1 Compute resource provider (Microsoft.ClassicCompute) cannot be used to create virtual machines using a v2 Compute resource provider (Microsoft.Compute) or the other way around. If you need a new image after reading this, see *Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager* in the [References](#References) section. ### The Custom VM image needs to reside in the same storage account as your virtual machine at creation time Another important limitation is that the image needs to be present at creation time in the very same storage account that will host your virtual machine's vhd. *The custom VM image can be deleted afterward without problems.* It's not that big thing if you are using a standard storage account. On the other hand, if you want your virtual machine to run on premium storage, leaving that P10 (or bigger) custom VM image around, doing nothing, will cost you the same money per month as any other premium storage disk. For more details, see *Azure Storage Pricing* link in the [References](#References) section. ## Creating a virtual machine from the custom image Now the fun part... In a basic example, you'll see how to reference your custom image in the VM creation process using Azure PowerShell cmdlets. Ready? *We assume the storage account already exists since you are supposed to have your custom VM image already in it at this point.* First we need to authenticate against Azure, use the desired subscription and storage account. ```language-powershell Login-AzureRmAccount Select-AzureRmSubscription -SubscriptionId $subscriptionId $storageAccount = Get-AzureRmStorageAccount | ? StorageAccountName -EQ $storageAccountName ``` We create the networking resources for the VM ```language-powershell # Create the VNET $vnetDef = New-AzureRmVirtualNetwork -ResourceGroupName $resourceGroupName -Location $location -Name $vnetName -AddressPrefix '10.0.0.0/16' $vnet = $vnetDef | Add-AzureRmVirtualNetworkSubnetConfig -Name 'Subnet-1' -AddressPrefix '10.0.0.0/24' | Set-AzureRmVirtualNetwork # Create the NIC $pip = New-AzureRmPublicIpAddress -ResourceGroupName $resourceGroupName -Location $location -Name $ipName -DomainNameLabel $domName -AllocationMethod Dynamic $nic = New-AzureRmNetworkInterface -ResourceGroupName $resourceGroupName -Location $location -Name $nicName -PublicIpAddressId $pip.Id -SubnetId $vnet.Subnets[0].Id ``` Now we can create the VM configuration and glue it all together. Pay special attention to the `-SourceImageUri` parameter of the `Set-AzureRmVMOSDisk` cmdlet, this is where we specify the location of the custom VM image to use. ```language-powershell # Specify the VM name and size $vm = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize # Specify local administrator account, and then add the NIC $cred = New-Object PSCredential $adminUsername, ($adminPassword | ConvertTo-SecureString -AsPlainText -Force) # you could use Get-Credential instead to get prompted # NOTE: if you are deploying a Linux machine, replace the -Windows switch with the -Linux switch and remove the -EnableAutoUpdate switch. $vm = Set-AzureRmVMOperatingSystem -VM $vm -Windows -ComputerName $vmName -Credential $cred -ProvisionVMAgent -EnableAutoUpdate $vm = Add-AzureRmVMNetworkInterface -VM $vm -Id $nic.Id # Specify the OS disk $diskName = 'osdisk' $osDiskUri = '{0}vhds/{1}{2}.vhd' -f $storageAccount.PrimaryEndpoints.Blob.ToString(), $vmName.ToLower(), $diskName # NOTE: if you are deploying a Linux machine, replace the -Windows switch with a -Linux switch. $vm = Set-AzureRmVMOSDisk -VM $vm -Name $diskName -VhdUri $osDiskUri -CreateOption fromImage -SourceImageUri $sourceImageUri -Windows $result = New-AzureRmVM -ResourceGroupName $resourceGroupName -Location $location -VM $vm ``` ## Sample script Here is a basic but complete script, without much error handling to reduce complexity... Please note that this script deploys a Windows machine, replace the `-Windows` switch for the `-Linux` switch in the `Set-AzureRmVMOperatingSystem` & `Set-AzureRmVMOSDisk` cmdlets if you want to deploy a Linux machine. ```language-powershell # We'll use a couple of variable here, fill these with your own values $subscriptionId = '' # Your SubscriptionId $storageAccountName = '' # Storage account name where your custom image is and where your VM vhd will go $sourceImageUri = '' # custom VM image blob uri, ex: 'https://vmcapturetest.blob.core.windows.net/system/Microsoft.Compute/Images/mytemplates/template-osDisk.187d9455-535b-48b4-b10d-8370ec9bad42.vhd' # end of custom variables # Authenticate against Azure and cache subscription data Login-AzureRmAccount # Switch subscription Select-AzureRmSubscription -SubscriptionId $subscriptionId # Get the storage account $storageAccount = Get-AzureRmStorageAccount | ? StorageAccountName -EQ $storageAccountName if(-not $storageAccount) { throw "Unable to find storage account '$storageAccountName'. Cannot continue." } # Enable verbose output and stop on error $VerbosePreference = 'Continue' $ErrorActionPreference = 'Stop' # some reserved script variables $resourceGroupName = $storageAccount.ResourceGroupName $location = $storageAccount.Location $adminUsername = 'VmAdministrator' $adminPassword = '123!SomeUnSecurePassword!098' $vmSuffix = Get-Random -Minimum 10000 -Maximum 99999 $vmName = 'VM{0}' -f $vmSuffix $vmSize = 'Standard_D3' $nicName = 'VM{0}-NIC' -f $vmSuffix $ipName = 'VM{0}-IP' -f $vmSuffix $domName = 'vm-from-customimage-powershell-{0}' -f $vmSuffix $vnetName = $vmName # Create the VNET Write-Verbose 'Creating Virtual Network' $vnetDef = New-AzureRmVirtualNetwork -ResourceGroupName $resourceGroupName -Location $location -Name $vnetName -AddressPrefix '10.0.0.0/16' Write-Verbose 'Adding subnet to Virtual Network' $vnet = $vnetDef | Add-AzureRmVirtualNetworkSubnetConfig -Name 'Subnet-1' -AddressPrefix '10.0.0.0/24' | Set-AzureRmVirtualNetwork # Create the NIC Write-Verbose 'Creating Public IP' $pip = New-AzureRmPublicIpAddress -ResourceGroupName $resourceGroupName -Location $location -Name $ipName -DomainNameLabel $domName -AllocationMethod Dynamic Write-Verbose 'Creating NIC' $nic = New-AzureRmNetworkInterface -ResourceGroupName $resourceGroupName -Location $location -Name $nicName -PublicIpAddressId $pip.Id -SubnetId $vnet.Subnets[0].Id # Specify the VM name and size Write-Verbose 'Creating VM Config' $vm = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize # Specify local administrator account, and then add the NIC $cred = New-Object PSCredential $adminUsername, ($adminPassword | ConvertTo-SecureString -AsPlainText -Force) # you could use Get-Credential instead to get prompted # NOTE: if you are deploying a Linux machine, replace the -Windows switch with a -Linux switch. $vm = Set-AzureRmVMOperatingSystem -VM $vm -Windows -ComputerName $vmName -Credential $cred -ProvisionVMAgent -EnableAutoUpdate $vm = Add-AzureRmVMNetworkInterface -VM $vm -Id $nic.Id # Specify the OS disk $diskName = 'osdisk' $osDiskUri = '{0}vhds/{1}{2}.vhd' -f $storageAccount.PrimaryEndpoints.Blob.ToString(), $vmName.ToLower(), $diskName # NOTE: if you are deploying a Linux machine, replace the -Windows switch with a -Linux switch. $vm = Set-AzureRmVMOSDisk -VM $vm -Name $diskName -VhdUri $osDiskUri -CreateOption fromImage -SourceImageUri $sourceImageUri -Windows Write-Verbose 'Creating VM...' $result = New-AzureRmVM -ResourceGroupName $resourceGroupName -Location $location -VM $vm if($result.Status -eq 'Succeeded') { $result Write-Verbose ('VM named ''{0}'' is now ready, you can connect using username: {1} and password: {2}' -f $vmName, $adminUsername, $adminPassword) } else { Write-Error 'Virtual machine was not created successfully.' } ``` Hope it helped you a bit in your Azure adventure. ## References - [Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager](https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api) - [Azure Storage Pricing](http://azure.microsoft.com/en-us/pricing/details/storage/?ref=codeisahighway.com) ### How to use Azure PowerShell v1.0.x to capture your own custom virtual machine image under Azure Resource Manager URL: https://codeisahighway.com/how-to-use-azure-powershell-v1-0-x-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager/ Last updated: 2026-07-30T19:45:40.000Z You have a v2 Azure Virtual Machine that has been generalized and are ready to capture it using Azure PowerShell v1.0.x? All right, buckle your seat belt and follow this guide, at the end you should have your captured VHD in your storage account. > This post assume you already have a virtual machine on Azure that have been generalized and you want to capture it. You can find out how to generalize your VM and other alternatives for your capture in this article: [Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager](https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api) # Capture VM image with PowerShell v1.0.x Here is the 4 calls that you need to perform in PowerShell to capture your image... ```powershell # Login into Azure and select the desired subscription Login-AzureRmAccount Select-AzureRmSubscription -SubscriptionId {YourSubscriptionId} ``` ```powershell # Deallocate the virtual machine Stop-AzureRmVM -ResourceGroupName 'CaptureVmImageRG' -Name 'CaptureVmImage' ``` You should have a *Succeeded* status. ![After Stop-AzureRmVM Call](https://codeisahighway.com/content/images/2015/12/AfterStop-AzureRmVM.png) ```powershell # Set the Generalized state to the virtual machine Set-AzureRmVM -ResourceGroupName 'CaptureVmImageRG' -Name 'CaptureVmImage' -Generalized ``` You should have an *OK* StatusCode. ![After Set-AzureRmVM Generalize Call](https://codeisahighway.com/content/images/2015/12/AfterSetAzureRmVMGeneralizeCall.png) ```powershell # Capture the image to storage account. Save-AzureRmVMImage -ResourceGroupName 'CaptureVmImageRG' -VMName 'CaptureVmImage' -DestinationContainerName 'mytemplates' -VHDNamePrefix 'template' -Path C:\temp\capturevmtest\SampleTemplate.json ``` The `-Path` parameter of the `Save-AzureRmVMImage` cmdlet will download a copy of the the ARM template file generated in the storage account and save it where you specified. The JSON will also be outputted in the PowerShell window. ![After Save-AzureRmVMImage Call](https://codeisahighway.com/content/images/2015/12/VMImageCapturedInAzurePowerShellV1.png) Jump to [Capture is done, what's next?](https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api#AfterCapture) ### How to use Azure PowerShell v0.9.x to capture your own custom virtual machine image under Azure Resource Manager URL: https://codeisahighway.com/how-to-use-azure-powershell-v0-9-xxx-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager/ Last updated: 2026-08-10T07:12:36.000Z You have a v2 Azure Virtual Machine that has been generalized and are ready to capture it using Azure PowerShell v0.9.x? All right, buckle your seat belt and follow this guide, at the end you should have your captured VHD in your storage account. > This post assume you already have a virtual machine on Azure that have been generalized and you want to capture it. You can find out how to generalize your VM and other alternatives for your capture in this article: [Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager](https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api) # Capture VM image with PowerShell v0.9.x Here is the 3 calls that you need to perform in PowerShell to capture your image... ```powershell # Deallocate the virtual machine Stop-AzureVM -ResourceGroupName 'CaptureVmImageRG' -Name 'CaptureVmImage' ``` You should have a *Succeeded* status. ![After Stop-AzureVM Call](https://codeisahighway.com/content/images/2015/08/AfterSaveAzureVMCall.png) ```powershell # Set the Generalized state to the virtual machine Set-AzureVM -ResourceGroupName 'CaptureVmImageRG' -Name 'CaptureVmImage' -Generalized ``` You should have an *OK* StatusCode. ![After Set-AzureVM Generalize Call](https://codeisahighway.com/content/images/2015/08/AfterSetAzureVMGeneralizeCall.png) ```powershell # Capture the image to storage account. Save-AzureVMImage -ResourceGroupName 'CaptureVmImageRG' -VMName 'CaptureVmImage' -DestinationContainerName 'mytemplates' -VHDNamePrefix 'template' -Path C:\temp\capturevmtest\SampleTemplate.json ``` The `-Path` parameter of the `Save-AzureVMImage` cmdlet will download a copy of the the ARM template file generated in the storage account and save it where you specified. The JSON will also be outputted in the PowerShell window. ![After Save-AzureVMImage Call](https://codeisahighway.com/content/images/2015/08/VMImageCapturedInPowerShell.png) Jump to [Capture is done, what's next?](https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api#AfterCapture) ### Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager URL: https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api/ Last updated: 2026-08-10T07:12:28.000Z The IaaS v2 resource providers (Microsoft.Compute, Microsoft.Network & Microsoft.Storage) have been around for several months now and you may have wondered how to use your own custom images for creating virtual machines instead of one offered in the gallery. Let me show you how you can achieve this. **updated on 2015-12-20 to distinguish Azure PowerShell v0.9.x and v1.0.x** > Be advised that the experience is not perfect as RPs[\[1\]](#fn1) are is still in preview and improvements will come in waves as the resource providers are reaching GA[\[2\]](#fn2). In this article series you'll see several ways of capturing your custom VM image. One with ARM Explorer (UI friendly) and the others using Azure PowerShell cmdlets (automation/devops friendly). ## Prerequisites - Microsoft Azure PowerShell <= v0.9.xxx OR Microsoft Azure PowerShell >= v1.0.xxx - A virtual machine in Azure running Windows Server 2012 or later ## Create your Virtual machine The very first step is to actually create a Windows Server virtual machine from the portal with everything you want on it (I'll be using a Windows Server 2012 R2 VM). If you need help on this, you can check the *Create a virtual machine running Windows in the Azure portal* link in the [Resources](#Resources) section. Now the part that interest us... Creating a generalized VM image. ## Types of VM images There is two types of virtual machine images, Generalized and Specialized, each serving their own purpose. Here is a good explanation from *Christine Avanessians*, Christine is a Senior Program Manager, Microsoft Azure. > A generalized VM Image contains an OS disk, which, as the name suggests, has been generalized (for Windows, you have run Sysprep and for Linux, you have executed ‘waagent –deprovision’) and needs to be provisioned during deployment time. OS Images today are generalized. This type of VM Image is meant to be used as a “model” to quickly stamp out similar virtual machines, such as scaling out a front-end to your application in production or spinning up and tearing down similar development and test environments quickly. > A specialized VM Image contains an OS disk, which is already provisioned. It is similar to a disk today in that it is “ready-to-use”, but unlike a disk, the VHDs of a VM Image are treated as read-only and copied when deploying a new virtual machine. A specialized VM Image is meant to be used as a “snapshot” to deploy a VM to a good known point in time, such as checkpointing a developer machine, before performing a task which may go wrong and render the virtual machine useless. It is not meant to be a mechanism to clone multiple identical virtual machines in the same virtual network due to the Windows requirement of Sysprep for image replication. ## Prepare your virtual machine Now that your VM is ready and customized the way you want, you are ready to transform it as a VM image. To do so, you need a tool called sysprep. Be sure to be logged in your Windows Server VM on Azure, open a PowerShell window and execute the following : ```powershell & "$Env:SystemRoot\system32\sysprep\sysprep.exe" /generalize /oobe /shutdown ``` ![Invoke Sysprep from PowerShell](https://codeisahighway.com/content/images/2015/08/InvokeSysprep.png) You will see a dialog telling you that Sysprep is working, it will take at least 2-3 minutes. ![Sysprep generalize phase](https://codeisahighway.com/content/images/2015/08/SysprepInAction.png) The `/shutdown` parameter will shutdown the VM when sysprep is done generalizing the VM. Allow a minute or two so that you can see that your VM status is really marked as stopped in the portal. ![Stopped Virtual machine](https://codeisahighway.com/content/images/2015/08/StoppedVm.png) ### Capture the image Now you have the choice of two tools... Neither is really harder than the other, it is really a question of personal preferences. - [Capture VM image with ARM Explorer](https://codeisahighway.com/how-to-use-arm-explorer-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager) - [Capture VM image with PowerShell v1.0.x (Preferred for PowerShell capture)](https://codeisahighway.com/how-to-use-azure-powershell-v1-0-x-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager) - [Capture VM image with PowerShell v0.9.x](https://codeisahighway.com/how-to-use-azure-powershell-v0-9-x-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager) ## Capture is done, what's next? There is a bug in the actual implementation of the capture call. Whatever you specify in the *DestinationContainerName* it will save the image under a container named *System* in the storage account with a blob path containing the name you specified as the container name. This is an example of what you can expect as full path (yours will be a bit different depending on the parameter values you entered): `https://vmcapturedemo.blob.core.windows.net/system/Microsoft.Compute/Images/mytemplates/template-osDisk.c2a2a4e3-a2cb-44f1-9d55-921dfa29b314.vhd` If everything went well during the capture phase you'll have 2 new files in your storage account, a VHD file and an ARM template that was generated for you. This template is not usable as-is except if you already have a NIC that you can use, but you have all the information in it as to how to declare a virtual machine to use your custom VM image. Here is the `storageProfile` node from the file that was created for me: ```json "storageProfile": { "osDisk": { "osType": "Windows", "name": "template-osDisk.c2a2a4e3-a2cb-44f1-9d55-921dfa29b314.vhd", "createOption": "FromImage", "image": { "uri": "https://vmcapturedemo.blob.core.windows.net/system/Microsoft.Compute/Images/mytemplates/template-osDisk.c2a2a4e3-a2cb-44f1-9d55-921dfa29b314.vhd" }, "vhd": { "uri": "http://vmcapturedemo.blob.core.windows.net/vmcontainere14af8ec-3022-4fda-9a8f-dcc13ba5bdc0/osDisk.e14af8ec-3022-4fda-9a8f-dcc13ba5bdc0.vhd" }, "caching": "ReadWrite" } } ``` You now have an generalized VM image from which you can create as many virtual machines as you want. ## What's next? Want to create a new VM from the image you just captured? - See [How to create a virtual machine from a custom image using ARM and Azure PowerShell v1.0.x](https://codeisahighway.com/how-to-create-a-virtual-machine-from-a-custom-image-using-arm-and-azure-powershell-v1-0-x/) (Preferred for PowerShell) - See [How to create a virtual machine from a custom image using ARM and Azure PowerShell v0.9.x](https://codeisahighway.com/how-to-create-a-virtual-machine-from-a-custom-image-using-arm-api-and-powershell/) - See [How to create a virtual machine from a custom image using ARM Template](https://codeisahighway.com/how-to-create-a-virtual-machine-from-a-custom-image-using-an-arm-template/) ## Resources - [ARM Explorer](https://resources.azure.com/?ref=codeisahighway.com) - [Microsoft Azure PowerShell (latest release)](https://github.com/Azure/azure-powershell/releases/latest?ref=codeisahighway.com) - [Create a virtual machine running Windows in the Azure portal](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-tutorial/?ref=codeisahighway.com) ### See also - [Virtual Machines documentation](http://azure.microsoft.com/en-us/documentation/services/virtual-machines/?ref=codeisahighway.com) - [VM Image Blog Post](https://azure.microsoft.com/en-us/blog/vm-image-blog-post/?ref=codeisahighway.com) ### Footnotes --- 1. Resource Providers [↩︎](#fnref1) 2. Global Availability [↩︎](#fnref2) ### Use uniqueString() function to generate unique names for resources in ARM template URL: https://codeisahighway.com/use-uniquestring-function-to-generate-unique-names-for-resources-in-arm-template/ Last updated: 2026-08-10T07:12:41.000Z When playing with ARM templates in a team, you need a way to come up with unique names for your DNS dependent resources on Azure like storage accounts and public IPs. There is a function that has been released recently that will help you a lot with this need, the uniqueString() function. ## Unique but Non-Deterministic Having a unique value each time you perform a deployment is not very useful when dealing with ARM template. *I should add, you definitely don't want to do that as it goes against the deterministic state you intend to have in an ARM template*. A good example of this is if you use a GUID to be unique. You cannot, let say, use \[Guid\]::NewGuid() in PowerShell to generate a parameter value for a storage account simply because each time you'll deploy your template, you'll end up creating a new storage account, not really what you want. # Unique but deterministic... Say hello to uniqueString() `uniqueString (stringForCreatingUniqueString, ...)` What does this function? > Performs a 64-bit hash of the provided strings to create a unique string. This function is helpful when you need to create a unique name for a resource. You provide parameter values that represent the level of uniqueness for the result. You can specify whether the name is unique for your subscription, resource group, or deployment. The returned value is not a completely random string, but rather the result of a hash function. **The returned value is 13 characters long.** *It is not guaranteed to be globally unique. You may want to combine the value with a prefix from your naming convention to create a more friendly name.* You can use uniqueString() with the id of a subscription or resource group depending at which level you need the hashed result. You can even provide more than one parameter, all extra parameters will add to the hash calculation. An example of this is the following: `"[uniqueString( resourceGroup().id, deployment().name )]"` If you use the id of a subscription, the computed hash will change only when you deploy your template to a different subscription. It can be handful if you use different subscriptions as boundaries. Usually people have multiple resources in the same subscription so this option is good but not flexible enough in my scenario with multiple team members. What I usually suggest when dealing with a team of many developers is that each team member deploy in their own resource group. You can then use a unique prefix for your project or team to obtain global unique name. `[concat( parameters('storageNamePrefix'), uniqueString(resourceGroup().id) )]` ### Complete example Here is a complete example that creates a storage account. ``` { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageNamePrefix": { "type": "string", "metadata": { "description": "The prefix string to add to a generated string that is unique to the resourceGroup." } } }, "variables": { "storageName": "[toLower( concat( parameters('storageNamePrefix'), uniqueString(resourceGroup().id) ) )]", "location": "[resourceGroup().location]" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "name": "[variables('storageName')]", "apiVersion": "2015-06-15", "location": "[variables('location')]", "properties": { "accountType": "Standard_LRS" } } ], "outputs": { "storageAccountName": { "type": "string", "value": "[variables('storageName')]" } } } ``` Hope it help you in your unique naming quest! # Resources - [uniqueString ARM function](https://azure.microsoft.com/en-us/documentation/articles/resource-group-template-functions/?ref=codeisahighway.com#uniquestring) ### Understanding performance requirement and best practices with Azure Premium Storage URL: https://codeisahighway.com/understanding-performance-requirement-and-best-practices-with-azure-premium-storage/ Last updated: 2026-08-10T07:12:32.000Z In our modern world, IOPS, throughput and latency are key indicators when it comes to performance requirements of computers / Virtual Machines. I came across some really good best practices articles about how to identify and quantify your performance requirements for standard VM scenarios but also key scenarios like SQL Server when using Premium Storage. ## About Premium Storage Azure Premium Storage delivers high-performance, low-latency disk support for virtual machines running I/O-intensive workloads. Virtual machine (VM) disks that use Premium Storage store data on solid state drives (SSDs). You can migrate your application's VM disks to Azure Premium Storage to take advantage of the speed and performance of these disks. - [Premium Storage: High-Performance Storage for Azure Virtual Machine Workloads](https://azure.microsoft.com/documentation/articles/storage-premium-storage-preview-portal/?ref=codeisahighway.com) ## Plan & Gather Application Performance Indicators This article provides guidelines for building high performance applications using Azure Premium Storage. You can use the instructions provided in this document combined with performance best practices applicable to technologies used by your application. To illustrate the guidelines, we have used SQL Server running on Premium Storage as an example throughout this document. While we address performance scenarios for the Storage layer in this article, you will need to optimize the application layer. For example, if you are hosting a SharePoint Farm on Azure Premium Storage, you can use the SQL Server examples from this article to optimize the database server. Additionally, optimize the SharePoint Farm’s Web server and Application server to get the most performance. - [Azure Premium Storage: Design for High Performance](https://azure.microsoft.com/en-us/documentation/articles/storage-premium-storage-performance/?ref=codeisahighway.com) ## Azure Premium Storage with SQL Server This article provides planning and guidance for migrating a Virtual Machine running SQL Server to use Premium Storage. This includes Azure infrastructure (networking, storage) and guest Windows VM steps. > Azure has two different deployment models for creating and working with resources: Resource Manager and classic. This article covers using the classic deployment model. Microsoft recommends that most new deployments use the Resource Manager model. *Even if the article covers the classic deployment model, the principle underneath remain the sames whenever you use the classic or newer Resource Providers.* - [Use Azure Premium Storage with SQL Server on Virtual Machines](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-sql-server-use-premium-storage/?ref=codeisahighway.com) Have a good read and have fun with Premium Storage! ### How to troubleshoot Ghost installations & upgrades on Azure URL: https://codeisahighway.com/how-to-troubleshoot-ghost-installations-and-upgrades-on-azure/ Last updated: 2026-08-10T07:12:34.000Z I recently upgraded a Ghost site from a quite old version to a new one and like we often see it in a deployment... it did not went as expected. Let me tell you what I did to solve the problem so that it may save you some time if you encounter hat kind of problems with your Ghost deployment on Azure. ## All I see is a blank window Right after my deployment, I tried to hit the website to see if everything was OK... No error in the browser was shown but only a blank white page without any information. ![Blank site in error](https://codeisahighway.com/content/images/2015/11/SiteInErrorIsBlank.png) This is not what I expected, but how can you get more information when this happen on a web application where you cannot remote desktop on the machine behind? ## Say hello to the Kudu console! The Kudu console is a very helpful tool to get into the core of your web app, it enable you to perform tons of actions behind the scene. In this example, the site is named *ghost-azure5938*, which resolve to a url like: *ghost-azure5938.azurewebsites.net*. To access the Kudu console, you need to insert **scm** in the url like this: *ghost-azure5938.*scm*.azurewebsites.net* ![Kudu home](https://codeisahighway.com/content/images/2015/11/KuduHome.png) > I cannot emphasize enough that killing a process/deleting files can cause strange behaviors and may lead to data loss. Make sure you have a backup of your files before going further. ## View Ghost error logs ![PowerShell console in Kudu](https://codeisahighway.com/content/images/2015/11/KuduOpenPowerShellConsole.png) Now that you are in Kudu, we'll go see our node.js stderr logs. Open a PowerShell console using the menu at the top. Browse to *site/wwwroot/iisnode* and click edit (pencil button) to view the logs you are interested in, in my case, I checked one with *stderr* (error) in the filename. ![iisnode folder from console](https://codeisahighway.com/content/images/2015/11/KuduGhostLogsInIISNodeFolder.png) ![Error log in edit mode in Kudu](https://codeisahighway.com/content/images/2015/11/KuduGhostErrorLogEditMode.png) As you can see I have a problem with a dependency: sqlite3 In my case, I did the `npm install --production` command as instructed in the error message but it didn't help at all. I suspected a npm cache problem so I decided to delete the whole *site/wwwroot/node\_modules* folder thinking maybe an older dependency version was causing a problem during modules installation. I tried to delete *node\_modules* completely but the node.exe process was locking a dependency. To help here I needed to kill the node.exe process. ## Kill node.js process Browse to *Process explorer* and click on the *Properties* button of node.exe ![Process explorer in Kudu](https://codeisahighway.com/content/images/2015/11/KuduProcessExplorer.png) Browse to the bottom of the details window and you'll have the option to kill the process, this is what I've done in my case. I went back in a PowerShell console to the *site/wwwroot/node\_modules* and was able to delete the whole folder without problem. Now I needed to tell npm to reinstall all modules but the cache caused me problems before. Here is the commands I ran while being in the *site/wwwroot* folder: ![npm commands in wwwroot folder](https://codeisahighway.com/content/images/2015/11/KuduNpmCommands.png) ``` npm cache clean grunt clean npm install --production ``` After doing that, I tried to hit my website again and everything lifted as expected. ![Fixed and working Ghost installation](https://codeisahighway.com/content/images/2015/11/WorkingGhostWebsite.png) Hope it help you diagnose Ghost dependencies problems on Azure and where to look to have more information from node.js logs. ## Resources - [Ghost-Azure](https://github.com/felixrieseberg/Ghost-Azure?ref=codeisahighway.com) - [Felix Rieseberg](https://github.com/felixrieseberg?ref=codeisahighway.com) - [Using KUDU with Microsoft Azure Web Apps](http://blogs.msdn.com/b/benjaminperkins/archive/2014/03/24/using-kudu-with-windows-azure-web-sites.aspx?ref=codeisahighway.com) - [What is Kudu? - Azure Web Sites Deployment with David Ebbo](https://channel9.msdn.com/Shows/Azure-Friday/What-is-Kudu-Azure-Web-Sites-Deployment-with-David-Ebbo?ref=codeisahighway.com) ### ArtifactNotFound: References to Microsoft.Powershell DSC extension prior to v2.4 are broken and how to fix it URL: https://codeisahighway.com/artifactnotfound-references-to-microsoft-powershell-dsc-extension-prior-to-v2-4-are-broken-and-how-to-fix-it/ Last updated: 2026-07-23T03:03:38.000Z If you are experiencing this error: *"Extension with publisher 'Microsoft.Powershell', type 'DSC', and type handler version 'x.x' could not be found in the extension repository"* it is because Microsoft just pulled the cord on PowerShell DSC extension v1.x up to v2.3 a couple of days ago. And the reason is: > Today we retired versions 1.0 to 2.3 of the Azure DSC Extension. These versions use preview versions of WMF 5.0 whose signing certificates have expired, so it is no longer possible to install them. **This article apply only to Microsoft.Powershell DSC extension** and NOT for Microsoft.OSTCExtensions DSCForLinux. The recommended approach is to upgrade your scripts or templates to v2.4 or latest version (v2.8 is the latest version at the time of writing this). ## PowerShell You can be explicit and use the `Version` parameter to specify the version to use instead of the default one coded in the PowerShell cmdlet version you are using. ```powershell Set-AzureVMDscExtension -Version 2.8 … ``` ## ARM Templates There is no "useLatestVersion" option for ARM templates, the nearest thing you can use is the `autoUpgradeMinorVersion` property, this will automatically upgrade your extension to the latest minor version available. ie: If you were using v2.1, using this setting will enable v2.\* but not v3.0 ```json "properties": { "publisher": "Microsoft.Powershell", "type": "DSC", "typeHandlerVersion": "2.8", "autoUpgradeMinorVersion": "true", … } ``` **Important**: If you choose to use autoUpgradeMinorVersion property, be aware that when they release a new version with a new WMF your VM will be rebooted once during the upgrade. ### Reference - [Azure DSC Extension - Versions 1.0-2.3 no longer available](http://blogs.msdn.com/b/powershell/archive/2015/10/26/azure-dsc-extension-versions-1-0-2-3-no-longer-available.aspx?ref=codeisahighway.com) - [Release history for the Azure DSC Extension](http://blogs.msdn.com/b/powershell/archive/2014/11/20/release-history-for-the-azure-dsc-extension.aspx?ref=codeisahighway.com) ### PowerShell 1.0.0-Preview is here... Switch-AzureMode is dead, at last! URL: https://codeisahighway.com/powershell-1-0-0-preview-is-here-switch-azuremode-is-dead-at-last/ Last updated: 2026-08-23T10:22:12.000Z Azure PowerShell 1.0.0-preview is now available. It is in this version that the trigger is being pulled on Switch-AzureMode. Pow! Terminated! Gone!! Starting in version 1.0.0 both ASM and ARM PowerShell modules are able to coexists, but it also introduce breaking changes if you were already using Azure Resource Manager cmdlets. Here is a quick list of what has changed: - Cmdlets released to PowerShell Gallery - AzureResourceManager module split into component modules - Switch-AzureMode removed : cmdlets exist side-by-side - All ARM control plane cmdlets renamed from 'verb-Azure' to 'verb-AzureRm' - Stateless authentication for ARM cmdlets: new authentication cmdlets - Add-AzureRmAccount - login to azure using user, service principal, or access token credentials - Set-AzureRmContext - set the current subscription or tenant - Get-AzureRmSubscription - list subscriptions - Save-AzureRmProfile - save credential information to disk - Select-AzureRmProfile - load credential information from disk - Storage cmdlet enhancements for ARM storage accounts - Get-AzureRmStorageAccount | Get-AzureStorageContainer (or other storage commands that accept a StorageContext) - Set-AzureRmCurrentStorageAccount - set the current storage account for use by storage cmdlets You can have more information about the release here: - [Azure PowerShell 1.0 Preview](https://azure.microsoft.com/en-us/blog/azps-1-0-pre/?ref=codeisahighway.com) - [Changes to Azure Resource Manager management PowerShell cmdlets](https://azure.microsoft.com/en-us/documentation/articles/powershell-preview-resource-manager-changes/?ref=codeisahighway.com) You can get the release from here: [Azure PowerShell 1.0.0-preview (PowerShellGallery)](https://github.com/Azure/azure-powershell/releases/tag/v1.0.0-preview-gallery-October2015?ref=codeisahighway.com) Has stated above, this preview and the upcomming 1.0.0 release introduce breaking changes, please play with it in advance and plan some times to update your existing scripts targeting Azure Resource Manager API accordingly. If you need an introduction on how to install the preview and how to get started with the previre release, you can refer to this good article from Michael Jonsson: [Getting Started With Azure PowerShell 1.0 Preview #ARM](http://azurefabric.com/getting-started-with-azure-powershell-1-0-preview-arm/?ref=codeisahighway.com) Happy Scripting! ### I received a 2015 Microsoft Azure MVP Award URL: https://codeisahighway.com/i-received-a-2015-microsoft-azure-mvp-award/ Last updated: 2026-07-31T19:44:46.000Z It is with an immense pleasure that I got an email on October 1st 2015... The title was saying: **Congratulations 2015 Microsoft MVP!‏**, and inside: > Dear Stephane Lapointe, > Congratulations! We are pleased to present you with the 2015 Microsoft® MVP Award! This award is given to exceptional technical community leaders who actively share their high quality, real world expertise with others. We appreciate your outstanding contributions in Microsoft Azure technical communities during the past year. > ... > The Microsoft MVP Award provides us the unique opportunity to celebrate and honor your significant contributions and say "Thank you for your technical leadership." > Mike Hickman > Director > Community Engagement > Microsoft ![2015 Microsoft Azure MVP Award email](https://codeisahighway.com/content/images/2015/10/MVPAwardEmail.png) It is really a good pat on the back from Microsoft for the efforts I've put into the Azure community. It is really rewarding to receive that award knowing that there is only around 4000 Microsoft Most Valuable Professionals worldwide. ![Microsoft MVP Logo](https://codeisahighway.com/content/images/2015/10/MVP_Logo_Horizontal_Preferred_Cyan300_RGB_300ppi.png) I will continue that path and who knows... maybe I'll see that email again next year :D ### We are hosting a viewing party in Montreal for AzureCon 2015 URL: https://codeisahighway.com/hosting-a-viewing-party-in-montreal-for-azurecon-2015/ Last updated: 2026-07-17T08:37:03.000Z By now, you sure have heard of the AzureCon virtual conference at the end of September, the 29th to be precise. I have the pleasure to hold a viewing party with other Azure passionate people and some MVPs in Microsoft Canada's office in Montreal. Do you want to live this live instead of being alone in front of you computer? People are already on the waiting list but register if you want to come, we never know if some places free themselves at the last minute. [http://www.meetup.com/msdevmtl/events/225368241/](http://www.meetup.com/msdevmtl/events/225368241/?ref=codeisahighway.com) You'll be able to take on the AzureCon challenge with us. See you there! ### How to create a virtual machine from a custom image using an ARM template URL: https://codeisahighway.com/how-to-create-a-virtual-machine-from-a-custom-image-using-an-arm-template/ Last updated: 2026-08-10T07:12:31.000Z Wish you could deploy your own virtual machines from a custom image (specialized or generalized) using an Azure Resource Manager template? He're is how to do it... ## Prerequisites - A custom VM image captured using the Azure Resource Manager API (more detail just below) ## Things to know before you get started Here is few items you need to be aware before you continue... ### The custom VM image need to have been captured using a v2 Compute resource provider VM images captured from a v1 Compute resource provider (Microsoft.ClassicCompute) cannot be used to create virtual machines using a v2 Compute resource provider (Microsoft.Compute) or the other way around. If you need a new image after reading this, see *Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager API* in the [References](#References) section. ### The Custom VM image need to reside in the same storage account as your virtual machine at creation time Another important limitation is that the image need to be present at creation time in the very same storage account that will host your virtual machine's vhd. *The custom VM image can be deleted afterward without problems.* It's not that big thing if you are using a standard storage account. On the other hand, if you want your virtual machine to run on premium storage, leaving that P10 (or bigger) custom VM image around, doing nothing, will cost you the same money per month as any other premium storage disk. For more details, see *Azure Storage Pricing* link in the [References](#References) section. ## Creating a virtual machine from the custom image Now the fun part... In a basic example, you'll see how to reference your custom image in the VM creation process using an ARM template. *We assume the storage account already exists since you are supposed to have your custom VM image already in it at this point.* When you created your custom VM image there was a json file generated at the same time. In the storageProfile node, take a look at the image URI and save this information somewhere, we'll need it later. ```language-json { "storageProfile": { "osDisk": { "osType": "Windows", "name": "template-osDisk.187d9455-535b-48b4-b10d-8370ec9bad42.vhd", "createOption": "FromImage", "image": { "uri": "http://vmcapturetestdemo.blob.core.windows.net/system/Microsoft.Compute/Images/mytemplates/template-osDisk.187d9455-535b-48b4-b10d-8370ec9bad42.vhd" }, "vhd": { "uri": "http://vmcapturetestdemo.blob.core.windows.net/vmcontainerd1bd9914-b1e8-44a0-a06c-663eedda8d1a/osDisk.d1bd9914-b1e8-44a0-a06c-663eedda8d1a.vhd" }, "caching": "ReadWrite" } } } ``` The very first thing to do is to create an ARM template. There is plenty of way to do this. If you need full control over your template, you can create an *Azure Resource Group project* using the Azure SDK in Visual Studio. If you want to go this way I created an article a while ago that can help you get started named *How to create and deploy a development machine on Azure using Azure Resource Manager template in Visual Studio* (see the [References](#References) section). If you intend to do this, take the `storageProfile` node from your generated json file and replace that very same section in the template in Visual Studio. Be sure to adjust the image URI and vhd URI properties if needed. There is a basic template that already exist for this in the *Azure quickstart templates* repo on GitHub and we'll use it. Browse to the template page [101-vm-from-user-image template](https://github.com/Azure/azure-quickstart-templates/tree/master/101-vm-from-user-image?ref=codeisahighway.com) and take a minute to check the readme section. This template creates a VM from a custom image, a virtual network, a public IP and a NIC. ![101-vm-from-user-image template](https://codeisahighway.com/content/images/2015/09/TemplateOverview.png) Before you click the *Deploy to Azure* button, we'll take a look at the template parameters. There is more parameters than the three listed below, we'll only concentrate on those that are related to the custom image. ## Custom VM image related parameters in the template ```language-json "parameters": { "userImageStorageAccountName": { "type": "string", "metadata": { "description": "This is the name of the your storage account" } }, "userImageStorageContainerName": { "type": "string", "metadata": { "description": "This is the name of the container in your storage account" } }, "userImageVhdName": { "type": "string", "metadata": { "description": "This is the name of the your customized VHD" } } } ``` ### userImageStorageAccountName Correspond to the storage account name where your vhd will be created but also where your custom image is located. Ex: In our image URI, it correspond to the subdomain `vmcapturetestdemo` in the host *blob.core.windows.net* http://vmcapturetestdemo.blob.core.windows.net/system/Microsoft.Compute/Images/mytemplates/template-osDisk.187d9455-535b-48b4-b10d-8370ec9bad42.vhd ### userImageStorageContainerName Correspond to the storage account's container. Ex: In our image URI, it correspond to `system`. It is the first segment in the path. http://vmcapturetestdemo.blob.core.windows.net/system/Microsoft.Compute/Images/mytemplates/template-osDisk.187d9455-535b-48b4-b10d-8370ec9bad42.vhd ### userImageVhdName Correspond to the blob filename. Ex: In our image URI, it correspond to `Microsoft.Compute/Images/mytemplates/template-osDisk.187d9455-535b-48b4-b10d-8370ec9bad42.vhd`. It is all the remaining path after the container name. http://vmcapturetestdemo.blob.core.windows.net/system/Microsoft.Compute/Images/mytemplates/template-osDisk.187d9455-535b-48b4-b10d-8370ec9bad42.vhd ## Time to deploy You can now click the deploy button from the template page you just opened. ![Deploy To Azure button](https://codeisahighway.com/content/images/2015/09/DeployToAzureButton.png) You will be redirected to the Azure preview portal on the *Parameters* section of a *Custom deployment* blade. Fill the parameters values as needed and click the OK button. ![Custom Deployment Parameters](https://codeisahighway.com/content/images/2015/09/PortalTemplateParameters.png) If you need more information about a parameter you can click the little exclamation mark near the parameter name in the portal, ex: ![Template parameter description](https://codeisahighway.com/content/images/2015/09/PortalTemplateParameterDescription.png) You can change your subscription if needed. Now for the Resource Group, choose your storage account's Resource Group. ![Custom Deployment Resource Group selection](https://codeisahighway.com/content/images/2015/09/PortalTemplateSelectResourceGroup.png) You can ignore *Resource Group location* since you are not creating a new one. Click the *Legal terms* section, read the Legal terms and click the **Buy** button when ready. ![Custom Deployment Legal terms](https://codeisahighway.com/content/images/2015/09/PortalTemplateLegalTerms.png) As a last step, click the **Create** button to start the template deployment. ![Custom Deployment Ready to deploy template](https://codeisahighway.com/content/images/2015/09/PortalTemplateReadyToCreate.png) If all goes well you'll have a new virtual machine named *MyVm* for you to play with. Have fun! ## References - [Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager API](https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api) - [Azure Storage Pricing](http://azure.microsoft.com/en-us/pricing/details/storage/?ref=codeisahighway.com) - [Azure Resource Manager QuickStart Templates](https://github.com/Azure/azure-quickstart-templates?ref=codeisahighway.com) - [How to create and deploy a development machine on Azure using Azure Resource Manager template in Visual Studio](https://codeisahighway.com/how-to-create-and-deploy-a-development-machine-on-azure-using-azure-resource-manager-template-in-visual-studio) ### How to create a virtual machine from a custom image using ARM and Azure PowerShell v0.9.x URL: https://codeisahighway.com/how-to-create-a-virtual-machine-from-a-custom-image-using-arm-api-and-powershell/ Last updated: 2026-07-31T19:44:48.000Z You love PowerShell, have a custom VM image (specialized or generalized) and you want to create a new virtual machine from it under Azure Resource Manager API? You're at the right place... ## Prerequisites - Microsoft Azure PowerShell v0.9.4 or later, I used 0.9.7 - A custom VM image captured using the Azure Resource Manager API (more detail just below) ## Things to know before you get started Here is few items you need to be aware before you continue... ### The custom VM image need to have been captured using a v2 Compute resource provider VM images captured from a v1 Compute resource provider (Microsoft.ClassicCompute) cannot be used to create virtual machines using a v2 Compute resource provider (Microsoft.Compute) or the other way around. If you need a new image after reading this, see *Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager API* in the [References](#References) section. ### The Custom VM image need to reside in the same storage account as your virtual machine at creation time Another important limitation is that the image need to be present at creation time in the very same storage account that will host your virtual machine's vhd. *The custom VM image can be deleted afterward without problems.* It's not that big thing if you are using a standard storage account. On the other hand, if you want your virtual machine to run on premium storage, leaving that P10 (or bigger) custom VM image around, doing nothing, will cost you the same money per month as any other premium storage disk. For more details, see *Azure Storage Pricing* link in the [References](#References) section. ## Creating a virtual machine from the custom image Now the fun part... In a basic example, you'll see how to reference your custom image in the VM creation process using PowerShell cmdlets. Ready? *We assume the storage account already exists since you are supposed to have your custom VM image already in it at this point.* First we need to authenticate against Azure, use the desired subscription and storage account. ```language-powershell Add-AzureAccount Switch-AzureMode AzureResourceManager Select-AzureSubscription -SubscriptionId $subscriptionId $storageAccount = Get-AzureStorageAccount -Name $storageAccountName ``` We create the networking resources for the VM ```language-powershell # Create the VNET $vnetDef = New-AzureVirtualNetwork -ResourceGroupName $resourceGroupName -Location $location -Name $vnetName -AddressPrefix '10.0.0.0/16' $vnet = $vnetDef | Add-AzureVirtualNetworkSubnetConfig -Name 'Subnet-1' -AddressPrefix '10.0.0.0/24' | Set-AzureVirtualNetwork # Create the NIC $pip = New-AzurePublicIpAddress -ResourceGroupName $resourceGroupName -Location $location -Name $ipName -DomainNameLabel $domName -AllocationMethod Dynamic $nic = New-AzureNetworkInterface -ResourceGroupName $resourceGroupName -Location $location -Name $nicName -PublicIpAddressId $pip.Id -SubnetId $vnet.Subnets[0].Id ``` Now we can create the VM configuration and glue it all together. Pay special attention to the `-SourceImageUri` parameter of the `Set-AzureVMOSDisk` cmdlet, this is where we specify the location of the custom VM image to use. ```language-powershell # Specify the VM name and size $vm = New-AzureVMConfig -VMName $vmName -VMSize $vmSize # Specify local administrator account, and then add the NIC $cred = New-Object PSCredential $adminUsername, ($adminPassword | ConvertTo-SecureString -AsPlainText -Force) $vm = Set-AzureVMOperatingSystem -VM $vm -Windows -ComputerName $vmName -Credential $cred -ProvisionVMAgent -EnableAutoUpdate $vm = Add-AzureVMNetworkInterface -VM $vm -Id $nic.Id # Specify the OS disk $diskName = 'osdisk' $osDiskUri = '{0}vhds/{1}{2}.vhd' -f $storageAccount.PrimaryEndpoints.Blob.ToString(), $vmName.ToLower(), $diskName $vm = Set-AzureVMOSDisk -VM $vm -Name $diskName -VhdUri $osDiskUri -CreateOption fromImage -SourceImageUri $sourceImageUri -Windows ``` ## Sample script Here is a basic but complete script, without much error handling to reduce complexity... Please note that this script deploy a Windows machine, replace the `-Windows` switch for the `-Linux` switch in the `Set-AzureVMOperatingSystem` & `Set-AzureVMOSDisk` cmdlets if you want to deploy a Linux machine. ```language-powershell # We'll use a couple of variable here, fill these with your own values $subscriptionId = '' # Your SubscriptionId $storageAccountName = '' # Storage account name where your custom image is and where your VM vhd will go $sourceImageUri = '' # custom VM image blob uri, ex: 'https://vmcapturetest.blob.core.windows.net/system/Microsoft.Compute/Images/mytemplates/template-osDisk.187d9455-535b-48b4-b10d-8370ec9bad42.vhd' # end of custom variables # Authenticate against Azure and cache subscriptions data Add-AzureAccount # Switch to the Resource Manager mode, this will be deprecated really soon... Switch-AzureMode AzureResourceManager # Switch subscription Select-AzureSubscription -SubscriptionId $subscriptionId # Get the storage account $storageAccount = Get-AzureStorageAccount -Name $storageAccountName # Enable verbose output and stop on error $VerbosePreference = 'Continue' $ErrorActionPreference = 'Stop' # some reserved script variables $resourceGroupName = $storageAccount.ResourceGroupName $location = $storageAccount.Location $adminUsername = 'VmAdministrator' $adminPassword = '123!SomeUnSecurePassword!098' $vmSuffix = Get-Random -Minimum 10000 -Maximum 99999 $vmName = 'VM{0}' -f $vmSuffix $vmSize = 'Standard_D3' $nicName = 'VM{0}-NIC' -f $vmSuffix $ipName = 'VM{0}-IP' -f $vmSuffix $domName = 'vm-from-customimage-powershell-{0}' -f $vmSuffix $vnetName = $vmName # Create the VNET Write-Verbose 'Creating Virtual Network' $vnetDef = New-AzureVirtualNetwork -ResourceGroupName $resourceGroupName -Location $location -Name $vnetName -AddressPrefix '10.0.0.0/16' Write-Verbose 'Adding subnet to Virtual Network' $vnet = $vnetDef | Add-AzureVirtualNetworkSubnetConfig -Name 'Subnet-1' -AddressPrefix '10.0.0.0/24' | Set-AzureVirtualNetwork # Create the NIC Write-Verbose 'Creating Public IP' $pip = New-AzurePublicIpAddress -ResourceGroupName $resourceGroupName -Location $location -Name $ipName -DomainNameLabel $domName -AllocationMethod Dynamic Write-Verbose 'Creating NIC' $nic = New-AzureNetworkInterface -ResourceGroupName $resourceGroupName -Location $location -Name $nicName -PublicIpAddressId $pip.Id -SubnetId $vnet.Subnets[0].Id # Specify the VM name and size Write-Verbose 'Creating VM Config' $vm = New-AzureVMConfig -VMName $vmName -VMSize $vmSize # Specify local administrator account, and then add the NIC $cred = New-Object PSCredential $adminUsername, ($adminPassword | ConvertTo-SecureString -AsPlainText -Force) # you could use Get-Credential instead to get prompted # NOTE: if you are deploying a Linux machine, replace the -Windows switch with a -Linux switch. $vm = Set-AzureVMOperatingSystem -VM $vm -Windows -ComputerName $vmName -Credential $cred -ProvisionVMAgent -EnableAutoUpdate $vm = Add-AzureVMNetworkInterface -VM $vm -Id $nic.Id # Specify the OS disk $diskName = 'osdisk' $osDiskUri = '{0}vhds/{1}{2}.vhd' -f $storageAccount.PrimaryEndpoints.Blob.ToString(), $vmName.ToLower(), $diskName # NOTE: if you are deploying a Linux machine, replace the -Windows switch with a -Linux switch. $vm = Set-AzureVMOSDisk -VM $vm -Name $diskName -VhdUri $osDiskUri -CreateOption fromImage -SourceImageUri $sourceImageUri -Windows Write-Verbose 'Creating VM...' $result = New-AzureVM -ResourceGroupName $resourceGroupName -Location $location -VM $vm if($result.Status -eq 'Succeeded') { $result Write-Verbose ('VM named ''{0}'' is now ready, you can connect using username: {1} and password: {2}' -f $vmName, $adminUsername, $adminPassword) } else { Write-Error 'Virtual machine was not created sucessfully.' } ``` At the end you should have an output that look like this in your PowerShell window ![Execution Overview of VM creation](https://codeisahighway.com/content/images/2015/09/ExecutionOverview.png) Hope it helped you a bit in your Azure adventure. ## References - [Step by Step: How to capture your own custom virtual machine image under Azure Resource Manager](https://codeisahighway.com/how-to-capture-your-own-custom-virtual-machine-image-under-azure-resource-manager-api) - [Azure Storage Pricing](http://azure.microsoft.com/en-us/pricing/details/storage/?ref=codeisahighway.com) ### Speaker session: Azure Resource Manager templates: improve deployment time and reusability URL: https://codeisahighway.com/speaker-session-azure-resource-manager-templates-improve-deployment-time-and-reusability/ Last updated: 2026-07-23T03:05:14.000Z I am very proud that my session named: *Azure Resource Manager templates: improve deployment time and reusability* has been selected for the [COLLAB365](http://www.collab365.events/?ref=codeisahighway.com) event in October this year (2015) Drastically improve your deployment time when dealing with multiple Azure resources and reduce the amount of code you need to achieve the same result with a template compared to regular PowerShell provisioning code. You will learn : - How to create a template definition - How to use template parameters - What template functions are available and when to use them - How to use the virtual machine CustomScriptExtension to perform everything you want without the need of exposing remote PowerShell Join us in this big event where over 100 sessions will be given over 24h! ![COLLAB365 Speaker Badge](https://codeisahighway.com/content/images/2015/08/speakers-badge.png) ### How to create Microsoft Azure 3D blueprints using the 3D Visio template URL: https://codeisahighway.com/how-to-create-microsoft-azure-3d-blueprints-using-the-3d-visio-template/ Last updated: 2026-07-31T19:44:51.000Z Ever saw those beautiful Azure 3D blueprints from Microsoft and wanted to know how to create some yourself? The good news is that everything you need is now available. We have been used to 2D diagrams and blueprints for several years. Icons and symbols change from time to time but nothing really exciting happened in this field since a long time, until last year... I came across a series of 3D blueprints on Microsoft website and I wanted to create some like this ever since. ## Never heard of them... What 3D architecture blueprints? Ever came across diagrams like this? ![E-Commerce Website 3D architecture diagram](https://codeisahighway.com/content/images/2015/08/ECommerce3DBlueprintExample.png) The look is very appealing and produce a WOW effects for sure. Microsoft had a few of them on his website for a while now, you can take a look at them if you didn't have already [here](https://msdn.microsoft.com/dn630664?ref=codeisahighway.com). ## What you'll need - Microsoft Visio 2013 or later - The [3D blueprint Visio template](http://aka.ms/3DBlueprintTemplate?ref=codeisahighway.com) - The [Microsoft Azure symbols](http://aka.ms/CnESymbols?ref=codeisahighway.com) for the 3D template There is very good training video from Robert Boucher, the one who created the same 3D blueprints you can see on the Microsoft website, that explain how to create them yourself. With the 3D template, the symbols and the training video, you have everything you need to create yourself beautiful 3D blueprints that will impress your audience! ### Groupe Azure: Développer des microservices avec Service Fabric URL: https://codeisahighway.com/groupe-azure-developper-des-microservices-avec-service-fabric/ Last updated: 2026-07-23T03:05:17.000Z J'aurai la chance de présenter le 1 décembre 2015 une soirée complète sur Service Fabric pour les membres de [MSDEVMTL](http://www.meetup.com/msdevmtl/?ref=codeisahighway.com) *Voici le synopsis de la session en question:* Une soirée complète sur Service Fabric! Nous débuterons par la base en explorant l'architecture de Service Fabric et les modèles de programmation qu'il propose, les "Reliable Actors" et "Reliable Services". Nous discuterons des partitions et de l'importance à leur accorder en début de conception. Comme il est plus agréable d'apprendre avec des exemples, nous verrons le cycle de vie complet d'une application au sein de Service Fabric et les outils offert par la plateforme; développement, packaging, déploiement, tests de stabilités, mises à jour et maintenance sont les sujets que nous explorerons. À la fin de cette rencontre, vous aurez les connaissances nécessaires pour mener à bien un projet de microservices en utilisant Service Fabric. Conférencier: Stéphane Lapointe [Meetup ici](http://www.meetup.com/msdevmtl/events/223839887/?ref=codeisahighway.com) ### You can now jump directly to some resources in Azure Resource Explorer from Azure preview portal URL: https://codeisahighway.com/you-can-now-jump-directly-to-some-resources-in-azure-resource-explorer-from-azure-preview-portal/ Last updated: 2026-07-30T19:45:43.000Z The preview portal is in constant improvement and Azure web app got a little one lately. The ability from an Azure web app to jump to this specific resource in Azure Resource Explorer. ## What is Azure Resource Explorer This tool was created by David Ebbo and a few folks at Microsoft. Taken from his blog: > Azure Resource Explorer is a new web site where you can easily: - Discover the Azure Resource Management APIs - Get API documentation - Make actual API calls directly in your own subscriptions It is really a useful tool if you want to explore/perform Azure Resource Manager APIs calls. You even have some PowerShell equivalent scripts for the action you take on resources. ## Where is that link in the portal? If you open the Azure preview portal at: [http://portal.azure.com](http://portal.azure.com/?ref=codeisahighway.com) and you browse to your desired web app, and click the **Tools** button. ![Web App Tools button](https://codeisahighway.com/content/images/2015/07/WebAppToolButton.png) On the appearing blade, choose **ARM Explorer** and click **GO ->** to jump directly to your resource in Azure Resource Explorer. ![ARM Explorer link in blade](https://codeisahighway.com/content/images/2015/07/WebAppToolsBlade.png) It's little things like this that help you save time at the end. Great addition! ### Resources - [Azure Resource Explorer: a new tool to discover the Azure API](https://azure.microsoft.com/blog/2015/04/02/azure-resource-explorer-a-new-tool-to-discover-the-azure-api/?ref=codeisahighway.com) - [David Ebbo on Twitter](https://twitter.com/davidebbo?ref=codeisahighway.com) ### Free Azure and .NET courses from Pluralsight for MSDN subscribers URL: https://codeisahighway.com/free-azure-and-dotnet-courses-from-pluralsight-for-msdn-subscribers/ Last updated: 2026-07-17T08:38:18.000Z In your never ending quest for improvement, you may ask yourself where to get courses and content to learn more and more. You can find plenty of content on the internet, but as a MSDN subscriber you can add Pluralsight on your list. As a MSDN subscriber you have access to a a variety of Azure and .NET courses for free depending subscription level. If you are interested in Azure learning, here is what you can get at the time of writing this article (July 2015): - [Building a Site with Bootstrap, AngularJS, ASP.NET, EF and Azure](http://www.pluralsight.com/courses/site-building-bootstrap-angularjs-ef-azure?ref=codeisahighway.com) - [Microsoft Azure for Enterprises: What and Why](http://www.pluralsight.com/courses/pluralsight-original-microsoft-azure-enterprises?ref=codeisahighway.com) - [Plan, Create, and Deploy to Azure With Visual Studio Online](http://www.pluralsight.com/courses/deploy-azure-visual-studio-online?ref=codeisahighway.com) Want to improve your programming skill, here are 2-3 examples of what you can get: - [Asynchronous C# 5.0](http://www.pluralsight.com/courses/skeet-async?ref=codeisahighway.com) - [C# Generics](http://www.pluralsight.com/courses/csharp-generics?ref=codeisahighway.com) - [ASP.NET MVC 5 Fundamentals](http://www.pluralsight.com/courses/aspdotnet-mvc5-fundamentals?ref=codeisahighway.com) Interested in courses not included for free? > In addition, MSDN subscribers qualify for a special 30% discount on an individual annual or annual plus subscription to the entire Pluralsight library. Want more details? Visit [Which Courses are Included with the benefit?](http://support.pluralsight.com/knowledgebase/articles/456830-which-courses-are-included-with-the-benefit?ref=codeisahighway.com) Happy learning! ### How to create and deploy a development machine on Azure using Azure Resource Manager template in Visual Studio URL: https://codeisahighway.com/how-to-create-and-deploy-a-development-machine-on-azure-using-azure-resource-manager-template-in-visual-studio/ Last updated: 2026-07-31T19:44:52.000Z Azure Resource manager have been around for a while now and it made provisioning quite easy and convenient. A couple of persons have asked me how to create and manage development machines when I speak about dev/tests environment in Azure, I'll explain you one way of doing this. If you follow this step by step guide, at the end, you'll get a development box running Visual Studio 2015 community edition. Your VM will be running on Azure Premium Storage. > We'll use a premium storage account in our VM template. It is not that expensive for a 127GB disk and we'll have greater performance compared with standard storage. ## Pre-requisites - An Azure subscription - Visual Studio 2015 and Azure SDK 2.6 or later > This article is not an introduction to Azure Resource Manager, if you need to catch up or learn on ARM, please see the *References* section at the end of the article. ## Steps to create and customize your ARM template ### Step 1 Launch Visual Studio 2015 and create a new *Azure Resource Group Project*. ![Create Azure Resource Group project](https://codeisahighway.com/content/images/2015/07/NewResourceGroupProject.png) ### Step 2 Choose the *Windows Virtual Machine template* and click OK ![ARM Windows virtual machine template](https://codeisahighway.com/content/images/2015/07/ChooseWindowsVirtualMachineTemplate.png) This will create you a project in Visual Studio with a couple of files. The most important files are the one under the *Templates* folder, your deployment template and deployment parameters files. ![Files created by Azure Resource Group project](https://codeisahighway.com/content/images/2015/07/AfterARMProjectCreation.png) ### Step 3 Open the template file named: *WindowsVirtualMachine.json* ### Step 4 Locate the *windowsOSVersion* parameter and replace the whole parameter with the following: ```json "imageSku": { "type": "string", "defaultValue": "VS-2015-Community-AzureSDK-2.7-WS2012R2", "allowedValues": [ "VS-2015-Community-AzureSDK-2.7-WS2012R2", "VS-2015-Enterprise-AzureSDK-2.7-WS2012R2" ], "metadata": { "description": "The Visual Studio version for the VM. This will pick a fully patched image of this Visual Studio version. Allowed values: VS-2015-Community-AzureSDK-2.7-WS2012R2, VS-2015-Enterprise-AzureSDK-2.7-WS2012R2." } } ``` Add the following parameter at the end of the parameters section: ``` "resourcesLocation": { "type": "string", "defaultValue": "East US 2", "allowedValues": [ "West US", "East US 2", "West Europe", "East China", "Southeast Asia", "West Japan", "Australia East" ], "metadata": { "description": "The location of resources created in this template. Default value is East US 2." } } ``` ### Step 5 Change the values of the following variables: ```json "vmName": "MyDevBoxVM" "location": "[parameters('resourcesLocation')]" "OSDiskName": "osdisk-devbox" "imageOffer": "VisualStudio" "imagePublisher": "MicrosoftVisualStudio" "nicName": "devBoxNic" "publicIPAddressName": "devBoxPublicIP" "storageAccountType": "Premium_LRS" "vmName": "MyVS2015DevBoxVM" "vmSize": "Standard_DS2" ``` The important changes to understand in the variables above are: - **imagePublisher**: We changed this because we want to use the Visual Studio images instead of Windows images - **ImageOffer**: Again, we want to use a Visual Studio image offering - **storageAccountType**: We use a premium storage account instead of a regular storage account - **vmSize**: We need to use a DS serie VM, only them at the moment support premium storage. - **location**: At the time of writing this article (July 2015), Premium Storage is not available in all Azure locations, see *Important Things to Know About Premium Storage* in *References* section for more information. ### Step 6 Replace the *imageReference* section of the virtual machine resource with the following: ```json "imageReference": { "publisher": "[variables('imagePublisher')]", "offer": "[variables('imageOffer')]", "sku": "[parameters('imageSku')]", "version": "latest" } ``` ### Resulting template You should end up with the following result for your template: ```json { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "adminPassword": { "metadata": { "description": "Password for the Virtual Machine." }, "type": "securestring" }, "adminUsername": { "metadata": { "description": "Username for the Virtual Machine." }, "type": "string" }, "dnsNameForPublicIP": { "metadata": { "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." }, "type": "string" }, "imageSku": { "allowedValues": [ "VS-2015-Community-AzureSDK-2.7-WS2012R2", "VS-2015-Enterprise-AzureSDK-2.7-WS2012R2" ], "defaultValue": "VS-2015-Community-AzureSDK-2.7-WS2012R2", "metadata": { "description": "The Visual Studio version for the VM. This will pick a fully patched image of this Visual Studio version. Allowed values: VS-2015-Community-AzureSDK-2.7-WS2012R2, VS-2015-Enterprise-AzureSDK-2.7-WS2012R2." }, "type": "string" }, "newStorageAccountName": { "metadata": { "description": "Unique DNS Name for the Storage Account where the Virtual Machine's disks will be placed." }, "type": "string" }, "resourcesLocation": { "allowedValues": [ "West US", "East US 2", "West Europe", "East China", "Southeast Asia", "West Japan", "Australia East" ], "defaultValue": "East US 2", "metadata": { "description": "The location of resources created in this template. Default value is East US 2." }, "type": "string" } }, "resources": [ { "apiVersion": "2015-05-01-preview", "location": "[variables('location')]", "name": "[parameters('newStorageAccountName')]", "properties": { "accountType": "[variables('storageAccountType')]" }, "tags": { "displayName": "StorageAccount" }, "type": "Microsoft.Storage/storageAccounts" }, { "apiVersion": "2015-05-01-preview", "location": "[variables('location')]", "name": "[variables('publicIPAddressName')]", "properties": { "dnsSettings": { "domainNameLabel": "[parameters('dnsNameForPublicIP')]" }, "publicIPAllocationMethod": "[variables('publicIPAddressType')]" }, "tags": { "displayName": "PublicIPAddress" }, "type": "Microsoft.Network/publicIPAddresses" }, { "apiVersion": "2015-05-01-preview", "location": "[variables('location')]", "name": "[variables('virtualNetworkName')]", "properties": { "addressSpace": { "addressPrefixes": [ "[variables('addressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[variables('subnetPrefix')]" } } ] }, "tags": { "displayName": "VirtualNetwork" }, "type": "Microsoft.Network/virtualNetworks" }, { "apiVersion": "2015-05-01-preview", "dependsOn": [ "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" ], "location": "[variables('location')]", "name": "[variables('nicName')]", "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" }, "subnet": { "id": "[variables('subnetRef')]" } } } ] }, "tags": { "displayName": "NetworkInterface" }, "type": "Microsoft.Network/networkInterfaces" }, { "apiVersion": "2015-05-01-preview", "dependsOn": [ "[concat('Microsoft.Storage/storageAccounts/', parameters('newStorageAccountName'))]", "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" ], "location": "[variables('location')]", "name": "[variables('vmName')]", "properties": { "hardwareProfile": { "vmSize": "[variables('vmSize')]" }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" } ] }, "osProfile": { "adminPassword": "[parameters('adminPassword')]", "adminUsername": "[parameters('adminUsername')]", "computername": "[variables('vmName')]" }, "storageProfile": { "imageReference": { "offer": "[variables('imageOffer')]", "publisher": "[variables('imagePublisher')]", "sku": "[parameters('imageSku')]", "version": "latest" }, "osDisk": { "caching": "ReadWrite", "createOption": "FromImage", "name": "osdisk", "vhd": { "uri": "[concat('http://',parameters('newStorageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/',variables('OSDiskName'),'.vhd')]" } } } }, "tags": { "displayName": "VirtualMachine" }, "type": "Microsoft.Compute/virtualMachines" } ], "variables": { "OSDiskName": "osdisk-devbox", "addressPrefix": "10.0.0.0/16", "imageOffer": "VisualStudio", "imagePublisher": "MicrosoftVisualStudio", "location": "[parameters('resourcesLocation')]", "nicName": "devBoxNic", "publicIPAddressName": "devBoxPublicIP", "publicIPAddressType": "Dynamic", "storageAccountType": "Premium_LRS", "subnetName": "Subnet", "subnetPrefix": "10.0.0.0/24", "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", "virtualNetworkName": "MyVNET", "vmName": "MyDevBoxVM", "vmSize": "Standard_DS2", "vmStorageAccountContainerName": "vhds", "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]" } } ``` ### Step 8 Right-click your project node in Visual studio and choose *Deploy* / *New Deployment...* ![New ARM template deployment from Visual Studio](https://codeisahighway.com/content/images/2015/07/NewTemplateDeploymentFromVS.png) - Choose your Azure subscription - Select and existing or a create a new resource group. (**Ensure your resource group location support Premium storage**) ![Create resource group](https://codeisahighway.com/content/images/2015/07/CreateResourceGroup.png) ![Deploy to Resource group dialog](https://codeisahighway.com/content/images/2015/07/DeployToResourceGroupDialog.png) - Click Deploy You'll get prompted for parameters values, specially the *adminPassword* if you don't click the "save passwords" checkbox. - Enter the information and click save. > Pay special attention to the format you use for the dnsNameForPublicIP and newStorageAccountName parameters. **They need to be alphanumeric only and lowercase** ![Deployment parameters](https://codeisahighway.com/content/images/2015/07/DeploymentParameters.png) In 4-8 minutes, you'll get a development machine on Azure! Have fun developing in the cloud! [Download the Visual Studio 2015 project](https://github.com/slapointe/BlogSamples/blob/master/ARM-DevelopmentMachine/?ref=codeisahighway.com) ## References - [Azure - Free one-month trial](http://azure.microsoft.com/en-us/pricing/free-trial/?ref=codeisahighway.com) - [Azure Resource Manager Overview](https://azure.microsoft.com/en-us/documentation/articles/resource-group-overview/?ref=codeisahighway.com) - [Premium storage](http://azure.microsoft.com/en-us/services/storage/premium-storage/?ref=codeisahighway.com) - [Important Things to Know About Premium Storage](https://azure.microsoft.com/en-us/documentation/articles/storage-premium-storage-preview-portal/?ref=codeisahighway.com#important-things-to-know-about-premium-storage) - [Microsoft Azure PowerShell](https://github.com/Azure/azure-powershell/releases?ref=codeisahighway.com) ### Set-AzureVMCustomScriptExtension: Multiple extensions per handler not supported URL: https://codeisahighway.com/set-azurevmcustomscriptextension-multiple-extensions-per-handler-not-supported/ Last updated: 2026-08-10T07:12:25.000Z The introduction of agents and extensions bring a lot of possibilities to virtual machines in Azure. The CustomScript extension let you run one or a set of scripts on a virtual machine. The usage is simple, you upload one or many scripts & their required files if any to Azure Storage, then you invoke the CustomScript extension. The extension will download the designated files on the virtual machine in the extension directory: *C:\\Packages\\Plugins\\Microsoft.Compute.CustomScriptExtension{version-number}\\Downloads{iteration}* and will execute the script designed to run. ## There can be just one You might be tempted to think that you'll create a script to install a database server, another one for configuring IIS and another one to join the machine to a domain and invoke 3 times the extension. If you call the `Set-AzureVMCustomScriptExtension` cmdlet and you already used a CustomScript extension with a difference reference name on that particular VM, you'll get this error: Set-AzureVMCustomScriptExtension : BadRequest: Multiple extensions per handler not supported for OS type 'Windows'. Extension 'InstallDevVMPowerShellScript' with handler 'Microsoft.Compute.CustomScriptExtension' already added. At D:\\wkspc\\Repos\\ARMProvisioning\\ProofOfConcepts\\VMInTheCloud\\v2.1\\Invoke-VMExtension.ps1:13 char:1 - Set-AzureVMCustomScriptExtension -ResourceGroupName TestARM95165 -VMN ... - ``` + CategoryInfo : CloseError: (:) [Set-AzureVMCustomScriptExtension], CloudException + FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.SetAzureVMCustomScriptExtensionCommand ``` ## How can I do this? Simple, instead of calling the CustomScript extension multiple times for different scripts, specify all your scripts using the `-Filename` or `-FileUri` parameters. Here is an example where you have 3 scripts, script1.ps1, script2.ps1 and script3.ps1\. The 3 files will be automatically downloaded in the download folder by the extension. Since script1.ps1 is designated to run, it is this script that'll be launched by the extension. Here we have 3 scripts but what you specify in the `-Filename` or `-FileUri` parameters can be zip files or any other file types that you want. The minimum you need is one script to download and run. ``` PS C:\> Set-AzureVMCustomScriptExtension -VM $x -ContainerName 'test' -FileName 'script1.ps1','script2.ps1','script3.ps1' -Run 'script1.ps1' -Argument 'arg1 arg2' | Update-AzureVM ``` `-FileUri` is helpful when you want to use blobs with a SAS token. That way you don't have to specify any storage key or storage context like when you use the `-Filename` parameter. ### References - [CustomScript extension](https://msdn.microsoft.com/en-us/library/azure/dn781373.aspx?ref=codeisahighway.com) ### How to get the current Azure subscription information every time you start a new PowerShell session URL: https://codeisahighway.com/how-to-get-the-current-azure-subscription-information-every-time-you-start-a-new-powershell-session/ Last updated: 2026-07-31T19:44:54.000Z If you're like me and you open many PowerShell windows to work on Azure, this tip is for you. ## Am I on the right Azure subscription? At work and at home, I have to deal with a lot of Azure subscriptions. I also use a lot of PowerShell windows to perform the tasks I have to and it can be easy to forget what is the last subscription I selected. A couple of releases ago, the Azure PowerShell team decided that every time you call `Select-AzureSubscription` it sets the subscription you specified as default in your user profile. This mean that if you call `Select-AzureSubscription` in a PowerShell session, every new session created after will use that subscription by default. This can cause you problems if you have multiple subscriptions and you switch regularly between them. You can think that you are still in a development subscription but a colleague ask you 15 min ago to do something in a production environment and now you will point to this environment in all your new PS sessions. Good luck to explain your boss that you destroyed all VMs in environment B because you thought you were still pointing to environment A. You can't do much about this behavior, except if you work with Azure profiles (aka memory profiles were introduced in version 0.8.15). What you can do though is just set a visual reminder displaying what is the default Azure subscription of your new PowerShell session. ## Current Azure subscription visual reminder With PowerShell you have profiles that enable you to execute custom logic and/or declare variables and functions every time a new PowerShell session is created. You have plenty of control over which host is the target because you can target all hosts or only PowerShell ISE or new PowerShell window for example. We will target all hosts. To know where your profile file should reside, simply check the `$profile` variable in PowerShell. It will point in your My Documents folder, more specifically : %UserProfile%\\My Documents\\WindowsPowerShell\\profile.ps1 What you want to do in there is determine the current subscription and output it to the host. ```powershell $azureModule = Get-Module -ListAvailable Azure* | ? ModuleBase -match sdk if($azureModule) { $subscription = Get-AzureSubscription -Current -ErrorAction SilentlyContinue if(-not $subscription) { $subscriptionMessage = "There is actually no selected Azure subscription." } else { $subscriptionMessage = ("Actually targeting Azure subscription: {0} - {1}." -f $subscription.SubscriptionName, $subscription.SubscriptionId) } Write-Host -BackgroundColor Black -ForegroundColor Yellow ('Using Azure PowerShell v{0}' -f $azureModule.Version) Write-Host -BackgroundColor Black -ForegroundColor Yellow $subscriptionMessage } ``` Now every time you'll start a new PowerShell host session you will see this visual clue to remind you where you are pointing. ![Azure subscription visual clue](https://codeisahighway.com/content/images/2015/06/CurrentSubscriptionVisualClue.png) I wish you enjoy this little utility script. [Download the script here](https://gallery.technet.microsoft.com/scriptcenter/Current-Azure-subscription-bb76498a?ref=codeisahighway.com) ## Reference - [Windows PowerShell Profiles](https://technet.microsoft.com/en-us/library/bb613488.aspx?ref=codeisahighway.com) - [Azure profile (memory profile)](https://github.com/Azure/azure-powershell/wiki/Proposed-Design-Stateless-Azure-Profile?ref=codeisahighway.com) ### Switch-AzureMode deprecation - Prepare yourself for the migration ahead URL: https://codeisahighway.com/switch-azuremode-deprecation-how-to-prepare-yourself-for-the-migration-ahead/ Last updated: 2026-07-31T19:44:55.000Z The signal of the transition between ASM (Azure Service Management) to ARM (Azure Resource Management) APIs have been given not long ago with the recent deprecation of the Switch-AzureMode cmdlet in v0.9.2 of the Azure PowerShell cmdlets. [Switch-AzureMode is now deprecated in release v.0.9.2](https://codeisahighway.com/switch-azuremode-is-now-deprecated-in-release-v-0-9-2/) ## This is for the best The differences between ASM (v1) and ARM (v2) resources are important and you need to prepare in advance to ensure the transition is as smooth as possible. Let's see some of the improvements in the Compute, Network & Storage APIs under Azure Resource Manager: - Enabling massive and parallel deployment of Virtual Machines - Support for 3 Fault Domains in Availability Sets - Improved Custom Script extension that allows specification of scripts from any publicly accessible custom URL - Integration of Virtual Machines with the Azure Key Vault for highly secure storage and private deployment of secrets from FIPS-validated Hardware Security Modules - Provides the basic building blocks of networking through APIs to enable customers to construct complicated applications that include Network Interfaces, Load Balancers, and Virtual Networks - Network Interfaces as a new object allows complicated network configuration to be sustained and reused for Virtual Machines - Load Balancers as a first-class resource enables IP Address assignments - Granular Virtual Network APIs allow you to simplify the management of individual Virtual Networks ### Some of the conceptual differences with the introduction of new APIs - In ARM, Cloud Service is no longer an object required for creating a Virtual Machine using the new model. In ASM, Cloud Service was a container for holding the virtual machines that required Availability from the platform and Load Balancing. - In ARM, Network Interface is a resource exposed by Microsoft.Network Provider. The lifecycle of the Network Interface is not tied to a Virtual Machine. In ASM, Primary and Secondary Network Interface and its properties were defined as network configuration of a Virtual machine. - In ARM, DNS Names are optional parameters that can be specified on a Public IP Address resource. The FQDN will be in the following format - ..cloudapp.azure.com. In ASM, A cloud service would get an implicit globally unique DNS Name. For example: mycoffeeshop.cloudapp.net. You can get the full detail of these changes in the *Conceptual differences with the introduction of new APIs* of the *Azure Compute, Network & Storage Providers under the Azure Resource Manager* documentation on the Azure web site (link in the *Reference* section) ## Proposed changes to come for the PowerShell cmdlets The proposed changes on GitHub are the following: - The Azure module will be renamed to "ASM". - All ASM cmdlets will be prefixed with "ASM", so Azure/New-AzureVM will become ASM/New-AsmVM or simply New-AsmVM. - AzureResourceManager cmdlets will keep their existing names, so New-AzureVM will be the ARM version. - A new convenience script will be added to provide backward compatibility to existing scripts, which only use the Azure module. The script will alias the ASM cmdlets back to their original names and remove the AzureResourceManager module from the session. - AzureResourceManager module will be broken into many modules by service and behavior. Examples of the module names would be the following: AzureCompute, AzureNetwork, AzureStorage, … - Azure PowerShell and all of its modules will be distributed via MSI and PowerShellGet. MSI cadence will decrease because the MSI will be a wrapper for a PowerShellGet script. There are some significant performance advancements in the new APIs but no direct migration between v1 (ASM) to v2 (ARM) resources. The vast majority of the cmdlets that share the same names in both APIs have different parameters, the obvious one being the `-ResourceGroupName` parameter that is found everywhere in v2 cmdlets. To resume the PowerShell cmdlets transition, it is planned to look like this (subject to change): ARM module decomposition should start in July. Still in July and through August, the distribution of smaller Azure PowerShell modules will start. The actual removal of the Switch-AzureMode cmdlet should take place somewhere in September, at the same time that ASM cmdlet rename is performed. Azure automation updates is also planned for September. David Justice (Program Manager - ADX SDK) said the following about the upcoming transition > These changes will affect a large number of users and have the potential to break many scripts. In fact, with out the use of the backward compatibility script, this change will break everyone except the users who are only using ARM cmdlets in their scripts. ## What about Azure automation? - Azure Automation will continue to ship the Azure module out of the box as a global module, but the proposed ASM module will also become a global module. The “split-out” ARM modules (AzureCompute, AzureStorage, etc) will also ship as global modules. - Only the ASM and split-out ARM modules will have their global modules updated to the latest versions going forward. - So as not to break existing Azure Automation users, existing runbooks will continue to be served the Azure module, and will not be served the ASM or ARM modules. Jobs of these runbooks will note that they are using the Azure module, that this module is now deprecated in Azure Automation, and that these runbooks should be recreated to target the ASM module instead. - New runbooks will not be served the Azure module, and instead will be served the ASM and split-out ARM modules. These are *proposed* steps, if you have any suggestions or concerns, I strongly suggest you to voice them in issue#428 on GitHub (see the *Reference* section for the link). ## How can you prepare? First, you need to understand the differences (conceptual and functional) in the ARM Resource Providers. Second, stop the bleeding by using Azure Resource Manager APIs as soon as possible. Easier said than done you'll tell me but at least your new resources will be future proof and it will reduce the number of resources you need to migrate later. Third but not least, migrate your ASM resources to ARM resources as well as your PowerShell scripts and Azure Automation workflows. Last advice, start planning this today don't wait to start working on this ;) ### References - [Azure Compute, Network & Storage Providers under the Azure Resource Manager](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-azurerm-versus-azuresm/?ref=codeisahighway.com) - [Deprecation of Switch AzureMode in Azure PowerShell](https://github.com/Azure/azure-powershell/wiki/Deprecation-of-Switch-AzureMode-in-Azure-PowerShell?ref=codeisahighway.com) - [Get rid of Switch-Azuremode - Issue #428](https://github.com/Azure/azure-powershell/issues/428?ref=codeisahighway.com) ### How to deploy the Cluster Monitor sample from Service Fabric samples URL: https://codeisahighway.com/how-to-deploy-the-clustermonitor-sample-from-service-fabric-samples/ Last updated: 2026-07-30T19:45:46.000Z If you followed Service Fabric a bit since it's announcement, you surely saw the Cluster Monitor in one or several public events. Beside being extremely fun to watch when your services are moving around the cluster or when a node is down for example, it gives you the ability to learn more about the Management API of Service Fabric in a realistic scenario. ![Cluster Monitor Sample](https://codeisahighway.com/content/images/2015/06/ClusterMonitor.png) To test it yourself, you can download a zip file containing the Service Fabric samples from GitHub (See the *References* section) or clone the *Service Fabric samples* repository in Visual Studio, I'll show the later. ## Cloning the repository Fire up a version of Visual Studio that have support for Git (I'll use VS 2015, but you can clone a Git repository with 2012 or later - UI will change a little though) - Open the *Team Explorer* tab, in the **Local Git Repositories** section, click *Clone* link. - Enter the repository url: [https://github.com/Azure/servicefabric-samples.git](https://github.com/Azure/servicefabric-samples.git?ref=codeisahighway.com) - Choose the path where the repository is gonna be cloned on your local computer. - Click the *Clone* button ![Clone Service Fabric samples repository](https://codeisahighway.com/content/images/2015/06/CloneServiceFabricSamplesRepo.png) ## Build the Cluster Monitor sample - Open the solution located at *{Repo}\\samples\\Services\\VS2015\\ClusterMonitor\\ClusterMonitor.sln* where {Repo} is the folder where you cloned your repository. - Build the solution. it should automatically download the required NuGet packages. ## Deploy the Cluster Monitor sample - Right-click the *ClusterMonitorApplication* project in Solution Explorer and click *Deploy* ![](https://codeisahighway.com/content/images/2015/06/DeployClusterMonitorApplication.png) Wait for the deployment to complete and here you go. You can now browse the Cluster Monitor by entering `http://localhost:8081/cluster/index.html` in your web browser. Happy visualization! In a future article, I'll dig with you in the code of this sample, stay tuned! ## References - [Azure Service Fabric Samples](https://github.com/Azure/servicefabric-samples?ref=codeisahighway.com) - [Getting started with Service Fabric](http://aka.ms/servicefabricsdk?ref=codeisahighway.com) - [Use Visual Studio with Git](https://msdn.microsoft.com/en-us/library/hh850437.aspx?ref=codeisahighway.com) ### Switch-AzureMode is now deprecated in release v.0.9.2 URL: https://codeisahighway.com/switch-azuremode-is-now-deprecated-in-release-v-0-9-2/ Last updated: 2026-08-10T07:12:27.000Z Version 0.8.0 introduced an aberration in the world of PowerShell modules in my opinion when they added the `Switch-AzureMode` cmdlet. The purpose of this cmdlet is to enable a switch between the Azure module and the AzureResourceManager module. In release 0.9.2 when you call `Switch-AzureMode` you get the a warning saying WARNING: The Switch-AzureMode cmdlet is deprecated and will be removed in a future release. ![The Switch-AzureMode cmdlet is deprecated and will be removed in a future release](https://codeisahighway.com/content/images/2015/06/SwitchAzureModeWarning.png) > This demonstrate that Microsoft is starting the transition between the AzureServiceManagement cmdlets and the AzureResourceManager cmdlets. > This change will not happen overnight and you will have plenty of time to prepare and perform this migration. One thing is sure though, they are heading this way. This is the good decision because they will enable the two modules to evolve separately and also because it caused a lot of little problems here and there. For example if you use Azure Automation today, the Azure module is loaded by default but you cannot call the Switch-AzureMode as you would normally do in a standard PowerShell session window. If you want to use the AzureResourceManager module, you have to manually zip the module folder from your machine and upload the archive as an asset in the Azure Automation. You can also manually load the module on a 64bits OS by calling `Import-Module "C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\AzureResourceManager.psd1"`. If you are on a 32bits OS, replace "Program Files (x86)" by "Program Files". Happy automation! ### Read Also [Switch-AzureMode deprecation - Prepare yourself for the migration ahead](https://codeisahighway.com/switch-azuremode-deprecation-how-to-prepare-yourself-for-the-migration-ahead/) ### How to get the status of an #Azure Virtual Machine under the v2 compute model in #PowerShell v0.9.x URL: https://codeisahighway.com/how-to-get-the-status-of-an-azure-virtual-machine-status-under-the-v2-compute-model-in-powershell/ Last updated: 2026-08-10T07:12:24.000Z Since version 0.8.0, the Azure PowerShell can target multiple APIs, included in 2 PowerShell modules. Even if the name of some cmdlets are the same, they greatly differ in their inputs and responses. First we have the older cmdlets, the PowerShell [Azure Service Management Cmdlets](http://go.microsoft.com/fwlink/?LinkID=396348&ref=codeisahighway.com) and then we have the newer APIs [Azure Resource Manage Cmdlets](http://go.microsoft.com/fwlink/?LinkID=394765&ref=codeisahighway.com) A newer version of this article for Azure PowerShell v1.0.x is available here: [How to get the status of a Virtual Machine under the v2 compute model in Azure PowerShell v1.0](https://codeisahighway.com/how-to-get-the-status-of-a-virtual-machine-under-the-v2-compute-model-in-azure-powershell-v1-0) ## Do it, the older cmdlets style In the older API, to get the VM status you would do the following: ``` Add-AzureAccount -Credential $cred Select-AzureSubscription -SubscriptionId $mySubscriptionId $vm = Get-AzureVM -ServiceName 'MyCloudService' -Name 'MyVMName' $vm | Select-Object Status, PowerState ``` In this example you'll get the state of the VM and cloud service. Under the newer API (AzureResourceManager), if you call the Get-AzureVM like you would have done in the older API you'll get the deployed definition of the VM but will find no traces of the Virtual machine status. ``` Switch-AzureMode -Name AzureResourceManager Add-AzureAccount -Credential $cred Select-AzureSubscription -SubscriptionId $mySubscriptionId Get-AzureVM -ResourceGroupName "myRG" -Name "MyVMName" ``` > It is important to remember that Virtual Machines in the new model (Compute Resource Provider/v2) do not rely on Cloud Services anymore. In the older model, a virtual machine required a Cloud Service to exist, this is not the case anymore. There is a link to an excellent article about changes in the new IaaS model in the *Reference* section. ## Do it, the newer cmdlets style To get the status of the virtual machine under the ARM API, you need to specify a new switch in the PowerShell cmdlet named `-Status`. It will take a little bit more time, but this time you'll have a completely different response than the previous call we made. It will contains the information you are looking for in the `Statuses` member. ``` Switch-AzureMode -Name AzureResourceManager Add-AzureAccount -Credential $cred Select-AzureSubscription -SubscriptionId $mySubscriptionId $vm = Get-AzureVM -ResourceGroupName "myRG" -Name "MyVMName" -Status $vm.Statuses ``` You will have all the VM information you need to automate your scale up/down and automation scenarios... Enjoy! ### References - [IaaS Just got easier again](http://azure.microsoft.com/blog/2015/04/29/iaas-just-got-easier-again/?ref=codeisahighway.com) - [Azure PowerShell Cmdlet Reference](https://msdn.microsoft.com/en-us/library/azure/mt617088.aspx?ref=codeisahighway.com) - [Azure PowerShell v0.9.8.1 release](https://github.com/Azure/azure-powershell/releases/tag/v0.9.8.1-October2015?ref=codeisahighway.com) ### Groupe ASP.NET/.NET: Retour sur //Build - La pratique URL: https://codeisahighway.com/groupe-asp-net-et-net-retour-sur-conference-build-la-pratique/ Last updated: 2026-07-30T19:45:47.000Z J'aurai le plaisir de donner une brève introduction à Service Fabric qui a été annoncé un peu avant le //Build il y a quelques semaines... # Agenda Pour faire suite au meeting du retour sur la conférence //Build où Erik et Mario nous parlaient des nouveautés et des enjeux, nous vous proposons un meeting plus pratico-pratique lors duquel nous allons démontrer certaines de ces nouveautés. - Sujet 1 : Visual Studio 2015 – améliorations à l'IDE (Eric Moreau) Eric vous présentera des améliorations apportées à l'IDE de Visual Studio 2015. Eric Moreau est un consultant .Net. Il est aussi MVP (Microsoft Most Valuable Professional). Eric peut être rejoint à [eric@moer.ca](mailto:eric@moer.ca) et son blog est disponible à www.emoreau.com. - Sujet 2: Visual Studio Code (Maxime Rouiller) Maxime fera une visite guidée de l'éditeur Visual Studio Code. Maxime Rouiller est un consultant .NET. Il est MVP ASP.NET/IIS depuis 2010\. Vous pouvez le rejoindre à [maxime@novawebsolutions.ca](mailto:maxime@novawebsolutions.ca) - Sujet 3: Faire tourner une application ASP.NET 5 sur Linux et sur Mac (Guy Barrette) Guy déploiera une application ASP.NET 5 dans un conteneur Docker sur un serveur Linux sur Azure avec le framework .NET Core. Et tant qu'à y être, pourquoi pas voir tourner du code .NET sur Mac OS X ! :-) Guy est consultant .NET, MVP Microsoft Azure, conférencier, co-animateur du podcast Visual Studio Talk Show. www.guybarrette.com - Sujet 4: Une démo de Service Fabric (Stéphane Lapointe) Stéphane fera le tour de quelques services livré en exemple avec Service Fabric pour comprendre rapidement les différences entre les services stateless, stateful et les actors. twitter: @s\_lapointe Plus de détails et inscription ici: [http://www.meetup.com/msdevmtl/events/221749922/](http://www.meetup.com/msdevmtl/events/221749922/?ref=codeisahighway.com) ### Configure Application Insights for your Ghost blog running node.js on Azure URL: https://codeisahighway.com/configure-application-insights-for-your-ghost-blog-running-node-js-on-azure/ Last updated: 2026-08-11T15:52:47.000Z Application Insights will work for sure with .Net applications, either web or console. But what about the open source stack? What about node.js? The good news is that you can use Application Insights in your node.js application. ## Why Application Insights? With telemetry you are able to see usage statistics and diagnostic data about your application like never before. You gain the ability to detect issues earlier and take action as soon as they occur instead of learning about them from your users. You can see what features people use the most and focus your efforts there, where it pay. In short... you'll be able to be proactive and take better decision. > The best way to have success with your application is to have visibility over what is happening. *Note that Application Insights is still in preview at the time of writing this article.* ## Prerequisite: Ghost This article assume you already have a Ghost blog configured, it can be hosted locally or on Azure. If you want to know how to host Ghost on Azure, there is a excellent article from Scott Hanselman about this topic. (See 'How to install the nodejs Ghost blog software' in the *Reference* section at the end of this post) # Configuring Application Insights for Ghost on node.js You need to create an Application Insights account in Azure, to do so: - Login to [http://portal.azure.com](http://portal.azure.com/?ref=codeisahighway.com) and create a new Application Insights account. - Click the *New* button, click the *Developer Services* category and choose *Application Insights* ![New Application Insights](https://codeisahighway.com/content/images/2015/05/NewApplicationInsightsAccount.png) In the Application Insights blade that just appeared, fill the following: For the name: *Enter the name of your blog*. Application Type: Other (preview) Resource Group: Choose an existing or create a new Resource Group Subscription: Choose the target subscription - Click the Create button ![New Application Insights Details Blade](https://codeisahighway.com/content/images/2015/05/NewApplicationInsightsAccountDetails.png) After your account is created, you'll need to find your instrumentation key. - Open your account, go to *Settings* ![Application Insights Settings button](https://codeisahighway.com/content/images/2015/05/ApplicationInsightsSettings.png) - Choose *Properties*, copy your *Instrumentation Key* and keep that information, we'll use it later. ![Application Insights Settings button](https://codeisahighway.com/content/images/2015/05/ApplicationInsightsSettingsInstrumentationKey.png) I use the 'Git Push' deployment model. Meaning that all my changes are made offline and when I'm finished, I push the changes to my website for them to be deployed. You could also use the Kudu console to perform the following steps. Now that you have Ghost installed and your instrumentation key, you need to install the Application Insights package with the following command (in your Ghost directory) `npm install applicationinsights` This will install the necessary files to use Application Insights with node.js. Still in your Ghost installation folder, locate and open the file *core/server/index.js*. Add this line `AppInsights = require('applicationinsights'),` right below `GhostServer = requires('./ghost-server'),`. Pay attention to the commas before and/or after your statement to ensure your *Requires* statements are well written. Locate the middleware statement in the *init* function, and insert the following right below it: `AppInsights.setup('YOUR INSTRUMENTATION KEY').start();`. It should look like this: ``` function init(options) { ... // ## Middleware and Routing middleware(blogApp, adminApp); // Application Insights AppInsights.setup('YOUR INSTRUMENTATION KEY').start(); ... } ``` **Be sure to replace** the string 'YOUR INSTRUMENTATION KEY' with your real instrumentation key that you copied from the Azure portal. The next step is to get the monitoring code into your pages. First, in your Application Insights account, click the *Quickstart* icon, click the *Node.js* tab and then click the arrow next to "Get code to monitor my web pages" ![Get Application Insights Monitoring Code](https://codeisahighway.com/content/images/2015/05/ApplicationInsightsMonitoringCode.png) Select all the code from the new blade that just appeared and copy it. ![Copy the Application Insights Monitoring Code](https://codeisahighway.com/content/images/2015/05/ApplicationInsightsMonitoringCodeToCopy.png) If you use a newer version of Ghost that support *Code Injection*, please use it instead of editing your default.hbs file directly. Just paste the copied code into the Blog Header section and that's it. (more information on Ghost *Code Injection* in the *Reference* section) If you use an older version of Ghost that don't support *Code Injection*, locate and edit the file *content/themes/casper/default.hbs* Insert the copied monitoring code on the next line below the `{{ghost_head}}` statement. It should give you something that look like this: ``` ... {{ghost_head}} ... ``` Save all the changes you just made (and push the changes to your website if needed). If you used Kudu to perform your modification, don't forget to restart your website from the console, otherwise your bootstrap code that kick the instrumentation won't run and you won't get any data out. Browse your site around and you should see instrumentation data starting to appear in your Application Insights account after a minute or two. ![Application Insights Integrated In Ghost and Node.js](https://codeisahighway.com/content/images/2015/05/ApplicationInsightsIntegrated.png) This is just the tip of the iceberg. You have plenty of control over how auto-collection behave, you can create custom events, etc. Please read about Application Insights and his SDK, there is a ton of stuff to grab and learn, links are just below. Have fun with telemetry, node.js and Azure! ## Reference - [Ghost Blog engine](https://ghost.org/?ref=codeisahighway.com) - [UPDATED for 2015: How to install the nodejs Ghost blog software on Azure Web Apps (and the Deploy to Azure Button)](http://www.hanselman.com/blog/UPDATEDFor2015HowToInstallTheNodejsGhostBlogSoftwareOnAzureWebAppsAndTheDeployToAzureButton.aspx?ref=codeisahighway.com) - [Ghost Code Injection](http://support.ghost.org/use-code-injection/?ref=codeisahighway.com) - [Get started with Visual Studio Application Insights](http://azure.microsoft.com/en-us/documentation/articles/app-insights-get-started/?ref=codeisahighway.com) - [Microsoft Application Insights SDK for node.js](https://github.com/Microsoft/ApplicationInsights-node.js?ref=codeisahighway.com) - [The Kudu Debug Console, Azure Websites best kept secret](http://guyb.ca/1OiRsMT?ref=codeisahighway.com) ### "The remote server returned an error: (400) Bad Request. " when specifying ACL on an #Azure premium storage container URL: https://codeisahighway.com/the-remote-server-returned-an-error-400-bad-request-when-specifying-acl-on-an-azure-premium-storage-container/ Last updated: 2026-07-31T19:44:58.000Z updated: May 10th 2015 - Added SAS workaround I played quite a bit with Azure Premium storage accounts recently and I have to say that I welcome with arms wide open this new performance level. Especially for dev/test environments in Azure. Even if I deeply think that this is what we should have had in the first place or at least something in between the latency of XIO and a standard storage account. It is good to know that > Premium Storage supports only Azure page blobs, which are used to hold persistent disks for Azure Virtual Machines (VMs) To create a premium storage account, you declare as "Premium\_LRS" or "Premium-LRS" depending if you are using PowerShell scripts or Azure Resource Manager templates. During my tests and scripts migration to use the new storage account type faced an error message. Given the following code: ``` New-AzureStorageAccount -StorageAccountName 'myaccount3456485' -Type Premium_LRS -Location 'East US 2' New-AzureStorageContainer -Name 'myaccount3456485' -Permission Blob ``` this cause the following error: > New-AzureStorageContainer : The remote server returned an error: (400) Bad Request. HTTP Status Code: 400 - HTTP Error Message: One > of the headers specified in the request is not supported. > At C:\\Temp\\Demos\\New-DevTestEnvironmentFromPowerShell.ps1:32 char:1 - New-AzureStorageContainer -Name 'myaccount3456485' -Permission Blob If you either specify `Container` or `Blob` permission you will end up with this error message. You won't have this error if you specify `Off` or if you don't specify the `-Permission` parameter. The only think I know is that it's not yet supported. No official word about when it will be, but I'm pretty sure it's only a matter of time before we see it working. ### Workaround You can use SAS (Shared Access Signature) to mimic the public permission on a container or blob. Be sure to remember that if you change the storage keys, this will invalidate the SAS you generated with them. As a last resort, you could still use a standard storage account but you won't get the same performance. ### Reference - [Premium Storage: High-Performance Storage for Azure Virtual Machine Workloads](http://azure.microsoft.com/en-us/documentation/articles/storage-premium-storage-preview-portal/?rnd=1&ref=codeisahighway.com) - [Shared Access Signatures, Part 1: Understanding the SAS Model](http://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-shared-access-signature-part-1/?ref=codeisahighway.com) ### Bug: "Your Azure credentials have not been set up or have expired, please run Add-AzureAccount to set up your Azure credentials." URL: https://codeisahighway.com/your-azure-credentials-have-not-been-set-up-or-have-expired-please-run-add-azureaccount-to-set-up-your-azure-credentials/ Last updated: 2026-07-31T19:44:59.000Z I wanted to automate dev/test environments lately in Azure and I faced the following issue... Azure PowerShell cmdlets introduced in version 0.8.15 AzureProfile support: --- AzureProfile: New cmdlets to manage in-memory profiles - New-AzureProfile: Create a new in-memory Profile - Select-AzureProfile: Select the profile to be used in the current session Added -Profile parameter to every cmdlet - the cmdlet will use the passed-in profile to authenticate with Azure --- But I cannot get that to work like in this example, if I execute this script in a new PowerShell session, with valid credential, it fails the first time it run. ``` if(!$global:issueAzureCred) { $global:issueAzureCred = Get-Credential } Import-Module Azure Clear-AzureProfile -Force $random = Get-Random -Maximum 99999 $storageAccount = 'devtestpowershell{0}' -f $random $subscriptionId = '{SubscriptionIdHere}' $azureProfile = New-AzureProfile -SubscriptionId $subscriptionId -StorageAccount $storageAccount -Credential $global:issueAzureCred Select-AzureProfile -Profile $azureProfile New-AzureStorageAccount -StorageAccountName $storageAccount -Type Standard_LRS -Location 'East US 2' -Profile $azureProfile ``` Error: New-AzureStorageAccount : Your Azure credentials have not been set up or have expired, please run Add-AzureAccount to set up your Azure credentials. At C:\\Users\\someuser\\Desktop\\Add-AzureAccountIssue.ps1:15 char:1 New-AzureStorageAccount -StorageAccountName $storageAccount -Type Sta ... ``` CategoryInfo : NotSpecified: (:) [New-AzureStorageAccount], ArgumentException FullyQualifiedErrorId : System.ArgumentException,Microsoft.WindowsAzure.Commands.ServiceManagement.StorageServices.NewAzureStorageAccountCommand ##Impacted versions I tested the script on these version and always got the same behavior * 0.8.15.1 * 0.8.16.0 * 0.9.0 ##Workaround if you perform the *New-AzureProfile* and *Select-AzureProfile* statements back to back it will solve the problem... ``` $azureProfile = New-AzureProfile -SubscriptionId $subscriptionId -StorageAccount $storageAccount -Credential $global:issueAzureCred Select-AzureProfile -Profile $azureProfile $azureProfile = New-AzureProfile -SubscriptionId $subscriptionId -StorageAccount $storageAccount -Credential $global:issueAzureCred Select-AzureProfile -Profile $azureProfile Get-AzureVMImage ``` OR you can still use *Select-AzureSubscription* with *Add-AzureAccount* or Management certificates with *Import-AzurePublishSettingsFile* [I opened an issue on GitHub about this](https://github.com/Azure/azure-powershell/issues/362). ``` ### How to quickly retrieve your Azure subscription consumptions/limits (extended details) in PowerShell URL: https://codeisahighway.com/how-to-retrieve-your-azure-subscription-limits-extended-details-in-powershell/ Last updated: 2026-08-10T07:12:23.000Z Everytime that I needed to take a look at where I stand up from the limits of an Azure subscription I do the same thing... Open my web browser, go to the management portal and browse between my storage accounts, cloud services, etc... Here is a quick way in PowerShell to get that information without leaving your blue and white PowerShell console window. Use the **\-ExtendedDetails** switch when calling the Get-AzureSubscription cmdlet. To get the details of your current subscription ``` Get-AzureSubscription -Current -ExtendedDetails ``` or to get the details for all your subscriptions ``` Get-AzureSubscription -ExtendedDetails ``` This will give you this kind of informations ``` ActiveDirectoryUserId : someone@server.com Account : Microsoft.Azure.Common.Authentication.Models.AzureAccount Certificate : AccountAdminLiveEmailId : someone@server.com CurrentCoreCount : 2 CurrentHostedServices : 2 CurrentDnsServers : 0 CurrentLocalNetworkSites : 0 CurrentVirtualNetworkSites : 2 CurrentStorageAccounts : 5 MaxCoreCount : 20 MaxDnsServers : 20 MaxHostedServices : 20 MaxLocalNetworkSites : 20 MaxVirtualNetworkSites : 50 MaxStorageAccounts : 100 ServiceAdminLiveEmailId : someone@server.com SubscriptionRealName : Visual Studio Ultimate with MSDN SubscriptionStatus : Active OperationDescription : OperationId : OperationStatus : ServiceEndpoint : https://management.core.windows.net/ ResourceManagerEndpoint : https://management.azure.com/ GalleryEndpoint : SubscriptionId : 00000000-0000-0000-0000-000000000000 SubscriptionName : Visual Studio Ultimate with MSDN Environment : SupportedModes : AzureServiceManagement,AzureResourceManager DefaultAccount : Accounts : {someone@server.com, someone2@server.com} IsDefault : True IsCurrent : True CurrentStorageAccountName : mycurrentstorage TenantId : ``` Happy automation with Azure and PowerShell! ### Improve your visibility by redirecting console output to disk for your service in Service Fabric URL: https://codeisahighway.com/improve-your-visibility-by-redirecting-console-output-to-disk-for-your-service-in-service-fabric/ Last updated: 2026-07-31T19:45:00.000Z Service Fabric have been announced recently and we all want to start playing with it. We often so that without going through the documentation. I don't know for you but I often do that ;) The first thing I can recommend you is to read... Read about it. There is a LOT of stuff to absorb in Service Fabric and there is great documentation out here (links at the end of the article). If you skip a concept or two and need help with what is happening there is a tip you can use. ## What is happening? What if you need to have more details about what is going on in your application? You need to setup ports or play with the firewall during bootstrap let say for your service and something is not happening the way you want? You just need to add a element to your element in your ServiceManifest.xml and voila! You will end with the console output redirected. ``` HttpSetup.bat MyService.exe ``` You can surely use ETW which is great but you can rely on this mechanism for you service also. The redirect output to disk in your log folder. ``` MyService.exe ``` Your logs should show up on the each nodes where your service is deployed, e.g. in the folder: C:\\WFDevCluster\\Data\\Node.{NodeNumber}\\Fabric\\work\\Applications{ApplicationName}\\log ## Want to learn more - [Overview of Service Fabric](http://azure.microsoft.com/en-us/documentation/articles/service-fabric-overview/?ref=codeisahighway.com) - [Tutorial/Set up your Service Fabric development environment](http://azure.microsoft.com/en-us/documentation/articles/service-fabric-get-started?ref=codeisahighway.com) ### #Azure Service Fabric have been announced! URL: https://codeisahighway.com/azure-service-fabric-have-been-announced/ Last updated: 2026-07-31T19:45:01.000Z ![header-cover](https://codeisahighway.com/content/images/2015/04/microsoft-azure-blog-header-1.png) Mark Russinovich just announced Azure Service Fabric. I had the chance to play with it and it is really incredible. It is a real game changer for high-availability and high-density solutions. One of the problem right now on Azure is the density we achieve in PaaS, is not really optimal. Service Fabric enable multiple applications / microservices to run on a cluster. Multiple application can run on it and also multiple version of the same application. ![Service Fabric Architecture](https://codeisahighway.com/content/images/2015/04/azure-service-fabric-2.png) Azure already announced [App Services](http://azure.microsoft.com/en-us/services/app-service/?ref=codeisahighway.com) not long ago that enable you to have scalable applications without having to deal with all the complexity that comes with it. With Service Fabric framework gives you are a more close to the metal when it comes to having control. It enable you to work at a way deeper level, don't be fooled, a lot is abstracted if you don't want to get your hands dirty but if you wish to, you have this level of control. It is more complex to work with Service Fabric than Azure App Services, but you gain more control and more power. *Excerpt from Mark's announcement:* Service Fabric offers the following benefits: - It supports creating both stateless and stateful microservices – an architectural approach where complex applications are composed of small, independently versioned services – to power the most complex, low-latency, data-intensive scenarios and scale them into the cloud. - Provides the benefits of orchestration and automation for microservices with new levels of app awareness and insight. - Solves hard distributed systems problems like state management and provides application lifecycle management capabilities so developers don’t have to re-architect their applications as usage grows. - Includes Visual Studio tooling as well as command line support, which enables developers to quickly and easily build, test, debug, deploy and update their Service Fabric applications on single-box deployments, test deployments and production deployments. Downloadable bits will be available during the Build conference at the end of the month. I will be blogging a lot about Service Fabric in the following weeks/months so stay tuned. ### Use CNAME to reach the staging slot in #Azure cloud services with a well known url URL: https://codeisahighway.com/use-cname-to-reach-the-staging-slot-in-azure-cloud-services-with-a-well-known-url/ Last updated: 2026-08-10T07:12:21.000Z If you already used the VIP swap functionality in a cloud service, you quickly noticed that for the production slot you have a deterministic url in the format *{cloudservicename}.cloudapp.net*. For the staging slot, that is something totally different. ## The problem: random generated name You end up with a *{auto-generated-guid}.cloudapp.net* which makes it hard to give something usable to dev or testers since it will change again and again when you recreate a deployment in the staging slot. Azure will not help you there, they don't offer a way to have a deterministic DNS entry for the staging slot at the time of writing this article. ## A solution: Use a CNAME dns entry To avoid that problem, you can use a CNAME entry that point to *{auto-generated-guid}.cloudapp.net*. That way you can give your users a well known url that will never change. You will need to update your CNAME entry when you perform a new deployment to your staging slot though but this can be automated. ``` param( [Parameter(Position=0,Mandatory=$true)] [string] $SubscriptionName, [Parameter(Position=1,Mandatory=$true)] [string] $ServiceName ) $ErrorActionPreference = 'Stop' Select-AzureSubscription -SubscriptionName $SubscriptionName $service = Get-AzureService -ServiceName $ServiceName $deployment = $service | Get-AzureDeployment -Slot Staging 'Staging Url is: {0}' -f $deployment.Url ``` From that sample script you have access to the staging url via *$deployment.Url*, you can then use that value to update you DNS server. Get more information on deployments and how to manage cloud services - [How to Manage Cloud Services](http://azure.microsoft.com/en-us/documentation/articles/cloud-services-how-to-manage/?ref=codeisahighway.com) - [Manage Deployments in Azure](https://msdn.microsoft.com/library/azure/gg433027.aspx?ref=codeisahighway.com) ### List or export to rdp #Azure Cloud Services instances and VM's IP addresses URL: https://codeisahighway.com/list-or-export-azure-cloud-services-instances-and-vms-ip-addresses-as-rdp-files/ Last updated: 2026-07-17T08:41:17.000Z To improve security with our solutions, we use VNets on all our Azure subscriptions and do not expose remote desktop port (3389) publicly. Since internal endpoints are only reachable within a Cloud Service, this reduce the possible surface of attack. ## Connect to Cloud Services instances / Virtual machines without having to go in the Azure portal We needed a way to export all the virtual machines and cloud services role instances for an Azure subscription without having to go in the Azure portal to get the RDP files. For us, it would not have worked anyway since the rdp file that the portal generate point to the cloudapp.net address. > For our need, we use the private IP address of the instances but you can easily change the script to use the public DNS name instead. ## How to do that First, you select your subscription ``` Select-AzureSubscription -SubscriptionName $SubscriptionName ``` ## The script ``` #requires -Version 3.0 -Module Azure [CmdletBinding(DefaultParametersetName='NoExport')] param( [Parameter(Position=0, Mandatory=$true, ParameterSetName='NoExport')] [Parameter(Position=0, Mandatory=$true, ParameterSetName='ExportRdp')] [string] $SubscriptionName, [Parameter(Position=1, ParameterSetName='NoExport')] [Parameter(Position=1, ParameterSetName='ExportRdp')] [string] $ServiceName, [Parameter(Position=2, ParameterSetName='ExportRdp')] [Switch] $ExportRdp, [Parameter(Position=3, Mandatory=$true, ParameterSetName='ExportRdp')] [System.IO.DirectoryInfo] $RdpOutputDirectory ) $ErrorActionPreference = 'Stop' Import-Module Azure Write-Verbose "Using subscription $SubscriptionName" Select-AzureSubscription -SubscriptionName $SubscriptionName if($ServiceName) { Write-Verbose "Querying cloud service $ServiceName" $services = Get-AzureService -ServiceName $ServiceName } else { Write-Verbose "Querying all cloud services." $services = Get-AzureService } Write-Verbose "Getting deployments informations." $result = $services | Get-AzureDeployment -ErrorAction SilentlyContinue | % { $svcName = $_.ServiceName $_.RoleInstanceList | % { @{ ServiceName=$svcName; RoleName=$_.RoleName; InstanceName=$_.InstanceName; IpAddress=$_.IPAddress } } } if($ExportRdp) { $RdpOutputDirectory.Create() $dir = $RdpOutputDirectory.CreateSubdirectory("RDP-$SubscriptionName") Write-Verbose "Exporting rdp files to directory '$($dir.FullName)'." $result | % { $outputFilename = '{0}\{1}.{2}.{3}.rdp' -f $dir.FullName, $_.ServiceName, $_.RoleName, $_.InstanceName "full address:s:$($_.IpAddress)`r`nLoadBalanceInfo:s:Cookie: mstshash=$($_.RoleName)#$($_.InstanceName)" | Out-File $outputFilename } } $result ``` What it does is really simple, it loop through all deployments of all cloud services inside your subscription and construct an array of objects containing the service name, role name, instance name and ip address. If you use the *ExportRdp* switch you need to provide a mandatory *RdpOutputDirectory* parameter in which rdp files will be exported. Rdp files will have the following naming pattern: {ServiceName}.{RoleName}.{InstanceName}.rdp You can easily change this script to modify the generated rdp to include a default username by adding the following line ``` username:s:{RdpUsername} ``` where {RdpUsername} is the username ### What you'll need - An Azure subscription with at least one cloud services (can be a role or virtual machine) - [Azure PowerShell CmdLet](https://github.com/Azure/azure-powershell/releases?ref=codeisahighway.com) Let me know what you think! ### Samedi ALM: Become a great scrum master, TFS 2013, DevOps et DevTest URL: https://codeisahighway.com/samedi-alm-become-a-great-scrum-master-tfs-2013-devops-et-devtest/ Last updated: 2026-07-31T19:45:03.000Z J'aurai le plaisir de présenter une session sur: L’expérience DEVTEST ## Synopsis: Chaque équipe de développement a besoin d’une infrastructure de développement en place pour concevoir, développer, tester et livrer leur logiciel. Sans cette infrastructure de dev et de test, l’équipe ne peut tout simplement pas travailler de façon efficace. La mise en place et la maintenance d’une infrastructure de développement sur un réseau d’entreprise sont coûteuses et sujettes à des retards dus aux délais d’approvisionnement ou de manque de disponibilités des équipes IT. Une infrastructure cloud permet aux équipes dev et de tests d’être plus agiles, de livrer plus rapidement et avec plus de qualité. Il est possible d'obtenir une économie bien réelle puisque ces environnements pourront être préparés et utilisés seulement lorsque nécessaires. ## Agenda 8h30 - 9h00: Accueil 9h00 - 11h00: Top 10 Ways to Go from Good to Great Scrum Master Conférencier: Benjamin Day, ALM MVP, Boston USA 11h00 - 11h15: Pause 11h15 – 12h15: Comment utiliser TFS 2013 pour bien suivre une équipe de développement? Conférencier: Vincent Grondin, MVP C# 12h15 - 13h00: Diner Pizza et Boisson Gazeuses (Merci Microsoft!) 13h00 - 15h00: L’expérience DEVOPS Conférencier: Etienne Tremblay, MVP ALM 15h00 - 15h15: Pause 15h15 – 16h45: L’expérience DEVTEST Conférencier: Stéphane Lapointe Plus de détails ici: [Samedi ALM Mai 2015](http://www.meetup.com/msdevmtl/events/221512555/?ref=codeisahighway.com) ### BUG: PowerShell workflow execution hang when using PSObject parameter in a new PowerShell session URL: https://codeisahighway.com/bug-powershell-workflow-execution-hang-when-using-psobject-parameter-in-a-new-powershell-session/ Last updated: 2026-07-31T19:45:04.000Z One upon a time... I was playing with PowerShell workflows to automate stuff in Azure. The scripts were doing what I wanted them to, but the day after I started to have problems when trying to execute them again. After an hour of trials and errors, I discovered that if I have a parameter type declared in a workflow, in my case it was \[PSObject\], the execution hung to never come back... and I mean *never*. ## Non working snippet ``` $VerbosePreference = 'Continue' workflow Test-ScaleInfo { param( [PSObject] $ScaleInfo ) Write-Verbose 'Hello world' } @{Test='adasdd'} | Test-ScaleInfo ``` ## Working snippet ``` $VerbosePreference = 'Continue' workflow Test-ScaleInfo { param( $ScaleInfo ) Write-Verbose 'Hello world' } @{Test='adasdd'} | Test-ScaleInfo ``` One thing that let me think it might be an initialization issue... if I take the working snippet and execute it in a new PowerShell session *before* executing the non working snippet, the non working snippet will now work. ## Workaround What will work until this is fixed? Simply remove the type declaration from your parameter. A bug have been opened on Microsoft Connect for this issue. [Bug#1203243 on Microsoft Connect](https://connect.microsoft.com/PowerShell/feedbackdetail/view/1203243/workflow-execution-hang-when-using-psobject-parameter-in-a-new-powershell-session?ref=codeisahighway.com) ### Global Azure Bootcamp 2015 - Montreal (Samedi 25 avril 2015) URL: https://codeisahighway.com/global-azure-bootcamp-2015-montreal-samedi-25-avril-2015/ Last updated: 2026-07-31T19:45:05.000Z Samedi 25 April 2015 9:00 à 16:00 Microsoft Montréal (5e) 2000 McGill College, 5e étage, Montréal, QC, Montréal, QC ([edit map](http://www.meetup.com/msdevmtl/events/219039433/%5D?ref=codeisahighway.com)) ## Une journée complète "hands-on" Azure sans aucune présentation. Gratuit pour les membres avec un membership en règle, 5$ pour les non membres. Seulement 40 places disponibles. Vous désirez faire vos premiers pas avec Azure ? Cette journée sera entièrement consacrée à des labs et exercises que vous pourrez faire à votre propre rythme tout en étant accompagné par des experts avec qui vous pourrez "jaser" Azure. ## Voici la liste des "hands-on-labs" proposés: - Working with the Management Portal - Introduction to the Azure Preview Portal - Infrastructure as a Service in Microsoft Azure (Virtual Machines) - Getting started with Azure Websites and ASP.NET - Building a Single Page Application (SPA) with ASP.NET Web API and Angular.js using Azure Active Directory to Log in Users - Building a web application with ASP.NET MVC using DocumentDB - Get Started with the Azure WebJobs SDK - Get started with Mobile Services - How to Use Azure Redis Cache ## Afin de profiter au maximum de cette journée, vous devez: - Avoir créé un compte Azure **AVANT** d'arriver. Il est possible de créer un compte d'essai 30 jours sans frais. *C'EST SUPER IMPORTANT D'AVOIR CRÉÉ SON COMPTE AVANT D'ARRIVER CAR AZURE BLOQUE LA CRÉATION DE NOUVEAUX COMPTES S'IL Y A EN A TROP DEPUIS LA MÊME ADDRESSE IP.* [Veuillez consulter la procédure suivante](http://files.meetup.com/2140841/Creating%20a%20trial%20Azure%20account%20and%20activating%20MSDN%20benefits.pdf?ref=codeisahighway.com) - Avoir un ordinateur portatif (laptop) - Avoir installé Visual Studio 2013 - Avoir installé le SDK Azure 2.5 [http://www.microsoft.com/en-ca/download/details.aspx?id=44938](http://www.microsoft.com/en-ca/download/details.aspx?id=44938&ref=codeisahighway.com) - Avoir installé les hands-on-labs [https://github.com/Azure-Readiness/DevCamp/releases/](https://github.com/Azure-Readiness/DevCamp/releases/?ref=codeisahighway.com) Notez que le matériel est en anglais seulement. ## Bouffe Beignes le matin et pizza le midi, gracieuseté de Microsoft. Pensez à apportez votre café le matin. ### Azure/Cloud design patterns: architecture guidance URL: https://codeisahighway.com/azure-cloud-design-patterns-and-architecture-guidance/ Last updated: 2026-07-23T03:05:33.000Z ## On-premise applications... You don't usually deal with connectivity issues > It's relatively easy to create an application that can run on-premise where network connections never drops and resources are just a hop away. Creating an application is not easy but when you control all the elements on the network... It is, let say it straight, easier. You don't have to deal much with multiple network hops, latency and resources availability. This is not Azure specific, you'll deal with these problems on any public networks... Azure, AWS or any other cloud platform. Microsoft Pattern & Practices team released a guide containing 24 patterns about problems you can and will probably encounter when building a solution executing on a public network : - Availability - Data Management - Design and Implementation - Messaging - Management and Monitoring - Performance and Scalability - Resiliency - Security [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications](https://msdn.microsoft.com/en-us/library/dn568099.aspx?ref=codeisahighway.com) > Containing twenty-four design patterns and ten related guidance topics, this guide articulates the benefit of applying patterns by showing how each piece can fit into the big picture of cloud application architectures. It also discusses the benefits and considerations for each pattern. Most of the patterns have code samples or snippets that show how to implement the patterns using the features of Microsoft Azure. However the majority of topics described in this guide are equally relevant to all kinds of distributed systems, whether hosted on Azure or on other cloud platforms. I am one of the guy believing that doing robust software can be achieved with good methodology, patterns and dedication... Happy coding!!! ### DevOps tool: PSReadLine and how to install it using PowerShell v5.0 and OneGet URL: https://codeisahighway.com/how-to-install-psreadline-using-powershell-v5-0-and-oneget/ Last updated: 2026-08-10T07:12:16.000Z ## What is PSReadLine It's someone at work that told me about PSReadLine. I just took me 5 minutes to realize that this module is a life changer for everyone doing serious PowerShell. Here is what is does > This module replaces the command line editing experience in PowerShell.exe for versions 3 and up. It provides: - Syntax coloring - Simple syntax error notification - A good multi-line experience (both editing and history) - Customizable key bindings - Cmd and emacs modes (neither are fully implemented yet, but both are usable) - Many configuration options - Bash style completion (optional in Cmd mode, default in Emacs mode) - Bash/zsh style interactive history search (CTRL-R) - Emacs yank/kill ring - PowerShell token based "word" movement and kill - Undo/redo - Automatic saving of history, including sharing history across live sessions - "Menu" completion (somewhat like Intellisense, select completion with arrows) via Ctrl+Space More information about [PSReadLine](https://github.com/lzybkr/PSReadLine?ref=codeisahighway.com). ## How to install it First you'll need PowerShell 5\. You can get it from Microsoft website's download section. [Download PowerShell 5](http://www.microsoft.com/en-us/Search/result.aspx?q=powershell+5&x=0&y=0&ref=codeisahighway.com#downloads) In a PowerShell console, type the following: `Install-Package PSReadLine` ![Install-Package PSReadLine](https://codeisahighway.com/content/images/2015/03/Install-Package-PSReadLine-1.png) Now that the module is installed. Open or create the file named: `C:\Users\{username}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1` and insert the following statement: `Import-Module PSReadLine` The PSReadLine module will now be imported everytime the PowerShell console is invoked. Tryout this PowerShell module and let me know what you think... ### HTTP 503 error in Azure Worker/Web role when IP Address is not specified in IIS site binding URL: https://codeisahighway.com/http-503-error-in-azure-workerweb-role-when-ip-address-is-not-specified-in-iis-site-binding/ Last updated: 2026-08-10T07:12:14.000Z ## My load balancer probe isn't probing. Today I tried to define a custom load balancer probe on a worker role in Azure. On this worker role, IIS and other components were installed and configured using PowerShell scripts. ``` ``` After the deployment, I wasn't able to reach the website, why is that? I jumped onto the machine using Remote Desktop and took a look at IIS logs... Empty, nothing, no sign of a probe here... ## What's wrong? The probe was configured to listen on port 18045 in my service definition file, which is also what I saw in IIS. ![problematic IIS binding](https://codeisahighway.com/content/images/2015/02/bindings-before.png) On the machine itself I tried to make the same call as the load balancer, by IP address. > [http://10.74.56.22:18045](http://10.74.56.22:18045/?ref=codeisahighway.com) failed with a 503 error. > [http://localhost:18045](http://localhost:18045/?ref=codeisahighway.com) worked. Interesting. Something is really messing with this port when all IP addresses are configured in the binding. After several tests I realized that the *Windows Azure Guest Agent* windows service prevented communications on the IP address when the IIS bindings in the following format "\*:18045:". This translate to the following binding in IIS > {Type}:http, {host name}:, {port}:18145, {IP Address}:\* ## How does it looks now? We needed to explicitly set an IP address instead of \* like we were doing. I grabbed the IP addresses by using the following command in PowerShell: ``` Get-NetIPAddress -AddressFamily IPv4 -AddressState Preferred | ? InterfaceAlias -NotLike Loopback* ``` It can return more than an address so I decided to add a binding for each IPv4 address marked as preferred that is not the loopback interface I ended up with this in IIS: ![working IIS binding](https://codeisahighway.com/content/images/2015/02/bindings-after.png) After redeploying, everything started to work as expected with the custom probe. ### Microsoft Cloud Camp (Samedi 28 février 2015) URL: https://codeisahighway.com/microsoft-cloud-camp-samedi-28-fevrier-2015/ Last updated: 2026-08-10T07:12:19.000Z ## Événement Microsoft organisé par le Groupe Azure Montréal Coût: Gratuit Enregistrement via le site de Microsoft ([Cliquez ici](https://msevents.microsoft.com/CUI/InviteOnly.aspx?EventID=22-9D-1A-E0-50-DA-01-2A-A6-04-D8-4F-98-A2-61-11&Culture=en-CA&community=0&ref=codeisahighway.com)) Niveau: débutant avec Azure Langue: français avec matériel en anglais Bouffe incluse: beignes le matin et pizza le midi. Pensez à apporter votre café le matin. Comme c'est un événement Microsoft, vous devez vous inscrire obligatoirement via le site de Microsoft et non via Meetup ([cliquez ici](https://msevents.microsoft.com/CUI/InviteOnly.aspx?EventID=22-9D-1A-E0-50-DA-01-2A-A6-04-D8-4F-98-A2-61-11&Culture=en-CA&community=0&ref=codeisahighway.com)) ## Agenda - 8h30-9h00 Inscription et beignes (apportez votre café!) - 9h00-10h00 Survol de la plate forme Azure: *Alexandre Brisebois, Microsoft* - 10h00-11h00 Cloud Services (PAAS): *Stéphane Lapointe* - 11h00-11h15 Pause - 11h15-12h15 Websites: *Mathieu Richard MVP ASP.NET* - 12h15-13h00 Pizza! - 13h00-14h00 Data (SQL Azure, Table & Blob storage): *Eric Moreau MVP VB* - 14h00-15h00 Virtual Machines (IAAS): *Julien Stroheker MVP Azure* - 15h00 16h00 Mobile Services: *Guy Barrette, MVP Azure* ***Le contenu est de niveau "introduction" destiné à des développeurs n'ayant jamais assisté à une introduction à Azure.*** ***Il n'y aura pas de partie pratique, juste des présentations, donc pas besoin d'apporter votre laptop même si le site de Microsoft mentionne qu'un laptop est nécessaire. Si une partie pratique vous intéresse, nous organisons le Global Azure Bootcamp le 25 avril qui lui sera totalement hands-on!*** [Événement sur meetup](http://www.meetup.com/msdevmtl/events/219039420/?ref=codeisahighway.com) Au plaisir de vous y voir et de vous rencontrer ### Effectively handle Azure Active Directory or other STS keys rolling and avoid error ID4175 URL: https://codeisahighway.com/effectively-handle-azure-active-directory-or-other-sts-keys-rolling/ Last updated: 2026-07-17T08:42:45.000Z ## ID4175: The issuer of the security token was not recognized by the IssuerNameRegistry Boom... In the beginning of February 2015, Azure Active Directory (Azure AD) switched the primary key they used to sign security tokens. If you weren't ready for this, this meant a new rushed deployment to patch your configuration with the new values. ## Why is it happening? Every security token service (STS) will occasionally change their certificates. For security reason, they retire aging certificates for new ones. Rolling the keys limits the amount of time that bad intentioned peoples have for trying their luck against a system. It can also be because the certificates are expiring. ## How to handle this properly ``` Having the keys hardcoded in your web.config is not a viable option. Simply because for every roll of keys it forces you to redeploy your application. ``` In Visual Studio 2013 or later when you create a new web project with federation in the cloud, it will generate a custom *ValidatingIssuerNameRegistry* named DatabaseIssuerNameRegistry. Here is what is generated: ``` public class DatabaseIssuerNameRegistry : ValidatingIssuerNameRegistry { public static bool ContainsTenant(string tenantId) { using (TenantDbContext context = new TenantDbContext()) { return context.Tenants .Where(tenant => tenant.Id == tenantId) .Any(); } } public static bool ContainsKey(string thumbprint) { using (TenantDbContext context = new TenantDbContext()) { return context.IssuingAuthorityKeys .Where(key => key.Id == thumbprint) .Any(); } } public static void RefreshKeys(string metadataLocation) { IssuingAuthority issuingAuthority = ValidatingIssuerNameRegistry.GetIssuingAuthority(metadataLocation); bool newKeys = false; bool refreshTenant = false; foreach (string thumbprint in issuingAuthority.Thumbprints) { if (!ContainsKey(thumbprint)) { newKeys = true; refreshTenant = true; break; } } foreach (string issuer in issuingAuthority.Issuers) { if (!ContainsTenant(GetIssuerId(issuer))) { refreshTenant = true; break; } } if (newKeys || refreshTenant) { using (TenantDbContext context = new TenantDbContext()) { if (newKeys) { context.IssuingAuthorityKeys.RemoveRange(context.IssuingAuthorityKeys); foreach (string thumbprint in issuingAuthority.Thumbprints) { context.IssuingAuthorityKeys.Add(new IssuingAuthorityKey { Id = thumbprint }); } } if (refreshTenant) { foreach (string issuer in issuingAuthority.Issuers) { string issuerId = GetIssuerId(issuer); if (!ContainsTenant(issuerId)) { context.Tenants.Add(new Tenant { Id = issuerId }); } } } context.SaveChanges(); } } } private static string GetIssuerId(string issuer) { return issuer.TrimEnd('/').Split('/').Last(); } protected override bool IsThumbprintValid(string thumbprint, string issuer) { return ContainsTenant(GetIssuerId(issuer)) && ContainsKey(thumbprint); } } ``` The magic is invoked in this method of the IdentityConfig.cs ``` public static void RefreshValidationSettings() { string metadataLocation = ConfigurationManager.AppSettings["ida:FederationMetadataLocation"]; DatabaseIssuerNameRegistry.RefreshKeys(metadataLocation); } ``` In short, the RefreshKeys method will download the metadata document. If it detects a changes with the configuration that is stored in his local database, it will persists the new certificates thumbprints with other informations to the local database. This ensure that your STS can roll his keys whenever it needs and that your application be able to take the changes adequately. ### See Also [MSDN: Important Information About Signing Key Rollover in Azure AD](https://msdn.microsoft.com/en-us/library/azure/dn641920.aspx?ref=codeisahighway.com) Now let those keys roll! ### PowerShell Azure cmdlets: A parameter cannot be found that matches parameter name 'SubscriptionDataFile' URL: https://codeisahighway.com/powershell-azure-cmdlet-a-parameter-cannot-be-found-that-matches-parameter-name-subscriptiondatafile/ Last updated: 2026-08-10T07:12:22.000Z I recently encoutered an error with some of my PowerShell scripts, in some of them, I was using the -SubscriptionDataFile parameter with the following commands: ``` Get-AzureSubscription -SubscriptionName MySubscriptionName -SubscriptionDataFile C:\temp\subfile.xml Remove-AzureSubscription -SubscriptionName MySubscriptionName -SubscriptionDataFile C:\temp\subfile.xml Select-AzureSubscription -SubscriptionName MySubscriptionName -SubscriptionDataFile C:\temp\subfile.xml Set-AzureSubscription -SubscriptionName MySubscriptionName -SubscriptionDataFile C:\temp\subfile.xml ``` I upgraded my PowerShell Azure cmdlets and I got this error message: ``` C:\Temp\PrepareEnvironment.ps1 : A parameter cannot be found that matches parameter name 'SubscriptionDataFile'. At line:1 char:1 + .\PrepareEnvironment.ps1 @params + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [PrepareEnvironment.ps1], ParameterBindingException + FullyQualifiedErrorId : NamedParameterNotFound,PrepareEnvironment.ps1 ``` I was using this parameter to prevent the subscription data to be written to the user's default subscription file and keep things clean, leave no trace and to avoid concurency issues if a lot of "agents/users" where adding/removing data from the same subscription file. ## SubscriptionDataFile parameter is now deprecated Version [0.8.12](https://github.com/Azure/azure-powershell/releases/tag/v0.8.12-December2014?ref=codeisahighway.com) deprecated the *SubscriptionDataFile* parameter, we are now forced to write to the default subscription file in the user's profile. There is no workaround that I know of, the fix is not really complicated, just remove the parameter from your PowerShell calls and it will continue to work as expected, but, every calls will use in the same subscription file. ### Error SP324098 during Visual Studio 2015 license renewal URL: https://codeisahighway.com/error-sp324098-during-visual-studio-2015-license-renewal/ Last updated: 2026-07-31T19:45:06.000Z Thanks to the holidays, I didn't played with my Visual Studio 2015 preview install for the past two weeks. When I launched it today, I got a dialog telling me > Your license has gone stale and must be updated. Please make sure the Internet is connected, then check for an updated license to continue using this product. When trying to renew the license I immediately encountered the following error in the authentication dialog. > SP324098: Your browser could not complete the operation. ![SP324098: Your browser could not complete the operation](https://codeisahighway.com/content/images/2015/01/Visual-Studio-License-error.png) My Visual Studio 2015 is installed on Windows Server Technical Preview (Build 9841). The internet zone privacy setting is set to **Block All Cookies** which prevent the authentication process used by Visual Studio to work as expected. ![Incompatible Internet Explorer privacy setting](https://codeisahighway.com/content/images/2015/01/Incompatible-Privacy-Settings.png) To fix the problem, decrease the security level to **High** and click *OK*. ![Compatible Internet Explorer privacy setting](https://codeisahighway.com/content/images/2015/01/Compatible-Privacy-Settings.png) With cookies not blocked anymore, the authentication will work as expected. Go back to your Visual Studio and renew your stale license. ### Testing code that rely on Microsoft Azure Management Libraries using Microsoft Fakes URL: https://codeisahighway.com/testing-code-that-rely-on-microsoft-azure-management-libraries-using-microsoft-fakes/ Last updated: 2026-08-10T07:12:17.000Z I've played with Azure a lot since last year and I can tell you that the Microsoft Azure Management Libraries (MAML) from and Azure SDK are very well designed and that writing tests against code that use them is a charm. # What is Microsoft Fakes? > Microsoft Fakes help you isolate the code you are testing by replacing other parts of the application with stubs or shims. These are small pieces of code that are under the control of your tests. By isolating your code for testing, you know that if the test fails, the cause is there and not somewhere else. Stubs and shims also let you test your code even if other parts of your application are not working yet. First I created a UnitTest project in Visual Studio. I then added *Microsoft.WindowsAzure.Management* NuGet package to my unit test project. This will add a lot of other depedencies. To enable Fakes for our example, select the *Microsoft.WindowsAzure.Managemement* reference, right-click on it and choose *Add Fakes Assembly*. ![AddFakesAssembly](https://codeisahighway.com/content/images/2014/10/AzureAndFakes-AddFakesAssembly.png) This will add a *Fakes* folder to your project with a file named *Microsoft.WindowsAzure.Management.fakes*. This is the xml file you can use to limit which fakes will be generated. If you don't modify it, everything that can be generated will be. I usually scope the generation to only the types I use. Let's do a unit test as a basic scenario that will prevent the actual http call to Azure but still return a list of fake subscription via a normal SubscriptionClient instance. ## Create a ShimsContext ``` using (var context = ShimsContext.Create()) { // Insert your code here } ``` It is within this `Disposable` object that the magic of Fakes happen. ## Create a Stub for ISubscriptionOperations ``` var fakeSubscriptionId = new Guid("14201e53-1921-4a12-a1f0-c95735706f7a"); var fakeRequestId = new Guid("6a1c1756-fa31-49a5-8c24-f013214692ae"); ISubscriptionOperations subscriptions = new Microsoft.WindowsAzure.Subscriptions.Fakes.StubISubscriptionOperations { ListAsyncCancellationToken = (cancelationToken) => Task.FromResult(new SubscriptionListOperationResponse { RequestId = fakeRequestId.ToString(), StatusCode = System.Net.HttpStatusCode.OK, Subscriptions = new[] { new SubscriptionListOperationResponse.Subscription { SubscriptionId = fakeSubscriptionId.ToString(), SubscriptionName = "Fake subscription", SubscriptionStatus = SubscriptionStatus.Active } } } ) }; ``` ## Override the default behavior for SubscriptionClient.Subscriptions using Shim ``` Microsoft.WindowsAzure.Subscriptions.Fakes.ShimSubscriptionClient.AllInstances.SubscriptionsGet = (subscriptionClient) => subscriptions; ``` ## Now do your normal stuff ``` // Act: var results = CloudContext.Clients .CreateSubscriptionClient(new AnonymousCloudCredentials()) .Subscriptions .List(); ``` That's it! This is a basic example of how you can use Microsoft Fakes to alter the behavior of a class, in this example using MAML libraries. > Since everything is very well decoupled and there's an interface for every clients and operations in MAML libraries it is really easy to replace the original behavior *with or without* Microsoft Fakes. SampleCode [AzureAndFakes.zip](https://github.com/slapointe/BlogSamples/blob/master/AzureAndFakes/AzureAndFakes.zip?ref=codeisahighway.com) The sample project requires Visual Studio 2013 Learn about [Microsoft Fakes](http://msdn.microsoft.com/en-us/library/hh549175.aspx?ref=codeisahighway.com) ### Install Web Platform Installer and Azure SDK using PowerShell DSC URL: https://codeisahighway.com/install-web-platform-installer-and-azure-sdk-using-powershell-dsc/ Last updated: 2026-07-31T19:45:08.000Z Did you ever wanted to configure a developer machine in less than two minutes with minimal scripting effort? ## Say Hi to DSC! DSC (Desired State Configuration) is really fun when you need to enforce a configuration or state on a Windows machine. It is shipped as part of PowerShell v4 and requires WinRM to communicate with remote machines. Here is the configuration I use to accomplish the installation of Web Platform Installer, WebDeploy v3.5 & the Azure SDK v2.3. ``` $configurationData = @{ AllNodes = @( @{ NodeName = 'localhost' WebPiSourcePath = Join-Path $PSScriptRoot WebPi WebPiCmdPath = "$env:ProgramFiles\Microsoft\Web Platform Installer\WebPiCmd-x64.exe" } ); } Configuration DevToolsConfiguration { Node $AllNodes.NodeName { Package WebPi_Installation { Ensure = "Present" Name = "Microsoft Web Platform Installer 5.0" Path = Join-Path $($Node.WebPiSourcePath) wpilauncher.exe ProductId = '4D84C195-86F0-4B34-8FDE-4A17EB41306A' Arguments = '' } Package WebDeploy_Installation { Ensure = "Present" Name = "Microsoft Web Deploy 3.5" Path = $Node.WebPiCmdPath ProductId = '' Arguments = "/install /products:WDeploy /AcceptEula" DependsOn = @("[Package]WebPi_Installation") } Package AzureSDK_2_3_Installation { Ensure = "Present" Name = "Windows Azure Libraries for .NET – v2.3" Path = $Node.WebPiCmdPath ProductId = '' Arguments = "/install /products:WindowsAzureSDK_2_3 /AcceptEula" DependsOn = @("[Package]WebDeploy_Installation") } } } ``` Now all we need to do is create the MOF file from this configuration and and apply it to the local machine. ``` $configPath = Join-Path $PSScriptRoot _configurations\push #Create the MOF file using the configuration data DevToolsConfiguration -OutputPath $configPath\DevToolsConfiguration –ConfigurationData $configurationData #Make it happen - invoke configuration Start-DscConfiguration -Path $configPath\DevToolsConfiguration -Wait -Verbose -Force ``` > That's it! You now have a machine with Web Deploy & the Azure SDK installed. That is impressive for 3 PowerShell statements. Let me know what you think! DSC is available as part of Windows 8.1 and Windows Server 2012 R2; you can start building configuration files in Windows PowerShell ISE if you’re running either of those new operating systems. If you’re running Windows 7, Windows Server 2008 R2, or Windows Server 2012, install [Windows Management Framework 4.0](http://www.microsoft.com/download/details.aspx?id=40855&ref=codeisahighway.com) to get the benefits of DSC. Learn more about how to get started from the [DSC documentation on Microsoft TechNet](http://technet.microsoft.com/library/dn249918.aspx?ref=codeisahighway.com). [DSC-WebPi sample](https://github.com/slapointe/BlogSamples/tree/master/DSC-WebPI?ref=codeisahighway.com)