Vue normale

Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.
À partir d’avant-hierFlux principal

Microsoft Retires Azure Automation Run As Accounts in September 2023

Azure Automation for IT Pros

I’ve spent a lot of time working with Azure Automation over the last few years. It’s an extremely useful facility for tenant administrators who want to run PowerShell scripts using a more modern mechanism than offered by Windows Scheduler. This is especially true so in large tenants where processing hundreds or thousands of objects is common, which is why I started to use Run As accounts with Azure Automation.

Converting scripts to run on Azure Automation isn’t too difficult, once you understand the headless nature of the beast and that PowerShell runs on virtual machines spun up for the purpose. The biggest issue often faced when moving scripts from running interactively to being an Azure Automation runbook is how to create output from scripts, but it’s possible to send email, post to Teams channels, and create files in SharePoint document libraries.

Microsoft seems to communicate with developers and administrators (aka IT Pros) in different ways. For instance, the news about the retirement of Azure Automation Run As accounts on September 30, 2023, didn’t appear in any notification in the Microsoft 365 admin center. In fact, apart from the notices posted in Azure Automation documentation (like that shown in Figure 1), I can’t find a formal announcement from Microsoft.

Microsoft notice about the retirement of Run As accounts
Figure 1: Microsoft notice about the retirement of Run As accounts

Informing the Technical Community About the Run As Retirement

The possibility exists that I might not be looking hard enough. Normally, I am reasonably proficient with search (Google), but the first hit I find is a 27 September 2022 Microsoft Answers post saying “On 30 September 2023, we’ll retire the Azure Automation Run As account that you use for Runbook authentication.” I can find an earlier “plan for change” note for July 2022 in the What’s new in Azure Automation page. Apart from that, Microsoft seems to have updated the documentation on 18 October 2022 (here’s the FAQ).

I suppose that it’s reasonable to expect people to learn about developments from documentation. In this instance, I think Microsoft dropped the ball and didn’t do a great job of telling people what’s going to happen when Run As accounts retire.

Managed Identities Are a Better Solution

The logic for retiring Run As accounts is undeniable. A better and more secure solution (managed identities) exists. Run As accounts authenticate using a self-signed certificate that needs to be renewed yearly. Microsoft has removed the ability to renew these certificates from the Azure portal, meaning that Run As accounts are counting down to a time when they won’t be able to authenticate. Microsoft has a script to renew certificates for Run As accounts and the script will run after September 30, 2023. However, Run As accounts will then be unsupported, which isn’t a great situation for production components.

The nice thing about managed identities from an Office 365 perspective is that the important PowerShell modules used for automation support managed identities. Some do so very smoothly (like the latest Exchange Online management module, where even the latest RBAC for applications feature supports managed identities) and some do it with a little extra work. For example, V1.0 of the Microsoft Graph PowerShell SDK needs to get an access token from the Azure Automation account that owns a managed identity while V2.0 will be able to sign in using a managed identity. Here’s an example of a simple runbook that:

  • Connects to the Azure Automation account using a managed identity.
  • Gets an access token from Azure AD.
  • Uses the access token to connect to the Graph with Connect-MgGraph.
  • Retrieves the service domain (like office365itpros.onmicrosoft.com) using the Get-MgOrganization cmdlet.
  • Uses the service domain and a managed identity to connect to Exchange Online.
  • Lists details of user mailboxes.
# Connect to Microsoft Graph with Azure Automation
Connect-AzAccount -Identity
$AccessToken = Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com"
Connect-MgGraph -AccessToken $AccessToken.Token
# Get Tenant service domain using Get-MgOrganization
$TenantName = (Get-MgOrganization).VerifiedDomains | Where-Object {$_.IsInitial -eq $True} | Select-Object -ExpandProperty Name
# Connect to Exchange Online
Connect-ExchangeOnline -ManagedIdentity -Organization $TenantName 
Get-ExoMailbox -RecipientTypeDetails UserMailbox | Format-Table DisplayName, UserPrincipalName

When V2.0 of the Microsoft Graph PowerShell SDK is available, you’ll be able to replace the first three lines of code with a simple Connect-MgGraph -Identity.

Another example of using a managed identity with Exchange Online is to monitor events gathered in the audit log to detect and report events that might indicate potential tenant compromise. Running the script on an Azure Automation schedule makes sure that audit events are checked without human intervention.

Time to Move Forward

Apart from the poor communication, I don’t have any problem with Microsoft’s decision to retire Run As accounts. They worked as a mechanism to connect resources to Azure Automation. We’re just moving on to adopt a new approach. Microsoft documents the migration steps to move from a Run As account to use managed identities. It’s a manual process, but not onerous.

Goals for your IT Team When They Free Up Time Through Automation

Back in October, I was lucky enough to visit my friends at ShareGate, along with fellow MVPs Jasper Oosterveld (@jappie1981) and Maarten Eekels (@maarteneekels) We had several conversations with ShareGate’s Laurent St. Pierre (@laurent_sp), and those were recorded and released as a series of videos: The evolution of IT: Improving digital employee experience to boost productivity. The conversations have also led to ongoing asynchronous discussions about the things we said, for more elaboration and to expand on our thoughts.

Recently, ShareGate’s Rafael Spuldar did a new blog post: 5 IT Goals for Your Team When They Free up Time – ShareGate.

Emily Mancini (@eemancini) and I had kicked around the topic and came up with the following list of ideas. Some made it into Rafael’s post, and others didn’t, so I figured I’d post our full list here.

Let us know what you think in the comments!

  1. Clean up AD/AAD data – In most cases, targeting content to the right people is based on AAD data. This data determines which people belong in particular Microsoft 365 Group, especially if they are dynamic groups. If the organization can actually rely on that data being correct, they can build out much more personalized experiences. In most organizations, not only is the data wrong, but everyone knows it’s wrong and they can’t rely on it. No one even tries to get it fixed because they think it’s pointless. Spending time improving this data provides many benefits.
  2. Focus on consultative customer service – If you’re like many IT departments, people don’t come to you for advice and assistance because they can’t get your time. Set up an informal (or formal) consulting capability for the organization. Let anyone in the organization get in touch during office hours to help them think through technical issues and starting solutions for themselves. This consultative focus can also become “market sensing”, in that it tells you what the organization is doing and what they need that you aren’t providing. Unless you have an amazing help desk, they probably don’t fulfill this role. Help desks tend to focus on solving immediate problems (which everyone wants them to do), and not longer-term efforts. If nothing else, it’s a different mindset.
  3. Think about places you could solve problems – Imagine going out into the organization and saying something like “We know you struggle with people filling out so many of these forms. We’d like to help you automate and improve the process.” You’d be heroes! In other words, do external outreach in the organization: offering the very services you have capacity for – for free! You’ll be amazed at the goodwill this engenders.
  4. Search analysis – Take a look at the searches people are doing and what happens. How many searches lead to useful results, and how many fail? A failed search is a content opportunity, and a successful search means that content matters and may need a review. That doesn’t mean that you in IT need to do that review, but you’d be providing great information to the content owners to make their content more valuable. You have the tools to do this in Microsoft 365, but many organizations simply don’t.
  5. Run the assessment tool – The Microsoft 365 Assessment tool was created to help people move from classic to modern and from on prem to the cloud originally. It’s been expanded to help people understand how Microsoft Syntex might be a valuable toolset. But as part of the output, it gives you information about how to improve your information architecture. You need to be at least a SharePoint Admin to run the scanner, so running it for your Site Owners is a way to give them a gift to improve their content and its structure.

Creating a SharePoint page using Microsoft Graph API and Power Automate

Thanks to the workflow that notifies me of updates to the Microsoft Graph API, I saw a new addition to the list: the sitePage resource type.

This is exciting for me, as I currently have some workflows that distribute SharePoint pages to various sites both within our own tenant, as well as client tenants. Currently these are triggered by a page being published in a central location, with specific information used as trigger conditions.

What’s annoying about this scenario is that I need to create connectors in Power Automate to the client tenant using an account in their environment. It also means I need a workflow per client (to keep it clean).

Now with the addition of the sitePage resource type in Microsoft Graph, I can make this work programmatically across any number of clients — all from a single workflow.

WARNING: This is a beta feature at present, so don’t use it for production systems unless you’re find to accept the risks.

Requirements

The requirements of this are fairly simple. We need:

  • An app registration in Azure AD that has the “Sites.ReadWrite.All” application permission added
  • A repository where the details are stored, including:
  • Client name
  • Tenant ID
  • App/Client ID
  • Secret
  • SharePoint site ID

Now, we could use a different way to authenticate, and we could also use an action to perform a search in the tenant to find the relevant site by name or URL, but if we’ve got that — then it’s not exactly difficult to get the SharePoint site ID and store it in our repository.

For the purposes of this, I’m going to store it in a SharePoint list:

Workflow

At a high-level, my workflow is quite simple:

In my specific scenario, all the workflow is doing is publishing a page with an embedded video, as part of a program of regular content I create for clients. So all I need to provide is a page title and the URL suffix from the embed code.

The next step of the workflow takes my page title, and turns it into a file name:

The code used here is:

concat(replace(triggerBody()['text'],' ','-'),'.aspx')

From here, we’re now ready to retrieve all the sites we want to apply this to:

Within our Apply to Each, we have three steps:

  1. Create the page
  2. Parse the JSON of the page creation
  3. Publish the page, using the ID from step 2

(If you’re comfortable with extracting the page ID value directly from the results of step 1, then you don’t need the Parse JSON action.)

In the page creation action, I’m creating a very simple page that only has a single embed web part on it, and I’m passing variables from both the trigger as well as the Get Items action.

The Parse JSON is relatively straightforward:

And for the final step we hit publish on the page:

And that’s it! We have a simple page published in each tenant listed, with the same content.

If you want something more glamorous, refer to the sitePage resource type page to get a breakdown of the structure of the body of the content.

Appendix

Here’s the full details of the body of the page creation and Parse JSON actions.

Create page

{
"name": "@{outputs('Compose_-_replace_spaces_with_hyphens_and_add_file_extension')}",
"title": "@{triggerBody()['text']}",
"pageLayout": "article",
"promotionKind": "newsPost",
"showComments": false,
"showRecommendedPages": false,
"titleArea": {
"enableGradientEffect": true,
"imageWebUrl": "/_layouts/15/images/sleektemplateimagetile.jpg",
"layout": "plain",
"showAuthor": false,
"showPublishedDate": true,
"showTextBlockAboveTitle": false,
"textAboveTitle": "",
"textAlignment": "left",
"imageSourceType": 2,
"title": "@{triggerBody()['text']}"
},
"canvasLayout": {
"horizontalSections": [
{
"layout": "oneColumn",
"id": "1",
"emphasis": "none",
"columns": [
{
"id": "1",
"webparts": [
{
"id": "669d4d75-eca0-4e8b-95d7-2e765dd4859a",
"webPartType": "490d7c76-1824-45b2-9de3-676421c997fa",
"data": {
"audiences": [],
"dataVersion": "1.2",
"description": "Embed content from other sites such as Sway, YouTube, Vimeo, and more",
"title": "Embed",
"properties": {
"embedCode": "<iframe src=\"https://player.vimeo.com/video/@{triggerBody()['text_2']}\" width=\"640\" height=\"360\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen=\"\"></iframe>",
"cachedEmbedCode": "<iframe src=\"https://player.vimeo.com/video/@{triggerBody()['text_2']}\" width=\"640\" height=\"360\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen=\"\"></iframe>",
"shouldScaleWidth": true,
"thumbnailUrl": "",
"cachedEmbedCodeThumbnail": ""
},
"serverProcessedContent": {
"imageSources": [
{
"key": "imageSource",
"value": "/_LAYOUTS/IMAGES/VISUALTEMPLATEIMAGE1.JPG"
}
]
}
}
}
]
}
]
}
]
}
}

Parse JSON

{
"type": "object",
"properties": {
"@@odata.context": {
"type": "string"
},
"@@odata.etag": {
"type": "string"
},
"eTag": {
"type": "string"
},
"id": {
"type": "string"
},
"lastModifiedDateTime": {
"type": "string"
},
"name": {
"type": "string"
},
"webUrl": {
"type": "string"
},
"title": {
"type": "string"
},
"pageLayout": {
"type": "string"
},
"thumbnailWebUrl": {
"type": "string"
},
"promotionKind": {
"type": "string"
},
"showComments": {
"type": "boolean"
},
"showRecommendedPages": {
"type": "boolean"
},
"createdBy": {
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"displayName": {
"type": "string"
}
}
}
}
},
"lastModifiedBy": {
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"displayName": {
"type": "string"
}
}
}
}
},
"parentReference": {
"type": "object",
"properties": {
"siteId": {
"type": "string"
}
}
},
"contentType": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"publishingState": {
"type": "object",
"properties": {
"level": {
"type": "string"
},
"versionId": {
"type": "string"
}
}
},
"reactions": {
"type": "object",
"properties": {}
},
"titleArea": {
"type": "object",
"properties": {
"enableGradientEffect": {
"type": "boolean"
},
"imageWebUrl": {
"type": "string"
},
"layout": {
"type": "string"
},
"showAuthor": {
"type": "boolean"
},
"showPublishedDate": {
"type": "boolean"
},
"showTextBlockAboveTitle": {
"type": "boolean"
},
"textAboveTitle": {
"type": "string"
},
"textAlignment": {
"type": "string"
},
"title": {
"type": "string"
},
"authors@odata.type": {
"type": "string"
},
"authors": {
"type": "array"
},
"authorByline@odata.type": {
"type": "string"
},
"authorByline": {
"type": "array"
},
"imageSourceType": {
"type": "integer"
},
"serverProcessedContent": {
"type": "object",
"properties": {
"imageSources": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"key",
"value"
]
}
}
}
}
}
}
}
}

Originally published at Loryan Strant, Microsoft 365 MVP.


Creating a SharePoint page using Microsoft Graph API and Power Automate was originally published in REgarding 365 on Medium, where people are continuing the conversation by highlighting and responding to this story.

❌
❌