Invoke-AADExporter.ps1

<#
 .Synopsis
  Exports the Azure AD Configuration and settings for a tenant
 .Description
  This cmdlet reads the configuration information from the target Azure AD Tenant and produces the output files
  in a target directory
 
 .PARAMETER OutputDirectory
    Specifies the directory path where the output files will be generated.
 
.PARAMETER Type
    Specifies the type of objects to export. Default to Config which exports the key configuration settings of the tenant.
 
.PARAMETER All
    If specified performs a full export of all objects and configuration in the tenant.
 
.EXAMPLE
   .\Invoke-AADExporter -Path 'c:\temp\contoso'
 
   Runs a default export and includes the key tenant configuration settings. Does not include large data collections such as Users, Groups, Applications, Service Principals, etc.
.EXAMPLE
   .\Invoke-AADExporter -Path 'c:\temp\contoso' -All
    
   Runs a full export of all objects and configuration settings.
 
.EXAMPLE
   .\Invoke-AADExporter -Path 'c:\temp\contoso' -Type ConditionalAccess, AppProxy
 
   Runs an export that includes just the Conditional Access and Application Proxy settings.
 
.EXAMPLE
   .\Invoke-AADExporter -Path 'c:\temp\contoso' -Type B2C
 
   Runs an export of all B2C settings.
#>


Function Invoke-AADExporter {
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
        [String]$Path,        
        [Parameter(Mandatory = $false)]
        [ValidateSet('All', 'Config', 'AccessReviews', 'ConditionalAccess', 'Users', 'Groups', 'Applications', 'ServicePrincipals','B2C','B2B','PIM','PIMAzure','PIMAAD', 'AppProxy')]
        [String[]]$Type = 'Config',
        [Parameter(Mandatory = $false)]
        [object]$ExportSchema,
        [Parameter(Mandatory = $false)]
        [string[]]$Parents,
        [switch]
        $All
    )

    if($All) {$Type = @('All')}
    $global:TenantID = (Get-MgContext).TenantId
    $global:Type = $Type #Used in places like Groups where Config flag will limit the resultset to just dynamic groups.

    if (!$ExportSchema) {
        $ExportSchema = @(
            # Organization
            @{
                GraphUri = 'organization' 
                Path = 'Organization/Organization.json'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'organization/{0}/settings' -f $TenantID
                Path = 'Organization/Settings.json'
                ApiVersion = 'beta'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'organization/{0}/branding/localizations' -f $TenantID
                Path = 'Organization/Branding/Localizations.json'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'organization/{0}/certificateBasedAuthConfiguration' -f $TenantID
                Path = 'Organization/CertificateBasedAuthConfiguration.json'
                Tag = @('All', 'Config')
            },

            @{
                GraphUri = 'identity/apiConnectors'
                Path = 'Identity/APIConnectors'
                ApiVersion = 'beta'
                IgnoreError = 'The feature self service sign up is not enabled for the tenant'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'domains'
                Path = 'Domains'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'identityProviders'
                Path = 'IdentityProviders'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'identity/continuousAccessEvaluationPolicy'
                Path = 'Identity/ContinuousAccessEvaluationPolicy'
                ApiVersion = 'beta'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'subscribedSkus'
                Path = 'SubscribedSkus'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'directoryRoles'
                Path = 'DirectoryRoles'
                Tag = @('All', 'Config')
                Children = @(
                    @{
                        GraphUri = 'directoryRoles/{id}/members'
                        Select = 'id, userPrincipalName, displayName'
                        Path = 'Members'
                        Tag = @('All', 'Config')
                    }
                    @{
                        GraphUri = 'directoryroles/{id}/scopedMembers'
                        Path = 'ScopedMembers'
                        Tag = @('All', 'Config')
                    }
                )
            },
            # Applications
            @{
                GraphUri = 'applications'
                Path = 'Applications'
                Tag = @('All', 'Applications')
                Children = @(
                    @{
                        GraphUri = 'applications/{id}/extensionProperties'
                        Path = 'ExtensionProperties'
                        Tag = @('All', 'Applications')
                    },
                    @{
                        GraphUri = 'applications/{id}/owners'
                        Select = 'id, userPrincipalName, displayName'
                        Path = 'Owners'
                        Tag = @('All', 'Applications')
                    },
                    @{
                        GraphUri = 'applications/{id}/tokenIssuancePolicies'
                        Path = 'TokenIssuancePolicies'
                        Tag = @('All', 'Applications')
                    },
                    @{
                        GraphUri = 'applications/{id}/tokenLifetimePolicies'
                        Path = 'TokenLifetimePolicies'
                        Tag = @('All', 'Applications')
                    }
                )
            },
            @{
                GraphUri = 'servicePrincipals'
                Path = 'ServicePrincipals'
                Tag = @('All', 'ServicePrincipals')
                Children = @(
                    @{
                        GraphUri = 'servicePrincipals/{id}/appRoleAssignments'
                        Path = 'AppRoleAssignments'
                        Tag = @('All', 'ServicePrincipals')
                    },
                    @{
                        GraphUri = 'servicePrincipals/{id}/oauth2PermissionGrants'
                        Path = 'Oauth2PermissionGrants'
                        Tag = @('All', 'ServicePrincipals')
                    },
                    @{
                        GraphUri = 'servicePrincipals/{id}/delegatedPermissionClassifications'
                        Path = 'DelegatedPermissionClassifications'
                        Tag = @('All', 'ServicePrincipals')
                    },
                    @{
                        GraphUri = 'servicePrincipals/{id}/owners'
                        Select = 'id, userPrincipalName, displayName'
                        Path = 'Owners'
                        Tag = @('All', 'ServicePrincipals')
                    },
                    @{
                        GraphUri = 'servicePrincipals/{id}/claimsMappingPolicies'
                        Path = 'claimsMappingPolicies'
                        Tag = @('All', 'ServicePrincipals')
                    },
                    @{
                        GraphUri = 'servicePrincipals/{id}/homeRealmDiscoveryPolicies'
                        Path = 'homeRealmDiscoveryPolicies'
                        Tag = @('All', 'ServicePrincipals')
                    },
                    @{
                        GraphUri = 'servicePrincipals/{id}/tokenIssuancePolicies'
                        Path = 'tokenIssuancePolicies'
                        Tag = @('All', 'ServicePrincipals')
                    },
                    @{
                        GraphUri = 'servicePrincipals/{id}/tokenLifetimePolicies'
                        Path = 'tokenLifetimePolicies'
                        Tag = @('All', 'ServicePrincipals')
                    }
                )
            },
            
            # Users
            @{
                Command = 'Get-AADExportUsers'
                Path = 'Users'
                Tag = @('All', 'Users')
                Children = @(
                    @{
                        GraphUri = 'users/{id}/authentication/fido2Methods'
                        Path = 'Authentication/FIDO2Methods'
                        Tag = @('All', 'Users')
                    },
                    @{
                        GraphUri = 'users/{id}/authentication/microsoftAuthenticatorMethods'
                        Path = 'Authentication/MicrosoftAuthenticatorMethods'
                        Tag = @('All', 'Users')
                    },
                    @{
                        GraphUri = 'users/{id}/authentication/windowsHelloForBusinessMethods'
                        Path = 'Authentication/WindowsHelloForBusinessMethods'
                        Tag = @('All', 'Users')
                    },
                    @{
                        GraphUri = 'users/{id}/authentication/temporaryAccessPassMethods'
                        Path = 'Authentication/TemporaryAccessPassMethods'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Users')
                    },
                    @{
                        GraphUri = 'users/{id}/authentication/phoneMethods'
                        Path = 'Authentication/PhoneMethods'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Users')
                    },
                    @{
                        GraphUri = 'users/{id}/authentication/emailMethods'
                        Path = 'Authentication/EmailMethods'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Users')
                    },
                    @{
                        GraphUri = 'users/{id}/authentication/passwordMethods'
                        Path = 'Authentication/PasswordMethods'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Users')
                    },
                    @{
                        GraphUri = 'users/{id}/extensions'
                        Path = 'Extensions'
                        Tag = @('All', 'Users')
                    }
                )
            },


            # Groups
            @{
                Command = 'Get-AADExportGroups' 
                Path = 'Groups'
                Tag = @('All', 'Config', 'Groups')
                Children = @(
                    @{
                        GraphUri = 'groups/{id}/members' 
                        Select = 'id, userPrincipalName, displayName'
                        Path = 'Members'
                        Tag = @('All', 'Groups')
                    }
                    @{
                        GraphUri =  'groups/{id}/owners'
                        Select = 'id, userPrincipalName, displayName'
                        Path = 'Owners'
                        Tag = @('All', 'Config', 'Groups')
                    },
                    @{
                        GraphUri = 'groups/{id}/extensions'
                        Path = 'Extensions'
                        Tag = @('All', 'Groups')
                    }
                )                
            },
            @{
                GraphUri = 'groupSettings'
                Path = 'GroupSettings'
                Tag = @('All', 'Config')
            },

            # B2C
            @{
                GraphUri = 'identity/userFlows'
                Path = 'Identity/UserFlows'
                Tag = @('B2C')
            },
            @{
                GraphUri = 'identity/b2cUserFlows'
                Path = 'Identity/B2CUserFlows'
                Tag = @('B2C')
                Children = @(
                    @{
                        GraphUri = 'identity/b2cUserFlows/{id}/identityProviders'
                        Path = 'IdentityProviders'
                        Tag = @('B2C')
                    },
                    @{
                        GraphUri = 'identity/b2cUserFlows/{id}/userAttributeAssignments'
                        QueryParameters = @{ expand = 'userAttribute' }
                        Path = 'UserAttributeAssignments'
                        Tag = @('B2C')
                    },
                    @{
                        GraphUri = 'identity/b2cUserFlows/{id}/apiConnectorConfiguration'
                        QueryParameters = @{ expand = 'postFederationSignup,postAttributeCollection' }
                        Path = 'ApiConnectorConfiguration'
                        Tag = @('B2C')
                    },
                    @{
                        GraphUri = 'identity/b2cUserFlows/{id}/languages'
                        Path = 'Languages'
                        Tag = @('B2C')
                    }
                )
            },

            # B2B
            @{
                GraphUri = 'identity/userFlowAttributes'
                Path = 'Identity/UserFlowAttributes'
                ApiVersion = 'beta'
                Tag = @('Config', 'B2B', 'B2C')
            },
            @{
                GraphUri = 'identity/b2xUserFlows'
                Path = 'Identity/B2XUserFlows'
                ApiVersion = 'beta'
                Tag = @('All', 'Config', 'B2B')
                Children = @(
                    @{
                        GraphUri = 'identity/b2xUserFlows/{id}/identityProviders'
                        Path = 'IdentityProviders'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Config', 'B2B')
                    },
                    @{
                        GraphUri = 'identity/b2xUserFlows/{id}/userAttributeAssignments'
                        QueryParameters = @{ expand = 'userAttribute' }
                        Path = 'AttributeAssignments'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Config', 'B2B')
                    },
                    @{
                        GraphUri = 'identity/b2xUserFlows/{id}/apiConnectorConfiguration'
                        QueryParameters = @{ expand = 'postFederationSignup,postAttributeCollection' }
                        Path = 'APIConnectors'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Config', 'B2B')
                    },
                    @{
                        GraphUri = 'identity/b2xUserFlows/{id}/languages'
                        Path = 'Languages'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Config', 'B2B')
                    }
                )
            },

            # Policies
            @{
                GraphUri = 'policies/identitySecurityDefaultsEnforcementPolicy'
                Path =  'Policies/IdentitySecurityDefaultsEnforcementPolicy'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/authorizationPolicy'
                Path = 'Policies/AuthorizationPolicy'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/featureRolloutPolicies'
                Path = 'Policies/FeatureRolloutPolicies'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/activityBasedTimeoutPolicies'
                Path = 'Policies/ActivityBasedTimeoutPolicy'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/homeRealmDiscoveryPolicies'
                Path = 'Policies/HomeRealmDiscoveryPolicy'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/claimsMappingPolicies'
                Path = 'Policies/ClaimsMappingPolicy'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/tokenIssuancePolicies'
                Path = 'Policies/TokenIssuancePolicy'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/tokenLifetimePolicies'
                Path = 'Policies/TokenLifetimePolicy'
                Tag = @('All', 'Config')
            },            
            @{
                GraphUri = 'policies/authenticationMethodsPolicy/authenticationMethodConfigurations/email'
                Path = 'Policies/AuthenticationMethodsPolicy/AuthenticationMethodConfigurations/Email.json'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/authenticationMethodsPolicy/authenticationMethodConfigurations/fido2'
                Path = 'Policies/AuthenticationMethodsPolicy/AuthenticationMethodConfigurations/FIDO2.json'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator'
                Path = 'Policies/AuthenticationMethodsPolicy/AuthenticationMethodConfigurations/MicrosoftAuthenticator.json'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/authenticationMethodsPolicy/authenticationMethodConfigurations/sms'
                Path = 'Policies/AuthenticationMethodsPolicy/AuthenticationMethodConfigurations/SMS.json'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/authenticationMethodsPolicy/authenticationMethodConfigurations/temporaryAccessPass'
                Path = 'Policies/AuthenticationMethodsPolicy/AuthenticationMethodConfigurations/TemporaryAccessPass.json'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/adminConsentRequestPolicy'
                Path = 'Policies/AdminConsentRequestPolicy'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'policies/permissionGrantPolicies'
                Path = 'Policies/PermissionGrantPolicies'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'identity/conditionalAccess/policies'
                Path =  'Identity/Conditional/AccessPolicies'
                Tag = @('All', 'Config', 'ConditionalAccess')
            },
            @{
                GraphUri = 'identity/conditionalAccess/namedLocations'
                Path =  'Identity/Conditional/NamedLocations'
                Tag = @('All', 'Config', 'ConditionalAccess')
            },

            # Identity Governance
            @{
                GraphUri = 'identityGovernance/entitlementManagement/accessPackages'
                Path = 'IdentityGovernance\EntitlementManagement\AccessPackages'
                ApiVersion = 'beta'
                Tag = @('All', 'Config')
                Children = @(
                    @{
                        Command = 'Get-AADExportAccessPackageAssignmentPolicies'
                        Path = 'AssignmentPolicies'
                        Tag = @('All', 'Config')
                    },
                    @{
                        Command = 'Get-AADExportAccessPackageAssignments'
                        Path = 'Assignments'
                        Tag = @('All', 'Config')
                    },
                    @{
                        Command = 'Get-AADExportAccessPackageResourceScopes'
                        Path = 'ResourceScopes'
                        Tag = @('All', 'Config')
                    }
                )
            },
            @{
                GraphUri = 'businessFlowTemplates'
                Path = 'IdentityGovernance/AccessReviews'
                ApiVersion = 'beta'
                Tag = @('All','Config', 'AccessReviews')
                Children = @(
                    @{
                        Command = 'Get-AADExportAccessReviews'
                        Path = ''
                        Tag = @('All','Config', 'AccessReviews')
                        Children = @(
                            @{
                                GraphUri = 'accessReviews/{id}/reviewers'
                                Path = 'Reviewers'
                                ApiVersion = 'beta'
                                Tag = @('All','Config', 'AccessReviews')
                            }
                        )
                    }
                )
            },
            @{
                GraphUri = 'identityGovernance/termsOfUse/agreements'
                Path = 'IdentityGovernance/TermsOfUse/Agreements'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'identityGovernance/entitlementManagement/connectedOrganizations'
                Path = 'IdentityGovernance/EntitlementManagement/ConnectedOrganizations'
                ApiVersion = 'beta'
                Tag = @('All', 'Config')
                Children = @(
                    @{
                        GraphUri = 'identityGovernance/entitlementManagement/connectedOrganizations/{id}/externalSponsors'
                        Path = 'ExternalSponsors'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Config')
                    },
                    @{
                        GraphUri = 'identityGovernance/entitlementManagement/connectedOrganizations/{id}/internalSponsors'
                        Path = 'InternalSponsors'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Config')
                    }
                )    
            },            
            @{
                GraphUri = 'identityGovernance/entitlementManagement/settings'
                Path = 'IdentityGovernance/EntitlementManagement/Settings'
                ApiVersion = 'beta'
                Tag = @('All', 'Config')
            },
            @{
                GraphUri = 'AdministrativeUnits'
                Path = 'AdministrativeUnits'
                ApiVersion = 'beta'
                Tag = @('All', 'Config')
                Children = @(
                    @{
                        GraphUri = 'administrativeUnits/{id}/members'
                        Select = 'Id'
                        Path = 'Members'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Config')
                    },
                    @{
                        GraphUri = 'administrativeUnits/{id}/scopedRoleMembers'
                        Path = 'ScopedRoleMembers'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Config')
                    },
                    @{
                        GraphUri = 'administrativeUnits/{id}/extensions'
                        Path = 'Extensions'
                        ApiVersion = 'beta'
                        Tag = @('All', 'Config')
                    }
                )
            },

            # PIM
            @{
                GraphUri = 'privilegedAccess/aadroles/resources'
                Path = 'PrivilegedAccess/AADRoles/Resources'
                ApiVersion = 'beta'
                Tag = @('All', 'Config', 'PIM', 'PIMAAD')
                Children = @(
                    @{
                        GraphUri = 'privilegedAccess/aadroles/resources/{id}/roleDefinitions'
                        Path = 'RoleDefinitions'
                        ApiVersion = 'beta'
                        #'Filter' = 'Type ne 'BuiltInRole''
                        Tag = @('All', 'Config', 'PIM', 'PIMAAD')
                    },
                    @{
                        GraphUri = 'privilegedAccess/aadroles/resources/{id}/roleSettings'
                        Path = 'RoleSettings'
                        ApiVersion = 'beta'
                        #'Filter' = 'isDefault eq false'
                        Tag = @('All', 'Config', 'PIM', 'PIMAAD')
                    },
                    @{
                        GraphUri = 'privilegedAccess/aadroles/resources/{id}/roleAssignments'
                        Path = 'RoleAssignments'
                        ApiVersion = 'beta'
                        #'Filter' = 'endDateTime eq null'
                        Tag = @('All', 'Config', 'PIM', 'PIMAAD')
                    }
                )
            },
            @{
                GraphUri = 'privilegedAccess/azureResources/resources'
                Path = 'PrivilegedAccess/AzureResources/Resources'
                ApiVersion = 'beta'
                IgnoreError = 'The tenant has not onboarded to PIM.'
                Tag = @('All', 'Config', 'PIM', 'PIMAzure')
                Children = @(
                    @{
                        GraphUri = 'privilegedAccess/azureResources/resources/{id}/roleDefinitions'
                        Path = 'RoleDefinitions'
                        ApiVersion = 'beta'
                        #'Filter' = 'Type ne 'BuiltInRole''
                        Tag = @('All', 'Config', 'PIM', 'PIMAAzure')
                    },
                    @{
                        GraphUri = 'privilegedAccess/azureResources/resources/{id}/roleSettings'
                        Path = 'RoleSettings'
                        ApiVersion = 'beta'
                        #'Filter' = 'isDefault eq false'
                        Tag = @('All', 'Config', 'PIM', 'PIMAAzure')
                    },
                    @{
                        GraphUri = 'privilegedAccess/azureResources/resources/{id}/roleAssignments'
                        Path = 'RoleAssignments'
                        ApiVersion = 'beta'
                        #'Filter' = 'endDateTime eq null'
                        Tag = @('All', 'Config', 'PIM', 'PIMAzure')
                    }
                )
            },

            #Application Proxy
            @{
                GraphUri = 'onPremisesPublishingProfiles/provisioning'
                QueryParameters = @{ expand = 'publishedResources,agents,agentGroups' }
                Path = 'OnPremisesPublishingProfiles/Provisioning.json'
                ApiVersion = 'beta'
                Tag = @('All', 'Config', 'AppProxy')
            },
            @{
                GraphUri = 'onPremisesPublishingProfiles/provisioning/publishedResources'
                QueryParameters = @{ expand = 'agentGroups' }
                Path = 'OnPremisesPublishingProfiles/Provisioning/PublishedResources'
                ApiVersion = 'beta'
                Tag = @('All', 'Config', 'AppProxy')
            },
            @{
                GraphUri = 'onPremisesPublishingProfiles/provisioning/agentGroups'
                QueryParameters = @{ expand = 'agents,publishedResources' }
                Path = 'OnPremisesPublishingProfiles/Provisioning/AgentGroups'
                ApiVersion = 'beta'
                Tag = @('All', 'Config', 'AppProxy')
            },
            @{
                GraphUri = 'onPremisesPublishingProfiles/provisioning/agents'
                QueryParameters = @{ expand = 'agentGroups' }
                Path = 'OnPremisesPublishingProfiles/Provisioning/Agents'
                ApiVersion = 'beta'
                Tag = @('All', 'Config', 'AppProxy')
            },
            @{
                GraphUri = 'onPremisesPublishingProfiles/applicationProxy/connectors'
                Path = 'OnPremisesPublishingProfiles/ApplicationProxy/Connectors'
                ApiVersion = 'beta'
                Tag = @('All', 'Config', 'AppProxy')
            },
            @{
                GraphUri = 'onPremisesPublishingProfiles/applicationProxy/connectorGroups'
                Path = 'OnPremisesPublishingProfiles/ApplicationProxy/ConnectorGroups'
                ApiVersion = 'beta'
                Tag = @('All', 'Config', 'AppProxy')
                Children = @(
                    @{
                        GraphUri = 'onPremisesPublishingProfiles/applicationProxy/connectorGroups/{id}/applications'
                        Path = 'Applications'
                        ApiVersion = 'beta'
                        IgnoreError = 'ApplicationsForGroup_NotFound'
                        Tag = @('All', 'Config', 'AppProxy')
                    },
                    @{
                        GraphUri = 'onPremisesPublishingProfiles/applicationProxy/connectorGroups/{id}/members'
                        Path = 'Members'
                        ApiVersion = 'beta'
                        IgnoreError = 'ConnectorGroup_NotFound'
                        Tag = @('All', 'Config', 'AppProxy')
                    }
                )
            }
        )
    }

    foreach ($item in $ExportSchema) {
        $typeMatch = Compare-Object $item.Tag $Type -ExcludeDifferent -IncludeEqual
        $hasParents = $Parents -and $Parents.Count -gt 0
        if( ($typeMatch)) {
            $outputFileName = Join-Path -Path $Path -ChildPath $item.Path

            $spacer = ''
            if($hasParents) { $spacer = ''.PadRight($Parents.Count + 3, ' ') + $Parents[$Parents.Count-1] }
            
            Write-Host "$spacer $($item.Path)"

            $command = Get-ObjectProperty $item 'Command'
            $graphUri = Get-ObjectProperty $item 'GraphUri'
            $apiVersion = Get-ObjectProperty $item 'ApiVersion'
            $ignoreError = Get-ObjectProperty $item 'IgnoreError'
            if (!$apiVersion) { $apiVersion = 'v1.0' }
            $resultItems = $null
            if($command) {
                if ($hasParents){ $command += " -Parents $Parents" }
                $resultItems = Invoke-Expression -Command $command
            }
            else {
                if ($hasParents){ $graphUri = $graphUri -replace '{id}', $Parents[$Parents.Count-1] }
                try {
                    $resultItems = Invoke-Graph $graphUri -Filter (Get-ObjectProperty $item 'Filter') -Select (Get-ObjectProperty $item 'Select') -QueryParameters (Get-ObjectProperty $item 'QueryParameters') -ApiVersion $apiVersion    
                }
                catch {
                    $e = $_.ErrorDetails.Message
                    if($e.Contains($ignoreError) -or $e.Contains('Encountered an internal server error')){
                        Write-Debug $_
                    }
                    else {
                        Write-Error $_
                    }
                }
            }

            if ($outputFileName -match "\.json$") {
                if($resultItems){
                    ConvertTo-OrderedDictionary $resultItems | ConvertTo-Json -depth 100 | Out-File (New-Item -Path $outputFileName -Force)
                }
            } else {
                foreach($resultItem in $resultItems) {
                    if (!$resultItem.ContainsKey('id')) {
                        continue
                    }
                    $itemOutputFileName = Join-Path -Path $outputFileName -ChildPath $resultItem.id
                    $parentOutputFileName = Join-Path $itemOutputFileName -ChildPath $resultItem.id
                    ConvertTo-OrderedDictionary $resultItem | ConvertTo-Json -depth 100 | Out-File (New-Item -Path "$($parentOutputFileName).json" -Force)
                    if ($item.ContainsKey('Children')) {
                        $itemParents = $Parents
                        $itemParents += $resultItem.Id
                        Invoke-AADExporter -Path $itemOutputFileName -Type $Type -ExportSchema $item.Children -Parents $itemParents
                    }
                }
            }
        }
    }
}