diff --git a/src/EntraExporter.psd1 b/src/EntraExporter.psd1 index 38203a3..32eb7d2 100644 --- a/src/EntraExporter.psd1 +++ b/src/EntraExporter.psd1 @@ -73,6 +73,8 @@ 'internal\Search-AzGraph2.ps1' 'internal\Get-MgGraphAllPages.ps1' 'internal\Get-AzureDirectoryObject.ps1' + 'internal\Invoke-FilePathCheck.ps1' + 'internal/Invoke-RoleEligibilityScheduleRequestIdSimplification.ps1' 'command\Get-AccessPackageAssignmentPolicies.ps1' 'command\Get-AccessPackageAssignments.ps1' 'command\Get-AccessPackageResourceScopes.ps1' diff --git a/src/Export-Entra.ps1 b/src/Export-Entra.ps1 index 8d4875e..d6c0ace 100644 --- a/src/Export-Entra.ps1 +++ b/src/Export-Entra.ps1 @@ -523,9 +523,8 @@ $outputFileName = Join-Path (Join-Path -Path $outputFileName -ChildPath $itemId) -ChildPath "$itemId.json" } - if ($outputFileName.Length -gt 255 -and (Get-ItemPropertyValue HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem -Name LongPathsEnabled -ErrorAction SilentlyContinue) -ne 1) { - Write-Warning "Output file path '$outputFileName' is longer than 255 characters. Enable long path support to continue!" - return + if (!(Invoke-FilePathCheck -FilePath $outputFileName)) { + continue } $item | Select-Object * -ExcludeProperty RequestId | ConvertTo-Json -depth 100 | Out-File (New-Item -Path $outputFileName -Force) diff --git a/src/command/Get-AzurePIMDirectoryRoles.ps1 b/src/command/Get-AzurePIMDirectoryRoles.ps1 index 5ceaa05..324e1d7 100644 --- a/src/command/Get-AzurePIMDirectoryRoles.ps1 +++ b/src/command/Get-AzurePIMDirectoryRoles.ps1 @@ -229,9 +229,8 @@ $outputFileName = Join-Path -Path $rootFolder -ChildPath "$itemId.json" - if ($outputFileName.Length -gt 255 -and (Get-ItemPropertyValue HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem -Name LongPathsEnabled -ErrorAction SilentlyContinue) -ne 1) { - Write-Warning "Output file path '$outputFileName' is longer than 255 characters. Enable long path support to continue!" - return + if (!(Invoke-FilePathCheck -FilePath $outputFileName)) { + continue } $item | ConvertTo-Json -depth 100 | Out-File (New-Item -Path $outputFileName -Force) diff --git a/src/command/Get-AzurePIMGroups.ps1 b/src/command/Get-AzurePIMGroups.ps1 index f50fc9c..2a6f326 100644 --- a/src/command/Get-AzurePIMGroups.ps1 +++ b/src/command/Get-AzurePIMGroups.ps1 @@ -129,9 +129,8 @@ $outputFileName = Join-Path -Path $rootFolder -ChildPath "$itemId.json" - if ($outputFileName.Length -gt 255 -and (Get-ItemPropertyValue HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem -Name LongPathsEnabled -ErrorAction SilentlyContinue) -ne 1) { - Write-Warning "Output file path '$outputFileName' is longer than 255 characters. Enable long path support to continue!" - return + if (!(Invoke-FilePathCheck -FilePath $outputFileName)) { + continue } # Hide warning for depth when converting to JSON diff --git a/src/command/Get-AzurePIMResources.ps1 b/src/command/Get-AzurePIMResources.ps1 index f18e9e8..e2b4e92 100644 --- a/src/command/Get-AzurePIMResources.ps1 +++ b/src/command/Get-AzurePIMResources.ps1 @@ -269,35 +269,31 @@ } #endregion functions - $joinChar = "&" - Get-PIMManagementGroupEligibleAssignment | % { $item = $_ - $itemId = $item.roleEligibilityScheduleRequestId -replace "/", $joinChar + $itemId = Invoke-RoleEligibilityScheduleRequestIdSimplification -id $item.roleEligibilityScheduleRequestId $outputFileName = Join-Path -Path (Join-Path -Path $rootFolder -ChildPath "ManagementGroups") -ChildPath "$itemId.json" - if ($outputFileName.Length -gt 255 -and (Get-ItemPropertyValue HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem -Name LongPathsEnabled -ErrorAction SilentlyContinue) -ne 1) { - Write-Warning "Output file path '$outputFileName' is longer than 255 characters. Enable long path support to continue!" - return + if (!(Invoke-FilePathCheck -FilePath $outputFileName)) { + continue } - $item | ConvertTo-Json -depth 100 | Out-File (New-Item -Path $outputFileName -Force) + $item | ConvertTo-Json -Depth 100 | Out-File (New-Item -Path $outputFileName -Force) } Get-PIMSubscriptionEligibleAssignment | ? { $_ } | % { $item = $_ - $itemId = $item.roleEligibilityScheduleRequestId -replace "/", $joinChar + $itemId = Invoke-RoleEligibilityScheduleRequestIdSimplification -id $item.roleEligibilityScheduleRequestId $outputFileName = Join-Path -Path (Join-Path -Path $rootFolder -ChildPath "Subscriptions") -ChildPath "$itemId.json" - if ($outputFileName.Length -gt 255 -and (Get-ItemPropertyValue HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem -Name LongPathsEnabled -ErrorAction SilentlyContinue) -ne 1) { - Write-Warning "Output file path '$outputFileName' is longer than 255 characters. Enable long path support to continue!" - return + if (!(Invoke-FilePathCheck -FilePath $outputFileName)) { + continue } - $item | ConvertTo-Json -depth 100 | Out-File (New-Item -Path $outputFileName -Force) + $item | ConvertTo-Json -Depth 100 | Out-File (New-Item -Path $outputFileName -Force) } } \ No newline at end of file diff --git a/src/command/Get-AzureResourceAccessPolicies.ps1 b/src/command/Get-AzureResourceAccessPolicies.ps1 index 6b875a3..7c5397f 100644 --- a/src/command/Get-AzureResourceAccessPolicies.ps1 +++ b/src/command/Get-AzureResourceAccessPolicies.ps1 @@ -53,17 +53,16 @@ Search-AzGraph2 -query $query } - $joinChar = "&" + $joinChar = [System.IO.Path]::DirectorySeparatorChar Get-AzureResourceAccessPolicy | % { $result = $_ - $scopeId = $result.subscriptionId - $id = $result.id -replace "/", $joinChar + $id = $result.id + $id = $id -replace "/subscriptions/", "" + $id = $id -replace "/", $joinChar - $outputPath = Join-Path -Path (Join-Path -Path $rootFolder -ChildPath "Subscriptions") -ChildPath $scopeId + $outputFileName = Join-Path -Path $rootFolder -ChildPath "$id.json" - $outputFileName = Join-Path -Path $outputPath -ChildPath "$id.json" - - $result | ConvertTo-Json -depth 100 | Out-File (New-Item -Path $outputFileName -Force) + $result | ConvertTo-Json -Depth 100 | Out-File (New-Item -Path $outputFileName -Force) } } \ No newline at end of file diff --git a/src/command/Get-AzureResourceIAMData.ps1 b/src/command/Get-AzureResourceIAMData.ps1 index 5c605fb..2745c61 100644 --- a/src/command/Get-AzureResourceIAMData.ps1 +++ b/src/command/Get-AzureResourceIAMData.ps1 @@ -72,7 +72,7 @@ authorizationresources $kqlResult = Search-AzGraph2 -query $query # there can be duplicates with different createdOn/updatedOn, keep just the latest one - $kqlResult = $kqlResult | Group-Object -Property ($property | ? {$_ -notin "createdOn", "updatedOn"}) | % {if ($_.count -eq 1) {$_.group} else {$_.group | sort updatedOn | select -First 1}} + $kqlResult = $kqlResult | Group-Object -Property ($property | ? {$_ -notin "createdOn", "updatedOn"}) | % {if ($_.count -eq 1) {$_.group} else {$_.group | Sort-Object updatedOn | select -First 1}} if (!$kqlResult) { return } #endregion run the query @@ -80,43 +80,36 @@ authorizationresources # get the principal name from its id $idToNameList = Get-AzureDirectoryObject -id ($kqlResult.principalId | select -Unique) - $joinChar = "&" # output the final results $kqlResult | select @{n = 'PrincipalName'; e = { $id = $_.PrincipalId; $result = $idToNameList | ? Id -EQ $id; if ($result.DisplayName) { $result.DisplayName } else { $result.mailNickname } } }, PrincipalId, PrincipalType, RoleDefinitionName, RoleDefinitionId, Scope, @{ n = 'ScopeType'; e = { _scopeType $_.scope } }, ManagementGroupId, SubscriptionId, SubscriptionName, ResourceGroup, CreatedOn, UpdatedOn | % { $item = $_ - switch ($item.scopeType) { - 'root' { - $outputPath = Join-Path -Path $assignmentsFolder -ChildPath "Root" - } - 'managementGroup' { - $outputPath = Join-Path -Path (Join-Path -Path $assignmentsFolder -ChildPath "ManagementGroups") -ChildPath $item.ManagementGroupId - } - 'subscription' { - $outputPath = Join-Path -Path (Join-Path -Path $assignmentsFolder -ChildPath "Subscriptions") -ChildPath $item.SubscriptionId - } - 'resourceGroup' { - $outputPath = Join-Path -Path (Join-Path -Path (Join-Path -Path $assignmentsFolder -ChildPath "Subscriptions") -ChildPath $item.SubscriptionId) -ChildPath $item.ResourceGroup - } - 'resource' { - # $folder = ($item.Scope.Split("/")[-3..-1] -join $joinChar) - $folder = $item.Scope -replace "/", $joinChar - $outputPath = Join-Path -Path (Join-Path -Path (Join-Path -Path (Join-Path -Path $assignmentsFolder -ChildPath "Subscriptions") -ChildPath $item.SubscriptionId) -ChildPath $item.ResourceGroup) -ChildPath $folder - } - default { - Write-Warning "Undefined scope type $($item.scopeType)" - return - } + if ($item.scopeType -eq 'root') + { + $outputPath = Join-Path -Path $assignmentsFolder -ChildPath "root" + } + else + { + $joinChar = [System.IO.Path]::DirectorySeparatorChar + + # simplify the scope to create more readable file names and avoid too long path issues + $folder = $item.Scope + $folder = $folder -replace "/providers/Microsoft.Management/", "" + + # replace remaining "/" with directory separator char to create folder structure based on the scope + $folder = $folder -replace "/", $joinChar + + $outputPath = Join-Path -Path $assignmentsFolder -ChildPath $folder } + $joinChar = "&" $itemId = $item.principalId + $joinChar + ($item.roleDefinitionId).split("/")[-1] $outputFileName = Join-Path -Path $outputPath -ChildPath "$itemId.json" - if ($outputFileName.Length -gt 255 -and (Get-ItemPropertyValue HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem -Name LongPathsEnabled -ErrorAction SilentlyContinue) -ne 1) { - Write-Warning "Output file path '$outputFileName' is longer than 255 characters. Enable long path support to continue!" - return + if (!(Invoke-FilePathCheck -FilePath $outputFileName)) { + continue } if (Test-Path $outputFileName -ErrorAction SilentlyContinue) { diff --git a/src/internal/Invoke-FilePathCheck.ps1 b/src/internal/Invoke-FilePathCheck.ps1 new file mode 100644 index 0000000..699746f --- /dev/null +++ b/src/internal/Invoke-FilePathCheck.ps1 @@ -0,0 +1,11 @@ +function Invoke-FilePathCheck { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string] $FilePath + ) + + if ($env:OS -eq "Windows_NT" -and $FilePath.Length -gt 255 -and (Get-ItemPropertyValue "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name LongPathsEnabled -ErrorAction SilentlyContinue) -ne 1){ + throw "Output file path '$FilePath' is longer than 255 characters. Enable long path support to continue!" + } +} \ No newline at end of file diff --git a/src/internal/Invoke-RoleEligibilityScheduleRequestIdSimplification.ps1 b/src/internal/Invoke-RoleEligibilityScheduleRequestIdSimplification.ps1 new file mode 100644 index 0000000..020bdd9 --- /dev/null +++ b/src/internal/Invoke-RoleEligibilityScheduleRequestIdSimplification.ps1 @@ -0,0 +1,19 @@ +function Invoke-RoleEligibilityScheduleRequestIdSimplification { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string] $id + ) + + $joinChar = [System.IO.Path]::DirectorySeparatorChar + + # simplify the id to create more readable file names and avoid too long path issues + $id = $id -replace "/subscriptions/", "" + $id = $id -replace "/providers/Microsoft.Management/managementGroups/", "" + + $id = $id -replace "/providers/Microsoft.Authorization/roleEligibilityScheduleRequests", "" + # replace remaining "/" with directory separator char to create folder structure based on scope and assignment id + $id = $id -replace "/", $joinChar + + $id +} \ No newline at end of file