Skip to content

Azure role sort uses hashtable indexer on PSCustomObject (breaks on PS 5.1) #26

@StrongWind1

Description

@StrongWind1

Disclaimer: This issue was identified and written by Claude Code (model: claude-opus-4-6-1m) during an automated code review, and has had a cursory review by a human before submission.

Summary

The Azure IAM role assignment sorting in check_Roles.psm1 uses hashtable indexer syntax $_['Scope'] on PSCustomObject instances. PowerShell 5.1 does not support hashtable-style indexing on PSCustomObject — $_['Scope'] returns $null instead of the property value. This causes the entire sort to be based on $null comparisons, producing an effectively unsorted or incorrectly sorted Azure roles report on PowerShell 5.1.

Affected file

modules/check_Roles.psm1

Evidence

Object construction (lines 413-448)

Objects are created as [PSCustomObject]:

# Lines 413-423
$SortedAzureRolesList.Add([PSCustomObject]@{
    PrincipalDisplayName      = $PrincipalDetails.DisplayName
    PrincipalDisplayNameLink  = $PrincipalDetails.DisplayNameLink
    PrincipalType             = $PrincipalDetails.Type
    RoleType                  = $Assignment.RoleType
    Conditions                = $Assignment.Conditions
    Role                      = $Assignment.RoleDefinitionName
    Scope                     = $Assignment.Scope
    RoleTier                  = $RoleTier
    AssignmentType            = $Assignment.AssignmentType
})

Sort expression using hashtable indexer (lines 460-466)

# Lines 458-468
$SortedAzureRoles = $SortedAzureRoles | Sort-Object -Property @{
    Expression = {
        if ($_['Scope'] -eq '/') {              # <-- $_['Scope'] returns $null on PS 5.1
            0
        } elseif ($_['Scope'] -like '/providers/Microsoft.Management/managementGroups/*') {
            1
        } else {
            2 + ($_['Scope'] -split '/').Count
        }
    }
}

PowerShell 5.1 vs 7 behavior

# PowerShell 7:
$obj = [PSCustomObject]@{ Scope = "/subscriptions/123" }
$obj['Scope']   # Returns: /subscriptions/123

# PowerShell 5.1:
$obj = [PSCustomObject]@{ Scope = "/subscriptions/123" }
$obj['Scope']   # Returns: $null
$obj.Scope      # Returns: /subscriptions/123

Impact

On PowerShell 5.1, the Azure Role Assignments report is sorted incorrectly. All $_['Scope'] lookups return $null, so:

  • $null -eq '/' is $false — root scope is not prioritized
  • $null -like '/providers/*' is $false — management groups not prioritized
  • ($null -split '/').Count is 1 — all items sort to the same position

The report data is correct but the presentation order is wrong. The README claims PowerShell 5.1 support.

Suggested fix

Replace hashtable indexer with dot notation:

Expression = {
    if ($_.Scope -eq '/') {
        0
    } elseif ($_.Scope -like '/providers/Microsoft.Management/managementGroups/*') {
        1
    } else {
        2 + ($_.Scope -split '/').Count
    }
}

Version

V20260316

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions