Public/Export-DLPConfiguration.ps1
|
function Export-DLPConfiguration { <# .SYNOPSIS Exports Microsoft Purview DLP policy and rule configurations. .DESCRIPTION Retrieves DLP policy configurations from Security & Compliance Center including all rules and their notification settings. Exports data to JSON and/or CSV formats for backup, documentation, and migration purposes. The export includes: - Policy metadata and settings - Location scope information (accurate "All" vs specific detection) - All rule configurations and conditions - Notification settings (policy tips and emails) - Cross-tenant migration metadata - Distribution status .PARAMETER PolicyName Optional. Specific policy name to export. If not provided, all policies are exported. .PARAMETER PolicyId Optional. Specific policy GUID to export. If not provided, all policies are exported. .PARAMETER OutputPath Optional. Directory path where export files will be saved. Default: Current directory .PARAMETER ExportFormat Export format(s) to generate. Valid values: JSON, CSV, Both Default: Both .PARAMETER IncludeRules Include detailed rule information in the export. Default: $true .OUTPUTS None. Exports files to the specified output path. .EXAMPLE Export-DLPConfiguration Exports all policies and rules to both JSON and CSV in the current directory. .EXAMPLE Export-DLPConfiguration -OutputPath "C:\Backups\DLP" Exports all policies to the specified directory. .EXAMPLE Export-DLPConfiguration -PolicyName "GDPR Enhanced" -ExportFormat JSON Exports a specific policy to JSON format only. .EXAMPLE Export-DLPConfiguration -PolicyId "12345678-1234-1234-1234-123456789012" Exports a specific policy by GUID. .EXAMPLE Export-DLPConfiguration -IncludeRules $false -ExportFormat CSV Exports only policy summaries (no rules) to CSV. .NOTES Requires: Active connection to Security & Compliance Center (use Connect-PurviewDLP first) Author: PurviewDLP Module Output files are timestamped automatically: - dlp-policies-export-YYYY-MM-DD_HHMMSS.json - dlp-policies-summary-YYYY-MM-DD_HHMMSS.csv - dlp-rules-detail-YYYY-MM-DD_HHMMSS.csv .LINK https://github.com/uniQuk/PurviewDLP #> [CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$PolicyName, [Parameter(Mandatory = $false)] [string]$PolicyId, [Parameter(Mandatory = $false)] [string]$OutputPath, [Parameter(Mandatory = $false)] [ValidateSet("JSON", "CSV", "Both")] [string]$ExportFormat = "Both", [Parameter(Mandatory = $false)] [bool]$IncludeRules = $true ) begin { Write-Verbose "Starting Export-DLPConfiguration" # Resolve output path (defaults to current directory) $resolvedOutputPath = Get-DefaultOutputPath -OutputPath $OutputPath Write-Verbose "Resolved output path: $resolvedOutputPath" } process { try { # Display banner Write-Banner -Message "DLP Policy Configuration Export" -Type "Info" # Verify connection Write-ColorOutput "Checking connection to Security & Compliance Center..." -Type Info Test-DLPConnection # Throws if not connected Write-ColorOutput "✓ Connected successfully`n" -Type Success # Display export settings Write-ColorOutput "Export Settings:" -Type Info Write-ColorOutput " Output Path: $resolvedOutputPath" -Type Info Write-ColorOutput " Export Format: $ExportFormat" -Type Info Write-ColorOutput " Include Rules: $IncludeRules`n" -Type Info # Retrieve policies Write-ColorOutput "Retrieving DLP policies..." -Type Info $dlpPolicies = if ($PolicyId) { Write-ColorOutput "Filtering by Policy ID: $PolicyId" -Type Info Get-DlpCompliancePolicy -Identity $PolicyId -ErrorAction Stop } elseif ($PolicyName) { Write-ColorOutput "Filtering by Policy Name: $PolicyName" -Type Info Get-DlpCompliancePolicy | Where-Object { $_.Name -eq $PolicyName } } else { Write-ColorOutput "Retrieving all policies..." -Type Info Get-DlpCompliancePolicy -ErrorAction Stop } $policyCount = ($dlpPolicies | Measure-Object).Count Write-ColorOutput "Found $policyCount policy/policies`n" -Type Success if ($policyCount -eq 0) { Write-ColorOutput "No policies found matching the criteria." -Type Warning return } # Process each policy $policies = @() $counter = 0 foreach ($policy in $dlpPolicies) { $counter++ Write-ColorOutput "[$counter/$policyCount] Processing: $($policy.Name)" -Type Info $policyDetails = Get-PolicyDetailsInternal -Policy $policy -IncludeRules $IncludeRules $policies += $policyDetails } # Generate timestamp for filenames $timestamp = Get-Date -Format "yyyy-MM-dd_HHmmss" # Export results Write-Banner -Message "Exporting Results" -Type "Info" $exportSuccess = $true # Export JSON if ($ExportFormat -eq "JSON" -or $ExportFormat -eq "Both") { $jsonPath = Join-Path $resolvedOutputPath "dlp-policies-export-$timestamp.json" Write-ColorOutput "Exporting to JSON..." -Type Info try { $policies | ConvertTo-Json -Depth 10 | Out-File -FilePath $jsonPath -Encoding UTF8 -Force Write-ColorOutput "✓ JSON export saved: $jsonPath" -Type Success } catch { Write-ColorOutput "✗ Failed to export JSON: $($_.Exception.Message)" -Type Error $exportSuccess = $false } } # Export CSV if ($ExportFormat -eq "CSV" -or $ExportFormat -eq "Both") { $policyCSVPath = Join-Path $resolvedOutputPath "dlp-policies-summary-$timestamp.csv" $ruleCSVPath = Join-Path $resolvedOutputPath "dlp-rules-detail-$timestamp.csv" Write-ColorOutput "Exporting to CSV..." -Type Info try { # Export policy summary $policySummary = $policies | Select-Object PolicyName, PolicyId, Mode, Enabled, RuleCount, ` CreatedBy, CreatedDateTime, ModifiedBy, ModifiedDateTime, Comment, Workload, ` HasSpecificTargeting, HasLocationExceptions, IsCrossTenantPortable $policySummary | Export-Csv -Path $policyCSVPath -NoTypeInformation -Encoding UTF8 -Force Write-ColorOutput "✓ Policy CSV export saved: $policyCSVPath" -Type Success # Export rules $allRules = $policies | ForEach-Object { $_.Rules } if ($allRules.Count -gt 0) { $formattedRules = $allRules | ForEach-Object { Format-RuleForCSVInternal -Rule $_ } $formattedRules | Export-Csv -Path $ruleCSVPath -NoTypeInformation -Encoding UTF8 -Force Write-ColorOutput "✓ Rule CSV export saved: $ruleCSVPath" -Type Success } else { Write-ColorOutput " No rules to export to CSV" -Type Warning } } catch { Write-ColorOutput "✗ Failed to export CSV: $($_.Exception.Message)" -Type Error $exportSuccess = $false } } # Summary Write-Banner -Message "Export Summary" -Type "Info" Write-ColorOutput "Policies exported: $policyCount" -Type Info $totalRules = ($policies | ForEach-Object { $_.RuleCount } | Measure-Object -Sum).Sum Write-ColorOutput "Total rules: $totalRules" -Type Info Write-ColorOutput "Export location: $resolvedOutputPath" -Type Info Write-ColorOutput "Timestamp: $timestamp" -Type Info if ($exportSuccess) { Write-Host "" Write-ColorOutput "✓ Export completed successfully!" -Type Success Write-Host "" } else { Write-Host "" Write-ColorOutput "⚠ Export completed with warnings. Check messages above." -Type Warning Write-Host "" } } catch { Write-Host "" Write-ColorOutput "✗ Error during export:" -Type Error Write-ColorOutput $_.Exception.Message -Type Error Write-Verbose "Stack Trace: $($_.ScriptStackTrace)" Write-Host "" Write-ColorOutput "Troubleshooting tips:" -Type Warning Write-ColorOutput " 1. Ensure you are connected: Connect-PurviewDLP" -Type Info Write-ColorOutput " 2. Verify you have permissions to read DLP policies" -Type Info Write-ColorOutput " 3. Check that the output path is writable" -Type Info Write-Host "" throw } } end { Write-Verbose "Export-DLPConfiguration completed" } } #region Internal Helper Functions function Get-PolicyDetailsInternal { <# .SYNOPSIS Internal function to extract detailed policy information. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [object]$Policy, [Parameter(Mandatory = $false)] [bool]$IncludeRules = $true ) Write-ColorOutput " Processing policy: $($Policy.Name)" -Type Info # Extract active workloads $activeWorkloads = @() if ($Policy.ExchangeLocation -and $Policy.ExchangeLocation.Count -gt 0) { $activeWorkloads += "Exchange" } if ($Policy.SharePointLocation -and $Policy.SharePointLocation.Count -gt 0) { $activeWorkloads += "SharePoint" } if ($Policy.OneDriveLocation -and $Policy.OneDriveLocation.Count -gt 0) { $activeWorkloads += "OneDriveForBusiness" } if ($Policy.TeamsLocation -and $Policy.TeamsLocation.Count -gt 0) { $activeWorkloads += "Teams" } # Analyze location scopes using Private/LocationScope.ps1 functions $exchangeScope = Get-LocationScopeInfo -LocationArray $Policy.ExchangeLocation -LocationName "Exchange" ` -ScopingProperties @($Policy.ExchangeSender, $Policy.ExchangeSenderMemberOf) ` -AdaptiveScopeProperties @($Policy.ExchangeAdaptiveScopes) $sharePointScope = Get-LocationScopeInfo -LocationArray $Policy.SharePointLocation -LocationName "SharePoint" ` -AdaptiveScopeProperties @($Policy.SharePointAdaptiveScopes) $oneDriveScope = Get-LocationScopeInfo -LocationArray $Policy.OneDriveLocation -LocationName "OneDrive" ` -ScopingProperties @($Policy.OneDriveSharedBy, $Policy.OneDriveSharedByMemberOf) ` -AdaptiveScopeProperties @($Policy.OneDriveAdaptiveScopes) $teamsScope = Get-LocationScopeInfo -LocationArray $Policy.TeamsLocation -LocationName "Teams" ` -AdaptiveScopeProperties @($Policy.TeamsAdaptiveScopes) $endpointScope = Get-LocationScopeInfo -LocationArray $Policy.EndpointDlpLocation -LocationName "Endpoint" ` -AdaptiveScopeProperties @($Policy.EndpointDlpAdaptiveScopes) # Analyze exceptions $exchangeExceptionScope = Get-LocationScopeInfo -LocationArray $Policy.ExchangeLocationException -LocationName "ExchangeException" $sharePointExceptionScope = Get-LocationScopeInfo -LocationArray $Policy.SharePointLocationException -LocationName "SharePointException" $oneDriveExceptionScope = Get-LocationScopeInfo -LocationArray $Policy.OneDriveLocationException -LocationName "OneDriveException" $teamsExceptionScope = Get-LocationScopeInfo -LocationArray $Policy.TeamsLocationException -LocationName "TeamsException" # Determine cross-tenant portability $hasSpecificTargeting = $exchangeScope.IsSpecific -or $sharePointScope.IsSpecific -or $oneDriveScope.IsSpecific -or $teamsScope.IsSpecific -or $endpointScope.IsSpecific $hasExceptions = $exchangeExceptionScope.IsConfigured -or $sharePointExceptionScope.IsConfigured -or $oneDriveExceptionScope.IsConfigured -or $teamsExceptionScope.IsConfigured # Build policy object $policyInfo = [PSCustomObject]@{ PolicyName = $Policy.Name PolicyId = $Policy.Guid Mode = $Policy.Mode Enabled = $Policy.Enabled CreatedBy = $Policy.CreatedBy CreatedDateTime = $Policy.WhenCreated ModifiedBy = $Policy.LastModifiedBy ModifiedDateTime = $Policy.WhenChanged Comment = $Policy.Comment Workload = $activeWorkloads -join ", " # Cross-tenant migration metadata HasSpecificTargeting = $hasSpecificTargeting HasLocationExceptions = $hasExceptions IsCrossTenantPortable = -not ($hasSpecificTargeting -or $hasExceptions) # Location inclusions ExchangeLocation = $exchangeScope.Locations ExchangeLocationIsAll = $exchangeScope.IsAll SharePointLocation = $sharePointScope.Locations SharePointLocationIsAll = $sharePointScope.IsAll OneDriveLocation = $oneDriveScope.Locations OneDriveLocationIsAll = $oneDriveScope.IsAll TeamsLocation = $teamsScope.Locations TeamsLocationIsAll = $teamsScope.IsAll EndpointDlpLocation = $endpointScope.Locations EndpointDlpLocationIsAll = $endpointScope.IsAll # Location exceptions ExchangeLocationException = $exchangeExceptionScope.Locations SharePointLocationException = $sharePointExceptionScope.Locations OneDriveLocationException = $oneDriveExceptionScope.Locations TeamsLocationException = $teamsExceptionScope.Locations # Distribution status DistributionStatus = $Policy.DistributionStatus Priority = $Policy.Priority Type = $Policy.Type RuleCount = 0 Rules = @() } # Get rules if ($IncludeRules) { try { $rules = Get-DlpComplianceRule -Policy $Policy.Name -ErrorAction Stop $policyInfo.RuleCount = ($rules | Measure-Object).Count Write-ColorOutput " Found $($policyInfo.RuleCount) rule(s)" -Type Info foreach ($rule in $rules) { Write-Verbose " Processing rule: $($rule.Name)" $policyInfo.Rules += Get-RuleDetailsInternal -Rule $rule -PolicyName $Policy.Name } } catch { Write-ColorOutput " Warning: Could not retrieve rules for policy '$($Policy.Name)': $($_.Exception.Message)" -Type Warning } } return $policyInfo } function Get-RuleDetailsInternal { <# .SYNOPSIS Internal function to extract detailed rule information. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [object]$Rule, [Parameter(Mandatory = $true)] [string]$PolicyName ) return [PSCustomObject]@{ RuleName = $Rule.Name RuleId = $Rule.Guid PolicyName = $PolicyName Disabled = $Rule.Disabled Mode = $Rule.Mode Priority = $Rule.Priority # Advanced Rule (JSON-based conditions) AdvancedRule = $Rule.AdvancedRule # SIT configuration ContentContainsSensitiveInformation = if ($Rule.ContentContainsSensitiveInformation) { ($Rule.ContentContainsSensitiveInformation | ConvertTo-Json -Depth 10 -Compress) } else { $null } # Notification settings NotifyUser = $Rule.NotifyUser -join "; " NotifyUserType = $Rule.NotifyUserType NotifyAllowOverride = $Rule.NotifyAllowOverride -join "; " NotifyPolicyTipCustomText = $Rule.NotifyPolicyTipCustomText NotifyEmailCustomText = $Rule.NotifyEmailCustomText # Incident reporting GenerateIncidentReport = $Rule.GenerateIncidentReport -join "; " ReportSeverityLevel = $Rule.ReportSeverityLevel # Actions BlockAccess = $Rule.BlockAccess BlockAccessScope = $Rule.BlockAccessScope EncryptRMSTemplate = $Rule.EncryptRMSTemplate # Metadata CreatedBy = $Rule.CreatedBy CreatedDateTime = $Rule.WhenCreated ModifiedBy = $Rule.LastModifiedBy ModifiedDateTime = $Rule.WhenChanged Comment = $Rule.Comment } } function Format-RuleForCSVInternal { <# .SYNOPSIS Formats a rule object for CSV export readability. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [object]$Rule ) $formatted = $Rule.PSObject.Copy() # Truncate long HTML content for CSV readability if ($Rule.NotifyEmailCustomText -and $Rule.NotifyEmailCustomText.Length -gt 100) { $formatted.NotifyEmailCustomText = $Rule.NotifyEmailCustomText.Substring(0, 97) + "..." } if ($Rule.NotifyPolicyTipCustomText -and $Rule.NotifyPolicyTipCustomText.Length -gt 100) { $formatted.NotifyPolicyTipCustomText = $Rule.NotifyPolicyTipCustomText.Substring(0, 97) + "..." } return $formatted } #endregion |