Public/Discovery/Get-ResourcePermission.ps1

function Get-ResourcePermission {
    [cmdletbinding()]
    [OutputType([System.Collections.Concurrent.ConcurrentBag[PSCustomObject]])]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [ValidatePattern('^[0-9a-fA-F-]{36}$', ErrorMessage = "It does not match expected pattern '{1}'")]
        [Alias('subscription-id')]
        [string]$SubscriptionId,

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false)]
        [Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters.ResourceGroupCompleterAttribute()]
        [Alias('resource-group')]
        [string]$ResourceGroupName,

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false)]
        [Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters.ResourceTypeCompleterAttribute()]
        [Alias('resource-type')]
        [string]$ResourceType,

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false)]
        [Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters.ResourceNameCompleterAttribute(
        )]
        [Alias('resource-name')]
        [string]$ResourceName,

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false)]
        [Alias('permission-type')]
        [ValidateSet('Write', 'Action', 'All')]
        [string]$PermissionType = 'Write',

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false)]
        [Alias('throttle-limit')]
        [int]$ThrottleLimit = 100
    )

    begin {
        Write-Verbose "Starting function $($MyInvocation.MyCommand.Name)"
        $resourcePermissions = [System.Collections.Concurrent.ConcurrentBag[PSCustomObject]]::new()
        $baseUri = 'http://management.azure.com'
    }

    process {
        try {
            Write-Verbose "Retrieving all resources for the current user context"

                # Build a dynamic filter string based on provided parameters
                $filterParts = @()

                if ($SubscriptionId) {
                    $filterParts += "| where subscriptionId == '$SubscriptionId'"
                }
                if ($ResourceGroupName) {
                    $filterParts += "| where resourceGroup == '$ResourceGroupName'"
                }
                if ($ResourceType) {
                    $filterParts += "| where type == '$($ResourceType.ToLower())'"
                }
                if ($ResourceName) {
                    $filterParts += "| where name == '$ResourceName'"
                }

                if ($filterParts.Count -gt 0) {
                    $filterString = $filterParts -join ' '
                    $resources = Invoke-AzBatch -filter $filterString
                    Write-Verbose "Filter string: $filterString"
                } else {
                    $resources = Invoke-AzBatch
                }


            Write-Verbose "Processing $($resources.Count) resources"
            if ($resources.Count -gt 20) {
                Write-Message -FunctionName $($MyInvocation.MyCommand.Name) -Message "Processing $($resources.Count) resources, this may take a while" -Severity 'Information'
            }

            $resources | ForEach-Object -Parallel {
                $resourceId          = $_.id
                $permissionType      = $using:PermissionType
                $resourcePermissions = $using:resourcePermissions
                $baseUri             = $using:baseUri

                Write-Verbose "Check permissions for each resource: $($_.name)"

                    # Check permissions for each resource
                    $permissionsUri = "$baseUri$resourceId/providers/Microsoft.Authorization/permissions?api-version=2018-07-01"

                    $permRequestParam = @{
                        Headers = $using:script:authHeader
                        Uri     = $permissionsUri
                        Method  = 'GET'
                        ErrorAction = 'SilentlyContinue'
                    }

                    try {
                        $permissions = (Invoke-RestMethod @permRequestParam).value

                        # Filter permissions based on the requested type
                        $filteredPermissions = $permissions
                        if ($permissionType -eq 'Write') {
                            $filteredPermissions = $permissions | Where-Object { $_.actions -match '/write' -or $_.actions -eq '*' }
                        }
                        elseif ($permissionType -eq 'Action') {
                            $filteredPermissions = $permissions | Where-Object { $_.actions -match '/action' -or $_.actions -contains '*' }
                        }

                        if ($filteredPermissions.Count -gt 0) {
                            $resourceObject = [PSCustomObject]@{
                                ResourceId   = $resourceId
                                ResourceName = $_.name
                                ResourceType = $_.type
                                Subscription = $_.subscriptionId
                                ResourceGroup = $_.resourceGroup
                                Permissions  = $filteredPermissions
                                HasWritePermission  = ($permissions | Where-Object { $_.actions -match '/write$' -or $_.actions -eq '*' }).Count -gt 0
                                HasActionPermission = ($permissions | Where-Object { $_.actions -match '/action$'}).Count -gt 0
                            }
                            $resourcePermissions.Add($resourceObject)
                        }
                    }
                    catch {
                        Write-Verbose "Unable to fetch permissions for resource: $resourceId"
                    }
            } -ThrottleLimit $ThrottleLimit

            Write-Verbose "Completed retrieving resource permissions"
            return $resourcePermissions
        }
        catch {
            Write-Error "Error while retrieving resource permissions: $($_.Exception.Message)"
        }
    }
    <#
    .SYNOPSIS
        Validates which Azure resources the authenticated user has write or action permissions on.
 
    .DESCRIPTION
        The Get-AzureResourcePermission function identifies Azure resources where the authenticated user
        has specified permissions (write, action, or both). It supports filtering by subscription, resource group,
        and resource type, and processes subscriptions in parallel for efficiency.
 
    .PARAMETER SubscriptionId
        Optional. Specifies a specific subscription ID to check. If omitted, all accessible subscriptions are checked.
 
    .PARAMETER ResourceGroup
        Optional. Filters resources to a specific resource group.
 
    .PARAMETER ResourceType
        Optional. Filters resources by their type (e.g., 'Microsoft.Compute/virtualMachines' or just 'virtualMachines').
 
    .PARAMETER PermissionType
        Optional. Specifies what kind of permissions to check for. Valid options:
        - Write: Checks for write permissions
        - Action: Checks for action permissions
        - All: Checks for both write and action permissions (default)
 
    .PARAMETER ThrottleLimit
        Optional. Specifies the maximum number of concurrent operations. Default is 100.
 
    .OUTPUTS
        Returns a collection of resources with their permission details, including:
        - ResourceId: The full resource ID
        - ResourceName: The name of the resource
        - ResourceType: The type of the resource
        - Subscription: The subscription ID
        - ResourceGroup: The resource group name
        - Permissions: Detailed permission objects
        - HasWritePermission: Boolean indicating if the user has write permissions
        - HasActionPermission: Boolean indicating if the user has action permissions
 
    .EXAMPLE
        Get-AzureResourcePermission -PermissionType Write
        Returns all resources across all subscriptions where the user has write permissions.
 
    .EXAMPLE
        Get-AzureResourcePermission -SubscriptionId "00000000-0000-0000-0000-000000000000" -ResourceGroup "MyResourceGroup"
        Returns resources in the specified subscription and resource group where the user has any permissions.
 
    .EXAMPLE
        Get-AzureResourcePermission -ResourceType "virtualMachines" -PermissionType Action
        Returns all virtual machine resources where the user has action permissions.
 
    .NOTES
        - Requires authentication to Azure with appropriate permissions
        - Performance depends on the number of resources and subscriptions
    #>

}