Private/SID/Test-SIDFormat.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS SID Format Validation Module for Find-UnknownSID Solution .DESCRIPTION This module provides comprehensive SID format validation and well-known SID identification functionality for the Find-UnknownSID enterprise solution. This module follows the single-responsibility principle by focusing exclusively on SID format validation and structure checking. It serves as the foundation validation module for other SID processing modules. BUSINESS VALUE: - Ensures data quality by validating SID format before processing - Prevents processing errors from malformed SID strings - Identifies critical system SIDs to prevent accidental removal - Provides fast, lightweight validation for performance-critical operations TECHNICAL FEATURES: - Comprehensive SID format validation using .NET SecurityIdentifier - Well-known SID recognition with Microsoft specification compliance - Pipeline-optimized processing for bulk operations - Configuration-driven pattern matching for enterprise customization - Lightweight module design for selective loading .NOTES Author: Jeffrey Stuhr Blog: https://www.techbyjeff.net LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/ Last Updated: 2025-07-04 Version: 1.0.0 PowerShell Version: 5.1+ (Windows), 7.x+ (Cross-platform) MODULE DESIGN: This module implements the single-responsibility principle by focusing exclusively on SID format validation. It provides the foundation for other SID processing modules while maintaining high cohesion and minimal dependencies. TROUBLESHOOTING: - For format validation issues: .\Troubleshooting\Security\SID-Format-Issues.md - For well-known SID issues: .\Troubleshooting\Security\Well-Known-SID-Issues.md - For performance optimization: .\Troubleshooting\Performance\Format-Validation-Performance.md DEPENDENCIES: - Requires Logging.ps1 for Write-StructuredLog function - Uses script-scoped $script:Config variable for configuration access (optional) #> function Test-SIDFormat { <# .SYNOPSIS Validates whether a string represents a properly formatted Security Identifier (SID) .DESCRIPTION Performs comprehensive validation of SID format using both pattern matching and .NET SecurityIdentifier object creation. This function ensures SID strings conform to Microsoft's SID format specifications before processing. BUSINESS VALUE: - Prevents processing errors from malformed SID strings - Ensures data quality in security operations - Reduces false positives in SID analysis - Supports input validation for security compliance TECHNICAL FEATURES: - Pattern-based validation for basic SID structure - .NET SecurityIdentifier object creation for thorough validation - Comprehensive error handling and logging - Pipeline support for bulk validation .PARAMETER SID [String] (Mandatory: Yes, Pipeline: ByValue) The string to validate as a SID format. VALIDATION RULES: - Must start with "S-1-" pattern - Must be valid according to .NET SecurityIdentifier class BUSINESS CONTEXT: Used to validate SID strings before processing in security operations. EXAMPLES: - Valid domain SID: "S-1-5-21-1234567890-1234567890-1234567890-1001" - Valid well-known SID: "S-1-5-32-544" - Invalid format: "DOMAIN\username" .PARAMETER CorrelationId [String] (Mandatory: No) Correlation ID for tracking this operation across logs and troubleshooting. Defaults to auto-generated GUID if not provided. .EXAMPLE PS> Test-SIDFormat -SID "S-1-5-21-1234567890-1234567890-1234567890-1001" DESCRIPTION: Basic SID format validation OUTPUT: $true (valid SID format) USE CASE: Input validation before SID processing .EXAMPLE PS> @('S-1-5-32-544', 'DOMAIN\user', 'S-1-5-21-123-456-789-1001') | Test-SIDFormat DESCRIPTION: Pipeline validation of multiple SID candidates OUTPUT: $true, $false, $true USE CASE: Bulk validation of SID data from various sources .EXAMPLE PS> Test-SIDFormat -SID "invalid-sid" -CorrelationId $correlationId DESCRIPTION: Format validation with correlation tracking OUTPUT: $false with detailed logging USE CASE: Enterprise validation operations requiring audit trails .INPUTS [String] - SID string candidates via pipeline .OUTPUTS [Boolean] - $true if valid SID format, $false otherwise .NOTES Author: Jeffrey Stuhr Blog: https://www.techbyjeff.net LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/ Last Updated: 2025-07-04 Version: 1.0.0 PERFORMANCE CHARACTERISTICS: - Very fast validation using .NET built-in methods - Typical execution time: <5ms per SID TROUBLESHOOTING: - For validation errors: .\Troubleshooting\Security\SID-Format-Issues.md - For format issues: .\Troubleshooting\Common\SID-Format-Problems.md .LINK Test-WellKnownSID .\Troubleshooting\Security\SID-Format-Issues.md #> [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory, ValueFromPipeline)] [string]$SID, [Parameter()] [string]$CorrelationId = [System.Guid]::NewGuid().ToString() ) process { try { Write-StructuredLog "Validating SID format: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId # Basic pattern matching for performance if ($SID -notmatch '^S-1-\d+-\d+') { Write-StructuredLog "SID format invalid - does not match basic pattern: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $false } # Try to create SecurityIdentifier object for thorough validation try { $null = [System.Security.Principal.SecurityIdentifier]::new($SID) Write-StructuredLog "SID format valid: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $true } catch { Write-StructuredLog "SID format invalid - SecurityIdentifier creation failed: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $false } } catch { Write-StructuredLog "Error validating SID format $SID : $($_.Exception.Message)" -Level Error -Component 'SIDFormat' -CorrelationId $CorrelationId return $false } } } function Test-WellKnownSID { <# .SYNOPSIS Tests whether a SID is a well-known Security Identifier .DESCRIPTION Determines if a SID represents a well-known security principal by checking against comprehensive lists of Microsoft well-known SIDs, configuration-based patterns, and protected SID lists. This function is essential for preventing accidental removal of system-critical SIDs during cleanup operations. BUSINESS VALUE: - Prevents accidental removal of critical system SIDs - Ensures system stability during security cleanup operations - Supports compliance by protecting essential security principals - Reduces risk of breaking system functionality TECHNICAL FEATURES: - Comprehensive well-known SID database - Configuration-driven pattern matching - Protected SID list support - Domain-specific well-known SID recognition - Built-in domain SID detection .PARAMETER SID [String] (Mandatory: Yes, Pipeline: ByValue) The Security Identifier to test for well-known status. VALIDATION RULES: - Must be a valid SID string format - Checked against Microsoft's well-known SID specifications BUSINESS CONTEXT: Used to identify SIDs that should never be removed from ACLs due to their critical system importance. EXAMPLES: - System account: "S-1-5-18" (Local System) - Built-in group: "S-1-5-32-544" (Administrators) - Domain admin: "S-1-5-21-domain-512" (Domain Admins) .PARAMETER CorrelationId [String] (Mandatory: No) Correlation ID for tracking this operation across logs and troubleshooting. Defaults to auto-generated GUID if not provided. .EXAMPLE PS> Test-WellKnownSID -SID "S-1-5-18" DESCRIPTION: Test Local System account SID OUTPUT: $true (well-known system SID) USE CASE: Verify critical system SID protection .EXAMPLE PS> @('S-1-5-32-544', 'S-1-5-21-123-456-789-1001') | Test-WellKnownSID DESCRIPTION: Test multiple SIDs for well-known status OUTPUT: $true, $false (Administrators group vs. domain user) USE CASE: Bulk validation during ACL analysis .EXAMPLE PS> Test-WellKnownSID -SID "S-1-5-21-1234567890-1234567890-1234567890-512" DESCRIPTION: Test domain-specific well-known SID (Domain Admins) OUTPUT: $true (well-known domain admin group) USE CASE: Protect domain admin groups during cleanup .INPUTS [String] - SID string values via pipeline .OUTPUTS [Boolean] - $true if SID is well-known, $false otherwise .NOTES Author: Jeffrey Stuhr Blog: https://www.techbyjeff.net LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/ Last Updated: 2025-07-04 Version: 1.0.0 PERFORMANCE CHARACTERISTICS: - Fast pattern matching and list lookups - Typical execution time: <10ms per SID WELL-KNOWN SID COVERAGE: - Universal well-known SIDs (S-1-0-*, S-1-1-*, etc.) - NT Authority SIDs (S-1-5-*) - Built-in domain SIDs (S-1-5-32-*) - Service SIDs (S-1-5-80-*, etc.) - Domain-specific admin groups (512, 518, 519) TROUBLESHOOTING: - For recognition issues: .\Troubleshooting\Security\Well-Known-SID-Issues.md - For configuration: .\Troubleshooting\Common\Configuration-Problems.md .LINK Test-SIDFormat .\Troubleshooting\Security\Well-Known-SID-Issues.md #> [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNullOrEmpty()] [string]$SID, [Parameter()] [string]$CorrelationId = [System.Guid]::NewGuid().ToString() ) process { try { Write-StructuredLog "Testing SID for well-known status: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId # Check against configuration patterns if available if ($script:Config -and $script:Config.WellKnownSIDPatterns) { foreach ($pattern in $script:Config.WellKnownSIDPatterns) { if ($SID -match $pattern) { Write-StructuredLog "SID matches well-known pattern '$pattern': $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $true } } } # Check against protected SIDs configuration if ($script:Config -and $script:Config.ProtectedSIDs) { foreach ($protectedSID in $script:Config.ProtectedSIDs) { if ($SID -eq $protectedSID) { Write-StructuredLog "SID is in protected SIDs list: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $true } } } # Fallback to comprehensive well-known SIDs database $specificWellKnownSIDs = @( 'S-1-0-0', # Nobody 'S-1-1-0', # Everyone 'S-1-2-0', # Local 'S-1-2-1', # Console Logon 'S-1-3-0', # Creator Owner 'S-1-3-1', # Creator Group 'S-1-3-2', # Creator Owner Server 'S-1-3-3', # Creator Group Server 'S-1-3-4', # Owner Rights 'S-1-5-1', # Dialup 'S-1-5-2', # Network 'S-1-5-3', # Batch 'S-1-5-4', # Interactive 'S-1-5-6', # Service 'S-1-5-7', # Anonymous 'S-1-5-8', # Proxy 'S-1-5-9', # Enterprise Domain Controllers 'S-1-5-10', # Principal Self 'S-1-5-11', # Authenticated Users 'S-1-5-12', # Restricted Code 'S-1-5-13', # Terminal Server Users 'S-1-5-14', # Remote Interactive Logon 'S-1-5-15', # This Organization 'S-1-5-17', # This Organization Certificate 'S-1-5-18', # Local System 'S-1-5-19', # Local Service 'S-1-5-20', # Network Service 'S-1-5-80', # NT Service prefix 'S-1-5-90', # Windows Manager prefix 'S-1-5-96' # Font Driver Host prefix ) # Check for Built-in domain SIDs (S-1-5-32-*) if ($SID.StartsWith('S-1-5-32-')) { Write-StructuredLog "SID is built-in domain SID: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $true } # Check specific well-known SIDs (use exact matching or specific patterns) foreach ($wellKnown in $specificWellKnownSIDs) { # For single-component SIDs, use exact matching if ($wellKnown -match '^\S+-\d+-\d+$' -and $SID -eq $wellKnown) { Write-StructuredLog "SID is well-known exact match: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $true } # For prefix patterns (like S-1-5-80, S-1-5-90, S-1-5-96), ensure they don't conflict with domain SIDs elseif ($wellKnown -match '^\S+-\d+-\d+$' -and $SID.StartsWith($wellKnown + '-')) { Write-StructuredLog "SID is well-known prefix match: $SID (pattern: $wellKnown)" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $true } } # Special handling for domain-specific well-known SIDs # Domain Admins (512), Enterprise Admins (519), Schema Admins (518) if ($SID -match '^S-1-5-21-\d+-\d+-\d+-(512|518|519)$') { Write-StructuredLog "SID is well-known domain admin group: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $true } # Domain SIDs (S-1-5-21-*) are NOT well-known by default # They should be tested for orphaned status separately Write-StructuredLog "SID is not well-known: $SID" -Level Debug -Component 'SIDFormat' -CorrelationId $CorrelationId return $false } catch { Write-StructuredLog "Error testing well-known SID status for $SID : $($_.Exception.Message)" -Level Error -Component 'SIDFormat' -CorrelationId $CorrelationId return $false } } } |