Public/Protect-SensitiveData.ps1
|
function Protect-SensitiveData { <# .SYNOPSIS Masks sensitive data in files, folders, or strings by applying case-aware text replacements. .DESCRIPTION Protect-SensitiveData replaces occurrences of configured terms with their masked counterparts. Replacements are case-insensitive when matching but case-aware when substituting: an ALL-CAPS, all-lower, or PascalCase match is replaced with a value adapted to the same casing style. The function operates in one of two modes, selected automatically by the parameter used: - Path mode (-Path): masks the contents (and names) of a single file or every file in a folder. By default the masked output is written alongside the source using -Suffix; use -InPlace to overwrite the originals. - String mode (-InputString): masks a raw string and returns the masked string to the pipeline. No files are read or written, so this mode is suitable for inline use and piping. Status messages are suppressed so downstream output stays clean. The replacement map is supplied either via -Replacements (a hashtable) or -MappingFile (a JSON file). By default the mapping file is read from the current user's profile directory (MaskSensitiveData_Map.json). Manage the mapping file with Add-MaskMapping, Remove-MaskMapping, and Get-MaskMapping. Reverse the operation with Unprotect-SensitiveData. .PARAMETER Path Path to a file or folder to mask. When a folder is given, files matching -Include are processed (optionally recursively with -Recurse). Belongs to the 'Path' parameter set and is the default mode. .PARAMETER InputString A string to mask. Accepts pipeline input. The masked string is written to the pipeline and no file I/O is performed. Belongs to the 'String' parameter set. .PARAMETER MappingFile Path to a JSON file containing the replacement map (key = term to find, value = replacement). Defaults to MaskSensitiveData_Map.json in the user's profile folder. Ignored when -Replacements is supplied. .PARAMETER Replacements A hashtable of replacements (key = term to find, value = replacement). When supplied, this takes precedence over -MappingFile. .PARAMETER InPlace Path mode only. Overwrite the source files in place instead of writing masked copies. .PARAMETER Suffix Path mode only. Suffix appended to the masked output file/folder when not using -InPlace. Defaults to '.masked'. .PARAMETER Include Path mode only. One or more wildcard patterns used to filter files when -Path is a folder. Defaults to '*.*' (all files). .PARAMETER Recurse Path mode only. When -Path is a folder, also process files in subfolders. .EXAMPLE Protect-SensitiveData -Path .\report.txt Masks report.txt using the default mapping file and writes report.txt.masked alongside it. .EXAMPLE Protect-SensitiveData -Path .\logs -Recurse -InPlace Masks every file under the logs folder (recursively), overwriting the originals. .EXAMPLE 'Contact john.doe@contoso.com' | Protect-SensitiveData Masks the piped string and returns the masked text to the pipeline. .EXAMPLE Get-Content .\input.txt | Protect-SensitiveData -Replacements @{ 'Contoso' = 'Acme' } Pipes each line through the masker using an inline replacement hashtable. .LINK Unprotect-SensitiveData #> [CmdletBinding(DefaultParameterSetName = 'Path')] param( [Parameter(Mandatory, Position = 0, ParameterSetName = 'Path')] [string]$Path, [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'String')] [string]$InputString, [string]$MappingFile = (Join-Path $env:USERPROFILE 'MaskSensitiveData_Map.json'), [hashtable]$Replacements, [Parameter(ParameterSetName = 'Path')] [switch]$InPlace, [Parameter(ParameterSetName = 'Path')] [string]$Suffix = '.masked', [Parameter(ParameterSetName = 'Path')] [string[]]$Include = @('*.*'), [Parameter(ParameterSetName = 'Path')] [switch]$Recurse ) begin { $map = Resolve-ReplacementMap -Replacements $Replacements -MappingFile $MappingFile if ($PSCmdlet.ParameterSetName -eq 'Path') { Write-Host "Loaded $($map.Count) replacement(s)." } } process { if ($PSCmdlet.ParameterSetName -eq 'String') { # String mode: mask the text and emit it to the pipeline (no file I/O). Invoke-Replacements -Text $InputString -Map $map return } Invoke-MaskPath -Path $Path -Map $map -InPlace:$InPlace -Suffix $Suffix ` -Include $Include -Recurse:$Recurse } } |