SharePoint External Sharing Controls En Veilige Gasttoegang

💼 Management Samenvatting

Extern delen in SharePoint Online en OneDrive is onmisbaar voor samenwerking met leveranciers, ketenpartners en interbestuurlijke programma’s, maar introduceert rechtstreeks toegang tot documenten, sites en teams vanuit buiten de organisatie. Zonder strak ingerichte controles wordt externe samenwerking de zwakste schakel in het security- en compliance-landschap van Nederlandse overheidsorganisaties.

Aanbeveling
IMPLEMENT
Risico zonder
High
Risk Score
8/10
Implementatie
140u (tech: 60u)
Van toepassing op:
M365
SharePoint Online
OneDrive for Business

Veel organisaties laten de standaardinstellingen voor extern delen ongemoeid omdat projecten snel live moeten. Daardoor kunnen gebruikers iedereen met een e-mailadres uitnodigen, worden anonieme links niet ingeperkt en blijven gastaccounts jarenlang actief. Tijdens audits blijkt vervolgens dat er geen centraal overzicht bestaat van welke sites openstaan, welke documenten met ‘Iedereen met de link’ zijn gedeeld of welke leveranciers nog toegang hebben na contractbeëindiging. Het risico is concreet: vertrouwelijke dossiers, persoonsgegevens of blauwdrukken van kritieke infrastructuur kunnen buiten de organisatie belanden. Bovendien eisen BIO, AVG en NIS2 dat organisaties aantoonbaar grip hebben op gegevensuitwisseling. Onvoldoende beheersing leidt tot data-lekken, bestuurlijke druk, herstelkosten en mogelijke sancties van de Autoriteit Persoonsgegevens of sectorale toezichthouders.

PowerShell Modules Vereist
Primary API: SharePoint Admin Center, Microsoft Purview, Entra ID
Connection: Connect-SPOService, Connect-PnPOnline, Connect-MgGraph
Required Modules: Microsoft.Online.SharePoint.PowerShell, PnP.PowerShell, Microsoft.Graph

Implementatie

Deze beheersmaatregel beschrijft hoe u externe deelmogelijkheden beleidsmatig inperkt, technisch afdwingt en continu monitort. We behandelen governanceafspraken, licentie- en rolverdeling, configuratie van tenant-, site- en linkinstellingen, gecombineerd met Purview DLP, gevoelige etiketten en Entra-voorwaardelijke toegang. Verder tonen we hoe u rapportages en auditbewijzen genereert en hoe u afwijkingen snel herstelt met het gekoppelde PowerShell-script.

Governance en risicokaders voor extern delen

Een veilige aanpak begint bij expliciete bestuurlijke keuzes over waarom, wanneer en met wie externe samenwerking is toegestaan. Bestuur en directie benoemen kritieke processen die samenwerking buiten de organisatie vereisen, bepalen welke informatiecategorieën überhaupt extern gedeeld mogen worden en leggen drempels vast voor gevoelige gegevens volgens de rubricering uit de Nederlandse Baseline voor Veilige Cloud. Deze beleidsuitgangspunten worden vertaald naar een normatief kader dat beschrijft welke afdelingen externe toegangen mogen aanvragen, welke verificatie vereist is voor ketenpartners en hoe lang gastaccounts actief mogen blijven zonder review. Governance omvat ook de plicht om per leverancier een contractueel kader te hanteren waarin geheimhouding, gebruiksdoeleinden en verwijderingseisen zijn vastgelegd.

Organisaties stellen een multidisciplinair overleg in (CISO, privacy officer, juridisch, informatiebeheer en proceseigenaren) dat elk kwartaal beoordeelt of externe deelinstellingen nog aansluiten op veranderingen in wet- en regelgeving. Denk aan nieuwe sectorale normen vanuit Justitie, VWS of Defensie, maar ook aan richtlijnen uit NIS2 of aanvullende BIO-profielen. Dit overleg bepaalt tevens welke documenttypen alleen via beveiligde samenwerkingsomgevingen (bijvoorbeeld Rijksclouds of versleutelde kanalen) gedeeld mogen worden. Door governance expliciet te beleggen ontstaat draagvlak om technische blokkades daadwerkelijk te enforcen en om uitzonderingsprocessen strak te documenteren.

Een volwassen beleid onderscheidt verschillende scenario’s: incidentele uitwisseling met burgers, langdurige samenwerkingen met ketenpartners en samenwerking in crisissituaties. Voor elk scenario wordt vastgelegd welke SharePoint-sjablonen, Teams-channels of Project-sites mogen worden gebruikt, hoe lang data beschikbaar blijft en wie verantwoordelijk is voor periodieke review. Combineer dit met Purview recordlabels en retentiebeleid zodat documenten automatisch worden gelabeld en bewaartermijnen worden afgedwongen, zelfs wanneer bestanden buiten de primaire site terechtkomen. Hierdoor blijft de organisatie aantoonbaar ‘in control’ tijdens audits van de Algemene Rekenkamer of tijdens verantwoording in de gemeenteraad.

Naast procesafspraken is identity governance cruciaal. De Entra-ID beheerder configureert access packages en entitlement management om externe identiteitstoegang centraal te registreren, automatisch te laten verlopen en opnieuw te laten goedkeuren. Koppel deze processen aan autorisatiemodellen uit de BIO (bijvoorbeeld T18.01 en T12.04) zodat minimal access en segregeren van taken aantoonbaar zijn ingebouwd. Door identity governance vooraf te koppelen aan SharePoint-groepen ontstaan geen ‘schaduwsites’ waarin gebruikers lokaal gasten toevoegen zonder toezicht.

Tot slot vereist het beleid duidelijke compliance-eisen: elke externe uitnodiging moet te herleiden zijn naar een zaak, project of contract; documenteigenaren blijven verantwoordelijk voor contentclassificatie; en de organisatie bewaart beslisinformatie minimaal zeven jaar conform Archiefwet. Door deze eisen in te bedden in werkprocessen (bijvoorbeeld via Power Automate-goedkeuringen) wordt governance geen papieren tijger maar een praktisch hulpmiddel om risico’s te beheersen.

Technische configuratie van SharePoint en OneDrive

Gebruik PowerShell-script external-sharing-controls.ps1 (functie Invoke-ExternalSharingAssessment) – Inventariseert tenant- en site-instellingen voor extern delen, classificeert risico’s en licht afwijkingen uit..

Technische afdwinging start op tenantniveau. Stel in het SharePoint-beheercentrum de globale SharingCapability in op ‘ExistingExternalUserSharingOnly’ of, waar mogelijk, ‘Disabled’ voor sites die uitsluitend intern gebruikt worden. Maak onderscheid tussen SharePoint en OneDrive zodat persoonlijke opslag nooit ruimere rechten biedt dan teamsites. Definieer standaard linktypen als ‘Specifieke personen’ met vervaldatum en beperkte machtigingen. Schakel anonieme links uit en zorg dat alleen beheerders tijdelijke uitzonderingen kunnen activeren. Deze instellingen vormen de basis waarop per site fijnmazige uitzonderingen kunnen worden toegepast.

Beheerders configureren site templates met vooraf ingestelde groepsstructuren, beperkte gasttoegang en DLP-beleid. Gebruik sensitivity labels voor sites zodat classificatie direct bepaalt of extern delen is toegestaan. Een ‘Departement vertrouwelijk’-label kan extern delen volledig blokkeren, terwijl een ‘Project ketenpartner’-label alleen samenwerken met bestaande leveranciers toestaat. Combineer dit met Conditional Access beleid waarin multi-factor authenticatie, compliant devices en session controls verplicht worden voor gasten. Hierdoor kan een gast alleen toegang krijgen via een modern beleid dat voldoet aan Zero Trust principes.

Technische controles stoppen niet bij SharePoint. Purview DLP en Insider Risk policies moeten detecteren wanneer een gebruiker gevoelige informatie deelt via externe links en automatisch waarschuwingen sturen of delen blokkeren. Configureer alerts voor het delen van gegevens die onder AVG, Wet politiegegevens of medische geheimhouding vallen, zodat de organisatie direct kan ingrijpen. Gebruik daarnaast Microsoft Defender for Cloud Apps om riskante downloads te blokkeren of sessies te monitoren wanneer gasten verdachte activiteiten vertonen.

Naast configuratie is logging essentieel. Zorg dat Unified Audit Logging is ingeschakeld en dat gebeurtenissen zoals SharingSet, SharingInvitationCreated en FileAccessed worden doorgestuurd naar Microsoft Sentinel of een SIEM van de organisatie. Gebruik KQL-queries of Purview rapportages om te achterhalen welke documenten het meest extern zijn gedeeld en welke gebruikers afwijken van het gemiddelde. Deze data voedt de periodieke risicobeoordelingen en vormt bewijs richting auditors.

Monitoring, rapportage en bewijslast

Gebruik PowerShell-script external-sharing-controls.ps1 (functie Invoke-ExternalSharingReport) – Genereert CSV- en JSON-rapporten met site-instellingen, uitgenodigde gasten en verlopen toegang, geschikt voor audits..

Continue monitoring is noodzakelijk om te voorkomen dat uitzonderingen permanent worden. Richt een dashboard in (bijvoorbeeld in Power BI of Microsoft Sentinel) dat inzichten combineert uit SharePoint, Entra ID en Purview. Toon per organisatieonderdeel hoeveel sites extern delen toestaan, hoeveel gastaccounts actief zijn, hoeveel links binnenkort verlopen en welke documenten door DLP zijn geblokkeerd. Deze informatie ondersteunt bestuurders bij het prioriteren van maatregelen en geeft auditors direct inzicht in de maturity van het externe samenwerkingsmodel.

Rapportages moeten niet alleen volume tonen, maar ook kwaliteit. Hanteer KPI’s zoals ‘100% van de gastaccounts heeft een eigenaar’, ‘alle gasttoegangen verlopen binnen 90 dagen zonder review’ en ‘alle high-risk sites zijn gelabeld met gevoelige etiketten’. Door KPI’s te koppelen aan de planning- en controlcyclus kunnen CISO, CIO en proceseigenaren sturen op concrete verbeteracties en budgetten. Maak gebruik van Purview Access Reviews en Entitlement Management om automatisch herinneringen te sturen en de resultaten als bewijsstuk op te slaan.

Voor compliance is traceerbaarheid van besluiten essentieel. Archiveer alle goedkeuringsverzoeken voor extern delen, voeg ze toe aan het dossier van de betreffende zaak of samenwerking en zorg dat audittrail-events minimaal zeven jaar beschikbaar blijven conform Archiefwet. Documenteer waarom een uitzondering is toegestaan, welke mitigerende maatregelen zijn getroffen (bijvoorbeeld beperkingen op download) en wanneer de uitzondering afloopt. Deze documentatie vormt later het verdedigingsmateriaal bij parlementaire vragen of journalistieke verzoeken.

Gebruik het script in een gecontroleerde CI/CD-pijplijn (bijvoorbeeld GitHub Actions of Azure Automation) met lokale debuginstellingen om maandelijks exportbestanden te genereren. Versleutel de rapporten met Microsoft Information Protection en distribueer ze naar de CISO-office en interne audit. Door geautomatiseerde exports wordt afhankelijke arbeid geminimaliseerd en blijft de datakwaliteit consistent.

Remediatie, incidentrespons en ketencommunicatie

Gebruik PowerShell-script external-sharing-controls.ps1 (functie Invoke-ExternalSharingRemediation) – Past sharing capabilities van geselecteerde sites aan, forceert link-vervaldatums en kan optioneel gasten intrekken..

Wanneer monitoring afwijkingen detecteert, moet een vastgelegd remediatieproces bepalen hoe snel acties worden uitgevoerd en wie eigenaar is. Classificeer incidenten in categorieën (bijvoorbeeld ongeautoriseerde gast, verlopen contract, gevoelige data met openbare link) en koppel hier herstel-SLA’s aan. Proceseigenaren beslissen in overleg met CISO en privacy officer of toegang direct wordt ingetrokken of dat eerst aanvullende verificatie plaatsvindt. Documenteer elke stap zodat lessons learned beschikbaar zijn voor toekomstige oefeningen en audits.

Technische remediatie omvat het intrekken van gedeelde links, het blokkeren van gastaccounts en het forceren van site-evaluaties. Gebruik Purview voor bulk-actie op documenten (bijvoorbeeld het toepassen van een restrictief label) en gebruik SharePoint PowerShell om sharing capabilities direct terug te zetten. Het gekoppelde script automatiseert deze acties, logt resultaten in JSON-formaat en kan dankzij -WhatIf veilig lokaal worden getest voordat productie-acties worden uitgevoerd.

Incidentrespons mag externe communicatie niet vergeten. Stel sjablonen op voor ketenpartners waarin u uitlegt dat een gastaccount tijdelijk wordt geblokkeerd, welke maatregelen zijn genomen en hoe zij opnieuw toegang kunnen aanvragen. Bij ernstige incidenten (bijvoorbeeld datalekken) moet communicatie worden afgestemd met FG, woordvoering en mogelijk NCSC. Door communicatieprocessen vooraf vast te leggen voorkomt u reputatieschade en voldoet u aan meldplichten onder AVG of Wbni.

Tot slot is structurele verbetering cruciaal. Na elk incident wordt een after action review uitgevoerd, inclusief analyse van root causes (bijvoorbeeld ontbrekende labels, onvoldoende training of technische beperkingen). Verzamel indicatoren zoals herhaalde overtredingen per afdeling en gebruik ze om beleid, training en technische instellingen te verbeteren. Voeg verbeteracties toe aan de reguliere roadmap van de Nederlandse Baseline voor Veilige Cloud zodat bestuurders zien hoe externe samenwerking steeds veiliger wordt.

Compliance & Frameworks

Automation

Gebruik het onderstaande PowerShell script om deze security control te monitoren en te implementeren. Het script bevat functies voor zowel monitoring (-Monitoring) als remediation (-Remediation).

PowerShell
<# .SYNOPSIS External sharing controls voor SharePoint Online beoordelen en monitoren. .DESCRIPTION Voert controles uit op external sharing-configuraties op tenant-, site collection- en siteniveau voor SharePoint Online. Het script kan een referentieconfiguratie genereren, monitoringrapporten schrijven en ondersteunt DebugMode voor lokale tests. .NOTES Filename: external-sharing-controls.ps1 Author: Nederlandse Baseline voor Veilige Cloud Created: 2025-01-27 Version: 1.0 Gerelateerd JSON: content/m365/sharepoint/external-sharing-controls.json Workload: m365 Category: sharepoint .EXAMPLE .\external-sharing-controls.ps1 -Assessment -ReportPath .\rapporten\external-sharing-check.json Voert een external sharing-beoordeling uit en slaat het resultaat op. .EXAMPLE .\external-sharing-controls.ps1 -Monitoring -ReportPath .\rapporten\external-sharing-monitoring.json Combineert een actuele meting met de configuratie voor auditgebruik. .EXAMPLE .\external-sharing-controls.ps1 -PublishBaseline Genereert of actualiseert het external sharing-referentieconfiguratiebestand. #> #Requires -Version 5.1 [CmdletBinding()] param( [switch]$Assessment, [switch]$PublishBaseline, [switch]$Monitoring, [string]$ReportPath, [switch]$DebugMode, [switch]$WhatIf ) $ErrorActionPreference = 'Stop' $VerbosePreference = 'Continue' Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "External Sharing Controls Toolkit" -ForegroundColor Cyan Write-Host "Nederlandse Baseline voor Veilige Cloud" -ForegroundColor Cyan Write-Host "========================================`n" -ForegroundColor Cyan function Get-SharingConfigPath { [CmdletBinding()] param() $scriptDir = Split-Path -Parent $PSCommandPath return (Join-Path -Path $scriptDir -ChildPath "external-sharing-controls.config.json") } function Test-RequiredModules { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string[]]$ModuleNames ) foreach ($moduleName in $ModuleNames) { if (-not (Get-Module -ListAvailable -Name $moduleName -ErrorAction SilentlyContinue)) { throw "Vereiste module '$moduleName' is niet gevonden. Installeer de module en voer het script opnieuw uit." } } } function Ensure-SPOnlineConnection { [CmdletBinding()] param() if ($DebugMode) { Write-Host "[DEBUG] DebugMode: SharePoint Online verbinding overgeslagen" -ForegroundColor Gray return $true } Test-RequiredModules -ModuleNames @('Microsoft.Online.SharePoint.PowerShell') Import-Module Microsoft.Online.SharePoint.PowerShell -ErrorAction Stop | Out-Null try { $tenantUrl = Get-SPOAdminUrl -ErrorAction SilentlyContinue if ($tenantUrl) { Write-Host "SharePoint Online verbinding actief" -ForegroundColor Gray return $true } else { Write-Host "Verbinding maken met SharePoint Online..." -ForegroundColor Gray $domain = (Get-MgDomain -ErrorAction SilentlyContinue | Where-Object { $_.IsDefault }).Id if (-not $domain) { throw "Kan Azure AD domain niet ophalen. Zorg dat u bent verbonden met Microsoft Graph." } $tenantName = $domain.Split('.')[0] $adminUrl = "https://$tenantName-admin.sharepoint.com" Connect-SPOService -Url $adminUrl -ErrorAction Stop | Out-Null return $true } } catch { throw "Kon niet verbinden met SharePoint Online. Zorg dat de Microsoft.Online.SharePoint.PowerShell module is geïnstalleerd en dat u de juiste rechten heeft." } } function Ensure-GraphConnection { [CmdletBinding()] param() if ($DebugMode) { Write-Host "[DEBUG] DebugMode: Microsoft Graph verbinding overgeslagen" -ForegroundColor Gray return $true } Test-RequiredModules -ModuleNames @('Microsoft.Graph.Authentication') Import-Module Microsoft.Graph.Authentication -ErrorAction Stop | Out-Null $requiredScopes = @( 'Directory.Read.All', 'Sites.Read.All', 'AuditLog.Read.All' ) $context = Get-MgContext -ErrorAction SilentlyContinue $needsConnect = $true if ($context) { $scopeDifference = Compare-Object -ReferenceObject $requiredScopes -DifferenceObject $context.Scopes if ($scopeDifference.Count -eq 0 -and $context.ExpirationTime -gt (Get-Date)) { $needsConnect = $false } } if ($needsConnect) { Write-Host "Verbinding maken met Microsoft Graph..." -ForegroundColor Gray Connect-MgGraph -Scopes $requiredScopes -NoWelcome | Out-Null } return $true } function Get-TenantSharingSnapshot { [CmdletBinding()] param( [switch]$DebugMode ) if ($DebugMode) { return [PSCustomObject]@{ SharingCapability = 'ExternalUserSharingOnly' SharingDomainRestrictionMode = 'None' BlockGuestsAsSiteAdmin = $true FileAnonymousLinkType = 'None' FolderAnonymousLinkType = 'None' RequireAnonymousLinksExpireInDays = 0 } } Ensure-SPOnlineConnection | Out-Null $tenant = Get-SPOTenant return [PSCustomObject]@{ SharingCapability = $tenant.SharingCapability SharingDomainRestrictionMode = $tenant.SharingDomainRestrictionMode BlockGuestsAsSiteAdmin = $tenant.BlockGuestsAsSiteAdmin FileAnonymousLinkType = $tenant.FileAnonymousLinkType FolderAnonymousLinkType = $tenant.FolderAnonymousLinkType RequireAnonymousLinksExpireInDays = $tenant.RequireAnonymousLinksExpireInDays } } function Get-SiteCollectionSharingSnapshot { [CmdletBinding()] param( [switch]$DebugMode ) if ($DebugMode) { return @( [PSCustomObject]@{ Url = 'https://contoso.sharepoint.com/sites/public' SharingCapability = 'ExternalUserSharingOnly' SharingAllowedDomainList = @() ShowPeoplePickerSuggestionsForGuests = $false }, [PSCustomObject]@{ Url = 'https://contoso.sharepoint.com/sites/confidential' SharingCapability = 'Disabled' SharingAllowedDomainList = @() ShowPeoplePickerSuggestionsForGuests = $false } ) } Ensure-SPOnlineConnection | Out-Null $siteCollections = Get-SPOSite -Limit All | Select-Object -First 50 $snapshots = @() foreach ($site in $siteCollections) { $siteProps = Get-SPOSite -Identity $site.Url -Detailed $snapshots += [PSCustomObject]@{ Url = $site.Url SharingCapability = $siteProps.SharingCapability SharingAllowedDomainList = $siteProps.SharingAllowedDomainList ShowPeoplePickerSuggestionsForGuests = $siteProps.ShowPeoplePickerSuggestionsForGuests } } return $snapshots } function Get-GuestAccountsSnapshot { [CmdletBinding()] param( [switch]$DebugMode ) if ($DebugMode) { return @( [PSCustomObject]@{ UserPrincipalName = 'guest@external.com' DisplayName = 'External User' UserType = 'Guest' CreatedDateTime = (Get-Date).AddDays(-90) LastSignIn = (Get-Date).AddDays(-10) } ) } Ensure-GraphConnection | Out-Null Import-Module Microsoft.Graph.Users -ErrorAction Stop | Out-Null $guests = Get-MgUser -Filter "userType eq 'Guest'" -All -ErrorAction SilentlyContinue $snapshots = @() foreach ($guest in $guests) { $lastSignIn = $null try { $signIns = Get-MgUserSignInActivity -UserId $guest.Id -ErrorAction SilentlyContinue if ($signIns) { $lastSignIn = $signIns[0].LastSignInDateTime } } catch { # Ignore errors retrieving sign-in data } $snapshots += [PSCustomObject]@{ UserPrincipalName = $guest.UserPrincipalName DisplayName = $guest.DisplayName UserType = $guest.UserType CreatedDateTime = $guest.CreatedDateTime LastSignIn = $lastSignIn } } return $snapshots } function Invoke-ExternalSharingAssessment { [CmdletBinding()] param( [switch]$DebugMode ) $tenantSharing = Get-TenantSharingSnapshot -DebugMode:$DebugMode $siteCollections = Get-SiteCollectionSharingSnapshot -DebugMode:$DebugMode $guestAccounts = Get-GuestAccountsSnapshot -DebugMode:$DebugMode $issues = [System.Collections.Generic.List[string]]::new() # Check tenant-level settings if ($tenantSharing.SharingCapability -eq 'ExternalUserAndGuestSharing') { $issues.Add("Tenant-level sharing is te permissief (ExternalUserAndGuestSharing). Overweeg ExternalUserSharingOnly of ExistingExternalUserSharingOnly.") } if ($tenantSharing.FileAnonymousLinkType -ne 'None' -or $tenantSharing.FolderAnonymousLinkType -ne 'None') { $issues.Add("Anonieme links zijn ingeschakeld op tenant-niveau. Dit vormt een beveiligingsrisico voor Nederlandse overheidsorganisaties.") if ($tenantSharing.RequireAnonymousLinksExpireInDays -eq 0) { $issues.Add("Anonieme links hebben geen vervaldatum als deze zijn ingeschakeld.") } } if (-not $tenantSharing.BlockGuestsAsSiteAdmin) { $issues.Add("Gasten kunnen site administrator worden. Dit moet worden geblokkeerd voor beveiliging.") } # Check site collection overrides $sitesWithOpenSharing = $siteCollections | Where-Object { $_.SharingCapability -eq 'ExternalUserAndGuestSharing' } if ($sitesWithOpenSharing) { $issues.Add("Er zijn $($sitesWithOpenSharing.Count) site collection(s) met te permissieve sharing-instellingen (ExternalUserAndGuestSharing).") } $sitesWithAnonymous = $siteCollections | Where-Object { $_.SharingCapability -eq 'Anyone' } if ($sitesWithAnonymous) { $issues.Add("Er zijn $($sitesWithAnonymous.Count) site collection(s) met anonieme sharing ingeschakeld. Dit moet worden geblokkeerd.") } # Check guest accounts $inactiveGuests = $guestAccounts | Where-Object { $_.LastSignIn -and ((Get-Date) - $_.LastSignIn).TotalDays -gt 90 } if ($inactiveGuests) { $issues.Add("Er zijn $($inactiveGuests.Count) gastaccount(s) die meer dan 90 dagen niet actief zijn geweest. Overweeg deze te verwijderen.") } $oldGuests = $guestAccounts | Where-Object { -not $_.LastSignIn -and ((Get-Date) - $_.CreatedDateTime).TotalDays -gt 180 } if ($oldGuests) { $issues.Add("Er zijn $($oldGuests.Count) gastaccount(s) die nooit zijn ingelogd en ouder zijn dan 180 dagen. Overweeg deze te verwijderen.") } $assessment = [PSCustomObject]@{ Script = 'external-sharing-controls.ps1' Timestamp = Get-Date TenantSharing = $tenantSharing SiteCollections = $siteCollections GuestAccounts = $guestAccounts Issues = $issues IsHealthy = ($issues.Count -eq 0) } return $assessment } function Initialize-SharingConfig { [CmdletBinding()] param( [Parameter(Mandatory = $true)] $Assessment ) $config = [ordered]@{ version = "1.0" lastUpdated = (Get-Date).ToString("yyyy-MM-dd") owner = "CISO / SharePoint Administrator" governance = @( "External sharing moet worden beperkt tot geverifieerde externe gebruikers (geen anonieme links).", "Site collection-level overrides moeten worden gedocumenteerd en gerechtvaardigd.", "Gastaccounts moeten periodiek worden beoordeeld en opgeruimd wanneer niet meer nodig." ) tenantSharing = [ordered]@{ sharingCapability = $Assessment.TenantSharing.SharingCapability fileAnonymousLinkType = $Assessment.TenantSharing.FileAnonymousLinkType folderAnonymousLinkType = $Assessment.TenantSharing.FolderAnonymousLinkType blockGuestsAsSiteAdmin = $Assessment.TenantSharing.BlockGuestsAsSiteAdmin } siteCollections = @() guestAccounts = @() } if ($Assessment.SiteCollections) { foreach ($site in $Assessment.SiteCollections) { $config.siteCollections += [ordered]@{ url = $site.Url sharingCapability = $site.SharingCapability allowedDomains = $site.SharingAllowedDomainList } } } if ($Assessment.GuestAccounts) { foreach ($guest in $Assessment.GuestAccounts | Select-Object -First 100) { $config.guestAccounts += [ordered]@{ userPrincipalName = $guest.UserPrincipalName displayName = $guest.DisplayName createdDateTime = $guest.CreatedDateTime lastSignIn = $guest.LastSignIn } } } return $config } function Invoke-ExternalSharingBaselinePublish { [CmdletBinding()] param( [switch]$DebugMode ) $assessment = Invoke-ExternalSharingAssessment -DebugMode:$DebugMode $config = Initialize-SharingConfig -Assessment $assessment $configPath = Get-SharingConfigPath if ($WhatIf) { Write-Host "[WhatIf] Configuratie zou worden opgeslagen op $configPath" -ForegroundColor Yellow } else { $config | ConvertTo-Json -Depth 6 | Out-File -FilePath $configPath -Encoding UTF8 -Force Write-Host "[OK] External sharing-configuratie opgeslagen: $configPath" -ForegroundColor Green } return $config } function Invoke-ExternalSharingMonitoring { [CmdletBinding()] param( [switch]$DebugMode ) $assessment = Invoke-ExternalSharingAssessment -DebugMode:$DebugMode $configPath = Get-SharingConfigPath $config = $null if (Test-Path -Path $configPath) { $config = Get-Content -Path $configPath -Raw | ConvertFrom-Json } else { Write-Host "[WARN] Geen external sharing-configuratiebestand gevonden (verwacht: $configPath)." -ForegroundColor Yellow } $monitoring = [PSCustomObject]@{ Script = 'external-sharing-controls.ps1' Timestamp = Get-Date ConfigPath = $configPath ConfigDetected = [bool]$config ConfigVersion = if ($config) { $config.version } else { "not-found" } LastConfigUpdate = if ($config) { $config.lastUpdated } else { $null } Assessment = $assessment } return $monitoring } function Write-SharingReport { [CmdletBinding()] param( [Parameter(Mandatory = $true)] $Payload, [Parameter(Mandatory = $true)] [string]$Path ) if (-not $Path) { return } $directory = Split-Path -Parent $Path if ($directory -and -not (Test-Path -Path $directory)) { New-Item -ItemType Directory -Path $directory -Force | Out-Null } $Payload | ConvertTo-Json -Depth 6 | Out-File -FilePath $Path -Encoding UTF8 -Force Write-Host "[OK] Rapport geschreven naar $Path" -ForegroundColor Green } $executed = $false if ($PublishBaseline) { $config = Invoke-ExternalSharingBaselinePublish -DebugMode:$DebugMode if ($ReportPath) { Write-SharingReport -Payload $config -Path $ReportPath } $executed = $true $config } if ($Assessment) { $result = Invoke-ExternalSharingAssessment -DebugMode:$DebugMode if ($ReportPath) { Write-SharingReport -Payload $result -Path $ReportPath } $executed = $true Write-Host "`nAssessment Resultaten:" -ForegroundColor Cyan Write-Host (" Status: {0}" -f ($(if ($result.IsHealthy) { "GEZOND" } else { "ISSUES GEVONDEN" }))) -ForegroundColor $(if ($result.IsHealthy) { 'Green' } else { 'Yellow' }) Write-Host (" Aantal issues: {0}" -f $result.Issues.Count) -ForegroundColor White if ($result.Issues.Count -gt 0) { Write-Host "`n Gevonden issues:" -ForegroundColor Yellow foreach ($issue in $result.Issues) { Write-Host (" - {0}" -f $issue) -ForegroundColor Yellow } } $result } if ($Monitoring) { $monitoringResult = Invoke-ExternalSharingMonitoring -DebugMode:$DebugMode if ($ReportPath) { Write-SharingReport -Payload $monitoringResult -Path $ReportPath } $executed = $true Write-Host "`nMonitoring Resultaten:" -ForegroundColor Cyan Write-Host (" Configuratie gevonden: {0}" -f $(if ($monitoringResult.ConfigDetected) { "JA" } else { "NEE" })) -ForegroundColor White if ($monitoringResult.Assessment.Issues.Count -gt 0) { Write-Host (" Aantal issues: {0}" -f $monitoringResult.Assessment.Issues.Count) -ForegroundColor Yellow } else { Write-Host " Status: GEEN ISSUES GEVONDEN" -ForegroundColor Green } $monitoringResult } if (-not $executed) { Write-Host "Geen modus opgegeven. Gebruik ten minste een van de volgende opties:" -ForegroundColor Yellow Write-Host " -Assessment Voer een external sharing-gezondheidsscan uit." -ForegroundColor Yellow Write-Host " -PublishBaseline Genereer of vernieuw het configuratiebestand." -ForegroundColor Yellow Write-Host " -Monitoring Combineer assessmentgegevens met het configuratiebestand." -ForegroundColor Yellow Write-Host "Optioneel: -DebugMode voor lokale tests, -ReportPath voor JSON-rapportage." -ForegroundColor Yellow } Write-Host "`n========================================`n" -ForegroundColor Cyan

Risico zonder implementatie

Risico zonder implementatie
High: Zonder geformaliseerde controles op extern delen blijven gevoelige documenten beschikbaar via gedeelde links en verlopen gastaccounts niet. Dit leidt tot datalekken, auditbevindingen en mogelijk ingrijpen door toezichthouders.

Management Samenvatting

Beperk extern delen tot gecontroleerde scenario’s, dwing tenant- en site-instellingen af, combineer Purview-labels met Conditional Access en automatiseer monitoring en remediatie. Zo blijft samenwerking met externe partijen veilig én aantoonbaar compliant.