# How to create your own autopatch-like "ring" groups in Azure using Azure Automation and PowerShell

I like the idea of Autopatch ring groups where you have one "root" group, whose members are distributed across several "ring" groups based on a given percentage proportion.

And because I needed the same thing for my [gradual applications update automation](https://doitpsway.com/gradual-update-of-all-applications-using-winget-and-custom-azure-ring-groups) I've created my own "ring" groups solution.

**OK, so what will be the result of this post?**

One main Azure "root" group whose members will be distributed on schedule across several Azure "ring" groups by Azure Automation Runbook that will run my function `Set-AzureRingGroup` (part of my module [AzureGroupStuff](https://www.powershellgallery.com/packages/AzureGroupStuff)).

Interested? OK, let's go! 😉

## Create Azure "root" group + "ring" groups

### Root group

A "root" group is nothing else than an ordinary group whose members will be distributed across the "ring" groups based on a defined percentage proportion.

Therefore you can use any existing group, or create a new one.

Group should be of **security** type!

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">The only important thing is that you <strong>can't mix user and device accounts in this group</strong>! But the group can contain other groups (recursive search is supported)</div>
</div>

### Ring groups

A "ring" group is where members are managed automatically through the created Azure Automation Runbook.

Members are picked from the "root" group and distributed across the "ring" groups based on the percentage proportion defined in the Runbook code. The group members are reorganized when needed.

Groups should be of **security** type with **manually assigned members**. **Don't add** any members now!

So create as many groups as you need. Make a note of each created group and its ID. We will need this when setting up the Azure automation later.

It is a good idea to specify the group purpose in the group name (ring1, ring2,...), to make it easier to identify the group purpose later (TIP: the group description will be automatically set using our automation)

---

## Create & set Azure automation for managing "ring" group members

To keep members in our "ring" groups up to date, we need some automation that will do the rebalancing for us. This is where Azure Automation steps in.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">You can use Scheduled Task instead of Azure Automation Runbook if you want to save a few bucks</div>
</div>

### Create an Azure Automation Account

How to create an Azure Automation Account is outside the scope of this article, but you can follow the [official documentation](https://learn.microsoft.com/en-us/azure/automation/quickstarts/create-azure-automation-account-portal).

### Create Runbook

Inside your Automation Account create a new runbook. Choose **PowerShell** type and **5.1** as a runtime version.

Once created, open the Runbook, choose `Edit` &gt; `Edit in portal` and insert the code below

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1709293622231/7d3da8ba-a664-4375-b628-ed638e08c920.png align="center")

```powershell
#requires -modules AzureGroupStuff, MSGraphStuff, Microsoft.Graph.Authentication, Microsoft.Graph.Groups, Microsoft.Graph.DirectoryObjects, Microsoft.Graph.Users, Microsoft.Graph.Identity.DirectoryManagement

# group whose members will be distributed between ring groups
$rootGroup = 'IDofYOURrootGROUP'
# ring groups configuration
$ringGroupConfig = [ordered]@{
    # automatically set members
    'IDofYOURring1GROUP' = 10 # testo_ring_daily
    'IDofYOURring2GROUP' = 10 # testo_ring_weekly
    'IDofYOURring3GROUP' = 20 # testo_ring_biweekly
    'IDofYOURring4GROUP' = 60 # testo_ring_monthly
}

Connect-MgGraph -Identity -NoWelcome

# Set-AzureRingGroup is part of the AzureGroupStuff module
Set-AzureRingGroup -rootGroup $rootGroup -ringGroupConfig $ringGroupConfig -forceRecalculate -skipUnderscoreInNameCheck -Verbose
```

Don't forget to modify `$rootGroup` variable to match the ID of your "root" group.

Also you need to modify `$ringGroupConfig` hashtable.

`Keys` in the hash are the IDs of the "ring" groups created earlier and `values` are integers representing the percentage of how many members of the "root" group should be placed in this "ring" group.

The sum of the `values` must be obviously 100 in total.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1709027418322/78110967-0264-4b5a-b211-4c997ec2730b.png align="center")

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">There is also an option to have a "ring" group with manually set members (ideal for early adopters). Check <code>firstRingGroupMembersSetManually</code> parameter of the <code>Set-AzureRingGroup</code> function for more details.</div>
</div>

Used function `Set-AzureRingGroup` is part of my module [AzureGroupStuff](https://www.powershellgallery.com/packages/AzureGroupStuff) and I really encourage you to check its help to better understand how it works and what option does it offer.

### Schedule the Runbook

Schedule the Runbook to run regularly using the button `Link to schedule` in your Runbook pane

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1709024383823/23ae99ab-e45a-4da6-aa45-3b81decb8178.png align="center")

Create a new schedule to run every three hours or so (based on your needs).

### Assign required permissions to the Automation Account Managed Identity

Every Automation Account has automatically created `Managed Identity` (enterprise application a.k.a. service principal). It allows the runbook to access and perform actions on other Azure resources without storing any credentials in the runbook code or configuration.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1709027193703/7f449585-0d2c-4063-a447-936969330314.png align="center")

For this identity to have appropriate Graph API permissions to manipulate group members, the following application permissions have to be granted.

* [`Device.Read`](http://Device.Read)`.All`
    
    * to be able to work with member device objects
        
* [`User.Read`](http://User.Read)`.All`
    
    * to be able to work with member user objects
        
* `Group.ReadWrite.All`
    
    * to be able to set group members and description
        

You can do this using my function `Grant-AzureServicePrincipalPermission` (part of my module [AzureApplicationStuff](https://www.powershellgallery.com/packages/AzureApplicationStuff))

```powershell
Grant-AzureServicePrincipalPermission -servicePrincipalId 'IDofYOURAUTOMATIONmanagedIDENTITY' -permissionType application -permissionList Grant-AzureServicePrincipalPermission -servicePrincipalId '2de94e47-895d-4780-8f8f-b803d5e243b2' -permissionType application -permissionList Directory.Read.All, User.Read.All, Group.ReadWrite.All
```

### Import required modules to the Automation Account

The following PowerShell modules need to be imported so the Runbook can run

* `AzureGroupStuff`
    
* `MSGraphStuff`
    
* `Microsoft.Graph.Authentication`
    
* `Microsoft.Graph.Groups`
    
* `Microsoft.Graph.DirectoryObjects`
    
* `Microsoft.Graph.Users`
    
* `Microsoft.Graph.Identity.DirectoryManagement`
    

You can do this manually using `Add a module` button.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1709023386795/a1428327-a1ea-4f73-9c25-2e7f7fd71c55.png align="center")

Or using my function `New-AzureAutomationModule` (part of my [AzureResourceStuff](https://www.powershellgallery.com/packages/AzureResourceStuff) module).

```powershell
'AzureGroupStuff', 'MSGraphStuff', 'Microsoft.Graph.Authentication','Microsoft.Graph.Groups','Microsoft.Graph.DirectoryObjects','Microsoft.Graph.Users','Microsoft.Graph.Identity.DirectoryManagement' | % {
    New-AzureAutomationModule -moduleName $_ -resourceGroupName yourRESOURCEgroupNAME -automationAccountName yourAUTOMATIONaccountNAME
}
```

For more details check my post [Import new (or update existing) PowerShell module (including its dependencies!) into Azure Automation Account using PowerShell](https://doitpsway.com/import-new-or-update-existing-powershell-module-including-its-dependencies-into-azure-automation-account-using-powershell)

## Add members to the "root" group

In case you didn't do so already. Add some test users or devices to your "root" group that should be targeted by this updating solution.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💥</div>
<div data-node-type="callout-text"><strong>It is a good idea to select just a few testing accounts right now and add more later once you test this solution!</strong></div>
</div>

## Set "ring" groups members by running the Runbook

Run your Runbook using the `Start` button.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1709024819885/ef71c2ff-8cd8-46b8-a9d5-5ebbdfc6ce23.png align="center")

When the Runbook ends you should see members from the "root" group added to the "ring" groups based on the percent ratio specified in the Runbook code `$ringGroupConfig` hashtable.

And that's it 👍.

From now on, members of the "root" group will be automatically distributed across your "ring" groups whenever the Automation will run.
