{"id":169,"date":"2026-04-21T12:05:47","date_gmt":"2026-04-21T12:05:47","guid":{"rendered":"https:\/\/unen.nl\/?p=169"},"modified":"2026-04-21T12:14:00","modified_gmt":"2026-04-21T12:14:00","slug":"volledig-inzicht-in-entra-applicaties-zonder-handmatig-geklik","status":"publish","type":"post","link":"https:\/\/unen.nl\/?p=169","title":{"rendered":"Volledig inzicht in Entra applicaties \u2014 zonder handmatig geklik"},"content":{"rendered":"\n<p>Als je regelmatig in Entra ID (voorheen Azure AD) werkt, ken je het probleem: applicaties staan overal. App registrations hier, enterprise applications daar\u2026 en als iemand vraagt <em>\u201cwelke rechten heeft deze app eigenlijk?\u201d<\/em>, begint het klikken.<\/p>\n\n\n\n<p>Veel klikken.<br>Te veel klikken.<\/p>\n\n\n\n<p>Dus laten we dat gewoon niet meer doen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Van handwerk naar \u00e9\u00e9n export<\/h2>\n\n\n\n<p>In veel omgevingen groeit het aantal applicaties sneller dan je denkt. Integraties, API-koppelingen, SaaS-apps, interne tooling\u2026 en voor je het weet heb je geen compleet overzicht meer.<\/p>\n\n\n\n<p>De vragen die je blijft krijgen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Welke applicaties hebben API-permissies \u2014 en welke precies?<\/li>\n\n\n\n<li>Waar worden secrets en certificaten gebruikt?<\/li>\n\n\n\n<li>Welke apps hebben (te) brede rechten?<\/li>\n\n\n\n<li>Wie is eigenaar van deze applicatie?<\/li>\n\n\n\n<li>Welke redirect URL\u2019s staan er ingesteld?<\/li>\n<\/ul>\n\n\n\n<p>Het antwoord zit er wel. Alleen niet op \u00e9\u00e9n plek.<\/p>\n\n\n\n<p>Tot nu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wat dit script voor je doet<\/h2>\n\n\n\n<p>Het PowerShell-script <strong>SCA_Export-EntraApplications.ps1<\/strong> haalt in \u00e9\u00e9n run alles op wat je wilt weten en zet dat om naar twee overzichtelijke exports:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>App registrations<\/li>\n\n\n\n<li>Enterprise applications<\/li>\n<\/ul>\n\n\n\n<p>Inclusief de details die er echt toe doen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Naam en ID\u2019s<\/li>\n\n\n\n<li>Key credentials (certificaten \/ secrets)<\/li>\n\n\n\n<li>API-permissies (delegated + application)<\/li>\n\n\n\n<li>URL\u2019s (redirects, login, logout, etc.)<\/li>\n\n\n\n<li>Owners (inclusief naam en e-mailadres)<\/li>\n<\/ul>\n\n\n\n<p>Alles netjes in CSV. Direct bruikbaar.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Waarom dit w\u00e9l werkt<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd0d API-permissies die leesbaar zijn<\/h3>\n\n\n\n<p>Geen GUID\u2019s, maar gewoon:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Microsoft Graph [Application] User.Read.All<\/li>\n\n\n\n<li>SharePoint [Delegated] Sites.Read.All<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udc64 Owners die kloppen<\/h3>\n\n\n\n<p>Geen object ID\u2019s, maar echte namen met e-mail of UPN.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd10 Key credentials inzichtelijk<\/h3>\n\n\n\n<p>Direct zichtbaar welke keys actief zijn en hoe ze gebruikt worden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u26a1 Performance zonder gedoe<\/h3>\n\n\n\n<p>Slimme caching voorkomt onnodige Graph-calls.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Gebruik<\/h2>\n\n\n\n<p>De basis:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.\\SCA_Export-EntraApplications.ps1<\/pre>\n\n\n\n<p>Silent mode:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.\\SCA_Export-EntraApplications.ps1 -Silent<\/pre>\n\n\n\n<p>Graph import overslaan:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.\\SCA_Export-EntraApplications.ps1 -SkipGraphImport<\/pre>\n\n\n\n<p>Alles combineren:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.\\SCA_Export-EntraApplications.ps1 -Silent -SkipGraphImport<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Output<\/h2>\n\n\n\n<p>De bestanden worden hier geplaatst:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">C:\\Temp\\EntraAppExport\\<\/pre>\n\n\n\n<p>Met:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>AppRegistrations.csv<\/li>\n\n\n\n<li>EnterpriseApplications.csv<\/li>\n<\/ul>\n\n\n\n<p>Logging:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">C:\\Log\\<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Het script<\/h2>\n\n\n\n<p>Voor wie \u2019m direct wil gebruiken of aanpassen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">param (<br>    [switch]$Silent,<br>    [switch]$SkipGraphImport<br>)<br><br>&lt;#<br>    .NOTES<br>    ===========================================================================<br>     Created on:    2026-04-21<br>     Created by:    Vincent van Unen<br>     Filename:      SCA_Export-EntraApplications.ps1<br>    ===========================================================================<br>    .DESCRIPTION<br>     Exporteert alle App Registrations en Enterprise Applications uit een tenant<br>     met daarbij de velden naam, key type, API-permissions, URL's en owners.<br>    .SYNOPSIS<br>        Exporteert alle App Registrations en Enterprise Applications uit een tenant<br>        met daarbij de velden naam, key type, API-permissions, URL's en owners.<br>    .PARAMETER Silent<br>        Wanneer deze switch is opgegeven, worden er geen statusberichten naar de console geschreven en worden alleen foutmeldingen getoond.<br>    .PARAMETER SkipGraphImport  <br>        Wanneer deze switch is opgegeven, wordt er niet gecontroleerd op de aanwezigheid van de Microsoft.Graph module en wordt deze ook niet ge\u00efmporteerd. Gebruik deze optie als je zeker weet dat de module al ge\u00efnstalleerd en ge\u00efmporteerd is in de huidige sessie.<br>    .EXAMPLE    <br>        .\\SCA_Export-EntraApplications.ps1<br>        Exporteert alle App Registrations en Enterprise Applications en toont statusberichten in de console.<br>    .EXAMPLE<br>        .\\SCA_Export-EntraApplications.ps1 -Silent  <br>        Exporteert alle App Registrations en Enterprise Applications zonder statusberichten in de console, alleen foutmeldingen worden getoond.<br>    .EXAMPLE<br>        .\\SCA_Export-EntraApplications.ps1 -SkipGraphImport<br>        Exporteert alle App Registrations en Enterprise Applications zonder te controleren op de Microsoft.Graph module. Gebruik deze optie als je zeker weet dat de module al ge\u00efnstalleerd en ge\u00efmporteerd is in de huidige sessie.<br>    .EXAMPLE<br>        .\\SCA_Export-EntraApplications.ps1 -Silent -SkipGraphImport<br>        Exporteert alle App Registrations en Enterprise Applications zonder statusberichten in de console en zonder te controleren op de Microsoft.Graph module. Gebruik deze optie als je zeker weet dat de module al ge\u00efnstalleerd en ge\u00efmporteerd is in de huidige sessie.<br>    <br>#><br><br>#region Changelog<br>#################################################################################<br># Version History<br>$SCA_ScriptAuthor        = \"Vincent van Unen\"<br>$SCA_ScriptVersion       = \"1.1\"<br>$SCA_ScriptChangeDate    = \"2026-04-21\"<br>$SCA_ScriptChangeLog     = \"Toegevoegd: optionele skip voor Import-Module Microsoft.Graph\"<br>$SCA_ScriptCurrentUser   = $env:UserName<br>$SCA_ScriptRunningDevice = $env:COMPUTERNAME<br>$SCA_GetCurrentDate      = Get-Date -Format \"yyyy-MM-dd\"<br>$SCA_LogName             = \"SCA_Export-EntraApplications\"<br><br>try {<br>    $SCA_GetPublicIP = (Invoke-WebRequest -Uri \"http:\/\/ifconfig.me\/ip\" -UseBasicParsing -ErrorAction Stop).Content<br>}<br>catch {<br>    $SCA_GetPublicIP = \"Onbekend\"<br>}<br><br>try {<br>    $SCA_GetPrivateIP = (<br>        Get-NetIPAddress -ErrorAction Stop |<br>        Where-Object {<br>            $_.AddressFamily -eq \"IPv4\" -and<br>            $_.AddressState -eq \"Preferred\" -and<br>            $_.IPAddress -notlike \"169.254*\"<br>        } |<br>        Select-Object -ExpandProperty IPAddress -Unique<br>    ) -join \", \"<br>}<br>catch {<br>    $SCA_GetPrivateIP = \"Onbekend\"<br>}<br><br>&lt;# Change Log<br>[1.0]    2026-04-21    -    Eerste versie van exportscript<br>[1.1]    2026-04-21    -    Parameter toegevoegd om Import-Module Microsoft.Graph over te slaan<br>#><br>#endregion Changelog<br><br>#region Base configuration<br>[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12<br><br>Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope LocalMachine -Force -WarningAction Ignore -ErrorAction Ignore<br>Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process -Force -WarningAction Ignore -ErrorAction Ignore<br>Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser -Force -WarningAction Ignore -ErrorAction Ignore<br><br>$MaximumFunctionCount = 16384<br>$MaximumVariableCount = 16384<br>#endregion Base configuration<br><br>#region Folder checks<br>$SCA_ModuleDirTemp1  = \"C:\\Temp\"<br>$SCA_ModuleDirTemp2  = \"C:\\Tmp\"<br>$SCA_ModuleDirLog    = \"C:\\Log\"<br>$SCA_ModuleDirExport = \"C:\\Temp\\EntraAppExport\"<br><br>if (!(Test-Path -Path $SCA_ModuleDirTemp1))  { New-Item -ItemType Directory -Path $SCA_ModuleDirTemp1  -Force | Out-Null }<br>if (!(Test-Path -Path $SCA_ModuleDirTemp2))  { New-Item -ItemType Directory -Path $SCA_ModuleDirTemp2  -Force | Out-Null }<br>if (!(Test-Path -Path $SCA_ModuleDirLog))    { New-Item -ItemType Directory -Path $SCA_ModuleDirLog    -Force | Out-Null }<br>if (!(Test-Path -Path $SCA_ModuleDirExport)) { New-Item -ItemType Directory -Path $SCA_ModuleDirExport -Force | Out-Null }<br><br>Clear-Host<br>#endregion Folder checks<br><br>#region Functions<br>function SCA_WriteToLogFile {<br>    [CmdletBinding()]<br>    param(<br>        [Parameter(Mandatory = $false)]<br>        [ValidateSet(\"INFO\", \"WARN\", \"ERROR\", \"FATAL\", \"DEBUG\")]<br>        [string]$Level = \"INFO\",<br><br>        [Parameter(Mandatory = $true)]<br>        [string]$Message,<br><br>        [Parameter(Mandatory = $false)]<br>        [string]$LogFile = \"$SCA_ModuleDirLog\\$SCA_LogName $SCA_GetCurrentDate.log\"<br>    )<br><br>    if ($Message -eq \" \") {<br>        Add-Content -Path $LogFile -Value \" \" -ErrorAction SilentlyContinue<br>    }<br>    else {<br>        $SCA_Date = (Get-Date).ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss.fff')<br>        Add-Content -Path $LogFile -Value \"[$SCA_Date] [$Level] $Message\" -ErrorAction SilentlyContinue<br>    }<br><br>    if (-not $Silent) {<br>        Write-Host \"[$Level] $Message\"<br>    }<br>}<br><br>function SCA_JoinSafe {<br>    param(<br>        [object[]]$Values,<br>        [string]$Separator = \" | \"<br>    )<br><br>    if (-not $Values) { return $null }<br><br>    $SCA_FilteredValues = $Values | Where-Object { $_ -ne $null -and $_ -ne \"\" }<br>    if (-not $SCA_FilteredValues) { return $null }<br><br>    return ($SCA_FilteredValues -join $Separator)<br>}<br><br>function SCA_GetOwnerDisplay {<br>    param(<br>        [ValidateSet(\"Application\", \"ServicePrincipal\")]<br>        [string]$Type,<br>        [string]$Id<br>    )<br><br>    try {<br>        if ($Type -eq \"Application\") {<br>            $SCA_Owners = Get-MgApplicationOwner -ApplicationId $Id -All -ErrorAction Stop<br>        }<br>        else {<br>            $SCA_Owners = Get-MgServicePrincipalOwner -ServicePrincipalId $Id -All -ErrorAction Stop<br>        }<br><br>        $SCA_ResolvedOwners = foreach ($SCA_Owner in $SCA_Owners) {<br>            if ($SCA_Owner.AdditionalProperties.displayName) {<br>                $SCA_Mail = $SCA_Owner.AdditionalProperties.mail<br>                $SCA_UPN  = $SCA_Owner.AdditionalProperties.userPrincipalName<br><br>                if ($SCA_Mail) {<br>                    \"$($SCA_Owner.AdditionalProperties.displayName) &lt;$SCA_Mail>\"<br>                }<br>                elseif ($SCA_UPN) {<br>                    \"$($SCA_Owner.AdditionalProperties.displayName) &lt;$SCA_UPN>\"<br>                }<br>                else {<br>                    $SCA_Owner.AdditionalProperties.displayName<br>                }<br>            }<br>            elseif ($SCA_Owner.Id) {<br>                $SCA_Owner.Id<br>            }<br>        }<br><br>        return (SCA_JoinSafe -Values $SCA_ResolvedOwners)<br>    }<br>    catch {<br>        return \"ERROR: $($_.Exception.Message)\"<br>    }<br>}<br><br>function SCA_GetKeyTypes {<br>    param(<br>        [object[]]$KeyCredentials<br>    )<br><br>    if (-not $KeyCredentials) { return $null }<br><br>    $SCA_KeyItems = foreach ($SCA_Key in $KeyCredentials) {<br>        $SCA_Usage = $SCA_Key.Usage<br>        $SCA_Type  = $SCA_Key.Type<br>        $SCA_Name  = $SCA_Key.DisplayName<br><br>        @(<br>            if ($SCA_Name)  { $SCA_Name }<br>            if ($SCA_Usage) { \"usage=$SCA_Usage\" }<br>            if ($SCA_Type)  { \"type=$SCA_Type\" }<br>        ) -join \"; \"<br>    }<br><br>    return (SCA_JoinSafe -Values $SCA_KeyItems)<br>}<br><br>$script:SCA_ServicePrincipalCache = @{}<br><br>function SCA_GetResourceSpByAppId {<br>    param(<br>        [string]$AppId<br>    )<br><br>    if ([string]::IsNullOrWhiteSpace($AppId)) { return $null }<br><br>    if (-not $script:SCA_ServicePrincipalCache.ContainsKey($AppId)) {<br>        $SCA_ServicePrincipal = Get-MgServicePrincipal -Filter \"appId eq '$AppId'\" -Property \"id,appId,displayName,appRoles,oauth2PermissionScopes\" -All<br>        $script:SCA_ServicePrincipalCache[$AppId] = $SCA_ServicePrincipal | Select-Object -First 1<br>    }<br><br>    return $script:SCA_ServicePrincipalCache[$AppId]<br>}<br><br>function SCA_ResolveAppRegistrationPermissions {<br>    param(<br>        [object[]]$RequiredResourceAccess<br>    )<br><br>    if (-not $RequiredResourceAccess) { return $null }<br><br>    $SCA_Output = foreach ($SCA_RRA in $RequiredResourceAccess) {<br>        $SCA_ResourceAppId = $SCA_RRA.ResourceAppId<br>        $SCA_ResourceSp    = SCA_GetResourceSpByAppId -AppId $SCA_ResourceAppId<br>        $SCA_ResourceName  = if ($SCA_ResourceSp.DisplayName) { $SCA_ResourceSp.DisplayName } else { $SCA_ResourceAppId }<br><br>        foreach ($SCA_RA in $SCA_RRA.ResourceAccess) {<br>            $SCA_PermissionName = $null<br>            $SCA_PermissionKind = $SCA_RA.Type<br><br>            if ($SCA_PermissionKind -eq \"Scope\" -and $SCA_ResourceSp.Oauth2PermissionScopes) {<br>                $SCA_Match = $SCA_ResourceSp.Oauth2PermissionScopes | Where-Object { $_.Id -eq $SCA_RA.Id } | Select-Object -First 1<br>                if ($SCA_Match) { $SCA_PermissionName = $SCA_Match.Value }<br>            }<br>            elseif ($SCA_PermissionKind -eq \"Role\" -and $SCA_ResourceSp.AppRoles) {<br>                $SCA_Match = $SCA_ResourceSp.AppRoles | Where-Object { $_.Id -eq $SCA_RA.Id } | Select-Object -First 1<br>                if ($SCA_Match) { $SCA_PermissionName = $SCA_Match.Value }<br>            }<br><br>            if (-not $SCA_PermissionName) {<br>                $SCA_PermissionName = $SCA_RA.Id<br>            }<br><br>            \"$SCA_ResourceName [$SCA_PermissionKind] $SCA_PermissionName\"<br>        }<br>    }<br><br>    return (SCA_JoinSafe -Values $SCA_Output)<br>}<br><br>function SCA_GetSPDelegatedPermissions {<br>    param(<br>        [string]$ServicePrincipalId<br>    )<br><br>    try {<br>        $SCA_Grants = Get-MgServicePrincipalOauth2PermissionGrant -ServicePrincipalId $ServicePrincipalId -All -ErrorAction Stop<br>        if (-not $SCA_Grants) { return $null }<br><br>        $SCA_Result = foreach ($SCA_Grant in $SCA_Grants) {<br>            $SCA_ResourceSp = $null<br>            try {<br>                $SCA_ResourceSp = Get-MgServicePrincipal -ServicePrincipalId $SCA_Grant.ResourceId -Property \"displayName\"<br>            }<br>            catch {<br>            }<br><br>            $SCA_ResourceName = if ($SCA_ResourceSp.DisplayName) { $SCA_ResourceSp.DisplayName } else { $SCA_Grant.ResourceId }<br>            \"$SCA_ResourceName [Delegated] $($SCA_Grant.Scope)\"<br>        }<br><br>        return (SCA_JoinSafe -Values $SCA_Result)<br>    }<br>    catch {<br>        return \"ERROR: $($_.Exception.Message)\"<br>    }<br>}<br><br>function SCA_GetSPApplicationPermissions {<br>    param(<br>        [string]$ServicePrincipalId<br>    )<br><br>    try {<br>        $SCA_Assignments = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ServicePrincipalId -All -ErrorAction Stop<br>        if (-not $SCA_Assignments) { return $null }<br><br>        $SCA_Result = foreach ($SCA_Assignment in $SCA_Assignments) {<br>            $SCA_ResourceSp = $null<br>            try {<br>                $SCA_ResourceSp = Get-MgServicePrincipal -ServicePrincipalId $SCA_Assignment.ResourceId -Property \"displayName,appRoles\"<br>            }<br>            catch {<br>            }<br><br>            $SCA_ResourceName = if ($SCA_ResourceSp.DisplayName) { $SCA_ResourceSp.DisplayName } else { $SCA_Assignment.ResourceId }<br>            $SCA_RoleName     = $SCA_Assignment.AppRoleId<br><br>            if ($SCA_ResourceSp.AppRoles) {<br>                $SCA_Role = $SCA_ResourceSp.AppRoles | Where-Object { $_.Id -eq $SCA_Assignment.AppRoleId } | Select-Object -First 1<br>                if ($SCA_Role) { $SCA_RoleName = $SCA_Role.Value }<br>            }<br><br>            \"$SCA_ResourceName [Application] $SCA_RoleName\"<br>        }<br><br>        return (SCA_JoinSafe -Values $SCA_Result)<br>    }<br>    catch {<br>        return \"ERROR: $($_.Exception.Message)\"<br>    }<br>}<br>#endregion Functions<br><br>#region Logging start<br>SCA_WriteToLogFile -Message \"Current Date = $SCA_GetCurrentDate\"<br>SCA_WriteToLogFile -Message \"Script Author = $SCA_ScriptAuthor\"<br>SCA_WriteToLogFile -Message \"Script Version = $SCA_ScriptVersion\"<br>SCA_WriteToLogFile -Message \"Script ChangeDate = $SCA_ScriptChangeDate\"<br>SCA_WriteToLogFile -Message \"Current User Running this script = $SCA_ScriptCurrentUser\"<br>SCA_WriteToLogFile -Message \"Current Device Running this script = $SCA_ScriptRunningDevice\"<br>SCA_WriteToLogFile -Message \"Current Public IP = $SCA_GetPublicIP\"<br>SCA_WriteToLogFile -Message \"Current Private IP = $SCA_GetPrivateIP\"<br>SCA_WriteToLogFile -Message \"Silent parameter = $Silent\"<br>SCA_WriteToLogFile -Message \"SkipGraphImport parameter = $SkipGraphImport\"<br><br>$SCA_TranscriptFile = \"$SCA_ModuleDirLog\\$SCA_GetCurrentDate`_$SCA_LogName`_Transcript.log\"<br>Start-Transcript -Path $SCA_TranscriptFile -Force<br>#endregion Logging start<br><br>try {<br>    #region Module and connection checks<br>    SCA_WriteToLogFile -Message \"Controleren of Microsoft Graph module beschikbaar is\"<br><br>    if (-not $SkipGraphImport) {<br>        if (-not (Get-Module -ListAvailable -Name Microsoft.Graph)) {<br>            SCA_WriteToLogFile -Level \"WARN\" -Message \"Microsoft.Graph module niet gevonden. Installatie wordt gestart\"<br>            Install-Module Microsoft.Graph -Scope CurrentUser -Force -AllowClobber -ErrorAction Stop<br>        }<br><br>        SCA_WriteToLogFile -Message \"Importeren van Microsoft.Graph module\"<br>        Import-Module Microsoft.Graph -ErrorAction Stop<br>        SCA_WriteToLogFile -Message \"Microsoft.Graph module geladen\"<br>    }<br>    else {<br>        SCA_WriteToLogFile -Message \"Module check en import van Microsoft.Graph overgeslagen\"<br>    }<br><br>    SCA_WriteToLogFile -Message \"Verbinden met Microsoft Graph\"<br>    Connect-MgGraph -Scopes \"Application.Read.All\", \"Directory.Read.All\" -NoWelcome -ErrorAction Stop<br>    if (Get-Command Select-MgProfile -ErrorAction SilentlyContinue) {<br>        SCA_WriteToLogFile -Message \"Select-MgProfile beschikbaar, profiel wordt gezet naar v1.0\"<br>        Select-MgProfile -Name \"v1.0\" -ErrorAction Stop<br>    }<br>    else {<br>        SCA_WriteToLogFile -Message \"Select-MgProfile niet beschikbaar (Graph SDK v2+), stap wordt overgeslagen\"<br>    }<br>    SCA_WriteToLogFile -Message \"Verbonden met Microsoft Graph\"<br>    #endregion Module and connection checks<br><br>    #region Export app registrations<br>    SCA_WriteToLogFile -Message \"App registrations ophalen\"<br><br>    $SCA_AppRegistrations = Get-MgApplication -All -Property `<br>        \"id,appId,displayName,keyCredentials,requiredResourceAccess,identifierUris,web,spa,publicClient\"<br><br>    $SCA_AppRegistrationExport = foreach ($SCA_App in $SCA_AppRegistrations) {<br>        $SCA_Urls = @()<br><br>        if ($SCA_App.Web) {<br>            $SCA_Urls += $SCA_App.Web.HomePageUrl<br>            $SCA_Urls += $SCA_App.Web.RedirectUris<br>            $SCA_Urls += $SCA_App.Web.LogoutUrl<br>        }<br><br>        if ($SCA_App.Spa) {<br>            $SCA_Urls += $SCA_App.Spa.RedirectUris<br>        }<br><br>        if ($SCA_App.PublicClient) {<br>            $SCA_Urls += $SCA_App.PublicClient.RedirectUris<br>        }<br><br>        $SCA_Urls += $SCA_App.IdentifierUris<br><br>        [pscustomobject]@{<br>            ObjectType     = \"AppRegistration\"<br>            Name           = $SCA_App.DisplayName<br>            AppId          = $SCA_App.AppId<br>            ObjectId       = $SCA_App.Id<br>            KeyType        = SCA_GetKeyTypes -KeyCredentials $SCA_App.KeyCredentials<br>            ApiPermissions = SCA_ResolveAppRegistrationPermissions -RequiredResourceAccess $SCA_App.RequiredResourceAccess<br>            Urls           = SCA_JoinSafe -Values ($SCA_Urls | Select-Object -Unique)<br>            Owners         = SCA_GetOwnerDisplay -Type \"Application\" -Id $SCA_App.Id<br>        }<br>    }<br><br>    $SCA_AppRegistrationsCsv = Join-Path $SCA_ModuleDirExport \"AppRegistrations.csv\"<br>    $SCA_AppRegistrationExport | Export-Csv -Path $SCA_AppRegistrationsCsv -NoTypeInformation -Encoding UTF8<br>    SCA_WriteToLogFile -Message \"App registrations ge\u00ebxporteerd naar $SCA_AppRegistrationsCsv\"<br>    #endregion Export app registrations<br><br>    #region Export enterprise applications<br>    SCA_WriteToLogFile -Message \"Enterprise applications ophalen\"<br><br>    $SCA_ServicePrincipals = Get-MgServicePrincipal -All -Property `<br>        \"id,appId,displayName,servicePrincipalType,keyCredentials,homepage,loginUrl,logoutUrl,replyUrls\"<br><br>    $SCA_ServicePrincipalExport = foreach ($SCA_SP in $SCA_ServicePrincipals) {<br>        $SCA_PermDelegated   = SCA_GetSPDelegatedPermissions -ServicePrincipalId $SCA_SP.Id<br>        $SCA_PermApplication = SCA_GetSPApplicationPermissions -ServicePrincipalId $SCA_SP.Id<br><br>        $SCA_AllPermissions = @()<br>        if ($SCA_PermDelegated)   { $SCA_AllPermissions += $SCA_PermDelegated }<br>        if ($SCA_PermApplication) { $SCA_AllPermissions += $SCA_PermApplication }<br><br>        $SCA_Urls = @(<br>            $SCA_SP.Homepage<br>            $SCA_SP.LoginUrl<br>            $SCA_SP.LogoutUrl<br>        ) + $SCA_SP.ReplyUrls<br><br>        [pscustomobject]@{<br>            ObjectType     = \"EnterpriseApplication\"<br>            Name           = $SCA_SP.DisplayName<br>            AppId          = $SCA_SP.AppId<br>            ObjectId       = $SCA_SP.Id<br>            ServiceType    = $SCA_SP.ServicePrincipalType<br>            KeyType        = SCA_GetKeyTypes -KeyCredentials $SCA_SP.KeyCredentials<br>            ApiPermissions = SCA_JoinSafe -Values $SCA_AllPermissions<br>            Urls           = SCA_JoinSafe -Values ($SCA_Urls | Select-Object -Unique)<br>            Owners         = SCA_GetOwnerDisplay -Type \"ServicePrincipal\" -Id $SCA_SP.Id<br>        }<br>    }<br><br>    $SCA_EnterpriseApplicationsCsv = Join-Path $SCA_ModuleDirExport \"EnterpriseApplications.csv\"<br>    $SCA_ServicePrincipalExport | Export-Csv -Path $SCA_EnterpriseApplicationsCsv -NoTypeInformation -Encoding UTF8<br>    SCA_WriteToLogFile -Message \"Enterprise applications ge\u00ebxporteerd naar $SCA_EnterpriseApplicationsCsv\"<br>    #endregion Export enterprise applications<br><br>    #region Summary<br>    SCA_WriteToLogFile -Message \"Export succesvol afgerond\"<br>    SCA_WriteToLogFile -Message \"Outputbestand App registrations = $SCA_AppRegistrationsCsv\"<br>    SCA_WriteToLogFile -Message \"Outputbestand Enterprise applications = $SCA_EnterpriseApplicationsCsv\"<br><br>    if (-not $Silent) {<br>        Write-Host \"\"<br>        Write-Host \"Klaar met export.\" -ForegroundColor Green<br>        Write-Host \"Bestanden:\"<br>        Write-Host \" - $SCA_AppRegistrationsCsv\"<br>        Write-Host \" - $SCA_EnterpriseApplicationsCsv\"<br>    }<br>    #endregion Summary<br>}<br>catch {<br>    SCA_WriteToLogFile -Level \"ERROR\" -Message \"Er is een fout opgetreden: $($_.Exception.Message)\"<br>    throw<br>}<br>finally {<br>    try {<br>        Disconnect-MgGraph | Out-Null<br>        SCA_WriteToLogFile -Message \"Verbinding met Microsoft Graph gesloten\"<br>    }<br>    catch {<br>        SCA_WriteToLogFile -Level \"WARN\" -Message \"Verbinding met Microsoft Graph kon niet netjes worden afgesloten\"<br>    }<br><br>    try {<br>        Stop-Transcript | Out-Null<br>    }<br>    catch {<br>    }<br><br>    try {<br>        Copy-Item -Path $SCA_TranscriptFile -Destination \"C:\\ProgramData\\Microsoft\\IntuneManagementExtension\\Logs\" -Force -ErrorAction Stop<br>        SCA_WriteToLogFile -Message \"Transcript gekopieerd naar IntuneManagementExtension logs\"<br>    }<br>    catch {<br>        SCA_WriteToLogFile -Level \"WARN\" -Message \"Transcript kon niet worden gekopieerd naar IntuneManagementExtension logs\"<br>    }<br>}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Wanneer gebruik je dit<\/h2>\n\n\n\n<p>Dit script is ideaal voor:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd10 Security &amp; audits<\/h3>\n\n\n\n<p>Snel inzicht in permissies en eigenaarschap.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udcca Tenant assessments<\/h3>\n\n\n\n<p>Perfect voor onboarding of health checks.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd04 Lifecycle management<\/h3>\n\n\n\n<p>Opschonen van oude of ongebruikte apps.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83e\uddfe Rapportages<\/h3>\n\n\n\n<p>Direct bruikbaar in Excel of Power BI.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusie<\/h2>\n\n\n\n<p>Als je serieus met Entra ID werkt, wil je overzicht.<br>Niet verspreid over vijf portals, maar gewoon in \u00e9\u00e9n keer goed.<\/p>\n\n\n\n<p>Dit script doet precies dat.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Als je regelmatig in Entra ID (voorheen Azure AD) werkt, ken je het probleem: applicaties staan overal. App<\/p>\n","protected":false},"author":2,"featured_media":170,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,6],"tags":[],"class_list":["post-169","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-powershell"],"_links":{"self":[{"href":"https:\/\/unen.nl\/index.php?rest_route=\/wp\/v2\/posts\/169","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unen.nl\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unen.nl\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unen.nl\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/unen.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=169"}],"version-history":[{"count":2,"href":"https:\/\/unen.nl\/index.php?rest_route=\/wp\/v2\/posts\/169\/revisions"}],"predecessor-version":[{"id":172,"href":"https:\/\/unen.nl\/index.php?rest_route=\/wp\/v2\/posts\/169\/revisions\/172"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/unen.nl\/index.php?rest_route=\/wp\/v2\/media\/170"}],"wp:attachment":[{"href":"https:\/\/unen.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=169"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unen.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=169"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unen.nl\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=169"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}