InActive-Owners.ps1

Function InActive-Owners {
    <#
.SYNOPSIS
    Get DISABLED resource owners details from App reg, Security
    Group and subscription scoped Tags.
 
.DESCRIPTION
    Get list of DISABLED / InActive owners from Azure Security Group,
    Azure App Registration, And any Owner level Tags (limited to subscription scope.)
 
.PARAMETER SecurityGroup
    Switch used to run thru all the security groups within the tenanat.
    No support for explicit SGs at this point.
 
.PARAMETER AppReg
    Switch used to run thru all the Application Registrations within the tenanat.
    No support for explicit App registrations at this point.
 
 
.PARAMETER SubscriptionTags
    Switch used in combination with Owner_TagKey.
    For more details look at examples.
 
.PARAMETER Owner_TagKey
    Paramater that need to pass while used with SubscriptionTags.
    It includes the value of Tag name which holds subscription owners information.
 
.PARAMETER UPN
    Parameter used for single UPN or user status check.
    Pass email address of user for which you need status.
 
.EXAMPLE
    PS> $data = InActive-Owners -SecurityGroup
    $data | format-Table
    $data | Export-Csv -Path 'DisabledOwners.csv' -NoTypeInformation -Force
 
.EXAMPLE
    PS> $data = InActive-Owners -SubscriptionTags -Owner_TagKey '<TagName>'
    $data | format-Table
    $data | Export-Csv -Path 'DisabledOwners.csv' -NoTypeInformation -Force
 
.EXAMPLE
    PS> $data = InActive-Owners -AppReg
    $data | format-Table
    $data | Export-Csv -Path 'DisabledOwners.csv' -NoTypeInformation -Force
 
.EXAMPLE
    PS> InActive-Owners -UPN <UserEmailAddress>
 
.LINK
    Other packages: https://www.powershellgallery.com/packages?q=aammir
#>

    [CmdletBinding()]
    param (
        [Parameter(ParameterSetName = 'One', Position = 1)]$Owner_TagKey <#= 'iicsSubscriptionOwner'#>,
        [Parameter(ParameterSetName = 'One', Position = 0)][switch]$SubscriptionTags,
        [Parameter(ParameterSetName = 'Two')]$SubscriptionName,
        [Parameter(ParameterSetName = 'Three')][switch]$SecurityGroup,
        [Parameter(ParameterSetName = 'Four')][switch]$AppReg,
        [Parameter(ParameterSetName = 'Five')]$UPN
        # [Parameter(ParameterSetName = 'Two')]$mailaddress
    )
    $t1 = @'
    Designed and managed by
          ___ _
         / _ \ (_)
        / /_\ \ __ _ _ __ ___ _ __ ___ _ _ __
        | _ |/ _` | '_ ` _ \| '_ ` _ \| | '__|
        | | | | (_| | | | | | | | | | | | | |
        \_| |_/\__,_|_| |_| |_|_| |_| |_|_|_|
 
        Contact : aammir.mirza@hotmail.com
'@

    $t2 = @'
+------------------+-----------------------------------------------------------------+----------------------------------------------+
| Switch | Usage | Example |
+------------------+-----------------------------------------------------------------+----------------------------------------------+
| SecurityGroup | With this switch you can run accross all the | |
| | SGs within AzureAD for which you (identity | $data = InActive-Owners -SecurityGroup |
| | running functions) have access. | |
+------------------+-----------------------------------------------------------------+----------------------------------------------+
| SubscriptionTags | With this switch you can run for subscription scope | $data = InActive-Owners -SubscriptionTags |
| | Tags (service tags), having owner email address. | -Owner_TagKey '<TagName>' |
| | You need to specify the Tag key. | |
+------------------+-----------------------------------------------------------------+----------------------------------------------+
| AppReg | With this switch you can run for all Azure App Registrations to | $data = InActive-Owners -AppReg |
| | verify the owners and If they are inActive. | |
+------------------+-----------------------------------------------------------------+----------------------------------------------+
| UPN | With this switch you can run for individual UPN/ID to | InActive-Owners -UPN <UserEmailA> |
| | verify the owners and If they are inActive. | |
+------------------+-----------------------------------------------------------------+----------------------------------------------+
'@

    Write-Verbose "`n$($t1)"
    Write-Verbose 'For more help on command and switches use -Verbose'
    Write-Verbose "Switches and there operations.`n$($t2)"

    $connect = Connect-MgGraph -AccessToken (Get-AzAccessToken -ResourceTypeName MSGraph).Token
    $url = 'https://graph.microsoft.com'
    $endpoint = "users/?`$select="
    $graphversion = 'beta'
    $invalidUPN = @()
    $authHeader = @{
        'Content-Type'  = 'application/json'
        'Authorization' = 'Bearer ' + (Get-AzAccessToken -ResourceTypeName MSGraph).Token
    }
    if ($SubscriptionTags) {
        if ($SubscriptionName) {
            $subsName = Get-AzSubscription -SubscriptionName $SubscriptionName
        }
        else {
            $subsName = @()
            $subsName = (Get-AzSubscription <#| Select-Object -First 25#>)
        }
        foreach ($item in $subsName) {
            # | Where-Object -Property State -EQ 'Enabled')) {
            $context = Set-AzContext $item
            Write-Verbose "Execution for the subscription $($item.Name)"
            if ($($item.State) -eq 'Enabled') {
                Write-Verbose "Subscription State $($item.State)"
                # constructing Body
                $tags = Get-AzTag -ResourceId /subscriptions/$item
                Write-Verbose 'Parsing the TAGs now...'
                Write-Verbose "Checking subscription level tags for $($item.Name)"
                if ($tags) {
                    foreach ($tagKey in $tags.Properties.TagsProperty.Keys) {
                        $tagValue = $tags.Properties.TagsProperty[$tagKey]
                        # Write-Host " | -- - $($tagKey):$($tagValue)" -ForegroundColor DarkYellow
                        if ($tagKey -eq "$Owner_TagKey") { $iicsSubscriptionOwner = $tagValue }
                    }
                    if ($iicsSubscriptionOwner) {
                        $filterOwner = "DisplayName, mail, accountEnabled&filter=mail eq '$($iicsSubscriptionOwner)'"
                        $filterInactiveOwner = ' and accountEnabled eq false'
                        $body = @{}
                        $uri = "$url/$graphversion/$endpoint$filterOwner$filterInactiveOwner"
                        $results = Invoke-MgGraphRequest `
                            -Uri $uri `
                            -Method GET `
                            -Body $body

                        if ($results.value) {
                            Write-Verbose " [INACTIVE] $($iicsSubscriptionOwner)"
                            $invalidUPN += [PSCustomObject]@{
                                'SubscriptionName' = $item.Name
                                'OwnerUPN'         = $iicsSubscriptionOwner
                                'Status'           = 'INACTIVE'
                            }
                        }
                        else {
                            Write-Verbose " [ACTIVE] $($iicsSubscriptionOwner)'
                            Write-Verbose '$($item.Name) | $($iicsSubscriptionOwner)"

                        }
                    } # If block
                }
            }
        }
    }

    elseif ($SecurityGroup) {
        $invalidUPN = @()
        $sgCount = 0;
        # $groupId = '11e7b41d-d876-416c-abef-0ea1a23ab762'
        $graphversion = 'beta'
        $allGroupsEndpoint = 'groups?$filter=mailEnabled eq false'
        # Extracting all Security Groups
        $uriAllSg = "$url/$graphversion/$allGroupsEndpoint"
        $resultsAllSG = Invoke-MgGraphRequest `
            -Uri $uriAllSg `
            -Method GET
        $CloudSecurityGroups = $resultsAllSG.Value
        $UserNextLink = $resultsAllSG.'@odata.nextLink'
        while ($UserNextLink -ne $null) {
            $resultsAllSG = (Invoke-MgGraphRequest -Uri $UserNextLink -Method Get)
            $UserNextLink = $resultsAllSG.'@odata.nextLink'
            $CloudSecurityGroups += $resultsAllSG.value
        }
        Write-Verbose '-------------------------------'
        Write-Verbose "Total SG Count - $($CloudSecurityGroups.Count)"
        Write-Verbose '-------------------------------'

        foreach ($currentSG in $CloudSecurityGroups) {
            $sgCount = $sgCount + 1
            Write-Verbose "$($sgCount) - $($currentSG.displayName)"
            $endpointSg = "groups/$($currentSG.id)/owners?`$select=imAddresses"
            $uriSg = "$url/$graphversion/$endpointSg"
            $SgOwners = Invoke-MgGraphRequest -Uri $uriSg -Method GET
            $count = ($SgOwners.Value.imAddresses).Count
            foreach ($currentItemName in $SgOwners.Value.imAddresses) {
                if ($currentItemName) {
                    $filterOwner = "DisplayName, mail, accountEnabled&filter=mail eq '$($currentItemName)'"
                    $filterInactiveOwner = ' and accountEnabled eq false'
                    $body = @{}
                    $uri = "$url/$graphversion/$endpoint$filterOwner$filterInactiveOwner"
                    $results = Invoke-MgGraphRequest `
                        -Uri $uri `
                        -Method GET `
                        -Body $body

                    if ($results.value) {
                        $count = $count - 1
                        Write-Verbose " [INACTIVE] $($currentItemName)"
                        $invalidUPN += [PSCustomObject]@{
                            'SecurityGroupName'    = $($currentSG.displayName)
                            'OwnerUPN'             = $currentItemName
                            'Status'               = 'INACTIVE'
                            'NumberOfActiveOwners' = $count
                        }
                    }
                    else {
                        Write-Verbose " [ACTIVE] $($currentItemName)"
                    }
                } # If block
            }
            Write-Verbose "Active owners are - $($count)"
        }
    }

    elseif ($AppReg) {
        $invalidUPN = @()
        # Fetching all the App registrations
        $appRegistrations = Get-AzADApplication # | Select-Object -First 25
        foreach ($appRegistration in $appRegistrations) {
            ('-' * 75)
            Write-Verbose " +++++ Running for $($appRegistration.DisplayName)"
            $owner = "https://graph.microsoft.com/v1.0/myorganization/applications/$($appRegistration.Id)/owners"
            $response2 = Invoke-RestMethod $owner -Method 'GET' -Headers $authHeader
            $count = ($response2.Value.userPrincipalName).Count
            Write-Verbose "+++ List of owners`n$($response2.Value.userPrincipalName)"
            foreach ($currentItemName in $response2.Value.userPrincipalName) {
                if ($currentItemName) {
                    $filterOwner = "DisplayName, mail, accountEnabled&filter=mail eq '$($currentItemName)'"
                    $filterInactiveOwner = ' and accountEnabled eq false'
                    $body = @{}
                    $uri = "$url/$graphversion/$endpoint$filterOwner$filterInactiveOwner"
                    $results = Invoke-MgGraphRequest `
                        -Uri $uri `
                        -Method GET `
                        -Body $body
                    if ($results.value) {
                        $count = $count - 1
                        Write-Verbose " [INACTIVE] $($currentItemName)"
                        $invalidUPN += [PSCustomObject]@{
                            'AppRegName'           = $($appRegistration.DisplayName)
                            'OwnerUPN'             = $currentItemName
                            'Status'               = 'INACTIVE'
                            'NumberOfActiveOwners' = $count
                        }
                    }
                    else {
                        Write-Verbose " [ACTIVE] $($currentItemName)"
                    }
                }
            } # If block
            Write-Verbose "Active owners are - $($count)"
        }
    }

    elseif ($UPN) {
        $filterOwner = "DisplayName, mail, accountEnabled&filter=mail eq '$($UPN)'"
        $filterInactiveOwner = ' and accountEnabled eq false'
        $body = @{}
        $uri = "$url/$graphversion/$endpoint$filterOwner$filterInactiveOwner"
        $results = Invoke-MgGraphRequest `
            -Uri $uri `
            -Method GET `
            -Body $body
        if ($results.value.accountEnabled -eq 'false') {
            Write-Verbose " [INACTIVE] $($UPN)"
            else {
                Write-Verbose " [ACTIVE] $($UPN)"
            }
        }

    }

    else {
        $t = @'
        +------------------+-----------------------------------------------------------------+----------------------------------------------+
        | Switch | Usage | Example |
        +------------------+-----------------------------------------------------------------+----------------------------------------------+
        | SecurityGroup | With this switch you can run accross all the | |
        | | SGs within AzureAD for which you (identity | $data = InActive-Owners -SecurityGroup |
        | | running functions) have access. | |
        +------------------+-----------------------------------------------------------------+----------------------------------------------+
        | SubscriptionTags | With this switch you can run for subscription scope | $data = InActive-Owners -SubscriptionTags |
        | | Tags (service tags), having owner email address. | -Owner_TagKey '<TagName>' |
        | | You need to specify the Tag key. | |
        +------------------+-----------------------------------------------------------------+----------------------------------------------+
        | AppReg | With this switch you can run for all Azure App Registrations to | $data = InActive-Owners -AppReg |
        | | verify the owners and If they are inActive. | |
        +------------------+-----------------------------------------------------------------+----------------------------------------------+
        | UPN | With this switch you can run for individual UPN/ID to | InActive-Owners -UPN $mailaddress |
        | | verify the owners and If they are inActive. | |
        +------------------+-----------------------------------------------------------------+----------------------------------------------+
'@


        Write-Warning "You must select one of the switch to perform the operation.`n$($t)"
    }
    # Function Output
    Write-Output $invalidUPN
}