Private/FileSystem/Get-SafeFileName.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Get-SafeFileName - String manipulation utilities for Find-UnknownSID Solution .DESCRIPTION This module provides focused string manipulation and sanitization functions for the Find-UnknownSID enterprise solution. Specialized in safe string processing for file operations and data validation. BUSINESS VALUE: - Safe filename generation for backup and log operations - Consistent string sanitization across the solution - Protection against file system injection attacks - Cross-platform string handling compatibility TECHNICAL FEATURES: - Safe filename creation from arbitrary strings - Character filtering and length management - Unicode and special character handling - Performance-optimized string operations .NOTES Author: Jeffrey Stuhr Blog: https://www.techbyjeff.net LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/ Last Updated: 2025-01-27 Version: 1.0.0 PowerShell Version: 5.1+ (Windows), 7.x+ (Cross-platform) TROUBLESHOOTING: - For string processing issues: .\Troubleshooting\Common\String-Processing-Issues.md - For filename problems: .\Troubleshooting\Common\Filename-Issues.md DEPENDENCIES: - Integrates with enterprise logging infrastructure - Requires appropriate file system permissions for validation operations #> function Get-SafeFileName { <# .SYNOPSIS Creates safe filenames from arbitrary strings .DESCRIPTION Converts potentially unsafe strings (like Distinguished Names) into safe filenames by replacing illegal characters and handling length limitations. Designed for cross-platform compatibility and security. BUSINESS VALUE: - Enables safe file operations from dynamic content - Prevents file system errors from invalid characters - Supports automated backup and logging operations - Maintains data traceability through readable filenames SECURITY FEATURES: - Filters dangerous file system characters - Prevents path traversal through character replacement - Enforces maximum filename length limits - Provides fallback naming for error conditions .PARAMETER InputString [String] (Mandatory) The string to convert to a safe filename. Can be empty or null for parameter validation scenarios. .PARAMETER MaxLength [Int] (Optional) Maximum filename length. Default: 200 characters. Recommended to stay well below file system limits (255 chars). .PARAMETER CorrelationId [String] (Optional) Correlation ID for audit trail tracking. Auto-generated if not provided. .EXAMPLE PS> Get-SafeFileName -InputString "CN=Test User,OU=Users,DC=contoso,DC=com" DESCRIPTION: Converts DN to safe filename OUTPUT: "CN_Test_User_OU_Users_DC_contoso_DC_com" USE CASE: Creating backup files from AD object names .EXAMPLE PS> Get-SafeFileName -InputString "File<>Name:With|Illegal?Characters" -MaxLength 50 DESCRIPTION: Sanitizes string with custom length limit OUTPUT: "File__Name_With_Illegal_Characters_truncated" SECURITY: Replaces all illegal file system characters .EXAMPLE PS> $objectNames | Get-SafeFileName DESCRIPTION: Pipeline processing of multiple strings OUTPUT: Array of safe filename strings AUTOMATION: Bulk processing for file operations .OUTPUTS [String] Safe filename string suitable for file system operations .NOTES SECURITY CONSIDERATIONS: - Replaces illegal filename characters: \/:*?"<>| - Consolidates whitespace to prevent formatting issues - Enforces length limits to prevent file system errors - Provides unique fallback names for error conditions - Logs security-relevant character replacements CHARACTER REPLACEMENT RULES: - Illegal characters (\/:*?"<>|) → underscore (_) - Multiple whitespace → single underscore (_) - Leading/trailing spaces → trimmed - Empty/null strings → "Unknown" - Length exceeded → truncated with "_truncated" suffix PERFORMANCE CHARACTERISTICS: - Processing time: <1ms per string typically - Memory usage: Minimal, optimized for bulk operations - Thread safety: Stateless function safe for parallel processing - Cross-platform: Compatible with Windows, Linux, macOS file systems #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory, ValueFromPipeline)] [AllowEmptyString()] [string]$InputString, [Parameter()] [ValidateRange(10, 200)] [int]$MaxLength = 200, [Parameter()] [string]$CorrelationId = [System.Guid]::NewGuid().ToString() ) process { try { # Handle null or empty strings if ([string]::IsNullOrWhiteSpace($InputString)) { Write-StructuredLog "Safe filename generation: Input string was empty, using default" -Level Debug -CorrelationId $CorrelationId return "Unknown" } # Replace illegal filename characters with underscores # Illegal characters for Windows: \/:*?"<>| # Also handles characters that could cause issues on other platforms $safeName = $InputString -replace '[\\/:*?"<>|]', '_' # Consolidate multiple whitespace characters to single underscore $safeName = $safeName -replace '\s+', '_' # Trim leading and trailing underscores/spaces $safeName = $safeName.Trim('_', ' ') # Handle length limitations if ($safeName.Length -gt $MaxLength) { # Calculate space for suffix $suffixLength = "_truncated".Length $maxContentLength = $MaxLength - $suffixLength if ($maxContentLength -gt 0) { $safeName = $safeName.Substring(0, $maxContentLength) + "_truncated" Write-StructuredLog "Safe filename generation: Truncated filename from $($InputString.Length) to $MaxLength characters" -Level Debug -CorrelationId $CorrelationId } else { # If MaxLength is too small even for suffix, use just the suffix $safeName = "truncated" } } # Final validation - ensure we still have a valid filename if ([string]::IsNullOrWhiteSpace($safeName) -or $safeName -eq '_') { $safeName = "Unknown_$([System.Guid]::NewGuid().ToString('N').Substring(0,8))" Write-StructuredLog "Safe filename generation: Generated fallback filename due to invalid result" -Level Warning -CorrelationId $CorrelationId } Write-StructuredLog "Safe filename generation successful: '$InputString' → '$safeName'" -Level Debug -CorrelationId $CorrelationId return $safeName } catch { Write-StructuredLog "Error creating safe filename from '$InputString': $($_.Exception.Message)" -Level Warning -CorrelationId $CorrelationId # Return a safe fallback filename return "Error_$([System.Guid]::NewGuid().ToString('N').Substring(0,8))" } } } |