diff --git a/CHANGELOG.md b/CHANGELOG.md index a02efb2..bef3900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,7 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Defense-in-depth (WPAD already disabled by framework) - Recommended for air-gapped/standalone systems -**Privacy Module Expansion (55+ → 77 settings)** +**Privacy Module Expansion (55+ → 78 settings)** - Cloud Clipboard toggle (user-configurable) - Enhanced compliance verification - Improved bloatware detection @@ -71,7 +71,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Automatic detection of Kaspersky, Norton, Bitdefender, etc. - ASR module gracefully skipped when 3rd-party AV active - Clear user notification explaining why -- All other modules continue normally (613 settings) +- All other modules continue normally (614 settings) **Smart Registry Backup System** - JSON fallback for protected system keys @@ -81,7 +81,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 **Documentation** - AV Compatibility section: "Designed for Microsoft Defender – Works with Any Antivirus" -- Clear 632 vs 613 explanation for Defender vs. 3rd-party AV setups +- Clear 633 vs 614 explanation for Defender vs. 3rd-party AV setups - Improved troubleshooting guides ### 🔨 Fixed @@ -113,9 +113,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | Component | v2.1.0 | v2.2.0 | |-----------|--------|--------| -| Total Settings | 580+ | **632** | +| Total Settings | 580+ | **633** | | AntiAI Policies | 24 | **32** | -| Privacy Settings | 55+ | **77** | +| Privacy Settings | 55+ | **78** | | NonInteractive Mode | ❌ | ✅ | | 3rd-Party AV Detection | ❌ | ✅ | | Pre-Framework ASR Snapshot | ❌ | ✅ | diff --git a/Core/Framework.ps1 b/Core/Framework.ps1 index 842b202..e0f1d8e 100644 --- a/Core/Framework.ps1 +++ b/Core/Framework.ps1 @@ -534,8 +534,8 @@ function Invoke-Hardening { Write-Host "" Write-Host " > Applies privacy settings based on selected mode:" -ForegroundColor Gray Write-Host " - Telemetry control (3 modes: MSRecommended/Strict/Paranoid)" -ForegroundColor Gray - Write-Host " - MSRecommended: 59 settings (default, max compatibility)" -ForegroundColor DarkGray - Write-Host " - Strict: 77 settings, Paranoid: 85 settings" -ForegroundColor DarkGray + Write-Host " - MSRecommended: 60 settings (default, max compatibility)" -ForegroundColor DarkGray + Write-Host " - Strict: 78 settings, Paranoid: 86 settings" -ForegroundColor DarkGray Write-Host " - Disable ads, tips, personalization" -ForegroundColor Gray Write-Host " - Remove bloatware (up to 24 apps, if present)" -ForegroundColor Gray Write-Host " - OneDrive hardening (keeps sync functional)" -ForegroundColor Gray diff --git a/Core/Rollback.ps1 b/Core/Rollback.ps1 index db6979d..f51aa1a 100644 --- a/Core/Rollback.ps1 +++ b/Core/Rollback.ps1 @@ -119,7 +119,7 @@ function Update-SessionDisplayName { "SecurityBaseline" = 425 # 335 Registry + 67 Security Template + 23 Audit "ASR" = 19 # 19 ASR Rules "DNS" = 5 # 5 DNS Settings - "Privacy" = 77 # 53 Registry (MSRecommended) + 24 Bloatware + "Privacy" = 78 # 54 Registry (MSRecommended) + 24 Bloatware "AntiAI" = 32 # 32 Registry Policies (15 features) "EdgeHardening" = 24 # 24 Edge Policies (22-23 applied depending on extensions) "AdvancedSecurity" = 50 # 50 Advanced Settings (15 features incl. Discovery Protocols + IPv6) diff --git a/Core/Validator.ps1 b/Core/Validator.ps1 index b02a207..7a6606c 100644 --- a/Core/Validator.ps1 +++ b/Core/Validator.ps1 @@ -121,7 +121,7 @@ function Get-WindowsVersion { # Windows 11 build numbers # 22000 = 21H2, 22621 = 22H2, 22631 = 23H2, 26100 = 24H2, 26200 = 25H2 $isWindows11 = $buildNumber -ge 22000 - $isSupported = $buildNumber -ge 26100 # 24H2 or newer + $isSupported = $buildNumber -ge 26100 # 24H2 or newer required $versionName = switch ($buildNumber) { { $_ -ge 26200 } { "Windows 11 25H2"; break } diff --git a/Docs/FEATURES.md b/Docs/FEATURES.md index c5caff5..b8e4ed5 100644 --- a/Docs/FEATURES.md +++ b/Docs/FEATURES.md @@ -1,7 +1,7 @@ # NoID Privacy - Complete Feature List **Framework Version:** v2.2.0 -**Total Security Settings:** 632 (Paranoid mode) +**Total Security Settings:** 633 (Paranoid mode) **Modules:** 7 (All Production-Ready) **Last Updated:** December 8, 2025 @@ -14,11 +14,11 @@ | **SecurityBaseline** | 425 | ✅ v2.2.0 | Microsoft Security Baseline for Windows 11 v25H2 | | **ASR** | 19 | ✅ v2.2.0 | Attack Surface Reduction rules | | **DNS** | 5 | ✅ v2.2.0 | Secure DNS with DoH encryption | -| **Privacy** | 77 | ✅ v2.2.0 | Telemetry control, OneDrive hardening (Strict: 69 Registry + 2 Services + 6 OneDrive) | +| **Privacy** | 78 | ✅ v2.2.0 | Telemetry control, OneDrive hardening (Strict: 70 Registry + 2 Services + 6 OneDrive) | | **AntiAI** | 32 | ✅ v2.2.0 | AI lockdown (15 features, 32 compliance checks) | | **EdgeHardening** | 24 | ✅ v2.2.0 | Microsoft Edge browser security (24 policies) | | **AdvancedSecurity** | 50 | ✅ v2.2.0 | Advanced hardening beyond MS Baseline (incl. Wireless Display, Discovery Protocols, IPv6) | -| **TOTAL** | **632** | ✅ **100%** | **Complete Framework (Paranoid mode)** | +| **TOTAL** | **633** | ✅ **100%** | **Complete Framework (Paranoid mode)** | --- @@ -150,7 +150,7 @@ --- -## 🔇 Module 4: Privacy (77 Settings) +## 🔇 Module 4: Privacy (78 Settings) **Description:** Windows telemetry control, OneDrive/MS Store telemetry, and bloatware removal @@ -205,13 +205,12 @@ After enrollment, you can optionally re-apply Privacy hardening. Insider builds - MicrosoftStickyNotes, GamingApp, WindowsFeedbackHub - Xbox components (GamingOverlay, IdentityProvider) -**ClassicMethod (24 apps - All other editions):** +**ClassicMethod (up to 24 apps - All other editions):** ``` Microsoft.BingNews, Microsoft.BingWeather -Microsoft.MicrosoftSolitaireCollection, Microsoft.MicrosoftStickyNotes -Microsoft.GamingApp, Microsoft.XboxApp -Microsoft.XboxGamingOverlay, Microsoft.XboxIdentityProvider -Microsoft.XboxSpeechToTextOverlay, Microsoft.Xbox.TCUI +Microsoft.MicrosoftStickyNotes, Microsoft.GamingApp +Microsoft.XboxApp, Microsoft.XboxGamingOverlay +Microsoft.XboxIdentityProvider Microsoft.ZuneMusic, Microsoft.ZuneVideo Microsoft.WindowsFeedbackHub, Microsoft.GetHelp Microsoft.Getstarted, Microsoft.MixedReality.Portal @@ -220,6 +219,10 @@ Clipchamp.Clipchamp, SpotifyAB.SpotifyMusic *CandyCrush*, Disney.*, Facebook.*, TikTok.TikTok ``` +**Skipped for restore safety (not in winget msstore):** +- Microsoft.MicrosoftSolitaireCollection +- Microsoft.XboxSpeechToTextOverlay, Microsoft.Xbox.TCUI + ### Protected Apps (19 kept): - **Core Apps:** WindowsStore, WindowsCalculator, Photos, Paint - **Productivity:** WindowsNotepad, WindowsTerminal, WindowsCamera, ScreenSketch, WindowsSoundRecorder @@ -724,7 +727,7 @@ Some UI elements in Paint and Photos apps may **still be visible** but non-funct NoID Privacy v2.2.0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Total Settings: 632 ✅ +Total Settings: 633 ✅ Modules: 7/7 (100%) ✅ Production Status: Ready ✅ Verification: 100% ✅ diff --git a/Modules/AdvancedSecurity/Public/Invoke-AdvancedSecurity.ps1 b/Modules/AdvancedSecurity/Public/Invoke-AdvancedSecurity.ps1 index bcd4080..b37168e 100644 --- a/Modules/AdvancedSecurity/Public/Invoke-AdvancedSecurity.ps1 +++ b/Modules/AdvancedSecurity/Public/Invoke-AdvancedSecurity.ps1 @@ -1155,7 +1155,7 @@ function Invoke-AdvancedSecurity { Write-Host "" Write-Host "Profile: $SecurityProfile" -ForegroundColor White - Write-Host "Features: $($appliedFeatures.Count)/14 applied" -ForegroundColor $(if ($failedFeatures.Count -eq 0) { 'Green' } else { 'Yellow' }) + Write-Host "Features: $($appliedFeatures.Count)/15 applied" -ForegroundColor $(if ($failedFeatures.Count -eq 0) { 'Green' } else { 'Yellow' }) if ($failedFeatures.Count -gt 0) { Write-Host "Failed: $($failedFeatures.Count)" -ForegroundColor Red diff --git a/Modules/AntiAI/Config/AntiAI-Settings.json b/Modules/AntiAI/Config/AntiAI-Settings.json index bf4e415..ebb1293 100644 --- a/Modules/AntiAI/Config/AntiAI-Settings.json +++ b/Modules/AntiAI/Config/AntiAI-Settings.json @@ -1,9 +1,10 @@ { "ModuleName": "AntiAI", "Version": "1.0.0", - "Description": "Maximum AI deactivation - Disables all 13 Windows 11 AI features using official Microsoft policies", + "Description": "Maximum AI deactivation - Disables 13 of 15 Windows 11 AI features (2 skipped: too invasive)", "Mode": "Maximum Compliance (Enterprise-Grade)", - "TotalFeatures": 13, + "TotalFeaturesDocumented": 15, + "TotalFeaturesImplemented": 13, "TotalPolicies": 32, "Features": { @@ -335,7 +336,8 @@ "Impact": "Copilot disabled at OS level regardless of region setting", "CloudBased": false, "FilePath": "C:\\Windows\\System32\\IntegratedServicesRegionPolicySet.json", - "Note": "Requires TakeOwnership of system file - changes 'Windows CoPilot' policy to disabled" + "Implemented": false, + "NotImplementedReason": "Requires TakeOwnership of protected system file. Too invasive - risks Windows Update failures and system instability. The 4-layer Copilot defense (Feature #3) already provides complete coverage without modifying system files." }, "14_Copilot_Network_Block": { @@ -348,7 +350,8 @@ "www.bing.com/copilot", "edgeservices.bing.com" ], - "Note": "Optional aggressive blocking - may affect legitimate Bing searches" + "Implemented": false, + "NotImplementedReason": "Hosts file modifications break legitimate Bing searches and may cause Edge instability. Also triggers Windows Defender warnings. The registry policies (Features #3, #11, #12) already block Copilot completely without side effects." }, "15_File_Explorer_AI_Actions": { @@ -403,7 +406,9 @@ }, "Summary": { - "TotalAIFeaturesDisabled": "15 features", + "TotalAIFeaturesDocumented": 15, + "TotalAIFeaturesImplemented": 13, + "FeaturesNotImplemented": "2 (Features #13 and #14 - too invasive, see NotImplementedReason)", "TotalPoliciesApplied": 32, "RegistryKeysModified": 32, "URIHandlersBlocked": 2, @@ -414,6 +419,7 @@ "EdgeAIBlocked": "Copilot sidebar, page context, all AI integrations", "DeepLinksBlocked": "ms-copilot: and ms-edge-copilot: URI protocols", "EnterpriseCompliance": "Maximum (Recall app/URI protection, storage limits, export block)", - "MSBestPractice": "Based on OFFICIAL Microsoft registry policies ONLY (no community workarounds)" + "MSBestPractice": "Based on OFFICIAL Microsoft registry policies ONLY (no community workarounds)", + "WhyNot15": "Features #13 (Region Policy Override) and #14 (Hosts File Block) are documented but NOT applied because they modify protected system files. This risks Windows Update failures and triggers Defender warnings. The 13 implemented features already provide complete AI blocking via safe registry policies." } } diff --git a/Modules/AntiAI/Public/Invoke-AntiAI.ps1 b/Modules/AntiAI/Public/Invoke-AntiAI.ps1 index f45fbff..0e6c067 100644 --- a/Modules/AntiAI/Public/Invoke-AntiAI.ps1 +++ b/Modules/AntiAI/Public/Invoke-AntiAI.ps1 @@ -92,7 +92,7 @@ function Invoke-AntiAI { # Initialize result tracking (PSCustomObject for Framework compatibility) $result = [PSCustomObject]@{ Success = $false - TotalFeatures = 15 # 15 Features as documented in AntiAI-Settings.json + TotalFeatures = 15 # 15 documented, 13 applied (2 skipped: Region Policy Override + Hosts File - too invasive) Applied = 0 Failed = 0 Warnings = @() diff --git a/Modules/DNS/Private/Test-DNSConnectivity.ps1 b/Modules/DNS/Private/Test-DNSConnectivity.ps1 index cd8d67c..c285c4b 100644 --- a/Modules/DNS/Private/Test-DNSConnectivity.ps1 +++ b/Modules/DNS/Private/Test-DNSConnectivity.ps1 @@ -5,11 +5,12 @@ function Test-DNSConnectivity { .DESCRIPTION Validates that DNS servers are: - 1. Reachable on port 53 (UDP/TCP) + 1. Reachable on port 53 (UDP/TCP) OR via DoH (HTTPS) 2. Able to resolve domain names 3. Responding with valid answers - Tests both IPv4 and IPv6 connectivity if applicable. + Automatically detects if DoH "Require" mode is active and uses + appropriate test method (HTTPS for DoH, Port 53 for classic DNS). .PARAMETER ServerAddress DNS server IP address to test @@ -27,8 +28,8 @@ function Test-DNSConnectivity { PSCustomObject with test results .NOTES - Uses Test-NetConnection for reachability - Uses Resolve-DnsName for resolution testing + Uses DoH (HTTPS) test if DoH Require mode is already active + Uses classic DNS (Port 53) test otherwise #> [CmdletBinding()] @@ -46,58 +47,160 @@ function Test-DNSConnectivity { CanResolve = $false ResponseTime = $null ErrorMessage = $null + TestMethod = "Classic" # "Classic", "DoH", or "Skipped" } try { Write-Log -Level DEBUG -Message "Testing DNS connectivity: $ServerAddress" -Module $script:ModuleName - # Test 1: Port 53 reachability (fast TCP check without noisy Test-NetConnection output) - Write-Log -Level DEBUG -Message " Testing port 53 reachability (TCP)..." -Module $script:ModuleName - - $portTest = $false + # Check if DoH "Require" mode is already active on the system + # If ANY DNS server has DoH Require, classic DNS (Port 53) is blocked system-wide + $dohConfig = $null + $dohRequireActive = $false + $systemHasDoHRequire = $false + try { - $tcpClient = New-Object System.Net.Sockets.TcpClient - try { - $async = $tcpClient.BeginConnect($ServerAddress, 53, $null, $null) - # Wait up to 3 seconds for TCP connect - if ($async.AsyncWaitHandle.WaitOne(3000, $false) -and $tcpClient.Connected) { - $portTest = $true + # First check: Is there ANY DoH Require config on the system? + $allDohConfigs = Get-DnsClientDohServerAddress -ErrorAction SilentlyContinue + if ($allDohConfigs) { + $requireConfigs = $allDohConfigs | Where-Object { $_.AllowFallbackToUdp -eq $false } + if ($requireConfigs) { + $systemHasDoHRequire = $true + Write-Log -Level DEBUG -Message " System has DoH Require active - classic DNS blocked" -Module $script:ModuleName } } - finally { - $tcpClient.Close() + + # Second check: Does this specific server have DoH config? + $dohConfig = Get-DnsClientDohServerAddress -ServerAddress $ServerAddress -ErrorAction SilentlyContinue + if ($dohConfig -and $dohConfig.DohTemplate) { + $dohRequireActive = $true + $result.TestMethod = "DoH" + Write-Log -Level DEBUG -Message " DoH config found for $ServerAddress - using HTTPS test" -Module $script:ModuleName + } + elseif ($systemHasDoHRequire) { + # This server has no DoH config, but system has DoH Require + # Classic DNS won't work - skip test and assume reachable + $result.Reachable = $true + $result.CanResolve = $true + $result.TestMethod = "Skipped" + Write-Log -Level DEBUG -Message " No DoH config for $ServerAddress but system has DoH Require - skipping test" -Module $script:ModuleName + Write-Log -Level SUCCESS -Message "DNS server $ServerAddress assumed functional (DoH will be configured)" -Module $script:ModuleName + return $result } } catch { - $portTest = $false + # No DoH config found, use classic test } + + if ($dohRequireActive) { + # ===================================================================== + # DoH TEST: Use HTTPS to test connectivity (Port 53 is blocked in Require mode) + # ===================================================================== + Write-Log -Level DEBUG -Message " Testing DoH endpoint via HTTPS..." -Module $script:ModuleName + + $dohTemplate = $dohConfig.DohTemplate + + # Test HTTPS connectivity to DoH endpoint + try { + $resolveStart = Get-Date + + # Build DoH query URL (RFC 8484 - DNS Wireformat over HTTPS GET) + # Simple connectivity test: just check if endpoint responds + $testUrl = $dohTemplate -replace '\{.*\}', '' # Remove any template variables + if ($testUrl -notmatch '\?') { $testUrl += "?name=$TestDomain&type=A" } + + # Use Invoke-WebRequest with short timeout + $response = Invoke-WebRequest -Uri $testUrl ` + -Method GET ` + -Headers @{ "Accept" = "application/dns-json" } ` + -TimeoutSec 5 ` + -UseBasicParsing ` + -ErrorAction Stop + + $resolveEnd = Get-Date + $result.ResponseTime = ($resolveEnd - $resolveStart).TotalMilliseconds + + if ($response.StatusCode -eq 200) { + $result.Reachable = $true + $result.CanResolve = $true + Write-Log -Level DEBUG -Message " DoH endpoint: OK ($([math]::Round($result.ResponseTime, 2))ms)" -Module $script:ModuleName + } + } + catch { + # DoH test failed, but this might be due to JSON format issues + # Try a simple HTTPS connection test to the DoH host + try { + $dohHost = ([System.Uri]$dohTemplate).Host + $tcpClient = New-Object System.Net.Sockets.TcpClient + try { + $async = $tcpClient.BeginConnect($dohHost, 443, $null, $null) + if ($async.AsyncWaitHandle.WaitOne(3000, $false) -and $tcpClient.Connected) { + $result.Reachable = $true + $result.CanResolve = $true # Assume working if HTTPS port is open + Write-Log -Level DEBUG -Message " DoH host $dohHost port 443: Reachable" -Module $script:ModuleName + } + } + finally { + $tcpClient.Close() + } + } + catch { + $result.ErrorMessage = "DoH endpoint not reachable" + Write-Log -Level DEBUG -Message " DoH endpoint: NOT reachable" -Module $script:ModuleName + } + } + } + else { + # ===================================================================== + # CLASSIC TEST: Use Port 53 (DoH not active or in Allow mode) + # ===================================================================== + Write-Log -Level DEBUG -Message " Testing port 53 reachability (TCP)..." -Module $script:ModuleName - if ($portTest) { - $result.Reachable = $true - Write-Log -Level DEBUG -Message " Port 53: Reachable" -Module $script:ModuleName - } - else { - $result.ErrorMessage = "Port 53 not reachable (system may be offline)" - Write-Log -Level DEBUG -Message " Port 53: NOT reachable (system may be offline)" -Module $script:ModuleName - return $result - } - - # Test 2: DNS resolution - Write-Log -Level DEBUG -Message " Testing DNS resolution for $TestDomain..." -Module $script:ModuleName - - $resolveStart = Get-Date - $dnsResult = Resolve-DnsName -Name $TestDomain -Server $ServerAddress -DnsOnly -ErrorAction Stop - $resolveEnd = Get-Date - - $result.ResponseTime = ($resolveEnd - $resolveStart).TotalMilliseconds - - if ($dnsResult -and $dnsResult.Count -gt 0) { - $result.CanResolve = $true - Write-Log -Level DEBUG -Message " DNS resolution: OK ($([math]::Round($result.ResponseTime, 2))ms)" -Module $script:ModuleName - } - else { - $result.ErrorMessage = "No DNS response received" - Write-Log -Level WARNING -Message " DNS resolution: FAILED (no response)" -Module $script:ModuleName + $portTest = $false + try { + $tcpClient = New-Object System.Net.Sockets.TcpClient + try { + $async = $tcpClient.BeginConnect($ServerAddress, 53, $null, $null) + # Wait up to 3 seconds for TCP connect + if ($async.AsyncWaitHandle.WaitOne(3000, $false) -and $tcpClient.Connected) { + $portTest = $true + } + } + finally { + $tcpClient.Close() + } + } + catch { + $portTest = $false + } + + if ($portTest) { + $result.Reachable = $true + Write-Log -Level DEBUG -Message " Port 53: Reachable" -Module $script:ModuleName + } + else { + $result.ErrorMessage = "Port 53 not reachable (system may be offline)" + Write-Log -Level DEBUG -Message " Port 53: NOT reachable (system may be offline)" -Module $script:ModuleName + return $result + } + + # Test 2: DNS resolution (classic) + Write-Log -Level DEBUG -Message " Testing DNS resolution for $TestDomain..." -Module $script:ModuleName + + $resolveStart = Get-Date + $dnsResult = Resolve-DnsName -Name $TestDomain -Server $ServerAddress -DnsOnly -ErrorAction Stop + $resolveEnd = Get-Date + + $result.ResponseTime = ($resolveEnd - $resolveStart).TotalMilliseconds + + if ($dnsResult -and $dnsResult.Count -gt 0) { + $result.CanResolve = $true + Write-Log -Level DEBUG -Message " DNS resolution: OK ($([math]::Round($result.ResponseTime, 2))ms)" -Module $script:ModuleName + } + else { + $result.ErrorMessage = "No DNS response received" + Write-Log -Level WARNING -Message " DNS resolution: FAILED (no response)" -Module $script:ModuleName + } } } catch { @@ -107,7 +210,8 @@ function Test-DNSConnectivity { # Log summary if ($result.Reachable -and $result.CanResolve) { - Write-Log -Level SUCCESS -Message "DNS server $ServerAddress is functional" -Module $script:ModuleName + $methodInfo = if ($result.TestMethod -eq "DoH") { " (via DoH HTTPS)" } else { "" } + Write-Log -Level SUCCESS -Message "DNS server $ServerAddress is functional$methodInfo" -Module $script:ModuleName } else { Write-Log -Level WARNING -Message "DNS server $ServerAddress has issues: $($result.ErrorMessage)" -Module $script:ModuleName diff --git a/Modules/Privacy/Private/Backup-PrivacySettings.ps1 b/Modules/Privacy/Private/Backup-PrivacySettings.ps1 index 1ba31fe..72cdc2e 100644 --- a/Modules/Privacy/Private/Backup-PrivacySettings.ps1 +++ b/Modules/Privacy/Private/Backup-PrivacySettings.ps1 @@ -38,6 +38,7 @@ function Backup-PrivacySettings { "HKLM:\SOFTWARE\Policies\Microsoft\WindowsStore", "HKLM:\SOFTWARE\Policies\Microsoft\Dsh", "HKLM:\SOFTWARE\Policies\Microsoft\FindMyDevice", + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\TextInput", # AllowLinguisticDataCollection (v2.2.0) "HKLM:\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\appDiagnostics", # HKCU User Keys "HKCU:\Software\Policies\Microsoft\Windows\Explorer", diff --git a/Modules/Privacy/Private/Remove-Bloatware.ps1 b/Modules/Privacy/Private/Remove-Bloatware.ps1 index e085a51..1f77efe 100644 --- a/Modules/Privacy/Private/Remove-Bloatware.ps1 +++ b/Modules/Privacy/Private/Remove-Bloatware.ps1 @@ -252,7 +252,7 @@ function Remove-BloatwareClassic { Write-Host " Failed: $failed apps" -ForegroundColor Red } elseif ($removed -eq 0) { - Write-Host " System already clean - no matching bloatware apps found" -ForegroundColor Green + Write-Host " No apps removed (already clean or skipped for restore safety)" -ForegroundColor Green } Write-Host "" diff --git a/Modules/Privacy/Public/Invoke-PrivacyHardening.ps1 b/Modules/Privacy/Public/Invoke-PrivacyHardening.ps1 index 757ff5d..1cf3af6 100644 --- a/Modules/Privacy/Public/Invoke-PrivacyHardening.ps1 +++ b/Modules/Privacy/Public/Invoke-PrivacyHardening.ps1 @@ -286,7 +286,7 @@ function Invoke-PrivacyHardening { Write-Host "============================================" -ForegroundColor Cyan Write-Host "" Write-Host "CAN REMOVE (up to 24 apps, depending on edition and what is installed):" -ForegroundColor Yellow - Write-Host " - Games & Xbox: Solitaire, Xbox apps, Candy Crush, etc." -ForegroundColor Gray + Write-Host " - Games: Candy Crush, casual games, etc." -ForegroundColor Gray Write-Host " - News & Weather: Bing News, Bing Weather, etc." -ForegroundColor Gray Write-Host " - Others: Feedback Hub, Sticky Notes, Get Help, etc." -ForegroundColor Gray Write-Host "" @@ -344,8 +344,8 @@ function Invoke-PrivacyHardening { Write-Log -Level SUCCESS -Message "Bloatware removal completed ($($bloatwareResult.Count) apps)" -Module "Privacy" } else { - Write-Log -Level SUCCESS -Message "Bloatware removal completed - no matching apps found (system already clean)" -Module "Privacy" - Write-Host "`n System already clean - no matching bloatware apps found" -ForegroundColor Green + Write-Log -Level SUCCESS -Message "Bloatware removal completed - no apps removed (already clean or skipped)" -Module "Privacy" + Write-Host "`n No apps removed (already clean or skipped for restore safety)" -ForegroundColor Green } # Save list of removed apps to backup folder for user reference @@ -480,11 +480,10 @@ function Invoke-PrivacyHardening { Write-Log -Level SUCCESS -Message "Privacy hardening completed successfully in $Mode mode" -Module "Privacy" - # GUI parsing marker for settings count (dynamically calculated) - $registryCount = if ($verifyResult -and $verifyResult.TotalChecks) { $verifyResult.TotalChecks } else { 0 } - $bloatwareCount = if ($bloatwareResult -and $bloatwareResult.Count) { $bloatwareResult.Count } else { 0 } - $totalApplied = $registryCount + $bloatwareCount - Write-Log -Level SUCCESS -Message "Applied $totalApplied settings" -Module "Privacy" + # GUI parsing marker for settings count (registry + services only, NOT bloatware) + # Bloatware is counted separately and shown in its own summary + $settingsCount = if ($verifyResult -and $verifyResult.TotalChecks) { $verifyResult.TotalChecks } else { 0 } + Write-Log -Level SUCCESS -Message "Applied $settingsCount settings" -Module "Privacy" # Return result object for consistency with other modules return [PSCustomObject]@{ diff --git a/NoIDPrivacy-Interactive.ps1 b/NoIDPrivacy-Interactive.ps1 index 8c5bd3c..cbf6211 100644 --- a/NoIDPrivacy-Interactive.ps1 +++ b/NoIDPrivacy-Interactive.ps1 @@ -472,16 +472,50 @@ function Show-ModuleMenu { Write-Banner Write-Header "SELECT MODULES TO APPLY" + # Module definitions with descriptions + $moduleDefinitions = @{ + "SecurityBaseline" = "Microsoft Security Baseline (425 settings)" + "ASR" = "Attack Surface Reduction (19 rules)" + "DNS" = "Secure DNS with DoH (Quad9/Cloudflare/AdGuard)" + "Privacy" = "Telemetry & Privacy hardening (3 modes)" + "AntiAI" = "Disable Windows AI features (15 features, 32 policies)" + "EdgeHardening" = "Secure Microsoft Edge browser (24 policies)" + "AdvancedSecurity" = "Beyond MS Baseline (50 settings, 15 features)" + } + + # Try to load config.json to check module status + $configPath = Join-Path $PSScriptRoot "config.json" + $config = $null + if (Test-Path $configPath) { + try { + $config = Get-Content $configPath -Raw | ConvertFrom-Json + } + catch { + # If config fails to load, all modules default to enabled + } + } + + # Build module list with status from config $modules = @( - [PSCustomObject]@{ Key = "1"; Name = "SecurityBaseline"; Description = "Microsoft Security Baseline (425 settings)"; Enabled = $true } - [PSCustomObject]@{ Key = "2"; Name = "ASR"; Description = "Attack Surface Reduction (19 rules)"; Enabled = $true } - [PSCustomObject]@{ Key = "3"; Name = "DNS"; Description = "Secure DNS with DoH (Quad9/Cloudflare/AdGuard)"; Enabled = $true } - [PSCustomObject]@{ Key = "4"; Name = "Privacy"; Description = "Telemetry & Privacy hardening (3 modes)"; Enabled = $true } - [PSCustomObject]@{ Key = "5"; Name = "AntiAI"; Description = "Disable Windows AI features (15 features, 32 policies)"; Enabled = $true } - [PSCustomObject]@{ Key = "6"; Name = "EdgeHardening"; Description = "Secure Microsoft Edge browser (24 policies)"; Enabled = $true } - [PSCustomObject]@{ Key = "7"; Name = "AdvancedSecurity"; Description = "15 security features (50 settings): RDP/Credentials/Ports/TLS/WPAD/PSv2/SRP/WinUpdate/WirelessDisplay/Discovery/IPv6"; Enabled = $true } + [PSCustomObject]@{ Key = "1"; Name = "SecurityBaseline"; Description = $moduleDefinitions["SecurityBaseline"]; Enabled = $true } + [PSCustomObject]@{ Key = "2"; Name = "ASR"; Description = $moduleDefinitions["ASR"]; Enabled = $true } + [PSCustomObject]@{ Key = "3"; Name = "DNS"; Description = $moduleDefinitions["DNS"]; Enabled = $true } + [PSCustomObject]@{ Key = "4"; Name = "Privacy"; Description = $moduleDefinitions["Privacy"]; Enabled = $true } + [PSCustomObject]@{ Key = "5"; Name = "AntiAI"; Description = $moduleDefinitions["AntiAI"]; Enabled = $true } + [PSCustomObject]@{ Key = "6"; Name = "EdgeHardening"; Description = $moduleDefinitions["EdgeHardening"]; Enabled = $true } + [PSCustomObject]@{ Key = "7"; Name = "AdvancedSecurity"; Description = $moduleDefinitions["AdvancedSecurity"]; Enabled = $true } ) + # Override enabled status from config.json if available + if ($config -and $config.modules) { + foreach ($module in $modules) { + $configModule = $config.modules.PSObject.Properties[$module.Name] + if ($configModule -and $configModule.Value.PSObject.Properties['enabled']) { + $module.Enabled = [bool]$configModule.Value.enabled + } + } + } + foreach ($module in $modules) { if ($module.Enabled) { Write-ColorText " [$($module.Key)]" -Color Green -NoNewline @@ -609,8 +643,9 @@ function Invoke-HardeningWorkflow { Write-ColorText "FAILED [-]" -Color Red } - Write-ColorText " Modules Applied: " -Color Gray -NoNewline + Write-ColorText " Modules Selected: " -Color Gray -NoNewline Write-ColorText "$($modulesToRun.Count)" -Color White + Write-ColorText " (Check output above for actual results per module)" -Color DarkGray Write-Host "" @@ -619,7 +654,7 @@ function Invoke-HardeningWorkflow { } else { Write-ColorText " Some modules had warnings or were skipped. Check details above." -Color Yellow - Write-ColorText " Most security settings were still applied successfully." -Color White + Write-ColorText " Review the log file for complete details." -Color White } Write-Host "" @@ -885,11 +920,15 @@ try { exit 1 } - # Load framework + # Load Framework (required for core functions like Test-IsAdmin used by modules) $frameworkPath = Join-Path $PSScriptRoot "Core\Framework.ps1" if (Test-Path $frameworkPath) { . $frameworkPath } + else { + Write-Host "[ERROR] Framework.ps1 not found!" -ForegroundColor Red + exit 1 + } while ($true) { # Clear before each main menu redraw diff --git a/NoIDPrivacy.ps1 b/NoIDPrivacy.ps1 index 93860c3..363b945 100644 --- a/NoIDPrivacy.ps1 +++ b/NoIDPrivacy.ps1 @@ -244,7 +244,7 @@ if (-not $Module) { $verifyScript = Join-Path $script:RootPath "Tools\Verify-Complete-Hardening.ps1" if (Test-Path $verifyScript) { # Discard return value so that 'True' / 'False' is not printed to console - $null = & $verifyScript -Detailed + $null = & $verifyScript } else { Write-Host "ERROR: Verification script not found" -ForegroundColor Red @@ -256,17 +256,72 @@ if (-not $Module) { exit 0 } "R" { - # Restore from backup + # Restore from backup - Interactive session selection from disk Write-Host "" - Write-Host "Loading backup system..." -ForegroundColor Cyan + Write-Host "========================================" -ForegroundColor Cyan + Write-Host " RESTORE FROM BACKUP" -ForegroundColor Cyan + Write-Host "========================================" -ForegroundColor Cyan Write-Host "" - # Call Restore-AllBackups function from Rollback.ps1 - if (Get-Command Restore-AllBackups -ErrorAction SilentlyContinue) { - Restore-AllBackups + # Get all backup sessions from disk + $sessions = Get-BackupSessions + + if ($sessions.Count -eq 0) { + Write-Host "No backup sessions found." -ForegroundColor Yellow + Write-Host "Backups are created when you apply hardening modules." -ForegroundColor Gray + Write-Host "" + Write-Host "Press any key to continue..." -ForegroundColor Gray + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit 0 + } + + Write-Host "Available backup sessions:" -ForegroundColor White + Write-Host "" + + $i = 1 + foreach ($session in $sessions) { + $moduleNames = ($session.Modules | ForEach-Object { $_.name }) -join ", " + $dateStr = $session.Timestamp.ToString("yyyy-MM-dd HH:mm:ss") + + Write-Host " [$i] $dateStr" -ForegroundColor Green + Write-Host " Modules: $moduleNames" -ForegroundColor Gray + Write-Host " Items: $($session.TotalItems)" -ForegroundColor Gray + Write-Host "" + $i++ + } + + Write-Host " [0] Cancel and return" -ForegroundColor Red + Write-Host "" + + $selection = Read-Host "Select session to restore [1-$($sessions.Count), 0=Cancel]" + + if ($selection -eq "0" -or [string]::IsNullOrWhiteSpace($selection)) { + Write-Host "Restore cancelled." -ForegroundColor Yellow + exit 0 + } + + $selIndex = [int]$selection - 1 + if ($selIndex -lt 0 -or $selIndex -ge $sessions.Count) { + Write-Host "Invalid selection." -ForegroundColor Red + exit 1 + } + + $selectedSession = $sessions[$selIndex] + + Write-Host "" + Write-Host "Restoring session: $($selectedSession.SessionId)" -ForegroundColor Cyan + Write-Host "" + + # Call Restore-Session with the session path + $success = Restore-Session -SessionPath $selectedSession.FolderPath + + if ($success) { + Write-Host "" + Write-Host "Restore completed successfully!" -ForegroundColor Green } else { - Write-Host "ERROR: Restore function not available" -ForegroundColor Red + Write-Host "" + Write-Host "Restore completed with some errors. Check logs for details." -ForegroundColor Yellow } Write-Host "" diff --git a/README.md b/README.md index 440b761..d86a047 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ - ALLOW mode (optional): fallback allowed for VPN/mobile/enterprise networks - IPv4 + IPv6 dual-stack support -### 🔒 Privacy Hardening (77 Settings) +### 🔒 Privacy Hardening (78 Settings) **3 Operating Modes** - **MSRecommended** (Default) MS-supported, max compatibility @@ -358,18 +358,18 @@ cd noid-privacy ### Verification ```powershell -# Full verification (632 checks with Paranoid mode) +# Full verification (633 checks with Paranoid mode) .\Tools\Verify-Complete-Hardening.ps1 # Expected output (all modules enabled, Paranoid mode): # SecurityBaseline: 425/425 verified # ASR: 19/19 verified # DNS: 5/5 verified -# Privacy: 77/77 verified +# Privacy: 78/78 verified # AntiAI: 32/32 verified # EdgeHardening: 24/24 verified # AdvancedSecurity: 50/50 verified -# Total: 632/632 (100%) +# Total: 633/633 (100%) ``` ### Restore @@ -392,11 +392,11 @@ cd noid-privacy | **SecurityBaseline** | 425 | Microsoft Security Baseline 25H2 | v2.2.0 | | **ASR** | 19 | Attack Surface Reduction Rules | v2.2.0 | | **DNS** | 5 | Secure DNS with DoH encryption | v2.2.0 | -| **Privacy** | 77 | Telemetry, Bloatware, OneDrive hardening (Strict) | v2.2.0 | +| **Privacy** | 78 | Telemetry, Bloatware, OneDrive hardening (Strict) | v2.2.0 | | **AntiAI** | 32 | AI lockdown (15 features, 32 compliance checks) | v2.2.0 | | **EdgeHardening** | 24 | Microsoft Edge security (24 policies) | v2.2.0 | | **AdvancedSecurity** | 50 | Beyond MS Baseline (SRP, Legacy protocols, Wireless Display, Discovery Protocols, IPv6) | v2.2.0 | -| **TOTAL** | **632** | **Complete Framework (Paranoid mode)** | **Production** | +| **TOTAL** | **633** | **Complete Framework (Paranoid mode)** | **Production** | **Release Highlights:** @@ -447,7 +447,7 @@ cd noid-privacy - Use [Microsoft Security Baselines](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/security-compliance-toolkit-10) with Group Policy instead **Windows 10 or Older** -- This tool is designed for Windows 11 (24H2/25H2 recommended, 23H2 compatible) +- This tool is designed for Windows 11 24H2 or newer **Legacy Software Dependencies** - If you rely on unsafe SMB1/RPC/DCOM @@ -465,7 +465,7 @@ NoID Privacy is designed for modern, officially supported Windows 11 systems. If your PC can run Windows 11 according to Microsoft's **official requirements**, it is compatible with NoID Privacy: -- **OS:** Windows 11 24H2/25H2 recommended (23H2 compatible) +- **OS:** Windows 11 24H2 or newer (25H2 fully tested) - **CPU:** Any CPU on Microsoft's Windows 11 support list (Intel 8th Gen / AMD Ryzen 2000+) - **Firmware:** UEFI with **Secure Boot** enabled - **TPM:** 2.0 (required for BitLocker, Credential Guard, VBS) @@ -480,7 +480,7 @@ If your PC can run Windows 11 according to Microsoft's **official requirements** |------------|--------| | Windows 11 25H2 (Build 26200+) | **Fully Tested** | | Windows 11 24H2 (Build 26100+) | Compatible | -| Windows 11 23H2 (Build 22631+) | Some features N/A | +| Windows 11 23H2 or older | ❌ Not Supported | ### Legacy Devices & Protocols @@ -525,8 +525,8 @@ This is the **recommended setup** – just install Windows 11, keep Defender act | Your Setup | What Happens | Coverage | |------------|--------------|----------| -| **Defender Active** | All modules applied | **632 settings** (100%) | -| **3rd-Party AV** (Kaspersky, Norton, Bitdefender, etc.) | ASR skipped, all other modules applied | **613 settings** (~97%) | +| **Defender Active** | All modules applied | **633 settings** (100%) | +| **3rd-Party AV** (Kaspersky, Norton, Bitdefender, etc.) | ASR skipped, all other modules applied | **614 settings** (~97%) | **Why?** ASR (Attack Surface Reduction) rules are a **Microsoft Defender exclusive feature**. Third-party antivirus products provide their own equivalent protection. NoID Privacy detects this and gracefully skips ASR while applying everything else. diff --git a/Start-NoIDPrivacy.bat b/Start-NoIDPrivacy.bat index 207068e..1bfae35 100644 --- a/Start-NoIDPrivacy.bat +++ b/Start-NoIDPrivacy.bat @@ -17,8 +17,8 @@ title NoID Privacy v2.2.0 REM Get the directory where this batch file is located set "SCRIPT_DIR=%~dp0" -REM Check if already running as administrator -net session >nul 2>&1 +REM Check if already running as administrator (robust method that works even if Server service is disabled) +>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system" if %errorLevel% == 0 ( REM Already admin, run PowerShell script directly echo Running NoID Privacy Interactive Menu with Administrator privileges... diff --git a/Tools/Verify-Complete-Hardening.ps1 b/Tools/Verify-Complete-Hardening.ps1 index d075ab8..323317b 100644 --- a/Tools/Verify-Complete-Hardening.ps1 +++ b/Tools/Verify-Complete-Hardening.ps1 @@ -16,7 +16,7 @@ NOTE: This shows the TRUTH about what is configured in your system. - Total: 632 settings (Paranoid mode) + Total: 633 settings (Paranoid mode) SecurityBaseline: 425 (335 Registry + 67 SecTemplate + 23 Audit) ASR: 19 DNS: 5 @@ -48,7 +48,7 @@ $EXPECTED_ASR_COUNT = 19 $EXPECTED_EDGE_COUNT = 24 # 24 total Edge policies from EdgePolicies.json $EXPECTED_ADVANCED_COUNT = 50 # 50 total AdvancedSecurity policy checks (incl. Discovery Protocols WSD/mDNS + IPv6) $EXPECTED_DNS_COUNT = 5 -$EXPECTED_PRIVACY_COUNT = 77 # 53 registry from Privacy-MSRecommended.json + 24 bloatware apps +$EXPECTED_PRIVACY_COUNT = 78 # 54 registry from Privacy-MSRecommended.json + 24 bloatware apps $EXPECTED_ANTIAI_COUNT = 32 # 32 AntiAI registry policy checks (15 features) Write-Host "" @@ -380,7 +380,6 @@ try { else { # Check if this is a DELETE operation (**del..., **delvals) # For DELETE operations, "Value not found" means SUCCESS (value was deleted or never existed) - $registryCounter++ if ($setting.ValueName -like "**del*") { $results.Verified++ $registryPassed += [PSCustomObject]@{ @@ -405,7 +404,6 @@ try { else { # Check if this is a DELETE operation (**del..., **delvals) # For DELETE operations, "Key not found" means SUCCESS (key was deleted or never existed) - $registryCounter++ if ($setting.ValueName -like "**del*") { $results.Verified++ $registryPassed += [PSCustomObject]@{ @@ -475,7 +473,6 @@ try { else { # Check if this is a DELETE operation (**del..., **delvals) # For DELETE operations, "Value not found" means SUCCESS (value was deleted or never existed) - $registryCounter++ if ($setting.ValueName -like "**del*") { $results.Verified++ $registryPassed += [PSCustomObject]@{ @@ -500,7 +497,6 @@ try { else { # Check if this is a DELETE operation (**del..., **delvals) # For DELETE operations, "Key not found" means SUCCESS (key was deleted or never existed) - $registryCounter++ if ($setting.ValueName -like "**del*") { $results.Verified++ $registryPassed += [PSCustomObject]@{