Is this possible to run a Power Shell script unattended inside Azure Function using Azure Function managed identity

john john Pter 1,015 Reputation points
2025-05-08T13:57:34.09+00:00

I have this PowerShell script , to get all the groups assigned to a user as owner or as members and then remove the user from those groups.

# Connect to Microsoft Graph with required delegated scopes
Connect-MgGraph -Scopes "User.Read.All", "Group.Read.All", "GroupMember.ReadWrite.All", "Directory.Read.All", "Group.ReadWrite.All"

# Connect to Exchange Online
Connect-ExchangeOnline

# Target user email
$userEmail = "test@m********.onmicrosoft.com" 

# --- PART 1: Azure AD + Office 365 Groups ---
$userList = Get-MgUser -Filter "mail eq '$userEmail' or userPrincipalName eq '$userEmail'"  -ConsistencyLevel eventual -All -Property Id, DisplayName, UserPrincipalName, Mail

$userObj = $userList | Select-Object -First 1

if (-not $userObj) {
    Write-Host "User $userEmail not found in Microsoft Graph. Skipping AAD removal."
} elseif (-not $userObj.Id) {
    Write-Host "User objectId missing even after lookup. Skipping AAD removal."
} else {
    Write-Host "Found user: $($userObj.DisplayName) ($($userObj.UserPrincipalName))"

    $groups = Get-MgUserMemberOf -UserId $userObj.Id -All
    $groupsAsOwner = Get-MgUserOwnedObject -UserId $userObj.Id -All


    foreach ($group in $groups) {
        if ($group.AdditionalProperties.'@odata.type' -ne '#microsoft.graph.group') {
            continue
        }

        $groupId = $group.Id
        $groupName = $group.AdditionalProperties.DisplayName

        if (-not $groupId) {
            Write-Host "Skipping group with empty ID"
            continue
        }

        $fullGroup = Get-MgGroup -GroupId $groupId

        if ($fullGroup.GroupTypes -contains "DynamicMembership") {
            Write-Host "Skipping dynamic group: ${groupName}"
            continue
        }

        # Remove as MEMBER
        try {
            Remove-MgGroupMemberByRef -GroupId $groupId -DirectoryObjectId $userObj.Id -ErrorAction Stop
            Write-Host "Removed as MEMBER from ${groupName}"
        }
        catch {
            Write-Host "Failed MEMBER removal from ${groupName}: $($_.Exception.Message)"
        }}
foreach ($group2 in $groupsAsOwner) {
$groupId2 = $group2.Id
$groupName2 = $group2.AdditionalProperties.DisplayName
        # Remove as OWNER
        try {
            Remove-MgGroupOwnerByRef -GroupId $groupId2 -DirectoryObjectId $userObj.Id -ErrorAction Stop
            Write-Host "Removed as OWNER from ${groupName2}"
        }
        catch {
            Write-Host "Failed OWNER removal from ${groupName2}: $($_.Exception.Message)"
        }
    }
    }

# --- PART 2: Exchange Distribution Groups + Mail-enabled Security Groups ---
$dlGroups = Get-DistributionGroup -ResultSize Unlimited

foreach ($dl in $dlGroups) {
    try {
        # Remove as MEMBER
        $members = Get-DistributionGroupMember -Identity $dl.Identity -ResultSize Unlimited
        $memberMatch = $members | Where-Object { $_.PrimarySmtpAddress -ieq $userEmail }

        if ($memberMatch) {
            Remove-DistributionGroupMember -Identity $dl.Identity -Member $userEmail -BypassSecurityGroupManagerCheck -Confirm:$false
            Write-Host "Removed as MEMBER from Exchange group: $($dl.DisplayName)"
        }

        # Remove as OWNER
        # $owners = (Get-DistributionGroup -Identity $dl.Identity).ManagedBy
        $owners = (Get-DistributionGroup -Identity $dl.Identity).ManagedBy | Foreach-Object { Get-Mailbox $_ }
        $ownerMatch = $owners | Where-Object { $_.PrimarySmtpAddress -ieq $userEmail }

        if ($ownerMatch) {
            Set-DistributionGroup -Identity $dl.Identity -ManagedBy @{ Remove = "$userEmail" }
            Write-Host "Removed as OWNER from Exchange group: $($dl.DisplayName)"
        }
    }
    catch {
        Write-Host "Failed Exchange removal for group: $($dl.DisplayName) - $($_.Exception.Message)"
    }
}

Write-Host "Cleanup script completed."

now currently when i run the script, i login using Office 365 admin. and accept the consent message. now i want to run this power shell script unattended every 1 hour, and to read the email from a sharepoint list... so for this i will create an Azure Function. but i am not sure what are the required steps, to allow this Azure Function to run those scripts unattended using the azure function managed identity ?

Thanks

Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
5,775 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Michele Ariis 500 Reputation points MVP
    2025-05-08T14:18:42.1966667+00:00

    Sure John, it is totally feasible; let me explain in broad strokes:

    You can create an Azure Function in PowerShell with a trigger timer (for the time or cron you prefer) and enable its System-Assigned Managed Identity. Then, in Azure AD assign the necessary Graph roles (User.Read.All, Group.Read.All, GroupMember.ReadWrite.All, Directory.Read.All, and Sites.Read.All) and the Exchange Administrator role for ExchangeOnlineManagement to this identity as “Application permission.”

    In your run.ps1 replace the Connect-MgGraph -Scopes and Connect-ExchangeOnline with the -ManagedIdentity versions. At this point, when Function starts (manually or via timer), it authenticates itself and can read the SharePoint list, query Graph, and manage groups without any interaction.

    Do a first manual test, take a look at the logs, and you're up and running in unattended mode


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.