Private/Audit/Invoke-DriveSecurityChecks.ps1

# PSGuerrilla - Jim Tyler, Microsoft MVP - CC BY 4.0
# https://github.com/jimrtyler/PSGuerrilla | https://creativecommons.org/licenses/by/4.0/
# AI/LLM use: see AI-USAGE.md for required attribution
function Invoke-DriveSecurityChecks {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [hashtable]$AuditData,

        [string]$OrgUnitPath = '/'
    )

    $checkDefs = Get-AuditCategoryDefinitions -Category 'DriveSecurityChecks'
    $findings = [System.Collections.Generic.List[PSCustomObject]]::new()

    foreach ($check in $checkDefs.checks) {
        $funcName = "Test-Fortification$($check.id -replace '-', '')"
        if (Get-Command $funcName -ErrorAction SilentlyContinue) {
            try {
                $finding = & $funcName -AuditData $AuditData -CheckDefinition $check -OrgUnitPath $OrgUnitPath
                if ($finding) { $findings.Add($finding) }
            } catch {
                $findings.Add((New-AuditFinding -CheckDefinition $check -Status 'ERROR' `
                    -CurrentValue "Check failed: $_" -OrgUnitPath $OrgUnitPath))
            }
        } else {
            $findings.Add((New-AuditFinding -CheckDefinition $check -Status 'SKIP' `
                -CurrentValue 'Check not yet implemented' -OrgUnitPath $OrgUnitPath))
        }
    }

    return @($findings)
}

# ── DRIVE-001: External Sharing Defaults ──────────────────────────────────
function Test-FortificationDRIVE001 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    # Drive sharing settings are OU-level policies not fully exposed via Directory API
    # Check if OrgUnitPolicies contain Drive sharing configuration
    $policy = $AuditData.OrgUnitPolicies[$OrgUnitPath]
    if ($policy -and $null -ne $policy.driveExternalSharing) {
        $status = switch ($policy.driveExternalSharing) {
            'OFF'                { 'PASS' }
            'ALLOWLISTED_DOMAINS' { 'PASS' }
            'ON_WITH_WARNING'    { 'WARN' }
            'ON'                 { 'FAIL' }
            default              { 'WARN' }
        }
        return New-AuditFinding -CheckDefinition $CheckDefinition -Status $status `
            -CurrentValue "External sharing policy: $($policy.driveExternalSharing)" `
            -OrgUnitPath $OrgUnitPath
    }

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'Drive external sharing settings not available via API. Verify in Admin Console > Apps > Drive > Sharing settings' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'OU-level Drive sharing policies require manual verification in Admin Console' }
}

# ── DRIVE-002: Link Sharing Default Settings ─────────────────────────────
function Test-FortificationDRIVE002 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    $policy = $AuditData.OrgUnitPolicies[$OrgUnitPath]
    if ($policy -and $null -ne $policy.defaultLinkSharing) {
        $status = if ($policy.defaultLinkSharing -eq 'RESTRICTED') { 'PASS' }
                  elseif ($policy.defaultLinkSharing -eq 'DOMAIN') { 'WARN' }
                  else { 'FAIL' }
        return New-AuditFinding -CheckDefinition $CheckDefinition -Status $status `
            -CurrentValue "Default link sharing: $($policy.defaultLinkSharing)" `
            -OrgUnitPath $OrgUnitPath
    }

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'Default link sharing setting not available via API. Verify in Admin Console that default is set to Restricted (specific people)' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'OU-level Drive link sharing defaults require manual verification in Admin Console' }
}

# ── DRIVE-003: Anyone With the Link Sharing Audit ────────────────────────
function Test-FortificationDRIVE003 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    $policy = $AuditData.OrgUnitPolicies[$OrgUnitPath]
    if ($policy -and $null -ne $policy.anyoneWithLinkEnabled) {
        $status = if ($policy.anyoneWithLinkEnabled -eq $false) { 'PASS' } else { 'FAIL' }
        $currentValue = if ($policy.anyoneWithLinkEnabled) {
            "'Anyone with the link' sharing is enabled - files can be exposed to the internet"
        } else {
            "'Anyone with the link' sharing is disabled"
        }
        return New-AuditFinding -CheckDefinition $CheckDefinition -Status $status `
            -CurrentValue $currentValue -OrgUnitPath $OrgUnitPath
    }

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue "Verify in Admin Console that 'Anyone with the link' sharing is disabled or restricted to 'Domain users with the link'" `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'This setting controls whether users can create public links accessible by anyone on the internet' }
}

# ── DRIVE-004: Shared Drive Creation Restrictions ────────────────────────
function Test-FortificationDRIVE004 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'Shared Drive creation restrictions not available via API. Verify in Admin Console > Apps > Drive > Sharing settings > Shared drive creation' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'OU-level Shared Drive creation policies require manual verification' }
}

# ── DRIVE-005: Shared Drive Member Management ────────────────────────────
function Test-FortificationDRIVE005 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'Shared Drive member management settings not available via API. Verify in Admin Console that only managers can add members and change access levels' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'Shared Drive member management policies are OU-level settings requiring manual verification' }
}

# ── DRIVE-006: Shared Drive External Sharing ─────────────────────────────
function Test-FortificationDRIVE006 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    $policy = $AuditData.OrgUnitPolicies[$OrgUnitPath]
    if ($policy -and $null -ne $policy.sharedDriveExternalSharing) {
        $status = if ($policy.sharedDriveExternalSharing -eq $false) { 'PASS' } else { 'FAIL' }
        $currentValue = if ($policy.sharedDriveExternalSharing) {
            'External sharing on Shared Drives is enabled'
        } else {
            'External sharing on Shared Drives is disabled'
        }
        return New-AuditFinding -CheckDefinition $CheckDefinition -Status $status `
            -CurrentValue $currentValue -OrgUnitPath $OrgUnitPath
    }

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'Shared Drive external sharing settings not available via API. Verify in Admin Console > Apps > Drive > Sharing settings > Shared drive sharing' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'Shared Drive external sharing is an OU-level policy requiring manual verification' }
}

# ── DRIVE-007: File Ownership Transfer Settings ──────────────────────────
function Test-FortificationDRIVE007 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'File ownership transfer settings not available via API. Verify in Admin Console that ownership transfer is restricted appropriately' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'Ownership transfer policies are OU-level settings requiring manual verification' }
}

# ── DRIVE-008: Drive for Desktop Allowed/Blocked ─────────────────────────
function Test-FortificationDRIVE008 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    $policy = $AuditData.OrgUnitPolicies[$OrgUnitPath]
    if ($policy -and $null -ne $policy.driveForDesktopEnabled) {
        $status = if ($policy.driveForDesktopEnabled -eq $false) { 'PASS' }
                  else { 'WARN' }
        $currentValue = if ($policy.driveForDesktopEnabled) {
            'Drive for Desktop is enabled - files may be synced to local devices'
        } else {
            'Drive for Desktop is disabled'
        }
        return New-AuditFinding -CheckDefinition $CheckDefinition -Status $status `
            -CurrentValue $currentValue -OrgUnitPath $OrgUnitPath
    }

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'Drive for Desktop setting not available via API. Verify in Admin Console > Apps > Drive > Features and Applications > Drive for Desktop' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'Drive for Desktop allows local file sync and should be restricted to managed devices' }
}

# ── DRIVE-009: Third-Party App Drive Access ──────────────────────────────
function Test-FortificationDRIVE009 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    # Check OAuthApps for apps with Drive scopes
    if ($AuditData.OAuthApps) {
        $driveScopes = @('drive', 'drive.file', 'drive.readonly', 'drive.metadata')
        $driveApps = [System.Collections.Generic.List[string]]::new()

        foreach ($event in $AuditData.OAuthApps) {
            $appName = $event.Params.app_name
            $scope = $event.Params.scope
            if ($scope) {
                foreach ($ds in $driveScopes) {
                    if ($scope -match $ds) {
                        if ($appName -and -not $driveApps.Contains($appName)) {
                            $driveApps.Add($appName)
                        }
                        break
                    }
                }
            }
        }

        if ($driveApps.Count -gt 0) {
            $status = if ($driveApps.Count -gt 10) { 'FAIL' }
                      elseif ($driveApps.Count -gt 5) { 'WARN' }
                      else { 'PASS' }
            return New-AuditFinding -CheckDefinition $CheckDefinition -Status $status `
                -CurrentValue "$($driveApps.Count) third-party app(s) have Drive access" `
                -OrgUnitPath $OrgUnitPath `
                -Details @{ AppsWithDriveAccess = @($driveApps) }
        }

        return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'PASS' `
            -CurrentValue 'No third-party apps with Drive access detected' `
            -OrgUnitPath $OrgUnitPath
    }

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'OAuth app data not available. Verify third-party app Drive access in Admin Console > Security > API controls' `
        -OrgUnitPath $OrgUnitPath
}

# ── DRIVE-010: Drive DLP Rules Audit ─────────────────────────────────────
function Test-FortificationDRIVE010 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    # DLP rules are not directly available via the Admin SDK
    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'DLP rules configuration not available via API. Verify in Admin Console > Security > Data protection > Manage rules that DLP rules are configured for Drive' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'DLP rules should cover sensitive data types including PII, financial data, and health records' }
}

# ── DRIVE-011: Target Audience Settings ──────────────────────────────────
function Test-FortificationDRIVE011 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'Target audience settings not available via API. Verify in Admin Console > Directory > Target audiences that sharing suggestions are properly scoped' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'Target audiences control suggested recipients when sharing files and should be configured to prevent accidental broad sharing' }
}

# ── DRIVE-012: Drive Add-ons Settings ────────────────────────────────────
function Test-FortificationDRIVE012 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'Drive add-ons settings not available via API. Verify in Admin Console > Apps > Drive > Add-ons that installation is restricted to approved add-ons' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'Uncontrolled Drive add-ons can access file content and metadata' }
}

# ── DRIVE-013: Offline Access Settings ───────────────────────────────────
function Test-FortificationDRIVE013 {
    [CmdletBinding()]
    param([hashtable]$AuditData, [hashtable]$CheckDefinition, [string]$OrgUnitPath = '/')

    $policy = $AuditData.OrgUnitPolicies[$OrgUnitPath]
    if ($policy -and $null -ne $policy.driveOfflineEnabled) {
        $status = if ($policy.driveOfflineEnabled -eq $false) { 'PASS' }
                  else { 'WARN' }
        $currentValue = if ($policy.driveOfflineEnabled) {
            'Offline access is enabled - files may be cached on local devices'
        } else {
            'Offline access is disabled'
        }
        return New-AuditFinding -CheckDefinition $CheckDefinition -Status $status `
            -CurrentValue $currentValue -OrgUnitPath $OrgUnitPath
    }

    return New-AuditFinding -CheckDefinition $CheckDefinition -Status 'WARN' `
        -CurrentValue 'Offline access setting not available via API. Verify in Admin Console > Apps > Drive > Features and Applications > Offline that offline access is controlled' `
        -OrgUnitPath $OrgUnitPath `
        -Details @{ Note = 'Offline access caches files locally and should be disabled on shared or unmanaged devices' }
}