From 1ef1a1d264b131d9e18c17d3baa6074ff87e2bc8 Mon Sep 17 00:00:00 2001 From: Violet Hansen Date: Sat, 21 Dec 2024 07:38:05 +0200 Subject: [PATCH 1/4] Switch to file-scoped namespace style Switch to file-scoped namespace style --- .../BitLocker-AddKeyProtectors.cs | 6 +- .../CimInstances/BitLocker-DataCollection.cs | 5 +- .../C#/CimInstances/BitLocker-Disable.cs | 5 +- .../C#/CimInstances/BitLocker-Enable.cs | 6 +- .../BitLocker-EnableBitLockerAutoUnlock.cs | 5 +- .../BitLocker-EnableKeyProtectors.cs | 5 +- .../BitLocker-RemoveKeyProtectors.cs | 5 +- .../C#/CimInstances/ConfigDefenderHelper.cs | 5 +- .../C#/CimInstances/FirewallHelper.cs | 5 +- .../Main files/C#/CimInstances/MDM.cs | 5 +- .../C#/CimInstances/MpPreferenceHelper.cs | 5 +- .../C#/CimInstances/NetConnectionProfiles.cs | 5 +- .../C#/CimInstances/TaskSchedulerHelper.cs | 5 +- .../C#/Confirm Methods/InvokeConfirmation.cs | 5 +- .../Confirm Methods/SYSTEMScheduledTasks.cs | 5 +- .../Main files/C#/GUI/ASRRules/Variables.cs | 5 +- .../Main files/C#/GUI/ASRRules/View.cs | 5 +- .../Main files/C#/GUI/BitLocker/Variables.cs | 5 +- .../Main files/C#/GUI/BitLocker/View.cs | 5 +- .../Main files/C#/GUI/Confirm/SecOp.cs | 5 +- .../Main files/C#/GUI/Confirm/Variables.cs | 5 +- .../Main files/C#/GUI/Confirm/View.cs | 5 +- .../Main files/C#/GUI/Exclusions/Variables.cs | 5 +- .../Main files/C#/GUI/Exclusions/View.cs | 5 +- .../Main files/C#/GUI/GUIBootStrapper.cs | 5 +- .../Main files/C#/GUI/Log/Variables.cs | 5 +- .../Main files/C#/GUI/Log/View.cs | 5 +- .../Main files/C#/GUI/Main/GUI.cs | 5 +- .../Main files/C#/GUI/Main/Variables.cs | 5 +- .../C#/GUI/Protection/EventHandlers.cs | 1501 ++++++++--------- .../GUI/Protection/Miscellaneous methods.cs | 5 +- .../Main files/C#/GUI/Protection/Variables.cs | 5 +- .../Main files/C#/GUI/Protection/View.cs | 5 +- .../Main files/C#/GUI/Unprotect/Variables.cs | 5 +- .../Main files/C#/GUI/Unprotect/View.cs | 5 +- .../Main files/C#/Others/ActivityTracker.cs | 5 +- .../Main files/C#/Others/AsyncDownloader.cs | 5 +- .../C#/Others/AttackSurfaceReductionIntel.cs | 5 +- .../Main files/C#/Others/AuditPolicyHelper.cs | 5 +- .../Main files/C#/Others/CSVImporter.cs | 5 +- .../Main files/C#/Others/Categoriex.cs | 5 +- .../C#/Others/CategoryProcessing.cs | 5 +- .../C#/Others/ChangePSConsoleTitle.cs | 5 +- .../Main files/C#/Others/CiToolRunner.cs | 5 +- .../C#/Others/ConditionalResultAdd.cs | 5 +- .../Others/ConfirmSystemComplianceMethods.cs | 5 +- .../Others/ControlledFolderAccessHandler.cs | 5 +- .../Main files/C#/Others/DialogMsgHelper.cs | 5 +- .../Main files/C#/Others/EccCurveComparer.cs | 5 +- .../C#/Others/ExportSecurityPolicy.cs | 5 +- .../C#/Others/ForceRelocateImagesForFiles.cs | 5 +- .../Main files/C#/Others/GetLocalUser.cs | 5 +- .../Main files/C#/Others/GetMDMResultValue.cs | 5 +- .../C#/Others/GetOneDriveDirectories.cs | 5 +- .../Main files/C#/Others/GitExesFinder.cs | 5 +- .../C#/Others/GitHubDesktopFinder.cs | 5 +- .../Main files/C#/Others/GlobalVars.cs | 5 +- .../Main files/C#/Others/HResultHelper.cs | 5 +- .../Main files/C#/Others/HashtableChecker.cs | 5 +- .../Main files/C#/Others/HelperMethods.cs | 5 +- .../Main files/C#/Others/IniFileConverter.cs | 5 +- .../Main files/C#/Others/Initializer.cs | 5 +- .../Main files/C#/Others/JsonToHashtable.cs | 5 +- .../Main files/C#/Others/LGPORunner.cs | 5 +- .../Main files/C#/Others/LocalGroupMember.cs | 5 +- .../Main files/C#/Others/Logger.cs | 5 +- .../Main files/C#/Others/MDMClassProcessor.cs | 5 +- .../Main files/C#/Others/Miscellaneous.cs | 5 +- .../C#/Others/MitigationPolicyProcessor.cs | 5 +- .../C#/Others/PowerShellExecutor.cs | 5 +- .../Others/ProcessMitigationsApplication.cs | 5 +- .../C#/Others/ProcessMitigationsParser.cs | 5 +- .../Main files/C#/Others/PropertyHelper.cs | 5 +- .../Main files/C#/Others/RegistryEditor.cs | 5 +- .../Main files/C#/Others/RunCommand.cs | 5 +- .../Main files/C#/Others/SSHConfigurations.cs | 5 +- .../C#/Others/SecureStringComparer.cs | 5 +- .../C#/Others/SecuriryPolicyProcessor.cs | 5 +- .../C#/Others/SecurityPolicyCsvProcessor.cs | 5 +- .../Main files/C#/Others/SneakAndPeek.cs | 5 +- .../C#/Others/SystemInfoNativeMethods.cs | 5 +- .../Main files/C#/Others/ToastNotification.cs | 5 +- .../Main files/C#/Others/UserPrivCheck.cs | 5 +- .../C#/Others/VolumeWritabilityCheck.cs | 5 +- .../Main files/C#/Others/WinIdentityUser.cs | 5 +- .../C#/Others/WindowsFeatureChecker.cs | 5 +- .../AttackSurfaceReductionRules.cs | 5 +- .../C#/Protect Methods/BitLockerSettings.cs | 5 +- .../CertificateCheckingCommands.cs | 5 +- .../C#/Protect Methods/CountryIPBlocking.cs | 5 +- .../Protect Methods/CountryIPBlocking_OFAC.cs | 5 +- .../DangerousScriptHostsBlocking.cs | 5 +- .../C#/Protect Methods/DeviceGuard.cs | 5 +- .../DeviceGuard_MandatoryVBS.cs | 5 +- .../DownloadsDefenseMeasures.cs | 5 +- .../EdgeBrowserConfigurations.cs | 5 +- .../C#/Protect Methods/LockScreen.cs | 5 +- .../Protect Methods/LockScreen_CtrlAltDel.cs | 5 +- .../LockScreen_LastSignedIn.cs | 5 +- .../MSFTDefender_BetaChannels.cs | 5 +- .../MSFTDefender_EnableDiagData.cs | 5 +- .../C#/Protect Methods/MSFTDefender_SAC.cs | 5 +- .../MSFTDefender_ScheduledTask.cs | 5 +- .../Microsoft365AppsSecurityBaselines.cs | 5 +- .../C#/Protect Methods/MicrosoftDefender.cs | 5 +- .../MicrosoftSecurityBaselines.cs | 5 +- .../MiscellaneousConfigurations.cs | 5 +- ...ellaneousConfigurations_LongPathSupport.cs | 5 +- ...neousConfigurations_StrongKeyProtection.cs | 5 +- ...ousConfigurations_WindowsProtectedPrint.cs | 5 +- .../C#/Protect Methods/NonAdminCommands.cs | 5 +- .../OptionalWindowsFeatures.cs | 5 +- .../Protect Methods/SecBaselines_Overrides.cs | 5 +- .../C#/Protect Methods/TLSSecurity.cs | 5 +- .../C#/Protect Methods/UAC_NoFastSwitching.cs | 5 +- .../Protect Methods/UAC_OnlyElevateSigned.cs | 5 +- .../C#/Protect Methods/UserAccountControl.cs | 5 +- .../C#/Protect Methods/WindowsFirewall.cs | 5 +- .../C#/Protect Methods/WindowsNetworking.cs | 5 +- .../WindowsNetworking_BlockNTLM.cs | 5 +- .../WindowsUpdateConfigurations.cs | 5 +- .../Main files/C#/Types/CiPolicyInfo.cs | 5 +- .../Main files/C#/Types/CustomExceptions.cs | 7 +- .../Types/DefenderPlatformUpdatesChannels.cs | 5 +- .../C#/Types/EccCurveComparisonResult.cs | 5 +- .../C#/Types/IndividualResultClass.cs | 5 +- .../Main files/C#/Types/MDMResult.cs | 5 +- .../UnprotectWindowsSecurity.cs | 5 +- .../C#/Windows APIs/FirmwareType.cs | 5 +- .../Main files/C#/Windows APIs/TPM.cs | 5 +- Harden-Windows-Security Module/Program.cs | 5 +- 131 files changed, 1011 insertions(+), 1144 deletions(-) diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-AddKeyProtectors.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-AddKeyProtectors.cs index a77a40046..291c694e2 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-AddKeyProtectors.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-AddKeyProtectors.cs @@ -4,8 +4,8 @@ using System.Management; using System.Security.Principal; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static partial class BitLocker { @@ -647,5 +647,3 @@ internal static void AddSidProtector(string DriveLetter, string SID, bool Servic } } - -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-DataCollection.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-DataCollection.cs index af7238eee..c387a931e 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-DataCollection.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-DataCollection.cs @@ -12,8 +12,8 @@ /// $output /// $output.KeyProtector -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal partial class BitLocker { @@ -485,4 +485,3 @@ internal static List GetAllEncryptedVolumeInfo(bool OnlyNonOSDr return volumes; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Disable.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Disable.cs index 10e030a9a..d7d9fe310 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Disable.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Disable.cs @@ -2,8 +2,8 @@ using System.Globalization; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal partial class BitLocker { @@ -122,4 +122,3 @@ internal static void Disable(string DriveLetter) } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Enable.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Enable.cs index 7762bc590..0b61240ca 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Enable.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Enable.cs @@ -5,8 +5,8 @@ using System.Management; using System.Windows; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal partial class BitLocker { @@ -699,5 +699,3 @@ internal static void Enable(string DriveLetter, string? Password, bool FreePlusU } } - -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableBitLockerAutoUnlock.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableBitLockerAutoUnlock.cs index d82e95338..e2d58d89b 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableBitLockerAutoUnlock.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableBitLockerAutoUnlock.cs @@ -2,8 +2,8 @@ using System.Globalization; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal partial class BitLocker { /// @@ -121,4 +121,3 @@ internal static void EnableBitLockerAutoUnlock(string DriveLetter) } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableKeyProtectors.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableKeyProtectors.cs index 8a00ecede..42d0fac92 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableKeyProtectors.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableKeyProtectors.cs @@ -2,8 +2,8 @@ using System.Globalization; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal partial class BitLocker { /// @@ -48,4 +48,3 @@ internal static void EnableKeyProtectors(string DriveLetter) #endregion } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-RemoveKeyProtectors.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-RemoveKeyProtectors.cs index 20487dfa9..aba78b701 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-RemoveKeyProtectors.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-RemoveKeyProtectors.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal partial class BitLocker { @@ -123,4 +123,3 @@ internal static void RemoveKeyProtector(string DriveLetter, string KeyProtectorI } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/ConfigDefenderHelper.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/ConfigDefenderHelper.cs index 24cfa0c36..5a716b712 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/ConfigDefenderHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/ConfigDefenderHelper.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class ConfigDefenderHelper { // Get the MpComputerStatus from the MSFT_MpComputerStatus WMI class and returns it as a dynamic object @@ -164,4 +164,3 @@ internal static void ManageMpPreference(string preferenceName, T preferenceVa } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/FirewallHelper.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/FirewallHelper.cs index 1d1b99a27..cefcb7768 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/FirewallHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/FirewallHelper.cs @@ -6,8 +6,8 @@ using System.Management; using System.Net.Http; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class FirewallHelper { // Method to get firewall rules based on RuleGroup and Direction @@ -299,4 +299,3 @@ void CreateFirewallRule(CimSession cimSession, string name, string[] ipList, boo } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/MDM.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/MDM.cs index c45674760..bb8f3ee7b 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/MDM.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/MDM.cs @@ -7,8 +7,8 @@ /// root\cimv2\mdm is the namespace for CSPs /// https://learn.microsoft.com/en-us/windows/win32/wmisdk/common-information-model -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// Class that deals with MDM/CSPs/Intune /// @@ -180,4 +180,3 @@ private sealed class MdmRecord internal string? Authorized { get; set; } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/MpPreferenceHelper.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/MpPreferenceHelper.cs index 9e262f6fb..4badbbf68 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/MpPreferenceHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/MpPreferenceHelper.cs @@ -5,8 +5,8 @@ using System.Linq; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class MpPreferenceHelper { // Get the MpPreference from the MSFT_MpPreference WMI class and returns it as a dynamic object @@ -94,4 +94,3 @@ private static TimeSpan ConvertDmtfToTimeSpan(string dmtfTime) return TimeSpan.Zero; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/NetConnectionProfiles.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/NetConnectionProfiles.cs index cfe3b33b7..045115d36 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/NetConnectionProfiles.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/NetConnectionProfiles.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class NetConnectionProfiles { /// @@ -147,4 +147,3 @@ public enum IPv6Connectivity : uint Internet = 4 } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/TaskSchedulerHelper.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/TaskSchedulerHelper.cs index 77227c134..d1cbada76 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/TaskSchedulerHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/TaskSchedulerHelper.cs @@ -4,8 +4,8 @@ using System.Management; using System.Runtime.InteropServices; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class TaskSchedulerHelper { @@ -298,4 +298,3 @@ private static void DeleteTaskFolder(string FolderName) } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Confirm Methods/InvokeConfirmation.cs b/Harden-Windows-Security Module/Main files/C#/Confirm Methods/InvokeConfirmation.cs index 27879fae2..e6291b23f 100644 --- a/Harden-Windows-Security Module/Main files/C#/Confirm Methods/InvokeConfirmation.cs +++ b/Harden-Windows-Security Module/Main files/C#/Confirm Methods/InvokeConfirmation.cs @@ -3,8 +3,8 @@ using System.IO; using System.Threading; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class InvokeConfirmation { /// @@ -71,4 +71,3 @@ public static void Invoke(string[] Categories) } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Confirm Methods/SYSTEMScheduledTasks.cs b/Harden-Windows-Security Module/Main files/C#/Confirm Methods/SYSTEMScheduledTasks.cs index 944ab284f..f55e7ebb0 100644 --- a/Harden-Windows-Security Module/Main files/C#/Confirm Methods/SYSTEMScheduledTasks.cs +++ b/Harden-Windows-Security Module/Main files/C#/Confirm Methods/SYSTEMScheduledTasks.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class SYSTEMScheduledTasks { internal static void Invoke() @@ -22,4 +22,3 @@ internal static void Invoke() _ = PowerShellExecutor.ExecuteScript(script); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/Variables.cs b/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/Variables.cs index 402937ffb..75b748403 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/Variables.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/Variables.cs @@ -1,11 +1,10 @@ using System.Windows.Controls; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class GUIASRRules { internal static UserControl? View; internal static Grid? ParentGrid; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/View.cs b/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/View.cs index 4065dbfaf..9b7c9d326 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/View.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/View.cs @@ -8,8 +8,8 @@ using System.Windows.Markup; using System.Windows.Media.Imaging; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class GUIMain { @@ -404,4 +404,3 @@ await System.Threading.Tasks.Task.Run(() => } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/BitLocker/Variables.cs b/Harden-Windows-Security Module/Main files/C#/GUI/BitLocker/Variables.cs index 1270e2b0d..640c703d7 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/BitLocker/Variables.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/BitLocker/Variables.cs @@ -5,8 +5,8 @@ using System.Windows.Controls; using static HardenWindowsSecurity.BitLocker; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class GUIBitLocker { internal static UserControl? View; @@ -160,4 +160,3 @@ public static void CreateBitLockerVolumeViewModel(bool ExportToFile) } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/BitLocker/View.cs b/Harden-Windows-Security Module/Main files/C#/GUI/BitLocker/View.cs index 6a95ba1ea..cb9ef1000 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/BitLocker/View.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/BitLocker/View.cs @@ -9,8 +9,8 @@ using System.Windows.Markup; using System.Windows.Media.Imaging; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public partial class GUIMain { @@ -588,4 +588,3 @@ await Task.Run(() => } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/SecOp.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/SecOp.cs index e7cf9e263..6bc7fbaaf 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/SecOp.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/SecOp.cs @@ -4,8 +4,8 @@ using System.Windows.Media; using System.Windows.Media.Imaging; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + // Define the SecOp class, representing an individual security option in the data grid public class SecOp : INotifyPropertyChanged @@ -88,4 +88,3 @@ static private BitmapImage LoadImage(string fileName) return new BitmapImage(new Uri(imagePath, UriKind.Absolute)); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/Variables.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/Variables.cs index 0954bd7b9..669ba781e 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/Variables.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/Variables.cs @@ -1,11 +1,10 @@ using System.Windows.Controls; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class GUIConfirmSystemCompliance { internal static DataGrid? SecOpsDataGrid; internal static UserControl? View; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/View.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/View.cs index 176b3dfdb..c0bb6eea4 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/View.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Confirm/View.cs @@ -10,8 +10,8 @@ #nullable disable -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public partial class GUIMain { @@ -426,4 +426,3 @@ private void LoadMembers() } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Exclusions/Variables.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Exclusions/Variables.cs index e1c234148..a817c2f29 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Exclusions/Variables.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Exclusions/Variables.cs @@ -1,7 +1,7 @@ using System.Windows.Controls; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class GUIExclusions { internal static UserControl? View; @@ -16,4 +16,3 @@ public static class GUIExclusions internal static bool ControlledFolderAccessToggleButtonStatus; internal static bool AttackSurfaceReductionRulesToggleButtonStatus; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Exclusions/View.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Exclusions/View.cs index 44b22d0de..a3f6415c0 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Exclusions/View.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Exclusions/View.cs @@ -9,8 +9,8 @@ using System.Windows.Markup; using System.Windows.Media.Imaging; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public partial class GUIMain { @@ -298,4 +298,3 @@ await Task.Run(() => } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/GUIBootStrapper.cs b/Harden-Windows-Security Module/Main files/C#/GUI/GUIBootStrapper.cs index d10f6ffac..28fe9f03f 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/GUIBootStrapper.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/GUIBootStrapper.cs @@ -1,8 +1,8 @@ using System; using System.Threading; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class GUIHandOff { /// @@ -42,4 +42,3 @@ public static void Boot() thread.Join(); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Log/Variables.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Log/Variables.cs index cab67434c..f0c6de9a0 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Log/Variables.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Log/Variables.cs @@ -1,7 +1,7 @@ using System.Windows.Controls; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class GUILogs { internal static UserControl? View; @@ -17,4 +17,3 @@ public static class GUILogs // without this initial assignment, switching to Logs page wouldn't have auto-scrolling capability until the toggle button is set to off and on again. internal static bool AutoScroll = true; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Log/View.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Log/View.cs index 373f9592e..badd8ffd6 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Log/View.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Log/View.cs @@ -7,8 +7,8 @@ using System.Windows.Markup; using System.Windows.Media.Imaging; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public partial class GUIMain { @@ -129,4 +129,3 @@ private void LogsView(object obj) } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Main/GUI.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Main/GUI.cs index 6ec138d95..0a9758cc8 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Main/GUI.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Main/GUI.cs @@ -15,8 +15,8 @@ #nullable disable -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public partial class GUIMain { // ViewModelBase class @@ -505,4 +505,3 @@ Harden Windows Security operation log end } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Main/Variables.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Main/Variables.cs index 28b743dcb..6200dae97 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Main/Variables.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Main/Variables.cs @@ -3,8 +3,8 @@ using System.Windows.Controls; using System.Windows.Media; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// The following are XAML GUI Elements /// @@ -32,4 +32,3 @@ public partial class GUIMain // The slider at the bottom left that controls the background image opacity public static Slider? BackgroundSlider; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Protection/EventHandlers.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Protection/EventHandlers.cs index 673d490e3..7f100a5fd 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Protection/EventHandlers.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Protection/EventHandlers.cs @@ -1,758 +1,757 @@ -using Microsoft.Win32; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Controls; +using Microsoft.Win32; -namespace HardenWindowsSecurity +namespace HardenWindowsSecurity; + +/// +/// A class to store all of the data that is related to the GUI and its operations +/// +public static partial class GUIProtectWinSecurity { - /// - /// A class to store all of the data that is related to the GUI and its operations - /// - public static partial class GUIProtectWinSecurity - { - - // The method that defines all of the event handlers for the UI elements - public static void AddEventHandlers() - { - - #region - // null checks to make sure the elements are available to the AddEventHandlers method - // LoadXaml method doesn't need the checks because these values are initialized in that method - - if (View is null) - { - throw new InvalidOperationException("AddEventHandlers Method: Window object is empty!"); - } - - if (categories is null) - { - throw new InvalidOperationException("AddEventHandlers Method: categories object is empty!"); - } - - if (selectAllCategories is null) - { - throw new InvalidOperationException("AddEventHandlers Method: selectAllCategories object is empty!"); - } - - if (subCategories is null) - { - throw new InvalidOperationException("AddEventHandlers Method: subCategories object is empty!"); - } - - if (selectAllSubCategories is null) - { - throw new InvalidOperationException("AddEventHandlers Method: selectAllSubCategories object is empty!"); - } - - if (microsoft365AppsSecurityBaselineZipTextBox is null) - { - throw new InvalidOperationException("AddEventHandlers Method: microsoft365AppsSecurityBaselineZipTextBox object is empty!"); - } - - if (lgpoZipButton is null) - { - throw new InvalidOperationException("AddEventHandlers Method: lgpoZipButton object is empty!"); - } - - if (lgpoZipTextBox is null) - { - throw new InvalidOperationException("AddEventHandlers Method: lgpoZipTextBox object is empty!"); - } - - if (txtFilePath is null) - { - throw new InvalidOperationException("AddEventHandlers Method: txtFilePath object is empty!"); - } - - if (enableOfflineMode is null) - { - throw new InvalidOperationException("AddEventHandlers Method: enableOfflineMode object is empty!"); - } - - if (microsoftSecurityBaselineZipButton is null) - { - throw new InvalidOperationException("AddEventHandlers Method: microsoftSecurityBaselineZipButton object is empty!"); - } - - if (microsoftSecurityBaselineZipTextBox is null) - { - throw new InvalidOperationException("AddEventHandlers Method: microsoftSecurityBaselineZipTextBox object is empty!"); - } - - if (microsoft365AppsSecurityBaselineZipButton is null) - { - throw new InvalidOperationException("AddEventHandlers Method: microsoft365AppsSecurityBaselineZipButton object is empty!"); - } - - if (ExecuteButton is null) - { - throw new InvalidOperationException("AddEventHandlers Method: ExecuteButton object is empty!"); - } - - #endregion - - - // Add Checked and Unchecked event handlers to category checkboxes - foreach (var item in categories.Items) - { - ListViewItem categoryItem = (ListViewItem)item; - CheckBox checkBox = (CheckBox)categoryItem.Content; - checkBox.DataContext = categoryItem; - checkBox.Checked += (sender, e) => UpdateSubCategories(); - checkBox.Unchecked += (sender, e) => UpdateSubCategories(); - } - - // Add click event for 'Check All' button - selectAllCategories.Checked += (sender, e) => - { - - if (GlobalVars.HardeningCategorieX is null) - { - throw new ArgumentNullException("GlobalVars.HardeningCategorieX cannot be null."); - } - foreach (var item in categories.Items) - { - ListViewItem categoryItem = (ListViewItem)item; - if (GlobalVars.HardeningCategorieX.Contains(((CheckBox)categoryItem.Content).Name)) - { - ((CheckBox)categoryItem.Content).IsChecked = true; - } - } - }; - - // Add click event for 'Uncheck All' button - selectAllCategories.Unchecked += (sender, e) => - { - foreach (var item in categories.Items) - { - ((CheckBox)((ListViewItem)item).Content).IsChecked = false; - } - }; - - // Add click event for 'Check All' button for enabled sub-categories - selectAllSubCategories.Checked += (sender, e) => - { - - foreach (var item in subCategories.Items) - { - ListViewItem subCategoryItem = (ListViewItem)item; - if (subCategoryItem.IsEnabled) - { - ((CheckBox)subCategoryItem.Content).IsChecked = true; - } - } - }; - - // Add click event for 'Uncheck All' button from sub-categories, regardless of whether they are enabled or disabled - selectAllSubCategories.Unchecked += (sender, e) => - { - - foreach (var item in subCategories.Items) - { - ((CheckBox)((ListViewItem)item).Content).IsChecked = false; - } - }; - - - // Add Checked event handler to enable offline mode controls/buttons - // When the Offline Mode button it toggled - enableOfflineMode.Checked += (sender, e) => - { - microsoftSecurityBaselineZipButton.IsEnabled = true; - microsoftSecurityBaselineZipTextBox.IsEnabled = true; - microsoft365AppsSecurityBaselineZipButton.IsEnabled = true; - microsoft365AppsSecurityBaselineZipTextBox.IsEnabled = true; - lgpoZipButton.IsEnabled = true; - lgpoZipTextBox.IsEnabled = true; - }; - - // Add Unchecked event handler to disable offline mode controls/buttons - enableOfflineMode.Unchecked += (sender, e) => - { - DisableOfflineModeConfigInputs(); - }; - - - // Define the click event for the Microsoft Security Baseline Zip button - microsoftSecurityBaselineZipButton.Click += (sender, e) => - { - OpenFileDialog dialog = new() - { - InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop), - Filter = "Zip files (*.zip)|*.zip", - Title = "Select the Microsoft Security Baseline Zip file" - }; - - // Show the dialog and process the result - if (dialog.ShowDialog() == true) - { - try - { - // Check if the file contains the required script - if (!SneakAndPeek.Search("Windows*Security Baseline/Scripts/Baseline-LocalInstall.ps1", dialog.FileName)) - { - Logger.LogMessage("The selected Zip file does not contain the Microsoft Security Baselines Baseline-LocalInstall.ps1 which is required for the Harden Windows Security App to work properly", LogTypeIntel.WarningInteractionRequired); - } - else - { - // For displaying the text on the GUI's text box - microsoftSecurityBaselineZipTextBox.Text = dialog.FileName; - // The actual value that will be used - MicrosoftSecurityBaselineZipPath = dialog.FileName; - } - } - catch (Exception ex) - { - // Log the exception if any error occurs - Logger.LogMessage(ex.Message, LogTypeIntel.Error); - } - } - }; - - // Define the click event for the Microsoft 365 Apps Security Baseline Zip button - microsoft365AppsSecurityBaselineZipButton.Click += (sender, e) => - { - OpenFileDialog dialog = new() - { - InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop), - Filter = "Zip files (*.zip)|*.zip", - Title = "Select the Microsoft 365 Apps Security Baseline Zip file" - }; - - // Show the dialog and process the result - if (dialog.ShowDialog() == true) - { - try - { - // Check if the file contains the required script - if (!SneakAndPeek.Search("Microsoft 365 Apps for Enterprise*/Scripts/Baseline-LocalInstall.ps1", dialog.FileName)) - { - Logger.LogMessage("The selected Zip file does not contain the Microsoft 365 Apps for Enterprise Security Baselines Baseline-LocalInstall.ps1 which is required for the Harden Windows Security App to work properly", LogTypeIntel.WarningInteractionRequired); - } - else - { - // For displaying the text on the GUI's text box - microsoft365AppsSecurityBaselineZipTextBox.Text = dialog.FileName; - // The actual value that will be used - Microsoft365AppsSecurityBaselineZipPath = dialog.FileName; - } - } - catch (Exception ex) - { - // Log the exception if any error occurs - Logger.LogMessage(ex.Message, LogTypeIntel.Error); - } - } - }; - - // Define the click event for the LGPO Zip button - lgpoZipButton.Click += (sender, e) => - { - OpenFileDialog dialog = new() - { - InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop), - Filter = "Zip files (*.zip)|*.zip", - Title = "Select the LGPO Zip file" - }; - - // Show the dialog and process the result - if (dialog.ShowDialog() == true) - { - try - { - // Check if the file contains the required LGPO.exe - if (!SneakAndPeek.Search("LGPO_*/LGPO.exe", dialog.FileName)) - { - Logger.LogMessage("The selected Zip file does not contain the LGPO.exe which is required for the Harden Windows Security App to work properly", LogTypeIntel.WarningInteractionRequired); - } - else - { - // For displaying the text on the GUI's text box - lgpoZipTextBox.Text = dialog.FileName; - // The actual value that will be used - LGPOZipPath = dialog.FileName; - } - } - catch (Exception ex) - { - // Log the exception if any error occurs - Logger.LogMessage(ex.Message, LogTypeIntel.Error); - } - } - }; - - - - // Defining a set of commands to run when the GUI window is loaded, async - View.Loaded += async (sender, e) => - { - - // Only continue if there is no activity in other places - if (!ActivityTracker.IsActive) - { - // mark as activity started - ActivityTracker.IsActive = true; - - // Only proceed if this event hasn't already been triggered - if (!LoadEventHasBeenTriggered) - { - - // Set the flag to true indicating the view loaded event has been triggered - LoadEventHasBeenTriggered = true; - - // Run this entire section, including the downloading part, asynchronously - - #region Initial Preset Configuration - // Configure the categories and sub-categories for the Recommended preset when the Protect view page is first loaded - GUIMain.app.Dispatcher.Invoke(() => - { - - string presetName = "preset: recommended"; - - // Check if the preset exists in the dictionary - if (PresetsIntel.TryGetValue(presetName, out var categoriesAndSubcategories)) - { - // Access the categories and subcategories - List categories = categoriesAndSubcategories["Categories"]; - List subcategories = categoriesAndSubcategories["SubCategories"]; - - // Loop over each category in the dictionary - foreach (string category in categories) - { - - // Loop over each category in the GUI - foreach (var item in GUIProtectWinSecurity.categories.Items) - { - // Get the category item list view item - ListViewItem categoryItem = (ListViewItem)item; - - // get the name of the list view item as string - string categoryItemName = ((CheckBox)categoryItem.Content).Name.ToString(); - - // if the category is authorized to be available - if (GlobalVars.HardeningCategorieX!.Contains(categoryItemName)) - { - // If the name of the current checkbox list view item in the loop is the same as the category name in the outer loop, then set the category on the GUI to checked - if (string.Equals(categoryItemName, category, StringComparison.OrdinalIgnoreCase)) - { - ((CheckBox)categoryItem.Content).IsChecked = true; - } - - } - } - } - - foreach (string subcategory in subcategories) - { - - // Loop over each sub-category in the GUI - foreach (var item in subCategories.Items) - { - // Get the sub-category item list view item - ListViewItem SubCategoryItem = (ListViewItem)item; - - // get the name of the list view item as string - string SubcategoryItemName = ((CheckBox)SubCategoryItem.Content).Name.ToString(); - - // If the name of the current checkbox list view item in the loop is the same as the sub-category name in the outer loop, then set the sub-category on the GUI to checked - if (string.Equals(SubcategoryItemName, subcategory, StringComparison.OrdinalIgnoreCase)) - { - ((CheckBox)SubCategoryItem.Content).IsChecked = true; - } - - } - } - } - else - { - Logger.LogMessage($"Preset '{presetName}' not found.", LogTypeIntel.Error); - } - - }); - #endregion - - try - { - - #region Display a Welcome message - - string nameToDisplay = (!string.IsNullOrWhiteSpace(GlobalVars.userFullName)) ? GlobalVars.userFullName : GlobalVars.userName; - - Logger.LogMessage(UserPrivCheck.IsAdmin() ? $"Hello {nameToDisplay}, you have Administrator privileges" : $"Hello {nameToDisplay}, you don't have Administrator privileges, some categories are disabled", LogTypeIntel.Information); - #endregion - - // Use Dispatcher.Invoke to update the UI thread - View.Dispatcher.Invoke(() => - { - // Set the execute button to disabled until all the prerequisites are met - ExecuteButton.IsEnabled = false; - - // Start the execute button's operation to show the files are being downloaded - ExecuteButton.IsChecked = true; - }); - - // Only download and process the files when the GUI is loaded and if Offline mode is not used - // Because at this point, the user might have not selected the files to be used for offline operation - if (!GlobalVars.Offline) - { - Logger.LogMessage("Downloading the required files", LogTypeIntel.Information); - - // Run the file download process asynchronously - await Task.Run(() => - { - AsyncDownloader.PrepDownloadedFiles( - LGPOPath: LGPOZipPath, - MSFTSecurityBaselinesPath: MicrosoftSecurityBaselineZipPath, - MSFT365AppsSecurityBaselinesPath: Microsoft365AppsSecurityBaselineZipPath, - false - ); - }); - - Logger.LogMessage("Finished downloading the required files", LogTypeIntel.Information); - } - - // Using Dispatcher since the execute button is owned by the GUI thread, and we're in another thread - // Enabling the execute button after all files are downloaded and ready or if Offline switch was used and download was skipped - View.Dispatcher.Invoke(() => - { - ExecuteButton.IsEnabled = true; - ExecuteButton.IsChecked = false; - }); - } - catch (Exception ex) - { - Logger.LogMessage($"An error occurred while downloading the required files: {ex.Message}", LogTypeIntel.Error); - Logger.LogMessage($"{ex.StackTrace}", LogTypeIntel.Error); - Logger.LogMessage($"{ex.InnerException}", LogTypeIntel.Error); - // Re-throw the exception to ensure it's caught and handled appropriately - // throw; - } - } - - // mark as activity finished - ActivityTracker.IsActive = false; - } - }; - - - // When Execute button is pressed - ExecuteButton.Click += async (sender, e) => - { - // Only continue if there is no activity in other places - if (!ActivityTracker.IsActive) - { - // mark as activity started - ActivityTracker.IsActive = true; - - // Everything will run in a different thread - await Task.Run(() => - { - - bool OfflineGreenLightStatus = false; - bool OfflineModeToggleStatus = false; - - // Dispatcher to interact with the GUI elements - View.Dispatcher.Invoke(() => - { - // Call the method to get the selected categories and sub-categories - ExecuteButtonPress(); - // Disable the TextFilePath for the log file path - txtFilePath!.IsEnabled = false; - }); - - // If Offline mode is used - if (GlobalVars.Offline) - { - - View.Dispatcher.Invoke(() => - { - - // Handle the nullable boolean - if (enableOfflineMode.IsChecked.HasValue) - { - OfflineModeToggleStatus = enableOfflineMode.IsChecked.Value; - } - - OfflineGreenLightStatus = - !string.IsNullOrWhiteSpace(microsoftSecurityBaselineZipTextBox.Text) && - !string.IsNullOrWhiteSpace(microsoft365AppsSecurityBaselineZipTextBox.Text) && - !string.IsNullOrWhiteSpace(lgpoZipTextBox.Text); - }); - - - // If the required files have not been processed for offline mode already - if (!StartFileDownloadHasRun) - { - // If the checkbox on the GUI for Offline mode is checked - if (OfflineModeToggleStatus) - { - // Make sure all 3 fields for offline mode files were selected by the users and they are neither empty nor null - if (OfflineGreenLightStatus) - { - - // Process the offline mode files selected by the user - AsyncDownloader.PrepDownloadedFiles( - LGPOPath: LGPOZipPath, - MSFTSecurityBaselinesPath: MicrosoftSecurityBaselineZipPath, - MSFT365AppsSecurityBaselinesPath: Microsoft365AppsSecurityBaselineZipPath, - false - ); - - Logger.LogMessage("Finished processing the required files", LogTypeIntel.Information); - - // Set a flag indicating this code block should not run again when the execute button is pressed - StartFileDownloadHasRun = true; - - } - else - { - Logger.LogMessage("Enable Offline Mode checkbox is checked but you have not selected all of the 3 required files for offline mode operation. Please select them and press the execute button again.", LogTypeIntel.WarningInteractionRequired); - } - } - else - { - Logger.LogMessage("Offline mode is being used but the Enable Offline Mode checkbox is not checked. Please check it and press the execute button again.", LogTypeIntel.WarningInteractionRequired); - } - } - } - - if (!GlobalVars.Offline || (GlobalVars.Offline && StartFileDownloadHasRun)) - { - - if (!SelectedCategories.IsEmpty) - { - - // Loop over the ConcurrentQueue that contains the Categories - foreach (string Category in SelectedCategories) - { - - // A switch for the Categories - switch (Category) - { - - case "MicrosoftSecurityBaselines": - { - if (SelectedSubCategories.Contains("SecBaselines_NoOverrides")) - { - MicrosoftSecurityBaselines.Invoke(); - } - else - { - MicrosoftSecurityBaselines.Invoke(); - MicrosoftSecurityBaselines.SecBaselines_Overrides(); - } - break; - } - case "Microsoft365AppsSecurityBaselines": - { - Microsoft365AppsSecurityBaselines.Invoke(); - break; - } - case "MicrosoftDefender": - { - MicrosoftDefender.Invoke(); - - if (SelectedSubCategories.Contains("MSFTDefender_SAC")) - { - MicrosoftDefender.MSFTDefender_SAC(); - } - - if (GlobalVars.ShouldEnableOptionalDiagnosticData || string.Equals(PropertyHelper.GetPropertyValue(GlobalVars.MDAVConfigCurrent, "SmartAppControlState") ?? string.Empty, "on", StringComparison.OrdinalIgnoreCase)) - { - Logger.LogMessage("Enabling Optional Diagnostic Data because SAC is on or user selected to turn it on", LogTypeIntel.Information); - MicrosoftDefender.MSFTDefender_EnableDiagData(); - } - - if (!string.Equals(PropertyHelper.GetPropertyValue(GlobalVars.MDAVConfigCurrent, "SmartAppControlState") ?? string.Empty, "off", StringComparison.OrdinalIgnoreCase)) - { - if (SelectedSubCategories.Contains("MSFTDefender_NoDiagData")) - { - // do nothing - } - } - - if (!SelectedSubCategories.Contains("MSFTDefender_NoScheduledTask")) - { - MicrosoftDefender.MSFTDefender_ScheduledTask(); - } - - if (SelectedSubCategories.Contains("MSFTDefender_BetaChannels")) - { - MicrosoftDefender.MSFTDefender_BetaChannels(); - } - break; - } - case "AttackSurfaceReductionRules": - { - AttackSurfaceReductionRules.Invoke(); - break; - } - case "BitLockerSettings": - { - BitLockerSettings.Invoke(); - break; - } - case "DeviceGuard": - { - DeviceGuard.Invoke(); - if (SelectedSubCategories.Contains("DeviceGuard_MandatoryVBS")) - { - DeviceGuard.DeviceGuard_MandatoryVBS(); - } - break; - } - case "TLSSecurity": - { - TLSSecurity.Invoke(); - break; - } - case "LockScreen": - { - LockScreen.Invoke(); - - if (SelectedSubCategories.Contains("LockScreen_CtrlAltDel")) - { - LockScreen.LockScreen_CtrlAltDel(); - } - if (SelectedSubCategories.Contains("LockScreen_NoLastSignedIn")) - { - LockScreen.LockScreen_LastSignedIn(); - } - break; - } - case "UserAccountControl": - { - UserAccountControl.Invoke(); - - if (SelectedSubCategories.Contains("UAC_NoFastSwitching")) - { - UserAccountControl.UAC_NoFastSwitching(); - } - if (SelectedSubCategories.Contains("UAC_OnlyElevateSigned")) - { - UserAccountControl.UAC_OnlyElevateSigned(); - } - - break; - } - case "WindowsFirewall": - { - WindowsFirewall.Invoke(); - break; - } - case "OptionalWindowsFeatures": - { - OptionalWindowsFeatures.Invoke(); - break; - } - case "WindowsNetworking": - { - WindowsNetworking.Invoke(); - - if (SelectedSubCategories.Contains("WindowsNetworking_BlockNTLM")) - { - WindowsNetworking.WindowsNetworking_BlockNTLM(); - } - - break; - } - case "MiscellaneousConfigurations": - { - MiscellaneousConfigurations.Invoke(); - - if (SelectedSubCategories.Contains("Miscellaneous_WindowsProtectedPrint")) - { - MiscellaneousConfigurations.MiscellaneousConfigurations_WindowsProtectedPrint(); - } - - if (SelectedSubCategories.Contains("MiscellaneousConfigurations_LongPathSupport")) - { - MiscellaneousConfigurations.MiscellaneousConfigurations_LongPathSupport(); - } - - if (SelectedSubCategories.Contains("MiscellaneousConfigurations_StrongKeyProtection")) - { - MiscellaneousConfigurations.MiscellaneousConfigurations_StrongKeyProtection(); - } - - break; - } - case "WindowsUpdateConfigurations": - { - WindowsUpdateConfigurations.Invoke(); - break; - } - case "EdgeBrowserConfigurations": - { - EdgeBrowserConfigurations.Invoke(); - break; - } - case "CertificateCheckingCommands": - { - CertificateCheckingCommands.Invoke(); - break; - } - case "CountryIPBlocking": - { - CountryIPBlocking.Invoke(); - - if (SelectedSubCategories.Contains("CountryIPBlocking_OFAC")) - { - CountryIPBlocking.CountryIPBlocking_OFAC(); - } - break; - } - case "DownloadsDefenseMeasures": - { - DownloadsDefenseMeasures.Invoke(); - if (SelectedSubCategories.Contains("DangerousScriptHostsBlocking")) - { - DownloadsDefenseMeasures.DangerousScriptHostsBlocking(); - } - break; - } - case "NonAdminCommands": - { - NonAdminCommands.Invoke(); - break; - } - - default: - break; - } - } - - if (GlobalVars.UseNewNotificationsExp) - { - ToastNotification.Show(ToastNotification.Type.EndOfProtection, null, null, null, null); - } - } - else - { - Logger.LogMessage("No category was selected", LogTypeIntel.Warning); - } - } - - View.Dispatcher.Invoke(() => - { - // Manually trigger the ToggleButton to be unchecked to trigger the ending animation - ExecuteButton!.IsChecked = false; - - // Only enable the log file path TextBox if the log toggle button is toggled - if (log!.IsChecked == true) - { - txtFilePath!.IsEnabled = true; - } - }); - - }); - - // mark as activity completed - ActivityTracker.IsActive = false; - } - }; - } - } + + // The method that defines all of the event handlers for the UI elements + public static void AddEventHandlers() + { + + #region + // null checks to make sure the elements are available to the AddEventHandlers method + // LoadXaml method doesn't need the checks because these values are initialized in that method + + if (View is null) + { + throw new InvalidOperationException("AddEventHandlers Method: Window object is empty!"); + } + + if (categories is null) + { + throw new InvalidOperationException("AddEventHandlers Method: categories object is empty!"); + } + + if (selectAllCategories is null) + { + throw new InvalidOperationException("AddEventHandlers Method: selectAllCategories object is empty!"); + } + + if (subCategories is null) + { + throw new InvalidOperationException("AddEventHandlers Method: subCategories object is empty!"); + } + + if (selectAllSubCategories is null) + { + throw new InvalidOperationException("AddEventHandlers Method: selectAllSubCategories object is empty!"); + } + + if (microsoft365AppsSecurityBaselineZipTextBox is null) + { + throw new InvalidOperationException("AddEventHandlers Method: microsoft365AppsSecurityBaselineZipTextBox object is empty!"); + } + + if (lgpoZipButton is null) + { + throw new InvalidOperationException("AddEventHandlers Method: lgpoZipButton object is empty!"); + } + + if (lgpoZipTextBox is null) + { + throw new InvalidOperationException("AddEventHandlers Method: lgpoZipTextBox object is empty!"); + } + + if (txtFilePath is null) + { + throw new InvalidOperationException("AddEventHandlers Method: txtFilePath object is empty!"); + } + + if (enableOfflineMode is null) + { + throw new InvalidOperationException("AddEventHandlers Method: enableOfflineMode object is empty!"); + } + + if (microsoftSecurityBaselineZipButton is null) + { + throw new InvalidOperationException("AddEventHandlers Method: microsoftSecurityBaselineZipButton object is empty!"); + } + + if (microsoftSecurityBaselineZipTextBox is null) + { + throw new InvalidOperationException("AddEventHandlers Method: microsoftSecurityBaselineZipTextBox object is empty!"); + } + + if (microsoft365AppsSecurityBaselineZipButton is null) + { + throw new InvalidOperationException("AddEventHandlers Method: microsoft365AppsSecurityBaselineZipButton object is empty!"); + } + + if (ExecuteButton is null) + { + throw new InvalidOperationException("AddEventHandlers Method: ExecuteButton object is empty!"); + } + + #endregion + + + // Add Checked and Unchecked event handlers to category checkboxes + foreach (var item in categories.Items) + { + ListViewItem categoryItem = (ListViewItem)item; + CheckBox checkBox = (CheckBox)categoryItem.Content; + checkBox.DataContext = categoryItem; + checkBox.Checked += (sender, e) => UpdateSubCategories(); + checkBox.Unchecked += (sender, e) => UpdateSubCategories(); + } + + // Add click event for 'Check All' button + selectAllCategories.Checked += (sender, e) => + { + + if (GlobalVars.HardeningCategorieX is null) + { + throw new ArgumentNullException("GlobalVars.HardeningCategorieX cannot be null."); + } + foreach (var item in categories.Items) + { + ListViewItem categoryItem = (ListViewItem)item; + if (GlobalVars.HardeningCategorieX.Contains(((CheckBox)categoryItem.Content).Name)) + { + ((CheckBox)categoryItem.Content).IsChecked = true; + } + } + }; + + // Add click event for 'Uncheck All' button + selectAllCategories.Unchecked += (sender, e) => + { + foreach (var item in categories.Items) + { + ((CheckBox)((ListViewItem)item).Content).IsChecked = false; + } + }; + + // Add click event for 'Check All' button for enabled sub-categories + selectAllSubCategories.Checked += (sender, e) => + { + + foreach (var item in subCategories.Items) + { + ListViewItem subCategoryItem = (ListViewItem)item; + if (subCategoryItem.IsEnabled) + { + ((CheckBox)subCategoryItem.Content).IsChecked = true; + } + } + }; + + // Add click event for 'Uncheck All' button from sub-categories, regardless of whether they are enabled or disabled + selectAllSubCategories.Unchecked += (sender, e) => + { + + foreach (var item in subCategories.Items) + { + ((CheckBox)((ListViewItem)item).Content).IsChecked = false; + } + }; + + + // Add Checked event handler to enable offline mode controls/buttons + // When the Offline Mode button it toggled + enableOfflineMode.Checked += (sender, e) => + { + microsoftSecurityBaselineZipButton.IsEnabled = true; + microsoftSecurityBaselineZipTextBox.IsEnabled = true; + microsoft365AppsSecurityBaselineZipButton.IsEnabled = true; + microsoft365AppsSecurityBaselineZipTextBox.IsEnabled = true; + lgpoZipButton.IsEnabled = true; + lgpoZipTextBox.IsEnabled = true; + }; + + // Add Unchecked event handler to disable offline mode controls/buttons + enableOfflineMode.Unchecked += (sender, e) => + { + DisableOfflineModeConfigInputs(); + }; + + + // Define the click event for the Microsoft Security Baseline Zip button + microsoftSecurityBaselineZipButton.Click += (sender, e) => + { + OpenFileDialog dialog = new() + { + InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop), + Filter = "Zip files (*.zip)|*.zip", + Title = "Select the Microsoft Security Baseline Zip file" + }; + + // Show the dialog and process the result + if (dialog.ShowDialog() == true) + { + try + { + // Check if the file contains the required script + if (!SneakAndPeek.Search("Windows*Security Baseline/Scripts/Baseline-LocalInstall.ps1", dialog.FileName)) + { + Logger.LogMessage("The selected Zip file does not contain the Microsoft Security Baselines Baseline-LocalInstall.ps1 which is required for the Harden Windows Security App to work properly", LogTypeIntel.WarningInteractionRequired); + } + else + { + // For displaying the text on the GUI's text box + microsoftSecurityBaselineZipTextBox.Text = dialog.FileName; + // The actual value that will be used + MicrosoftSecurityBaselineZipPath = dialog.FileName; + } + } + catch (Exception ex) + { + // Log the exception if any error occurs + Logger.LogMessage(ex.Message, LogTypeIntel.Error); + } + } + }; + + // Define the click event for the Microsoft 365 Apps Security Baseline Zip button + microsoft365AppsSecurityBaselineZipButton.Click += (sender, e) => + { + OpenFileDialog dialog = new() + { + InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop), + Filter = "Zip files (*.zip)|*.zip", + Title = "Select the Microsoft 365 Apps Security Baseline Zip file" + }; + + // Show the dialog and process the result + if (dialog.ShowDialog() == true) + { + try + { + // Check if the file contains the required script + if (!SneakAndPeek.Search("Microsoft 365 Apps for Enterprise*/Scripts/Baseline-LocalInstall.ps1", dialog.FileName)) + { + Logger.LogMessage("The selected Zip file does not contain the Microsoft 365 Apps for Enterprise Security Baselines Baseline-LocalInstall.ps1 which is required for the Harden Windows Security App to work properly", LogTypeIntel.WarningInteractionRequired); + } + else + { + // For displaying the text on the GUI's text box + microsoft365AppsSecurityBaselineZipTextBox.Text = dialog.FileName; + // The actual value that will be used + Microsoft365AppsSecurityBaselineZipPath = dialog.FileName; + } + } + catch (Exception ex) + { + // Log the exception if any error occurs + Logger.LogMessage(ex.Message, LogTypeIntel.Error); + } + } + }; + + // Define the click event for the LGPO Zip button + lgpoZipButton.Click += (sender, e) => + { + OpenFileDialog dialog = new() + { + InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop), + Filter = "Zip files (*.zip)|*.zip", + Title = "Select the LGPO Zip file" + }; + + // Show the dialog and process the result + if (dialog.ShowDialog() == true) + { + try + { + // Check if the file contains the required LGPO.exe + if (!SneakAndPeek.Search("LGPO_*/LGPO.exe", dialog.FileName)) + { + Logger.LogMessage("The selected Zip file does not contain the LGPO.exe which is required for the Harden Windows Security App to work properly", LogTypeIntel.WarningInteractionRequired); + } + else + { + // For displaying the text on the GUI's text box + lgpoZipTextBox.Text = dialog.FileName; + // The actual value that will be used + LGPOZipPath = dialog.FileName; + } + } + catch (Exception ex) + { + // Log the exception if any error occurs + Logger.LogMessage(ex.Message, LogTypeIntel.Error); + } + } + }; + + + + // Defining a set of commands to run when the GUI window is loaded, async + View.Loaded += async (sender, e) => + { + + // Only continue if there is no activity in other places + if (!ActivityTracker.IsActive) + { + // mark as activity started + ActivityTracker.IsActive = true; + + // Only proceed if this event hasn't already been triggered + if (!LoadEventHasBeenTriggered) + { + + // Set the flag to true indicating the view loaded event has been triggered + LoadEventHasBeenTriggered = true; + + // Run this entire section, including the downloading part, asynchronously + + #region Initial Preset Configuration + // Configure the categories and sub-categories for the Recommended preset when the Protect view page is first loaded + GUIMain.app.Dispatcher.Invoke(() => + { + + string presetName = "preset: recommended"; + + // Check if the preset exists in the dictionary + if (PresetsIntel.TryGetValue(presetName, out var categoriesAndSubcategories)) + { + // Access the categories and subcategories + List categories = categoriesAndSubcategories["Categories"]; + List subcategories = categoriesAndSubcategories["SubCategories"]; + + // Loop over each category in the dictionary + foreach (string category in categories) + { + + // Loop over each category in the GUI + foreach (var item in GUIProtectWinSecurity.categories.Items) + { + // Get the category item list view item + ListViewItem categoryItem = (ListViewItem)item; + + // get the name of the list view item as string + string categoryItemName = ((CheckBox)categoryItem.Content).Name.ToString(); + + // if the category is authorized to be available + if (GlobalVars.HardeningCategorieX!.Contains(categoryItemName)) + { + // If the name of the current checkbox list view item in the loop is the same as the category name in the outer loop, then set the category on the GUI to checked + if (string.Equals(categoryItemName, category, StringComparison.OrdinalIgnoreCase)) + { + ((CheckBox)categoryItem.Content).IsChecked = true; + } + + } + } + } + + foreach (string subcategory in subcategories) + { + + // Loop over each sub-category in the GUI + foreach (var item in subCategories.Items) + { + // Get the sub-category item list view item + ListViewItem SubCategoryItem = (ListViewItem)item; + + // get the name of the list view item as string + string SubcategoryItemName = ((CheckBox)SubCategoryItem.Content).Name.ToString(); + + // If the name of the current checkbox list view item in the loop is the same as the sub-category name in the outer loop, then set the sub-category on the GUI to checked + if (string.Equals(SubcategoryItemName, subcategory, StringComparison.OrdinalIgnoreCase)) + { + ((CheckBox)SubCategoryItem.Content).IsChecked = true; + } + + } + } + } + else + { + Logger.LogMessage($"Preset '{presetName}' not found.", LogTypeIntel.Error); + } + + }); + #endregion + + try + { + + #region Display a Welcome message + + string nameToDisplay = (!string.IsNullOrWhiteSpace(GlobalVars.userFullName)) ? GlobalVars.userFullName : GlobalVars.userName; + + Logger.LogMessage(UserPrivCheck.IsAdmin() ? $"Hello {nameToDisplay}, you have Administrator privileges" : $"Hello {nameToDisplay}, you don't have Administrator privileges, some categories are disabled", LogTypeIntel.Information); + #endregion + + // Use Dispatcher.Invoke to update the UI thread + View.Dispatcher.Invoke(() => + { + // Set the execute button to disabled until all the prerequisites are met + ExecuteButton.IsEnabled = false; + + // Start the execute button's operation to show the files are being downloaded + ExecuteButton.IsChecked = true; + }); + + // Only download and process the files when the GUI is loaded and if Offline mode is not used + // Because at this point, the user might have not selected the files to be used for offline operation + if (!GlobalVars.Offline) + { + Logger.LogMessage("Downloading the required files", LogTypeIntel.Information); + + // Run the file download process asynchronously + await Task.Run(() => + { + AsyncDownloader.PrepDownloadedFiles( + LGPOPath: LGPOZipPath, + MSFTSecurityBaselinesPath: MicrosoftSecurityBaselineZipPath, + MSFT365AppsSecurityBaselinesPath: Microsoft365AppsSecurityBaselineZipPath, + false + ); + }); + + Logger.LogMessage("Finished downloading the required files", LogTypeIntel.Information); + } + + // Using Dispatcher since the execute button is owned by the GUI thread, and we're in another thread + // Enabling the execute button after all files are downloaded and ready or if Offline switch was used and download was skipped + View.Dispatcher.Invoke(() => + { + ExecuteButton.IsEnabled = true; + ExecuteButton.IsChecked = false; + }); + } + catch (Exception ex) + { + Logger.LogMessage($"An error occurred while downloading the required files: {ex.Message}", LogTypeIntel.Error); + Logger.LogMessage($"{ex.StackTrace}", LogTypeIntel.Error); + Logger.LogMessage($"{ex.InnerException}", LogTypeIntel.Error); + // Re-throw the exception to ensure it's caught and handled appropriately + // throw; + } + } + + // mark as activity finished + ActivityTracker.IsActive = false; + } + }; + + + // When Execute button is pressed + ExecuteButton.Click += async (sender, e) => + { + // Only continue if there is no activity in other places + if (!ActivityTracker.IsActive) + { + // mark as activity started + ActivityTracker.IsActive = true; + + // Everything will run in a different thread + await Task.Run(() => + { + + bool OfflineGreenLightStatus = false; + bool OfflineModeToggleStatus = false; + + // Dispatcher to interact with the GUI elements + View.Dispatcher.Invoke(() => + { + // Call the method to get the selected categories and sub-categories + ExecuteButtonPress(); + // Disable the TextFilePath for the log file path + txtFilePath!.IsEnabled = false; + }); + + // If Offline mode is used + if (GlobalVars.Offline) + { + + View.Dispatcher.Invoke(() => + { + + // Handle the nullable boolean + if (enableOfflineMode.IsChecked.HasValue) + { + OfflineModeToggleStatus = enableOfflineMode.IsChecked.Value; + } + + OfflineGreenLightStatus = + !string.IsNullOrWhiteSpace(microsoftSecurityBaselineZipTextBox.Text) && + !string.IsNullOrWhiteSpace(microsoft365AppsSecurityBaselineZipTextBox.Text) && + !string.IsNullOrWhiteSpace(lgpoZipTextBox.Text); + }); + + + // If the required files have not been processed for offline mode already + if (!StartFileDownloadHasRun) + { + // If the checkbox on the GUI for Offline mode is checked + if (OfflineModeToggleStatus) + { + // Make sure all 3 fields for offline mode files were selected by the users and they are neither empty nor null + if (OfflineGreenLightStatus) + { + + // Process the offline mode files selected by the user + AsyncDownloader.PrepDownloadedFiles( + LGPOPath: LGPOZipPath, + MSFTSecurityBaselinesPath: MicrosoftSecurityBaselineZipPath, + MSFT365AppsSecurityBaselinesPath: Microsoft365AppsSecurityBaselineZipPath, + false + ); + + Logger.LogMessage("Finished processing the required files", LogTypeIntel.Information); + + // Set a flag indicating this code block should not run again when the execute button is pressed + StartFileDownloadHasRun = true; + + } + else + { + Logger.LogMessage("Enable Offline Mode checkbox is checked but you have not selected all of the 3 required files for offline mode operation. Please select them and press the execute button again.", LogTypeIntel.WarningInteractionRequired); + } + } + else + { + Logger.LogMessage("Offline mode is being used but the Enable Offline Mode checkbox is not checked. Please check it and press the execute button again.", LogTypeIntel.WarningInteractionRequired); + } + } + } + + if (!GlobalVars.Offline || (GlobalVars.Offline && StartFileDownloadHasRun)) + { + + if (!SelectedCategories.IsEmpty) + { + + // Loop over the ConcurrentQueue that contains the Categories + foreach (string Category in SelectedCategories) + { + + // A switch for the Categories + switch (Category) + { + + case "MicrosoftSecurityBaselines": + { + if (SelectedSubCategories.Contains("SecBaselines_NoOverrides")) + { + MicrosoftSecurityBaselines.Invoke(); + } + else + { + MicrosoftSecurityBaselines.Invoke(); + MicrosoftSecurityBaselines.SecBaselines_Overrides(); + } + break; + } + case "Microsoft365AppsSecurityBaselines": + { + Microsoft365AppsSecurityBaselines.Invoke(); + break; + } + case "MicrosoftDefender": + { + MicrosoftDefender.Invoke(); + + if (SelectedSubCategories.Contains("MSFTDefender_SAC")) + { + MicrosoftDefender.MSFTDefender_SAC(); + } + + if (GlobalVars.ShouldEnableOptionalDiagnosticData || string.Equals(PropertyHelper.GetPropertyValue(GlobalVars.MDAVConfigCurrent, "SmartAppControlState") ?? string.Empty, "on", StringComparison.OrdinalIgnoreCase)) + { + Logger.LogMessage("Enabling Optional Diagnostic Data because SAC is on or user selected to turn it on", LogTypeIntel.Information); + MicrosoftDefender.MSFTDefender_EnableDiagData(); + } + + if (!string.Equals(PropertyHelper.GetPropertyValue(GlobalVars.MDAVConfigCurrent, "SmartAppControlState") ?? string.Empty, "off", StringComparison.OrdinalIgnoreCase)) + { + if (SelectedSubCategories.Contains("MSFTDefender_NoDiagData")) + { + // do nothing + } + } + + if (!SelectedSubCategories.Contains("MSFTDefender_NoScheduledTask")) + { + MicrosoftDefender.MSFTDefender_ScheduledTask(); + } + + if (SelectedSubCategories.Contains("MSFTDefender_BetaChannels")) + { + MicrosoftDefender.MSFTDefender_BetaChannels(); + } + break; + } + case "AttackSurfaceReductionRules": + { + AttackSurfaceReductionRules.Invoke(); + break; + } + case "BitLockerSettings": + { + BitLockerSettings.Invoke(); + break; + } + case "DeviceGuard": + { + DeviceGuard.Invoke(); + if (SelectedSubCategories.Contains("DeviceGuard_MandatoryVBS")) + { + DeviceGuard.DeviceGuard_MandatoryVBS(); + } + break; + } + case "TLSSecurity": + { + TLSSecurity.Invoke(); + break; + } + case "LockScreen": + { + LockScreen.Invoke(); + + if (SelectedSubCategories.Contains("LockScreen_CtrlAltDel")) + { + LockScreen.LockScreen_CtrlAltDel(); + } + if (SelectedSubCategories.Contains("LockScreen_NoLastSignedIn")) + { + LockScreen.LockScreen_LastSignedIn(); + } + break; + } + case "UserAccountControl": + { + UserAccountControl.Invoke(); + + if (SelectedSubCategories.Contains("UAC_NoFastSwitching")) + { + UserAccountControl.UAC_NoFastSwitching(); + } + if (SelectedSubCategories.Contains("UAC_OnlyElevateSigned")) + { + UserAccountControl.UAC_OnlyElevateSigned(); + } + + break; + } + case "WindowsFirewall": + { + WindowsFirewall.Invoke(); + break; + } + case "OptionalWindowsFeatures": + { + OptionalWindowsFeatures.Invoke(); + break; + } + case "WindowsNetworking": + { + WindowsNetworking.Invoke(); + + if (SelectedSubCategories.Contains("WindowsNetworking_BlockNTLM")) + { + WindowsNetworking.WindowsNetworking_BlockNTLM(); + } + + break; + } + case "MiscellaneousConfigurations": + { + MiscellaneousConfigurations.Invoke(); + + if (SelectedSubCategories.Contains("Miscellaneous_WindowsProtectedPrint")) + { + MiscellaneousConfigurations.MiscellaneousConfigurations_WindowsProtectedPrint(); + } + + if (SelectedSubCategories.Contains("MiscellaneousConfigurations_LongPathSupport")) + { + MiscellaneousConfigurations.MiscellaneousConfigurations_LongPathSupport(); + } + + if (SelectedSubCategories.Contains("MiscellaneousConfigurations_StrongKeyProtection")) + { + MiscellaneousConfigurations.MiscellaneousConfigurations_StrongKeyProtection(); + } + + break; + } + case "WindowsUpdateConfigurations": + { + WindowsUpdateConfigurations.Invoke(); + break; + } + case "EdgeBrowserConfigurations": + { + EdgeBrowserConfigurations.Invoke(); + break; + } + case "CertificateCheckingCommands": + { + CertificateCheckingCommands.Invoke(); + break; + } + case "CountryIPBlocking": + { + CountryIPBlocking.Invoke(); + + if (SelectedSubCategories.Contains("CountryIPBlocking_OFAC")) + { + CountryIPBlocking.CountryIPBlocking_OFAC(); + } + break; + } + case "DownloadsDefenseMeasures": + { + DownloadsDefenseMeasures.Invoke(); + if (SelectedSubCategories.Contains("DangerousScriptHostsBlocking")) + { + DownloadsDefenseMeasures.DangerousScriptHostsBlocking(); + } + break; + } + case "NonAdminCommands": + { + NonAdminCommands.Invoke(); + break; + } + + default: + break; + } + } + + if (GlobalVars.UseNewNotificationsExp) + { + ToastNotification.Show(ToastNotification.Type.EndOfProtection, null, null, null, null); + } + } + else + { + Logger.LogMessage("No category was selected", LogTypeIntel.Warning); + } + } + + View.Dispatcher.Invoke(() => + { + // Manually trigger the ToggleButton to be unchecked to trigger the ending animation + ExecuteButton!.IsChecked = false; + + // Only enable the log file path TextBox if the log toggle button is toggled + if (log!.IsChecked == true) + { + txtFilePath!.IsEnabled = true; + } + }); + + }); + + // mark as activity completed + ActivityTracker.IsActive = false; + } + }; + } } diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Protection/Miscellaneous methods.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Protection/Miscellaneous methods.cs index 935cc0637..77b6105a5 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Protection/Miscellaneous methods.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Protection/Miscellaneous methods.cs @@ -4,8 +4,8 @@ #nullable disable -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class GUIProtectWinSecurity { @@ -123,4 +123,3 @@ public static void ExecuteButtonPress() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Protection/Variables.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Protection/Variables.cs index f90b71c6a..21dea9a62 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Protection/Variables.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Protection/Variables.cs @@ -4,8 +4,8 @@ using System.Windows.Controls; using System.Windows.Controls.Primitives; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class GUIProtectWinSecurity { // During offline mode, this is the path that the button for MicrosoftSecurityBaselineZipPath assigns @@ -110,5 +110,4 @@ public static partial class GUIProtectWinSecurity }; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Protection/View.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Protection/View.cs index 20f577dc2..1ee477188 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Protection/View.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Protection/View.cs @@ -11,8 +11,8 @@ #nullable disable -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public partial class GUIMain { @@ -485,4 +485,3 @@ private void ProtectView(object obj) } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Unprotect/Variables.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Unprotect/Variables.cs index 88520ad47..f177b7460 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Unprotect/Variables.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Unprotect/Variables.cs @@ -1,7 +1,7 @@ using System.Windows.Controls; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class GUIUnprotect { internal static UserControl? View; @@ -12,4 +12,3 @@ public static class GUIUnprotect internal static byte AppControlPoliciesComboBoxSelection; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/Unprotect/View.cs b/Harden-Windows-Security Module/Main files/C#/GUI/Unprotect/View.cs index f49ff2f7f..dc462831b 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/Unprotect/View.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/Unprotect/View.cs @@ -8,8 +8,8 @@ using System.Windows.Markup; using System.Windows.Media.Imaging; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public partial class GUIMain { @@ -316,4 +316,3 @@ await Application.Current.Dispatcher.InvokeAsync(() => } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ActivityTracker.cs b/Harden-Windows-Security Module/Main files/C#/Others/ActivityTracker.cs index 85049f80f..f7af43b97 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ActivityTracker.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ActivityTracker.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Windows; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// This class is responsible for tracking the activity status of the application and managing the /// enabled/disabled state of registered UI elements based on this status. It is thread-safe to ensure @@ -132,4 +132,3 @@ private static void UpdateMainProgressBarVisibility() }); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/AsyncDownloader.cs b/Harden-Windows-Security Module/Main files/C#/Others/AsyncDownloader.cs index 53cf5ec71..83e1c45be 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/AsyncDownloader.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/AsyncDownloader.cs @@ -4,8 +4,8 @@ using System.Net.Http; using System.Threading.Tasks; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class AsyncDownloader { // HttpClient instance to be used and re-used for downloading files @@ -277,4 +277,3 @@ public static void PrepDownloadedFiles(string? LGPOPath, string? MSFTSecurityBas } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/AttackSurfaceReductionIntel.cs b/Harden-Windows-Security Module/Main files/C#/Others/AttackSurfaceReductionIntel.cs index 5d8e72864..384f28d39 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/AttackSurfaceReductionIntel.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/AttackSurfaceReductionIntel.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class AttackSurfaceReductionIntel { // A dictionary to store the ASR rule IDs and their descriptions @@ -83,4 +83,3 @@ internal static class AttackSurfaceReductionIntel }; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/AuditPolicyHelper.cs b/Harden-Windows-Security Module/Main files/C#/Others/AuditPolicyHelper.cs index c707632c7..b9ee56717 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/AuditPolicyHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/AuditPolicyHelper.cs @@ -3,8 +3,8 @@ using System.Security.AccessControl; using System.Security.Principal; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// This class is responsible for querying effective Audit policy information on the system. /// It uses registry instead of using cmdlets such as: (auditpol /get /subcategory:"Other Logon/Logoff Events" /r | ConvertFrom-Csv).'Inclusion Setting' @@ -398,4 +398,3 @@ internal SystemCategory(ReadOnlySpan data) } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/CSVImporter.cs b/Harden-Windows-Security Module/Main files/C#/Others/CSVImporter.cs index 84ac20101..c80de2ab5 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/CSVImporter.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/CSVImporter.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class HardeningRegistryKeys { // Define a public class to store the structure of the new CSV data @@ -74,4 +74,3 @@ public static void ReadCsv() } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/Categoriex.cs b/Harden-Windows-Security Module/Main files/C#/Others/Categoriex.cs index a17208a2e..fc3709a24 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/Categoriex.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/Categoriex.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public enum ComplianceCategories { @@ -143,4 +143,3 @@ public static string[] GetValidValues() return [.. categoriex]; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/CategoryProcessing.cs b/Harden-Windows-Security Module/Main files/C#/Others/CategoryProcessing.cs index ba478bdd3..963f9bbd7 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/CategoryProcessing.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/CategoryProcessing.cs @@ -6,8 +6,8 @@ using System.Linq; using System.Text; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + // Registry keys are case-insensitive // https://learn.microsoft.com/en-us/windows/win32/sysinfo/structure-of-the-registry public static class CategoryProcessing @@ -434,4 +434,3 @@ private static bool CompareRegistryValues(string type, object regValue, object e } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ChangePSConsoleTitle.cs b/Harden-Windows-Security Module/Main files/C#/Others/ChangePSConsoleTitle.cs index f745ff633..5065586a2 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ChangePSConsoleTitle.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ChangePSConsoleTitle.cs @@ -1,5 +1,5 @@ -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class ChangePSConsoleTitle { /// @@ -19,4 +19,3 @@ public static void Set(string Title) } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/CiToolRunner.cs b/Harden-Windows-Security Module/Main files/C#/Others/CiToolRunner.cs index 46d3373fa..b0afc0898 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/CiToolRunner.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/CiToolRunner.cs @@ -5,8 +5,8 @@ using System.IO; using System.Text.Json; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class CiToolRunner { /// @@ -281,4 +281,3 @@ internal static List GetPolicyOptionsOrDefault(this JsonElement element) return []; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ConditionalResultAdd.cs b/Harden-Windows-Security Module/Main files/C#/Others/ConditionalResultAdd.cs index d6285604c..da269e969 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ConditionalResultAdd.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ConditionalResultAdd.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class ConditionalResultAdd { /// @@ -49,4 +49,3 @@ internal static void Add(List nestedObjectArray, IndividualRes } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ConfirmSystemComplianceMethods.cs b/Harden-Windows-Security Module/Main files/C#/Others/ConfirmSystemComplianceMethods.cs index 2db034850..a46662402 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ConfirmSystemComplianceMethods.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ConfirmSystemComplianceMethods.cs @@ -10,8 +10,8 @@ using System.Management.Automation; using System.Threading.Tasks; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class ConfirmSystemComplianceMethods { @@ -2386,4 +2386,3 @@ private static Task VerifyMicrosoftDefender() }); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ControlledFolderAccessHandler.cs b/Harden-Windows-Security Module/Main files/C#/Others/ControlledFolderAccessHandler.cs index e504a61c7..cdaa8cef5 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ControlledFolderAccessHandler.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ControlledFolderAccessHandler.cs @@ -4,8 +4,8 @@ using System.IO; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// Class to handle Controlled Folder Access allowed applications /// Mostly for adding some system executables or Pwh.exe to the list during the module's operation @@ -176,4 +176,3 @@ public static void Reset() GlobalVars.CFABackup = null; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/DialogMsgHelper.cs b/Harden-Windows-Security Module/Main files/C#/Others/DialogMsgHelper.cs index cb7858893..2660858dc 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/DialogMsgHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/DialogMsgHelper.cs @@ -2,8 +2,8 @@ using System.Windows; using System.Windows.Controls; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class DialogMsgHelper { @@ -71,4 +71,3 @@ internal static void Show(string Message, string? Title = "An Error Occurred") thread.Start(); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/EccCurveComparer.cs b/Harden-Windows-Security Module/Main files/C#/Others/EccCurveComparer.cs index 57c8624f9..5680930fd 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/EccCurveComparer.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/EccCurveComparer.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Management.Automation; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class EccCurveComparer { /// @@ -67,4 +67,3 @@ private static List GetCurrentEccCurves() return currentEccCurvesToOutput; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ExportSecurityPolicy.cs b/Harden-Windows-Security Module/Main files/C#/Others/ExportSecurityPolicy.cs index a35ad8986..d3578fbc7 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ExportSecurityPolicy.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ExportSecurityPolicy.cs @@ -1,8 +1,8 @@ using System; using System.Diagnostics; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public partial class ConfirmSystemComplianceMethods { /// @@ -40,4 +40,3 @@ public static void ExportSecurityPolicy() } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ForceRelocateImagesForFiles.cs b/Harden-Windows-Security Module/Main files/C#/Others/ForceRelocateImagesForFiles.cs index f88ce8d00..02fa44969 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ForceRelocateImagesForFiles.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ForceRelocateImagesForFiles.cs @@ -1,8 +1,8 @@ using System; using System.Management.Automation; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class ForceRelocateImagesForFiles { @@ -48,4 +48,3 @@ internal static void SetProcessMitigationForFiles(string[] items) } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/GetLocalUser.cs b/Harden-Windows-Security Module/Main files/C#/Others/GetLocalUser.cs index 08fbb9308..bb69776c3 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/GetLocalUser.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/GetLocalUser.cs @@ -4,8 +4,8 @@ using System.Globalization; using System.Runtime.InteropServices; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + // Class to represent a local user account internal sealed class LocalUser { @@ -123,4 +123,3 @@ private static List GetGroupSIDs(UserPrincipal user) return groupSIDs; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/GetMDMResultValue.cs b/Harden-Windows-Security Module/Main files/C#/Others/GetMDMResultValue.cs index e8a093672..db431e6f2 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/GetMDMResultValue.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/GetMDMResultValue.cs @@ -1,8 +1,8 @@ using System; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class GetMDMResultValue { /// @@ -41,4 +41,3 @@ public static bool Get(string propertyName, string comparisonValue) } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/GetOneDriveDirectories.cs b/Harden-Windows-Security Module/Main files/C#/Others/GetOneDriveDirectories.cs index 9102cf09f..6a67c7dbd 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/GetOneDriveDirectories.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/GetOneDriveDirectories.cs @@ -3,8 +3,8 @@ using System.IO; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class GetOneDriveDirectories { @@ -67,4 +67,3 @@ internal static List Get() return directoriesList; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/GitExesFinder.cs b/Harden-Windows-Security Module/Main files/C#/Others/GitExesFinder.cs index 7f038edd8..f8a7640f4 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/GitExesFinder.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/GitExesFinder.cs @@ -2,8 +2,8 @@ using System.IO; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class GitExesFinder { // This method searches for .exe files in the specified path for Standalone Git program and returns a list of FileInfo objects @@ -43,4 +43,3 @@ internal static class GitExesFinder return fileList; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/GitHubDesktopFinder.cs b/Harden-Windows-Security Module/Main files/C#/Others/GitHubDesktopFinder.cs index ae2cce874..65fcfd1ed 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/GitHubDesktopFinder.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/GitHubDesktopFinder.cs @@ -3,8 +3,8 @@ using System.IO; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class GitHubDesktopFinder { // This method searches for .exe files in the specified path and returns a list of FileInfo objects @@ -47,4 +47,3 @@ internal static class GitHubDesktopFinder return fileList; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/GlobalVars.cs b/Harden-Windows-Security Module/Main files/C#/Others/GlobalVars.cs index ca8fd0b43..cb0ff354e 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/GlobalVars.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/GlobalVars.cs @@ -5,8 +5,8 @@ using System.IO; using System.Management.Automation.Host; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class GlobalVars { // Minimum required OS build number @@ -131,4 +131,3 @@ public static class GlobalVars internal readonly static string? userFullName = _identity.userFullName; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/HResultHelper.cs b/Harden-Windows-Security Module/Main files/C#/Others/HResultHelper.cs index cac0d41b1..4583b4767 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/HResultHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/HResultHelper.cs @@ -1,8 +1,8 @@ using System; using System.Runtime.InteropServices; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class HResultHelper { /// @@ -37,4 +37,3 @@ internal static void HandleHresultAndLog(uint? hresult) BitLocker.HasErrorsOccurred = true; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/HashtableChecker.cs b/Harden-Windows-Security Module/Main files/C#/Others/HashtableChecker.cs index efe8e8a40..52f6220e5 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/HashtableChecker.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/HashtableChecker.cs @@ -2,8 +2,8 @@ using System.Collections; using System.Collections.Generic; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + // Class to hold the result of the HashTable check internal sealed class HashTableCheckerResult { @@ -85,4 +85,3 @@ internal static HashTableCheckerResult CheckValue(Hashtable? hashTable, strin return result; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/HelperMethods.cs b/Harden-Windows-Security Module/Main files/C#/Others/HelperMethods.cs index 9a02a741d..cd92821f0 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/HelperMethods.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/HelperMethods.cs @@ -1,8 +1,8 @@ using System.Globalization; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class HelperMethods { // Helper method to convert object to string array @@ -19,4 +19,3 @@ internal static class HelperMethods return null; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/IniFileConverter.cs b/Harden-Windows-Security Module/Main files/C#/Others/IniFileConverter.cs index caaf92f42..2b2eb8dcb 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/IniFileConverter.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/IniFileConverter.cs @@ -3,8 +3,8 @@ using System.IO; using System.Text.RegularExpressions; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class IniFileConverter { /// @@ -53,4 +53,3 @@ internal static Dictionary> ConvertFromIniFil return iniObject; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/Initializer.cs b/Harden-Windows-Security Module/Main files/C#/Others/Initializer.cs index 4f9b4d2cd..0d7791d40 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/Initializer.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/Initializer.cs @@ -3,8 +3,8 @@ using System.Globalization; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + // prepares the environment. It also runs commands that would otherwise run in the default constructors of each method public static class Initializer { @@ -124,4 +124,3 @@ private static bool TryParseBuildVersion(string buildVersion, out decimal result } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/JsonToHashtable.cs b/Harden-Windows-Security Module/Main files/C#/Others/JsonToHashtable.cs index 744ee3f40..9811c7fcd 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/JsonToHashtable.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/JsonToHashtable.cs @@ -2,8 +2,8 @@ using System.IO; using System.Text.Json; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class JsonToHashTable { // Using HashTable since they don't throw error for non-existing keys @@ -106,4 +106,3 @@ private static ArrayList ConvertJsonArrayToArrayList(JsonElement jsonArray) return arrayList; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/LGPORunner.cs b/Harden-Windows-Security Module/Main files/C#/Others/LGPORunner.cs index 1015487a3..7a3152b54 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/LGPORunner.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/LGPORunner.cs @@ -1,7 +1,7 @@ using System; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class LGPORunner { // Enum to specify the file type @@ -31,4 +31,3 @@ internal static void RunLGPOCommand(string filePath, FileType fileType, string? ProcessStarter.RunCommand(LGPOExePath ?? GlobalVars.LGPOExe!, commandArgs); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/LocalGroupMember.cs b/Harden-Windows-Security Module/Main files/C#/Others/LocalGroupMember.cs index 7fc8c66c4..8e485ba0b 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/LocalGroupMember.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/LocalGroupMember.cs @@ -1,8 +1,8 @@ using System.DirectoryServices.AccountManagement; using System.Security.Principal; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class LocalGroupMember { internal static void Add(string userSid, string groupSid) @@ -55,4 +55,3 @@ internal static void Add(string userSid, string groupSid) } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/Logger.cs b/Harden-Windows-Security Module/Main files/C#/Others/Logger.cs index 1a030a28d..97cc43210 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/Logger.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/Logger.cs @@ -3,8 +3,8 @@ using System.IO; using System.Windows.Threading; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + // Log type used when calling the LogMessage method public enum LogTypeIntel { @@ -257,4 +257,3 @@ private static void WriteEventLog(string message, EventLogEntryType Type) } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/MDMClassProcessor.cs b/Harden-Windows-Security Module/Main files/C#/Others/MDMClassProcessor.cs index b6a273cb7..7d877d5be 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/MDMClassProcessor.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/MDMClassProcessor.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal partial class MDMClassProcessor { /// @@ -52,4 +52,3 @@ internal static List Process() return resultsList; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/Miscellaneous.cs b/Harden-Windows-Security Module/Main files/C#/Others/Miscellaneous.cs index 0f946ec52..04a4ae096 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/Miscellaneous.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/Miscellaneous.cs @@ -5,8 +5,8 @@ using System.Management; using System.Management.Automation; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class Miscellaneous { // Clean up the working directory at the end of each cmdlet @@ -122,4 +122,3 @@ public static void RequirementsCheck() } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/MitigationPolicyProcessor.cs b/Harden-Windows-Security Module/Main files/C#/Others/MitigationPolicyProcessor.cs index 462889d10..0077b6330 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/MitigationPolicyProcessor.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/MitigationPolicyProcessor.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Xml; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class MitigationPolicyProcessor { // This method processes the exploit mitigation policies of the current system and returns a dictionary of the mitigations applied to each executable @@ -131,4 +131,3 @@ internal static Dictionary> ProcessMitigationPolicies(st return revisedProcessMitigations; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/PowerShellExecutor.cs b/Harden-Windows-Security Module/Main files/C#/Others/PowerShellExecutor.cs index 3c976b02d..a679906a9 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/PowerShellExecutor.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/PowerShellExecutor.cs @@ -2,8 +2,8 @@ using System.Linq; using System.Management.Automation; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class PowerShellExecutor { /// @@ -124,4 +124,3 @@ internal static class PowerShellExecutor return null; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ProcessMitigationsApplication.cs b/Harden-Windows-Security Module/Main files/C#/Others/ProcessMitigationsApplication.cs index ddbd09c8c..bbf74df15 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ProcessMitigationsApplication.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ProcessMitigationsApplication.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Management.Automation; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class ProcessMitigationsApplication { internal static void Apply() @@ -88,4 +88,3 @@ internal static void Apply() } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ProcessMitigationsParser.cs b/Harden-Windows-Security Module/Main files/C#/Others/ProcessMitigationsParser.cs index 193bc0549..e7bcd07d0 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ProcessMitigationsParser.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ProcessMitigationsParser.cs @@ -2,8 +2,8 @@ using System.Globalization; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class ProcessMitigationsParser { // a class to store the structure of the new CSV data @@ -69,4 +69,3 @@ internal static void ReadCsv() } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/PropertyHelper.cs b/Harden-Windows-Security Module/Main files/C#/Others/PropertyHelper.cs index f86906b6c..deb20e4d0 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/PropertyHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/PropertyHelper.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class PropertyHelper { /// @@ -38,4 +38,3 @@ internal static class PropertyHelper return null; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/RegistryEditor.cs b/Harden-Windows-Security Module/Main files/C#/Others/RegistryEditor.cs index 4354d9b1c..b9fd28818 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/RegistryEditor.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/RegistryEditor.cs @@ -2,8 +2,8 @@ using System; using System.Globalization; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class RegistryEditor { private static readonly string[] separator = [";"]; @@ -121,4 +121,3 @@ internal static void EditRegistry(string path, string key, string value, string } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/RunCommand.cs b/Harden-Windows-Security Module/Main files/C#/Others/RunCommand.cs index c7c5520eb..86b43f30d 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/RunCommand.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/RunCommand.cs @@ -1,8 +1,8 @@ using System; using System.Diagnostics; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class ProcessStarter { /// @@ -57,4 +57,3 @@ internal static void RunCommand(string command, string? arguments = null, bool s } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/SSHConfigurations.cs b/Harden-Windows-Security Module/Main files/C#/Others/SSHConfigurations.cs index caf4f66a4..41d879989 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/SSHConfigurations.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/SSHConfigurations.cs @@ -3,8 +3,8 @@ using System.IO; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class SSHConfigurations { @@ -137,4 +137,3 @@ internal static bool TestSecureMACs() return false; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/SecureStringComparer.cs b/Harden-Windows-Security Module/Main files/C#/Others/SecureStringComparer.cs index e3c4a6537..477adae71 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/SecureStringComparer.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/SecureStringComparer.cs @@ -2,8 +2,8 @@ using System.Runtime.InteropServices; using System.Security; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class SecureStringComparer { /// @@ -57,4 +57,3 @@ internal static bool Compare(SecureString secureString1, SecureString secureStri } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/SecuriryPolicyProcessor.cs b/Harden-Windows-Security Module/Main files/C#/Others/SecuriryPolicyProcessor.cs index 68f026421..bc185b73c 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/SecuriryPolicyProcessor.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/SecuriryPolicyProcessor.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class SecurityPolicyChecker { /// @@ -66,4 +66,3 @@ sectionDict is not null && return nestedObjectArray; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/SecurityPolicyCsvProcessor.cs b/Harden-Windows-Security Module/Main files/C#/Others/SecurityPolicyCsvProcessor.cs index 60d41b9da..fd326f4d4 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/SecurityPolicyCsvProcessor.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/SecurityPolicyCsvProcessor.cs @@ -3,8 +3,8 @@ using System.IO; using System.Text; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + // Represents a record in the security policy public sealed class SecurityPolicyRecord { @@ -105,4 +105,3 @@ private static string[] ParseCsvLine(string line) return [.. fields]; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/SneakAndPeek.cs b/Harden-Windows-Security Module/Main files/C#/Others/SneakAndPeek.cs index bf2841d97..3cf84b871 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/SneakAndPeek.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/SneakAndPeek.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Text.RegularExpressions; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class SneakAndPeek { /// @@ -29,4 +29,3 @@ public static bool Search(string query, string zipFile) return content.Count > 0; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/SystemInfoNativeMethods.cs b/Harden-Windows-Security Module/Main files/C#/Others/SystemInfoNativeMethods.cs index 38e39492e..0083a354d 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/SystemInfoNativeMethods.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/SystemInfoNativeMethods.cs @@ -1,8 +1,8 @@ using System; using System.Runtime.InteropServices; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// bootDMAProtection check - checks for Kernel DMA Protection status in System information or msinfo32 /// can be used to find out if the DMA Protection is ON \ OFF. @@ -47,4 +47,3 @@ internal static byte BootDmaCheck() return 0; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/ToastNotification.cs b/Harden-Windows-Security Module/Main files/C#/Others/ToastNotification.cs index bf9a0ab8f..ee6c6fab6 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/ToastNotification.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/ToastNotification.cs @@ -2,8 +2,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class ToastNotification { @@ -249,4 +249,3 @@ public static void Show(Type Type, string? TotalCompliantValues, string? TotalNo } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/UserPrivCheck.cs b/Harden-Windows-Security Module/Main files/C#/Others/UserPrivCheck.cs index 5c0211ad0..4e9860189 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/UserPrivCheck.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/UserPrivCheck.cs @@ -1,7 +1,7 @@ using System.Security.Principal; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class UserPrivCheck { // Method to check if the user has Administrator privileges @@ -12,4 +12,3 @@ public static bool IsAdmin() return principal.IsInRole(WindowsBuiltInRole.Administrator); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/VolumeWritabilityCheck.cs b/Harden-Windows-Security Module/Main files/C#/Others/VolumeWritabilityCheck.cs index 46c4af4f0..71c84441f 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/VolumeWritabilityCheck.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/VolumeWritabilityCheck.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static partial class VolumeWritabilityCheck { /// @@ -67,4 +67,3 @@ internal static partial class VolumeWritabilityCheck return availableWritableVolumes; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/WinIdentityUser.cs b/Harden-Windows-Security Module/Main files/C#/Others/WinIdentityUser.cs index 20143bf21..2f4b573c8 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/WinIdentityUser.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/WinIdentityUser.cs @@ -2,8 +2,8 @@ using System.Linq; using System.Security.Principal; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal sealed class CurrentUserIdentityResult { @@ -63,4 +63,3 @@ internal static CurrentUserIdentityResult GetCurrentIdentity() }; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Others/WindowsFeatureChecker.cs b/Harden-Windows-Security Module/Main files/C#/Others/WindowsFeatureChecker.cs index a17dd19b0..47744c601 100644 --- a/Harden-Windows-Security Module/Main files/C#/Others/WindowsFeatureChecker.cs +++ b/Harden-Windows-Security Module/Main files/C#/Others/WindowsFeatureChecker.cs @@ -3,8 +3,8 @@ using System.Diagnostics; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class WindowsFeatureChecker { public sealed class FeatureStatus @@ -206,4 +206,3 @@ public static void SetWindowsFeature(string featureName, bool enable) _ = RunDismCommand(arguments); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/AttackSurfaceReductionRules.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/AttackSurfaceReductionRules.cs index 17dfc283c..3d76fe0ed 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/AttackSurfaceReductionRules.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/AttackSurfaceReductionRules.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class AttackSurfaceReductionRules { /// @@ -23,4 +23,3 @@ public static void Invoke() LGPORunner.RunLGPOCommand(Path.Combine(GlobalVars.path, "Resources", "Security-Baselines-X", "Attack Surface Reduction Rules Policies", "registry.pol"), LGPORunner.FileType.POL); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/BitLockerSettings.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/BitLockerSettings.cs index 0c8f3e42d..10b65af34 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/BitLockerSettings.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/BitLockerSettings.cs @@ -3,8 +3,8 @@ using System.IO; using System.Threading; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class BitLockerSettings { /// @@ -79,4 +79,3 @@ public static void Invoke() } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/CertificateCheckingCommands.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/CertificateCheckingCommands.cs index 57b21f29e..17b56fbdc 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/CertificateCheckingCommands.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/CertificateCheckingCommands.cs @@ -3,8 +3,8 @@ using System.IO; using System.Net.Http; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class CertificateCheckingCommands { /// @@ -97,4 +97,3 @@ private static void RunSigcheck(string exePath, string arguments) } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/CountryIPBlocking.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/CountryIPBlocking.cs index 2fde1c11e..ba46d5eae 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/CountryIPBlocking.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/CountryIPBlocking.cs @@ -1,7 +1,7 @@ using System; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class CountryIPBlocking { /// @@ -21,4 +21,3 @@ public static void Invoke() ); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/CountryIPBlocking_OFAC.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/CountryIPBlocking_OFAC.cs index 52a3aa5e9..018d2fee4 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/CountryIPBlocking_OFAC.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/CountryIPBlocking_OFAC.cs @@ -1,7 +1,7 @@ using System; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class CountryIPBlocking { /// @@ -18,4 +18,3 @@ public static void CountryIPBlocking_OFAC() ); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DangerousScriptHostsBlocking.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DangerousScriptHostsBlocking.cs index 6ba8243e8..d75755f30 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DangerousScriptHostsBlocking.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DangerousScriptHostsBlocking.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class DownloadsDefenseMeasures { /// @@ -40,4 +40,3 @@ public static void DangerousScriptHostsBlocking() _ = PowerShellExecutor.ExecuteScript(script); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DeviceGuard.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DeviceGuard.cs index 3e1c84ddb..d54366fb9 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DeviceGuard.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DeviceGuard.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class DeviceGuard { @@ -36,4 +36,3 @@ public static void Invoke() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DeviceGuard_MandatoryVBS.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DeviceGuard_MandatoryVBS.cs index 833a4bbaf..b21cc4bb7 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DeviceGuard_MandatoryVBS.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DeviceGuard_MandatoryVBS.cs @@ -1,7 +1,7 @@ using System; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public partial class DeviceGuard { @@ -31,4 +31,3 @@ public static void DeviceGuard_MandatoryVBS() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DownloadsDefenseMeasures.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DownloadsDefenseMeasures.cs index 663ce12a6..967b7e34b 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/DownloadsDefenseMeasures.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/DownloadsDefenseMeasures.cs @@ -1,5 +1,5 @@ -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class DownloadsDefenseMeasures { /// @@ -95,4 +95,3 @@ public static void Invoke() _ = PowerShellExecutor.ExecuteScript(script); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/EdgeBrowserConfigurations.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/EdgeBrowserConfigurations.cs index 10e57206f..2326ab112 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/EdgeBrowserConfigurations.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/EdgeBrowserConfigurations.cs @@ -1,7 +1,7 @@ using System; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class EdgeBrowserConfigurations { /// @@ -31,4 +31,3 @@ public static void Invoke() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen.cs index 5cd042ea3..63982d77b 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class LockScreen { /// @@ -25,4 +25,3 @@ public static void Invoke() LGPORunner.RunLGPOCommand(Path.Combine(GlobalVars.path, "Resources", "Security-Baselines-X", "Lock Screen Policies", "GptTmpl.inf"), LGPORunner.FileType.INF); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen_CtrlAltDel.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen_CtrlAltDel.cs index 9c1f00b70..31a445601 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen_CtrlAltDel.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen_CtrlAltDel.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class LockScreen { /// @@ -20,4 +20,3 @@ public static void LockScreen_CtrlAltDel() LGPORunner.RunLGPOCommand(Path.Combine(GlobalVars.path, "Resources", "Security-Baselines-X", "Lock Screen Policies", "Enable CTRL + ALT + DEL", "GptTmpl.inf"), LGPORunner.FileType.INF); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen_LastSignedIn.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen_LastSignedIn.cs index 1f4a54b96..b28a941a7 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen_LastSignedIn.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/LockScreen_LastSignedIn.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class LockScreen { /// @@ -22,4 +22,3 @@ public static void LockScreen_LastSignedIn() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_BetaChannels.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_BetaChannels.cs index 4a8ad6b72..611d493b0 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_BetaChannels.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_BetaChannels.cs @@ -1,7 +1,7 @@ using System; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MicrosoftDefender { /// @@ -23,4 +23,3 @@ public static void MSFTDefender_BetaChannels() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_EnableDiagData.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_EnableDiagData.cs index 80efae335..a0d6dd534 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_EnableDiagData.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_EnableDiagData.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MicrosoftDefender { /// @@ -23,4 +23,3 @@ public static void MSFTDefender_EnableDiagData() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_SAC.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_SAC.cs index e6c13b0fe..9340ad621 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_SAC.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_SAC.cs @@ -1,5 +1,5 @@ -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MicrosoftDefender { /// @@ -15,4 +15,3 @@ public static void MSFTDefender_SAC() GlobalVars.ShouldEnableOptionalDiagnosticData = true; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_ScheduledTask.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_ScheduledTask.cs index a8bdc3ad2..90a38618f 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_ScheduledTask.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MSFTDefender_ScheduledTask.cs @@ -1,8 +1,8 @@ using System; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MicrosoftDefender { /// @@ -248,4 +248,3 @@ PowerShell implementation of this } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/Microsoft365AppsSecurityBaselines.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/Microsoft365AppsSecurityBaselines.cs index b9b9ead9a..c8955a034 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/Microsoft365AppsSecurityBaselines.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/Microsoft365AppsSecurityBaselines.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class Microsoft365AppsSecurityBaselines { /// @@ -39,4 +39,3 @@ public static void Invoke() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MicrosoftDefender.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MicrosoftDefender.cs index 85f2db69b..e48b51908 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MicrosoftDefender.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MicrosoftDefender.cs @@ -3,8 +3,8 @@ using System.IO; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MicrosoftDefender { /// @@ -88,4 +88,3 @@ public static void Invoke() _ = PowerShellExecutor.ExecuteScript(@"Set-BcdElement -Element 'nx' -Type 'Integer' -Value '3'"); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MicrosoftSecurityBaselines.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MicrosoftSecurityBaselines.cs index 33ec3fd6a..d5c7550b1 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MicrosoftSecurityBaselines.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MicrosoftSecurityBaselines.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MicrosoftSecurityBaselines { /// @@ -44,4 +44,3 @@ public static void Invoke() _ = PowerShellExecutor.ExecuteScript(Command, false, true); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations.cs index 3c7f5c0bc..b9cfbe6a1 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MiscellaneousConfigurations { /// @@ -77,4 +77,3 @@ public static void Invoke() SSHConfigurations.SecureMACs(); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_LongPathSupport.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_LongPathSupport.cs index 232b13fa5..7cf07c34d 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_LongPathSupport.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_LongPathSupport.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MiscellaneousConfigurations { /// @@ -22,4 +22,3 @@ public static void MiscellaneousConfigurations_LongPathSupport() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_StrongKeyProtection.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_StrongKeyProtection.cs index f06a97244..39b18c496 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_StrongKeyProtection.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_StrongKeyProtection.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MiscellaneousConfigurations { /// @@ -22,4 +22,3 @@ public static void MiscellaneousConfigurations_StrongKeyProtection() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_WindowsProtectedPrint.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_WindowsProtectedPrint.cs index 6c56c8db8..031fabdb6 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_WindowsProtectedPrint.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/MiscellaneousConfigurations_WindowsProtectedPrint.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MiscellaneousConfigurations { /// @@ -22,4 +22,3 @@ public static void MiscellaneousConfigurations_WindowsProtectedPrint() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/NonAdminCommands.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/NonAdminCommands.cs index 98600c7ec..f6205fbaa 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/NonAdminCommands.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/NonAdminCommands.cs @@ -1,7 +1,7 @@ using System; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class NonAdminCommands { /// @@ -30,4 +30,3 @@ public static void Invoke() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/OptionalWindowsFeatures.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/OptionalWindowsFeatures.cs index f9634340b..2c7b22d65 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/OptionalWindowsFeatures.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/OptionalWindowsFeatures.cs @@ -1,8 +1,8 @@ using System; using System.Reflection; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class OptionalWindowsFeatures { // Declare the _FeaturesCheckResults as a private static field @@ -132,4 +132,3 @@ public static void Invoke() RemoveCapability("Browser.InternetExplorer", "Internet Explorer Mode for Edge"); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/SecBaselines_Overrides.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/SecBaselines_Overrides.cs index 269af37c6..61893c4cb 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/SecBaselines_Overrides.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/SecBaselines_Overrides.cs @@ -4,8 +4,8 @@ using System.IO; using System.Threading; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class MicrosoftSecurityBaselines { /// @@ -87,4 +87,3 @@ public static void SecBaselines_Overrides() #endregion } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/TLSSecurity.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/TLSSecurity.cs index 63df298ac..290a432d8 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/TLSSecurity.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/TLSSecurity.cs @@ -2,8 +2,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class TLSSecurity { public static void Invoke() @@ -68,4 +68,3 @@ public static void Invoke() } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/UAC_NoFastSwitching.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/UAC_NoFastSwitching.cs index 5fbc528ee..0fc8bb839 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/UAC_NoFastSwitching.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/UAC_NoFastSwitching.cs @@ -1,7 +1,7 @@ using System; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class UserAccountControl { /// @@ -19,4 +19,3 @@ public static void UAC_NoFastSwitching() LGPORunner.RunLGPOCommand(System.IO.Path.Combine(GlobalVars.path, "Resources", "Security-Baselines-X", "User Account Control UAC Policies", "Hides the entry points for Fast User Switching", "registry.pol"), LGPORunner.FileType.POL); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/UAC_OnlyElevateSigned.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/UAC_OnlyElevateSigned.cs index b8683c04f..7842af471 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/UAC_OnlyElevateSigned.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/UAC_OnlyElevateSigned.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class UserAccountControl { /// @@ -20,4 +20,3 @@ public static void UAC_OnlyElevateSigned() LGPORunner.RunLGPOCommand(Path.Combine(GlobalVars.path, "Resources", "Security-Baselines-X", "User Account Control UAC Policies", "Only elevate executables that are signed and validated", "GptTmpl.inf"), LGPORunner.FileType.INF); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/UserAccountControl.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/UserAccountControl.cs index 5d11a41a6..64a4ece24 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/UserAccountControl.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/UserAccountControl.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class UserAccountControl { /// @@ -22,4 +22,3 @@ public static void Invoke() LGPORunner.RunLGPOCommand(Path.Combine(GlobalVars.path, "Resources", "Security-Baselines-X", "User Account Control UAC Policies", "GptTmpl.inf"), LGPORunner.FileType.INF); } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsFirewall.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsFirewall.cs index 3d9d3e9a7..e0dcb2883 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsFirewall.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsFirewall.cs @@ -5,8 +5,8 @@ using System.Linq; using System.Management; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class WindowsFirewall { /// @@ -50,4 +50,3 @@ public static void Invoke() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsNetworking.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsNetworking.cs index 3e013c5d0..a34d58a6e 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsNetworking.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsNetworking.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class WindowsNetworking { /// @@ -38,4 +38,3 @@ public static void Invoke() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsNetworking_BlockNTLM.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsNetworking_BlockNTLM.cs index f50d65a7d..4e827030c 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsNetworking_BlockNTLM.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsNetworking_BlockNTLM.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static partial class WindowsNetworking { /// @@ -23,4 +23,3 @@ public static void WindowsNetworking_BlockNTLM() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsUpdateConfigurations.cs b/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsUpdateConfigurations.cs index e652837ad..296e6925b 100644 --- a/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsUpdateConfigurations.cs +++ b/Harden-Windows-Security Module/Main files/C#/Protect Methods/WindowsUpdateConfigurations.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class WindowsUpdateConfigurations { /// @@ -28,4 +28,3 @@ public static void Invoke() } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Types/CiPolicyInfo.cs b/Harden-Windows-Security Module/Main files/C#/Types/CiPolicyInfo.cs index ac83a0f84..b053ff763 100644 --- a/Harden-Windows-Security Module/Main files/C#/Types/CiPolicyInfo.cs +++ b/Harden-Windows-Security Module/Main files/C#/Types/CiPolicyInfo.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// Class to represent a policy with various attributes /// @@ -20,4 +20,3 @@ public sealed class CiPolicyInfo public bool IsAuthorized { get; set; } // Indicates if the policy is authorized public List? PolicyOptions { get; set; }// List of options or settings related to the policy } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Types/CustomExceptions.cs b/Harden-Windows-Security Module/Main files/C#/Types/CustomExceptions.cs index e479e4b37..95dffe3ec 100644 --- a/Harden-Windows-Security Module/Main files/C#/Types/CustomExceptions.cs +++ b/Harden-Windows-Security Module/Main files/C#/Types/CustomExceptions.cs @@ -1,7 +1,7 @@ using System; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + // Custom exception class for PowerShell execution errors public sealed class PowerShellExecutionException : Exception { @@ -16,5 +16,4 @@ public PowerShellExecutionException(string message, Exception innerException) : public PowerShellExecutionException() { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/Harden-Windows-Security Module/Main files/C#/Types/DefenderPlatformUpdatesChannels.cs b/Harden-Windows-Security Module/Main files/C#/Types/DefenderPlatformUpdatesChannels.cs index 832da5cf8..5219c2ee1 100644 --- a/Harden-Windows-Security Module/Main files/C#/Types/DefenderPlatformUpdatesChannels.cs +++ b/Harden-Windows-Security Module/Main files/C#/Types/DefenderPlatformUpdatesChannels.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// Microsoft Defender Update channel names for Platform and Engine /// @@ -17,4 +17,3 @@ internal static class DefenderPlatformUpdatesChannels { 6, "Delayed" } }; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Types/EccCurveComparisonResult.cs b/Harden-Windows-Security Module/Main files/C#/Types/EccCurveComparisonResult.cs index e848d4fd0..68dcc2ad0 100644 --- a/Harden-Windows-Security Module/Main files/C#/Types/EccCurveComparisonResult.cs +++ b/Harden-Windows-Security Module/Main files/C#/Types/EccCurveComparisonResult.cs @@ -1,10 +1,9 @@ using System.Collections.Generic; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal sealed class EccCurveComparisonResult { internal bool AreCurvesCompliant { get; set; } internal List? CurrentEccCurves { get; set; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Types/IndividualResultClass.cs b/Harden-Windows-Security Module/Main files/C#/Types/IndividualResultClass.cs index 60c81e33d..d080f6f31 100644 --- a/Harden-Windows-Security Module/Main files/C#/Types/IndividualResultClass.cs +++ b/Harden-Windows-Security Module/Main files/C#/Types/IndividualResultClass.cs @@ -1,5 +1,5 @@ -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// A class that defines a single compliance check result /// @@ -12,4 +12,3 @@ public sealed class IndividualResult public required ComplianceCategories Category { get; set; } public required ConfirmSystemComplianceMethods.Method Method { get; set; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Types/MDMResult.cs b/Harden-Windows-Security Module/Main files/C#/Types/MDMResult.cs index 22990cc0c..9be6bc6eb 100644 --- a/Harden-Windows-Security Module/Main files/C#/Types/MDMResult.cs +++ b/Harden-Windows-Security Module/Main files/C#/Types/MDMResult.cs @@ -1,9 +1,8 @@ -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal sealed partial class MDMClassProcessor(string name, string value, string cimInstance) { internal string Name { get; set; } = name; internal string Value { get; set; } = value; internal string CimInstance { get; set; } = cimInstance; } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Unprotect Methods/UnprotectWindowsSecurity.cs b/Harden-Windows-Security Module/Main files/C#/Unprotect Methods/UnprotectWindowsSecurity.cs index fa6224e08..9fc5f864e 100644 --- a/Harden-Windows-Security Module/Main files/C#/Unprotect Methods/UnprotectWindowsSecurity.cs +++ b/Harden-Windows-Security Module/Main files/C#/Unprotect Methods/UnprotectWindowsSecurity.cs @@ -5,8 +5,8 @@ using System.IO; using System.Linq; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class UnprotectWindowsSecurity { /// @@ -269,4 +269,3 @@ public static void RemoveAppControlPolicies(bool DownloadsDefenseMeasures, bool } } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Windows APIs/FirmwareType.cs b/Harden-Windows-Security Module/Main files/C#/Windows APIs/FirmwareType.cs index d45afea1d..4872bdf52 100644 --- a/Harden-Windows-Security Module/Main files/C#/Windows APIs/FirmwareType.cs +++ b/Harden-Windows-Security Module/Main files/C#/Windows APIs/FirmwareType.cs @@ -1,7 +1,7 @@ using System.Runtime.InteropServices; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + internal static class FirmwareChecker { // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfirmwaretype @@ -29,4 +29,3 @@ internal static FirmwareType CheckFirmwareType() return FirmwareType.FirmwareTypeUnknown; } } -} diff --git a/Harden-Windows-Security Module/Main files/C#/Windows APIs/TPM.cs b/Harden-Windows-Security Module/Main files/C#/Windows APIs/TPM.cs index e5d55f3e3..e8512cc1c 100644 --- a/Harden-Windows-Security Module/Main files/C#/Windows APIs/TPM.cs +++ b/Harden-Windows-Security Module/Main files/C#/Windows APIs/TPM.cs @@ -4,8 +4,8 @@ using System.Management; using System.Runtime.InteropServices; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + /// /// Class that contains the results of TPM status checks /// @@ -151,4 +151,3 @@ public static TpmResult GetV2() return result; } } -} diff --git a/Harden-Windows-Security Module/Program.cs b/Harden-Windows-Security Module/Program.cs index 590e8e7b8..b7cfdaab6 100644 --- a/Harden-Windows-Security Module/Program.cs +++ b/Harden-Windows-Security Module/Program.cs @@ -1,8 +1,8 @@ using System; using System.IO; -namespace HardenWindowsSecurity -{ +namespace HardenWindowsSecurity; + public static class Program { /// @@ -37,4 +37,3 @@ public static void Main() } } -} From a29789f98de7b4867c117e9e2710b85ad3a6e12d Mon Sep 17 00:00:00 2001 From: Violet Hansen Date: Sat, 21 Dec 2024 07:39:32 +0200 Subject: [PATCH 2/4] spacing fix via code clean up spacing fix via code clean up --- .../BitLocker-AddKeyProtectors.cs | 1180 ++-- .../CimInstances/BitLocker-DataCollection.cs | 940 ++-- .../C#/CimInstances/BitLocker-Disable.cs | 170 +- .../C#/CimInstances/BitLocker-Enable.cs | 1188 ++--- .../BitLocker-EnableBitLockerAutoUnlock.cs | 174 +- .../BitLocker-EnableKeyProtectors.cs | 88 +- .../BitLocker-RemoveKeyProtectors.cs | 170 +- .../C#/CimInstances/ConfigDefenderHelper.cs | 316 +- .../C#/CimInstances/FirewallHelper.cs | 586 +- .../Main files/C#/CimInstances/MDM.cs | 342 +- .../C#/CimInstances/MpPreferenceHelper.cs | 154 +- .../C#/CimInstances/NetConnectionProfiles.cs | 284 +- .../C#/CimInstances/TaskSchedulerHelper.cs | 584 +- .../C#/Confirm Methods/InvokeConfirmation.cs | 112 +- .../Confirm Methods/SYSTEMScheduledTasks.cs | 30 +- .../Main files/C#/GUI/ASRRules/Variables.cs | 10 +- .../Main files/C#/GUI/ASRRules/View.cs | 788 +-- .../Main files/C#/GUI/BitLocker/Variables.cs | 214 +- .../Main files/C#/GUI/BitLocker/View.cs | 1050 ++-- .../Main files/C#/GUI/Confirm/SecOp.cs | 162 +- .../Main files/C#/GUI/Confirm/Variables.cs | 10 +- .../Main files/C#/GUI/Confirm/View.cs | 780 +-- .../Main files/C#/GUI/Exclusions/Variables.cs | 22 +- .../Main files/C#/GUI/Exclusions/View.cs | 434 +- .../Main files/C#/GUI/GUIBootStrapper.cs | 76 +- .../Main files/C#/GUI/Log/Variables.cs | 22 +- .../Main files/C#/GUI/Log/View.cs | 242 +- .../Main files/C#/GUI/Main/GUI.cs | 966 ++-- .../Main files/C#/GUI/Main/Variables.cs | 42 +- .../GUI/Protection/Miscellaneous methods.cs | 234 +- .../Main files/C#/GUI/Protection/Variables.cs | 208 +- .../Main files/C#/GUI/Protection/View.cs | 948 ++-- .../Main files/C#/GUI/Unprotect/Variables.cs | 14 +- .../Main files/C#/GUI/Unprotect/View.cs | 578 +- .../Main files/C#/Others/ActivityTracker.cs | 238 +- .../Main files/C#/Others/AsyncDownloader.cs | 526 +- .../C#/Others/AttackSurfaceReductionIntel.cs | 146 +- .../Main files/C#/Others/AuditPolicyHelper.cs | 790 +-- .../Main files/C#/Others/CSVImporter.cs | 120 +- .../Main files/C#/Others/Categoriex.cs | 274 +- .../C#/Others/CategoryProcessing.cs | 854 +-- .../C#/Others/ChangePSConsoleTitle.cs | 38 +- .../Main files/C#/Others/CiToolRunner.cs | 548 +- .../C#/Others/ConditionalResultAdd.cs | 88 +- .../Others/ConfirmSystemComplianceMethods.cs | 4737 ++++++++--------- .../Others/ControlledFolderAccessHandler.cs | 340 +- .../Main files/C#/Others/DialogMsgHelper.cs | 110 +- .../Main files/C#/Others/EccCurveComparer.cs | 104 +- .../C#/Others/ExportSecurityPolicy.cs | 64 +- .../C#/Others/ForceRelocateImagesForFiles.cs | 82 +- .../Main files/C#/Others/GetLocalUser.cs | 234 +- .../Main files/C#/Others/GetMDMResultValue.cs | 70 +- .../C#/Others/GetOneDriveDirectories.cs | 108 +- .../Main files/C#/Others/GitExesFinder.cs | 78 +- .../C#/Others/GitHubDesktopFinder.cs | 84 +- .../Main files/C#/Others/GlobalVars.cs | 174 +- .../Main files/C#/Others/HResultHelper.cs | 60 +- .../Main files/C#/Others/HashtableChecker.cs | 148 +- .../Main files/C#/Others/HelperMethods.cs | 32 +- .../Main files/C#/Others/IniFileConverter.cs | 86 +- .../Main files/C#/Others/Initializer.cs | 240 +- .../Main files/C#/Others/JsonToHashtable.cs | 204 +- .../Main files/C#/Others/LGPORunner.cs | 54 +- .../Main files/C#/Others/LocalGroupMember.cs | 104 +- .../Main files/C#/Others/Logger.cs | 434 +- .../Main files/C#/Others/MDMClassProcessor.cs | 90 +- .../Main files/C#/Others/Miscellaneous.cs | 230 +- .../C#/Others/MitigationPolicyProcessor.cs | 254 +- .../C#/Others/PowerShellExecutor.cs | 216 +- .../Others/ProcessMitigationsApplication.cs | 166 +- .../C#/Others/ProcessMitigationsParser.cs | 110 +- .../Main files/C#/Others/PropertyHelper.cs | 64 +- .../Main files/C#/Others/RegistryEditor.cs | 220 +- .../Main files/C#/Others/RunCommand.cs | 108 +- .../Main files/C#/Others/SSHConfigurations.cs | 264 +- .../C#/Others/SecureStringComparer.cs | 106 +- .../C#/Others/SecuriryPolicyProcessor.cs | 110 +- .../C#/Others/SecurityPolicyCsvProcessor.cs | 200 +- .../Main files/C#/Others/SneakAndPeek.cs | 42 +- .../C#/Others/SystemInfoNativeMethods.cs | 78 +- .../Main files/C#/Others/ToastNotification.cs | 324 +- .../Main files/C#/Others/UserPrivCheck.cs | 20 +- .../C#/Others/VolumeWritabilityCheck.cs | 108 +- .../Main files/C#/Others/WinIdentityUser.cs | 94 +- .../C#/Others/WindowsFeatureChecker.cs | 394 +- .../AttackSurfaceReductionRules.cs | 34 +- .../C#/Protect Methods/BitLockerSettings.cs | 150 +- .../CertificateCheckingCommands.cs | 184 +- .../C#/Protect Methods/CountryIPBlocking.cs | 32 +- .../Protect Methods/CountryIPBlocking_OFAC.cs | 30 +- .../DangerousScriptHostsBlocking.cs | 40 +- .../C#/Protect Methods/DeviceGuard.cs | 50 +- .../DeviceGuard_MandatoryVBS.cs | 58 +- .../DownloadsDefenseMeasures.cs | 28 +- .../EdgeBrowserConfigurations.cs | 48 +- .../C#/Protect Methods/LockScreen.cs | 36 +- .../Protect Methods/LockScreen_CtrlAltDel.cs | 32 +- .../LockScreen_LastSignedIn.cs | 32 +- .../MSFTDefender_BetaChannels.cs | 34 +- .../MSFTDefender_EnableDiagData.cs | 32 +- .../C#/Protect Methods/MSFTDefender_SAC.cs | 26 +- .../MSFTDefender_ScheduledTask.cs | 328 +- .../Microsoft365AppsSecurityBaselines.cs | 64 +- .../C#/Protect Methods/MicrosoftDefender.cs | 122 +- .../MicrosoftSecurityBaselines.cs | 76 +- .../MiscellaneousConfigurations.cs | 146 +- ...ellaneousConfigurations_LongPathSupport.cs | 32 +- ...neousConfigurations_StrongKeyProtection.cs | 32 +- ...ousConfigurations_WindowsProtectedPrint.cs | 32 +- .../C#/Protect Methods/NonAdminCommands.cs | 48 +- .../OptionalWindowsFeatures.cs | 246 +- .../Protect Methods/SecBaselines_Overrides.cs | 162 +- .../C#/Protect Methods/TLSSecurity.cs | 90 +- .../C#/Protect Methods/UAC_NoFastSwitching.cs | 32 +- .../Protect Methods/UAC_OnlyElevateSigned.cs | 32 +- .../C#/Protect Methods/UserAccountControl.cs | 34 +- .../C#/Protect Methods/WindowsFirewall.cs | 58 +- .../C#/Protect Methods/WindowsNetworking.cs | 70 +- .../WindowsNetworking_BlockNTLM.cs | 32 +- .../WindowsUpdateConfigurations.cs | 40 +- .../Main files/C#/Types/CiPolicyInfo.cs | 34 +- .../Main files/C#/Types/CustomExceptions.cs | 26 +- .../Types/DefenderPlatformUpdatesChannels.cs | 30 +- .../C#/Types/EccCurveComparisonResult.cs | 10 +- .../C#/Types/IndividualResultClass.cs | 24 +- .../Main files/C#/Types/MDMResult.cs | 12 +- .../UnprotectWindowsSecurity.cs | 438 +- .../C#/Windows APIs/FirmwareType.cs | 50 +- .../Main files/C#/Windows APIs/TPM.cs | 280 +- Harden-Windows-Security Module/Program.cs | 68 +- 130 files changed, 15489 insertions(+), 15490 deletions(-) diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-AddKeyProtectors.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-AddKeyProtectors.cs index 291c694e2..e2c265b0f 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-AddKeyProtectors.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-AddKeyProtectors.cs @@ -7,643 +7,643 @@ namespace HardenWindowsSecurity; - internal static partial class BitLocker - { - - /// - /// Accepts a drive letter in the following format: "C:" - /// The returns the volume information acquired from the Win32_EncryptableVolume CIM Instance - /// - /// - /// ManagementObject - /// - private static ManagementObject GetVolumeFromLetter(string DriveLetter) - { - // Use `using` to properly dispose of the `ManagementObjectSearcher` and `ManagementObjectCollection` - using ManagementObjectSearcher searcher = new( - @"root\cimv2\Security\MicrosoftVolumeEncryption", - "SELECT * FROM Win32_EncryptableVolume"); - - using ManagementObjectCollection volumes = searcher.Get(); - - // Filter by drive letter - ManagementObject? driveInstance = volumes.Cast().FirstOrDefault(v => v["DriveLetter"]?.ToString() == DriveLetter); - - return driveInstance ?? throw new InvalidOperationException($"Volume for drive {DriveLetter} not found."); - } - - - - /// - /// Removes all key protectors of the specified type from the specified drive - /// https://learn.microsoft.com/en-us/windows/win32/secprov/getkeyprotectors-win32-encryptablevolume - /// - /// - /// - /// - private static void RemoveTpmBasedKeyProtectors(ManagementObject driveInstance, uint keyProtectorType) - { - // Create a ManagementBaseObject for the arguments to GetKeyProtectors. - ManagementBaseObject getKeyProtectorsArgs = driveInstance.GetMethodParameters("GetKeyProtectors"); - - // Set the KeyProtectorType argument to the specified type. - getKeyProtectorsArgs["KeyProtectorType"] = keyProtectorType; - - // Invoke GetKeyProtectors method to get all of the key protectors based on the selected type and store the results - ManagementBaseObject keyProtectorResult = driveInstance.InvokeMethod("GetKeyProtectors", getKeyProtectorsArgs, null); - - // Get the array of VolumeKeyProtectorID from the result. - string[] KeyProtectorIDs = (string[])keyProtectorResult["VolumeKeyProtectorID"]; - - // Check if there is at least 1 key protector - if (KeyProtectorIDs is not null && KeyProtectorIDs.Length >= 1) - { - // Loop over all of the key protectors of the specified type and remove all of them - foreach (string KeyProtectorID in KeyProtectorIDs) - { - - // Prepare arguments for DeleteKeyProtector method. - ManagementBaseObject deleteKeyProtectorArgs = driveInstance.GetMethodParameters("DeleteKeyProtector"); - - // Set the VolumeKeyProtectorID argument to the current KeyProtectorID in the loop - deleteKeyProtectorArgs["VolumeKeyProtectorID"] = KeyProtectorID; - - // Invoke DeleteKeyProtector method to remove the key protector - ManagementBaseObject deletionResult = driveInstance.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); - - #region Output handling - uint? deletionResultCode = null; - - if (deletionResult is not null) - { - deletionResultCode = Convert.ToUInt32(deletionResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (deletionResultCode is not null && deletionResultCode == 0) - { - Logger.LogMessage($"Successfully removed a key protector of type {keyProtectorType}", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(deletionResultCode); - return; - } - #endregion - - } - } - else - { - Logger.LogMessage($"No key protector of type {keyProtectorType} found.", LogTypeIntel.Information); - } - } - - - - /// - /// Adds the recovery password protector (NumericalPassword) to the specified drive - /// This is the same RecoveryPassword that is used to unlock the drive in case of a forgotten password after using the Harden Windows Security application - /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithnumericalpassword-win32-encryptablevolume - /// - /// - /// - /// - internal static void AddRecoveryPassword(string DriveLetter, string? Password) - { - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - - - // If we supply the password ourselves then it can be used, otherwise it should be null - // If it's null, the CIM method will automatically assign a random password - // If we want to supply in a password ourselves, it should be in the following format otherwise the return value will be non-zero indicating there was an error - // "111111-111111-111111-111111-111111-111111-111111-111111" - // Note that even the example above which only consists of 1s is acceptable since it follows the correct format. - - ManagementBaseObject protectWithPasswordArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithNumericalPassword"); - protectWithPasswordArgs["FriendlyName"] = null; - // If the password is null, empty or whitespace then use null, otherwise use the user supplied password - protectWithPasswordArgs["NumericalPassword"] = string.IsNullOrWhiteSpace(Password) ? null : Password; - - // Invoke the method and add the key protector - ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithNumericalPassword", protectWithPasswordArgs, null); - - #region Output handling - uint? MethodInvocationResultCode = null; - - if (MethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("Successfully added the Recovery Password key protector.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion - } - - - - /// - /// Adds the password protector (PassPhrase) to the specified drive - /// If the OS-drive is using TpmPin or TpmPinStartupKey then this cannot be used, so mostly suitable for non-OS drives - /// If the drive already has this type of key protector and user tries to add it again to it, results in an error. - /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithpassphrase-win32-encryptablevolume - /// - /// The drive letter - /// The password to be used as a key protector, e.g: "1a2b3c4b" - /// - internal static void AddPasswordProtector(string DriveLetter, string? PassPhrase) - { - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - - if (string.IsNullOrWhiteSpace(PassPhrase)) - { - throw new InvalidOperationException("PassPhrase cannot be null or empty"); - } - - // Prepare the method with arguments - ManagementBaseObject protectWithPassphraseArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithPassphrase"); - protectWithPassphraseArgs["FriendlyName"] = null; - protectWithPassphraseArgs["PassPhrase"] = PassPhrase; - - // Invoke the method to add the key protector - ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithPassphrase", protectWithPassphraseArgs, null); - - #region Output handling - uint? MethodInvocationResultCode = null; - - if (MethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("Successfully added Password key protector (aka Passphrase).", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion - - } - - - - /// - /// Adds the Tpm protector to the specified drive - /// Naturally, The group policy must allow the TPM-only protector otherwise this method results in an error - /// If other TPM based key protectors exist, they will be removed only after this one is added. - /// But adding this type of key protector while it is already added will result in an error. - /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithtpm-win32-encryptablevolume - /// - /// - internal static void AddTpmProtector(string DriveLetter) - { - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - - // Prepare the method and supply the arguments - ManagementBaseObject protectWithTpmArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithTPM"); - protectWithTpmArgs["FriendlyName"] = null; - protectWithTpmArgs["PlatformValidationProfile"] = null; - - // Invoke the method to add the key protector - ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithTPM", protectWithTpmArgs, null); - - - #region Output handling - uint? MethodInvocationResultCode = null; - - if (MethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("Successfully added the TPM key protector.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion - - // Have to remove all other TPM based key protectors - // There can only be 1 of this type - - RemoveTpmBasedKeyProtectors(VolumeInfo, 6); // TpmPinStartupKey - RemoveTpmBasedKeyProtectors(VolumeInfo, 5); // TpmStartupKey - RemoveTpmBasedKeyProtectors(VolumeInfo, 4); // TpmPin - - } - - - - /// - /// Adds the TpmAndPin protector to the specified drive - /// If other TPM based key protectors exist, they will be removed only after this one is added. - /// But adding this type of key protector while it is already added will result in an error. - /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithtpmandpin-win32-encryptablevolume - /// - /// - /// Startup PIN to be used during system boot - internal static void AddTpmAndPinProtector(string DriveLetter, string PIN) - { - - if (string.IsNullOrWhiteSpace(PIN)) - { - throw new InvalidOperationException("PIN cannot be null or empty"); - } - - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - - // Prepare the method with the arguments - ManagementBaseObject protectWithTpmAndPinArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithTPMAndPin"); - protectWithTpmAndPinArgs["FriendlyName"] = null; - protectWithTpmAndPinArgs["PlatformValidationProfile"] = null; - protectWithTpmAndPinArgs["PIN"] = PIN; - - // Invoke the method to add the key protector - ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithTPMAndPin", protectWithTpmAndPinArgs, null); - - - #region Output handling - uint? MethodInvocationResultCode = null; - - if (MethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("Successfully added the TpmAndPin key protector.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion - - - // Delete all other TPM based protectors, there can only be 1 of this type - RemoveTpmBasedKeyProtectors(VolumeInfo, 6); // TpmPinStartupKey - RemoveTpmBasedKeyProtectors(VolumeInfo, 5); // TpmStartupKey - RemoveTpmBasedKeyProtectors(VolumeInfo, 1); // Tpm - } - - - - /// - /// Adds the TPM + StartupKey key protector - /// If other TPM based key protectors exist, they will be removed only after this one is added. - /// But adding this type of key protector while it is already added will result in an error. - /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithtpmandstartupkey-win32-encryptablevolume - /// https://learn.microsoft.com/en-us/windows/win32/secprov/saveexternalkeytofile-win32-encryptablevolume - /// - /// The Drive letter in the format: "C:" - /// Path to a Drive or Folder, such as: @"C:\". The folder/drive path must exist otherwise error is thrown. - /// - internal static void AddTpmAndStartupKeyProtector(string DriveLetter, string StartupKeyPath) - { - - if (string.IsNullOrWhiteSpace(StartupKeyPath)) - { - throw new InvalidOperationException("Startup Key Path cannot be null or empty"); - } - - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - - - // Prepare the method with the arguments - ManagementBaseObject protectWithTpmAndStartupKeyArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithTPMAndStartupKey"); - protectWithTpmAndStartupKeyArgs["FriendlyName"] = null; - protectWithTpmAndStartupKeyArgs["PlatformValidationProfile"] = null; - protectWithTpmAndStartupKeyArgs["ExternalKey"] = null; - - // Invoke the method to add the key protector - ManagementBaseObject ProtectKeyWithTPMAndStartupKeyMethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithTPMAndStartupKey", protectWithTpmAndStartupKeyArgs, null); +internal static partial class BitLocker +{ + + /// + /// Accepts a drive letter in the following format: "C:" + /// The returns the volume information acquired from the Win32_EncryptableVolume CIM Instance + /// + /// + /// ManagementObject + /// + private static ManagementObject GetVolumeFromLetter(string DriveLetter) + { + // Use `using` to properly dispose of the `ManagementObjectSearcher` and `ManagementObjectCollection` + using ManagementObjectSearcher searcher = new( + @"root\cimv2\Security\MicrosoftVolumeEncryption", + "SELECT * FROM Win32_EncryptableVolume"); + + using ManagementObjectCollection volumes = searcher.Get(); + + // Filter by drive letter + ManagementObject? driveInstance = volumes.Cast().FirstOrDefault(v => v["DriveLetter"]?.ToString() == DriveLetter); + + return driveInstance ?? throw new InvalidOperationException($"Volume for drive {DriveLetter} not found."); + } + + + + /// + /// Removes all key protectors of the specified type from the specified drive + /// https://learn.microsoft.com/en-us/windows/win32/secprov/getkeyprotectors-win32-encryptablevolume + /// + /// + /// + /// + private static void RemoveTpmBasedKeyProtectors(ManagementObject driveInstance, uint keyProtectorType) + { + // Create a ManagementBaseObject for the arguments to GetKeyProtectors. + ManagementBaseObject getKeyProtectorsArgs = driveInstance.GetMethodParameters("GetKeyProtectors"); + + // Set the KeyProtectorType argument to the specified type. + getKeyProtectorsArgs["KeyProtectorType"] = keyProtectorType; + + // Invoke GetKeyProtectors method to get all of the key protectors based on the selected type and store the results + ManagementBaseObject keyProtectorResult = driveInstance.InvokeMethod("GetKeyProtectors", getKeyProtectorsArgs, null); + + // Get the array of VolumeKeyProtectorID from the result. + string[] KeyProtectorIDs = (string[])keyProtectorResult["VolumeKeyProtectorID"]; + + // Check if there is at least 1 key protector + if (KeyProtectorIDs is not null && KeyProtectorIDs.Length >= 1) + { + // Loop over all of the key protectors of the specified type and remove all of them + foreach (string KeyProtectorID in KeyProtectorIDs) + { + + // Prepare arguments for DeleteKeyProtector method. + ManagementBaseObject deleteKeyProtectorArgs = driveInstance.GetMethodParameters("DeleteKeyProtector"); + + // Set the VolumeKeyProtectorID argument to the current KeyProtectorID in the loop + deleteKeyProtectorArgs["VolumeKeyProtectorID"] = KeyProtectorID; + + // Invoke DeleteKeyProtector method to remove the key protector + ManagementBaseObject deletionResult = driveInstance.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); + + #region Output handling + uint? deletionResultCode = null; + + if (deletionResult is not null) + { + deletionResultCode = Convert.ToUInt32(deletionResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (deletionResultCode is not null && deletionResultCode == 0) + { + Logger.LogMessage($"Successfully removed a key protector of type {keyProtectorType}", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(deletionResultCode); + return; + } + #endregion + + } + } + else + { + Logger.LogMessage($"No key protector of type {keyProtectorType} found.", LogTypeIntel.Information); + } + } + + + + /// + /// Adds the recovery password protector (NumericalPassword) to the specified drive + /// This is the same RecoveryPassword that is used to unlock the drive in case of a forgotten password after using the Harden Windows Security application + /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithnumericalpassword-win32-encryptablevolume + /// + /// + /// + /// + internal static void AddRecoveryPassword(string DriveLetter, string? Password) + { + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + + + // If we supply the password ourselves then it can be used, otherwise it should be null + // If it's null, the CIM method will automatically assign a random password + // If we want to supply in a password ourselves, it should be in the following format otherwise the return value will be non-zero indicating there was an error + // "111111-111111-111111-111111-111111-111111-111111-111111" + // Note that even the example above which only consists of 1s is acceptable since it follows the correct format. + + ManagementBaseObject protectWithPasswordArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithNumericalPassword"); + protectWithPasswordArgs["FriendlyName"] = null; + // If the password is null, empty or whitespace then use null, otherwise use the user supplied password + protectWithPasswordArgs["NumericalPassword"] = string.IsNullOrWhiteSpace(Password) ? null : Password; + + // Invoke the method and add the key protector + ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithNumericalPassword", protectWithPasswordArgs, null); + + #region Output handling + uint? MethodInvocationResultCode = null; + + if (MethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("Successfully added the Recovery Password key protector.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion + } + + + + /// + /// Adds the password protector (PassPhrase) to the specified drive + /// If the OS-drive is using TpmPin or TpmPinStartupKey then this cannot be used, so mostly suitable for non-OS drives + /// If the drive already has this type of key protector and user tries to add it again to it, results in an error. + /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithpassphrase-win32-encryptablevolume + /// + /// The drive letter + /// The password to be used as a key protector, e.g: "1a2b3c4b" + /// + internal static void AddPasswordProtector(string DriveLetter, string? PassPhrase) + { + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + + if (string.IsNullOrWhiteSpace(PassPhrase)) + { + throw new InvalidOperationException("PassPhrase cannot be null or empty"); + } + + // Prepare the method with arguments + ManagementBaseObject protectWithPassphraseArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithPassphrase"); + protectWithPassphraseArgs["FriendlyName"] = null; + protectWithPassphraseArgs["PassPhrase"] = PassPhrase; + + // Invoke the method to add the key protector + ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithPassphrase", protectWithPassphraseArgs, null); + + #region Output handling + uint? MethodInvocationResultCode = null; + + if (MethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("Successfully added Password key protector (aka Passphrase).", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion + + } + + + + /// + /// Adds the Tpm protector to the specified drive + /// Naturally, The group policy must allow the TPM-only protector otherwise this method results in an error + /// If other TPM based key protectors exist, they will be removed only after this one is added. + /// But adding this type of key protector while it is already added will result in an error. + /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithtpm-win32-encryptablevolume + /// + /// + internal static void AddTpmProtector(string DriveLetter) + { + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + + // Prepare the method and supply the arguments + ManagementBaseObject protectWithTpmArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithTPM"); + protectWithTpmArgs["FriendlyName"] = null; + protectWithTpmArgs["PlatformValidationProfile"] = null; + + // Invoke the method to add the key protector + ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithTPM", protectWithTpmArgs, null); + + + #region Output handling + uint? MethodInvocationResultCode = null; + + if (MethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("Successfully added the TPM key protector.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion + + // Have to remove all other TPM based key protectors + // There can only be 1 of this type + + RemoveTpmBasedKeyProtectors(VolumeInfo, 6); // TpmPinStartupKey + RemoveTpmBasedKeyProtectors(VolumeInfo, 5); // TpmStartupKey + RemoveTpmBasedKeyProtectors(VolumeInfo, 4); // TpmPin + + } + + + + /// + /// Adds the TpmAndPin protector to the specified drive + /// If other TPM based key protectors exist, they will be removed only after this one is added. + /// But adding this type of key protector while it is already added will result in an error. + /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithtpmandpin-win32-encryptablevolume + /// + /// + /// Startup PIN to be used during system boot + internal static void AddTpmAndPinProtector(string DriveLetter, string PIN) + { + + if (string.IsNullOrWhiteSpace(PIN)) + { + throw new InvalidOperationException("PIN cannot be null or empty"); + } + + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + + // Prepare the method with the arguments + ManagementBaseObject protectWithTpmAndPinArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithTPMAndPin"); + protectWithTpmAndPinArgs["FriendlyName"] = null; + protectWithTpmAndPinArgs["PlatformValidationProfile"] = null; + protectWithTpmAndPinArgs["PIN"] = PIN; + + // Invoke the method to add the key protector + ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithTPMAndPin", protectWithTpmAndPinArgs, null); + + + #region Output handling + uint? MethodInvocationResultCode = null; + + if (MethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("Successfully added the TpmAndPin key protector.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion + + + // Delete all other TPM based protectors, there can only be 1 of this type + RemoveTpmBasedKeyProtectors(VolumeInfo, 6); // TpmPinStartupKey + RemoveTpmBasedKeyProtectors(VolumeInfo, 5); // TpmStartupKey + RemoveTpmBasedKeyProtectors(VolumeInfo, 1); // Tpm + } + + + + /// + /// Adds the TPM + StartupKey key protector + /// If other TPM based key protectors exist, they will be removed only after this one is added. + /// But adding this type of key protector while it is already added will result in an error. + /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithtpmandstartupkey-win32-encryptablevolume + /// https://learn.microsoft.com/en-us/windows/win32/secprov/saveexternalkeytofile-win32-encryptablevolume + /// + /// The Drive letter in the format: "C:" + /// Path to a Drive or Folder, such as: @"C:\". The folder/drive path must exist otherwise error is thrown. + /// + internal static void AddTpmAndStartupKeyProtector(string DriveLetter, string StartupKeyPath) + { + + if (string.IsNullOrWhiteSpace(StartupKeyPath)) + { + throw new InvalidOperationException("Startup Key Path cannot be null or empty"); + } + + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + + + // Prepare the method with the arguments + ManagementBaseObject protectWithTpmAndStartupKeyArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithTPMAndStartupKey"); + protectWithTpmAndStartupKeyArgs["FriendlyName"] = null; + protectWithTpmAndStartupKeyArgs["PlatformValidationProfile"] = null; + protectWithTpmAndStartupKeyArgs["ExternalKey"] = null; + + // Invoke the method to add the key protector + ManagementBaseObject ProtectKeyWithTPMAndStartupKeyMethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithTPMAndStartupKey", protectWithTpmAndStartupKeyArgs, null); - #region Output handling - uint? MethodInvocationResultCode = null; + #region Output handling + uint? MethodInvocationResultCode = null; - if (ProtectKeyWithTPMAndStartupKeyMethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(ProtectKeyWithTPMAndStartupKeyMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("The TpmAndStartupKey key protector was successfully added. Backing up the Startup key in the next step.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion - - - // Save the Startup key which is a hidden file in a path - ManagementBaseObject saveExternalKeyArgs = VolumeInfo.GetMethodParameters("SaveExternalKeyToFile"); - saveExternalKeyArgs["VolumeKeyProtectorID"] = ProtectKeyWithTPMAndStartupKeyMethodInvocationResult!["VolumeKeyProtectorId"]; - saveExternalKeyArgs["Path"] = StartupKeyPath; + if (ProtectKeyWithTPMAndStartupKeyMethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(ProtectKeyWithTPMAndStartupKeyMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("The TpmAndStartupKey key protector was successfully added. Backing up the Startup key in the next step.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion + + + // Save the Startup key which is a hidden file in a path + ManagementBaseObject saveExternalKeyArgs = VolumeInfo.GetMethodParameters("SaveExternalKeyToFile"); + saveExternalKeyArgs["VolumeKeyProtectorID"] = ProtectKeyWithTPMAndStartupKeyMethodInvocationResult!["VolumeKeyProtectorId"]; + saveExternalKeyArgs["Path"] = StartupKeyPath; - // Invoke the method to save the external key the file path - ManagementBaseObject SaveExternalKeyToFileMethodInvocationResult = VolumeInfo.InvokeMethod("SaveExternalKeyToFile", saveExternalKeyArgs, null); - - - #region Output handling - uint? MethodInvocationResultCode2 = null; - - if (SaveExternalKeyToFileMethodInvocationResult is not null) - { - MethodInvocationResultCode2 = Convert.ToUInt32(SaveExternalKeyToFileMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (MethodInvocationResultCode2 is not null && MethodInvocationResultCode2 == 0) - { - Logger.LogMessage($"Successfully backed up the Startup key to {StartupKeyPath}", LogTypeIntel.Information); - - // Delete all other TPM based protectors, there can only be 1 of this type - RemoveTpmBasedKeyProtectors(VolumeInfo, 4); // TpmPin - RemoveTpmBasedKeyProtectors(VolumeInfo, 1); // Tpm - RemoveTpmBasedKeyProtectors(VolumeInfo, 6); // TpmPinStartupKey - } - else - { - // If the key wasn't saved successfully, remove the protector as a safety measure - - ManagementBaseObject deleteKeyProtectorArgs = VolumeInfo.GetMethodParameters("DeleteKeyProtector"); - deleteKeyProtectorArgs["VolumeKeyProtectorID"] = ProtectKeyWithTPMAndStartupKeyMethodInvocationResult["VolumeKeyProtectorID"]; - _ = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); - - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode2); - return; - } - #endregion + // Invoke the method to save the external key the file path + ManagementBaseObject SaveExternalKeyToFileMethodInvocationResult = VolumeInfo.InvokeMethod("SaveExternalKeyToFile", saveExternalKeyArgs, null); + + + #region Output handling + uint? MethodInvocationResultCode2 = null; + + if (SaveExternalKeyToFileMethodInvocationResult is not null) + { + MethodInvocationResultCode2 = Convert.ToUInt32(SaveExternalKeyToFileMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (MethodInvocationResultCode2 is not null && MethodInvocationResultCode2 == 0) + { + Logger.LogMessage($"Successfully backed up the Startup key to {StartupKeyPath}", LogTypeIntel.Information); + + // Delete all other TPM based protectors, there can only be 1 of this type + RemoveTpmBasedKeyProtectors(VolumeInfo, 4); // TpmPin + RemoveTpmBasedKeyProtectors(VolumeInfo, 1); // Tpm + RemoveTpmBasedKeyProtectors(VolumeInfo, 6); // TpmPinStartupKey + } + else + { + // If the key wasn't saved successfully, remove the protector as a safety measure + + ManagementBaseObject deleteKeyProtectorArgs = VolumeInfo.GetMethodParameters("DeleteKeyProtector"); + deleteKeyProtectorArgs["VolumeKeyProtectorID"] = ProtectKeyWithTPMAndStartupKeyMethodInvocationResult["VolumeKeyProtectorID"]; + _ = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); + + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode2); + return; + } + #endregion - } - - - - /// - /// Add the TpmAndPinAndStartupKeyProtector to the drive - /// If other TPM based key protectors exist, they will be removed only after this one is added. - /// But adding this type of key protector while it is already added will result in an error. - /// - /// - /// Path to a Drive or Folder, such as: @"C:\". The folder/drive path must exist otherwise error is thrown. - /// A pin, its minimum length defined by policies - internal static void AddTpmAndPinAndStartupKeyProtector(string DriveLetter, string StartupKeyPath, string PIN) - { - - if (string.IsNullOrWhiteSpace(PIN) || string.IsNullOrWhiteSpace(StartupKeyPath)) - { - throw new InvalidOperationException("PIN or Startup Key Path cannot be null or empty"); - } + } + + + + /// + /// Add the TpmAndPinAndStartupKeyProtector to the drive + /// If other TPM based key protectors exist, they will be removed only after this one is added. + /// But adding this type of key protector while it is already added will result in an error. + /// + /// + /// Path to a Drive or Folder, such as: @"C:\". The folder/drive path must exist otherwise error is thrown. + /// A pin, its minimum length defined by policies + internal static void AddTpmAndPinAndStartupKeyProtector(string DriveLetter, string StartupKeyPath, string PIN) + { + + if (string.IsNullOrWhiteSpace(PIN) || string.IsNullOrWhiteSpace(StartupKeyPath)) + { + throw new InvalidOperationException("PIN or Startup Key Path cannot be null or empty"); + } - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - // Prepare the method with arguments - ManagementBaseObject protectWithTpmAndPinAndStartupKeyArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithTPMAndPinAndStartupKey"); - protectWithTpmAndPinAndStartupKeyArgs["FriendlyName"] = null; - protectWithTpmAndPinAndStartupKeyArgs["PlatformValidationProfile"] = null; - protectWithTpmAndPinAndStartupKeyArgs["ExternalKey"] = null; - protectWithTpmAndPinAndStartupKeyArgs["PIN"] = PIN; + // Prepare the method with arguments + ManagementBaseObject protectWithTpmAndPinAndStartupKeyArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithTPMAndPinAndStartupKey"); + protectWithTpmAndPinAndStartupKeyArgs["FriendlyName"] = null; + protectWithTpmAndPinAndStartupKeyArgs["PlatformValidationProfile"] = null; + protectWithTpmAndPinAndStartupKeyArgs["ExternalKey"] = null; + protectWithTpmAndPinAndStartupKeyArgs["PIN"] = PIN; - // Invoke the method to add the key protector - ManagementBaseObject ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithTPMAndPinAndStartupKey", protectWithTpmAndPinAndStartupKeyArgs, null); + // Invoke the method to add the key protector + ManagementBaseObject ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithTPMAndPinAndStartupKey", protectWithTpmAndPinAndStartupKeyArgs, null); - #region Output handling - uint? MethodInvocationResultCode = null; + #region Output handling + uint? MethodInvocationResultCode = null; - if (ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("The TpmAndPinAndStartupKey key protector was successfully added. Will backup the startup key in the next step.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion - - - ManagementBaseObject saveExternalKeyArgs = VolumeInfo.GetMethodParameters("SaveExternalKeyToFile"); - saveExternalKeyArgs["VolumeKeyProtectorID"] = ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult!["VolumeKeyProtectorId"]; - saveExternalKeyArgs["Path"] = StartupKeyPath; + if (ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("The TpmAndPinAndStartupKey key protector was successfully added. Will backup the startup key in the next step.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion + + + ManagementBaseObject saveExternalKeyArgs = VolumeInfo.GetMethodParameters("SaveExternalKeyToFile"); + saveExternalKeyArgs["VolumeKeyProtectorID"] = ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult!["VolumeKeyProtectorId"]; + saveExternalKeyArgs["Path"] = StartupKeyPath; - // Invoke the method to save the external key the file path - ManagementBaseObject SaveExternalKeyToFileMethodInvocationResult = VolumeInfo.InvokeMethod("SaveExternalKeyToFile", saveExternalKeyArgs, null); - - - #region Output handling - uint? MethodInvocationResultCode2 = null; + // Invoke the method to save the external key the file path + ManagementBaseObject SaveExternalKeyToFileMethodInvocationResult = VolumeInfo.InvokeMethod("SaveExternalKeyToFile", saveExternalKeyArgs, null); + + + #region Output handling + uint? MethodInvocationResultCode2 = null; - if (SaveExternalKeyToFileMethodInvocationResult is not null) - { - MethodInvocationResultCode2 = Convert.ToUInt32(SaveExternalKeyToFileMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (MethodInvocationResultCode2 is not null && MethodInvocationResultCode2 == 0) - { - Logger.LogMessage($"Successfully backed up the startup key to {StartupKeyPath}", LogTypeIntel.Information); - - // Delete all other TPM based protectors, there can only be 1 of this type - RemoveTpmBasedKeyProtectors(VolumeInfo, 4); // TpmPin - RemoveTpmBasedKeyProtectors(VolumeInfo, 1); // Tpm - RemoveTpmBasedKeyProtectors(VolumeInfo, 5); // TpmStartupKey - } - else - { - // If the key wasn't saved successfully, remove the protector as a safety measure - - ManagementBaseObject deleteKeyProtectorArgs = VolumeInfo.GetMethodParameters("DeleteKeyProtector"); - deleteKeyProtectorArgs["VolumeKeyProtectorID"] = ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult["VolumeKeyProtectorID"]; - _ = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); + if (SaveExternalKeyToFileMethodInvocationResult is not null) + { + MethodInvocationResultCode2 = Convert.ToUInt32(SaveExternalKeyToFileMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (MethodInvocationResultCode2 is not null && MethodInvocationResultCode2 == 0) + { + Logger.LogMessage($"Successfully backed up the startup key to {StartupKeyPath}", LogTypeIntel.Information); + + // Delete all other TPM based protectors, there can only be 1 of this type + RemoveTpmBasedKeyProtectors(VolumeInfo, 4); // TpmPin + RemoveTpmBasedKeyProtectors(VolumeInfo, 1); // Tpm + RemoveTpmBasedKeyProtectors(VolumeInfo, 5); // TpmStartupKey + } + else + { + // If the key wasn't saved successfully, remove the protector as a safety measure + + ManagementBaseObject deleteKeyProtectorArgs = VolumeInfo.GetMethodParameters("DeleteKeyProtector"); + deleteKeyProtectorArgs["VolumeKeyProtectorID"] = ProtectKeyWithTPMAndPinAndStartupKeyMethodInvocationResult["VolumeKeyProtectorID"]; + _ = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode2); - return; - } - #endregion - } + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode2); + return; + } + #endregion + } - /// - /// Adds the StartupKeyProtector or RecoveryKeyProtector, same thing - /// They can be added even if the volume already has a StartupKey key protector, there can be multiple Startup Key protectors (aka ExternalKey key protectors) for 1 drive. - /// It also works if the drive already has a TpmPinStartupKey key protector. - /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithexternalkey-win32-encryptablevolume - /// - /// - /// Path to a Drive or Folder, such as: @"C:\". The folder/drive path must exist otherwise error is thrown. - /// - internal static void AddStartupKeyProtector_OR_RecoveryKeyProtector(string DriveLetter, string StartupKeyPath) - { - - if (string.IsNullOrWhiteSpace(StartupKeyPath)) - { - throw new InvalidOperationException("Startup Key Path cannot be null or empty"); - } + /// + /// Adds the StartupKeyProtector or RecoveryKeyProtector, same thing + /// They can be added even if the volume already has a StartupKey key protector, there can be multiple Startup Key protectors (aka ExternalKey key protectors) for 1 drive. + /// It also works if the drive already has a TpmPinStartupKey key protector. + /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithexternalkey-win32-encryptablevolume + /// + /// + /// Path to a Drive or Folder, such as: @"C:\". The folder/drive path must exist otherwise error is thrown. + /// + internal static void AddStartupKeyProtector_OR_RecoveryKeyProtector(string DriveLetter, string StartupKeyPath) + { + + if (string.IsNullOrWhiteSpace(StartupKeyPath)) + { + throw new InvalidOperationException("Startup Key Path cannot be null or empty"); + } - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - // Prepare the method with arguments - ManagementBaseObject protectWithExternalKeyArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithExternalKey"); - protectWithExternalKeyArgs["FriendlyName"] = null; - protectWithExternalKeyArgs["ExternalKey"] = null; + // Prepare the method with arguments + ManagementBaseObject protectWithExternalKeyArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithExternalKey"); + protectWithExternalKeyArgs["FriendlyName"] = null; + protectWithExternalKeyArgs["ExternalKey"] = null; - // Invoke the method to add the key protector - ManagementBaseObject ProtectKeyWithExternalKeyMethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithExternalKey", protectWithExternalKeyArgs, null); + // Invoke the method to add the key protector + ManagementBaseObject ProtectKeyWithExternalKeyMethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithExternalKey", protectWithExternalKeyArgs, null); - #region Output handling - uint? MethodInvocationResultCode = null; + #region Output handling + uint? MethodInvocationResultCode = null; - if (ProtectKeyWithExternalKeyMethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(ProtectKeyWithExternalKeyMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } + if (ProtectKeyWithExternalKeyMethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(ProtectKeyWithExternalKeyMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("The StartupKey key protector was successfully added. Will back up it in the next step.", LogTypeIntel.Information); - // Will move forward to the next step - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("The StartupKey key protector was successfully added. Will back up it in the next step.", LogTypeIntel.Information); + // Will move forward to the next step + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion - // Prepare the method with arguments - ManagementBaseObject saveExternalKeyArgs = VolumeInfo.GetMethodParameters("SaveExternalKeyToFile"); - saveExternalKeyArgs["VolumeKeyProtectorID"] = ProtectKeyWithExternalKeyMethodInvocationResult!["VolumeKeyProtectorId"]; - saveExternalKeyArgs["Path"] = StartupKeyPath; + // Prepare the method with arguments + ManagementBaseObject saveExternalKeyArgs = VolumeInfo.GetMethodParameters("SaveExternalKeyToFile"); + saveExternalKeyArgs["VolumeKeyProtectorID"] = ProtectKeyWithExternalKeyMethodInvocationResult!["VolumeKeyProtectorId"]; + saveExternalKeyArgs["Path"] = StartupKeyPath; - // Invoke the method to backup the startup key - ManagementBaseObject SaveExternalKeyToFileMethodInvocationResult = VolumeInfo.InvokeMethod("SaveExternalKeyToFile", saveExternalKeyArgs, null); + // Invoke the method to backup the startup key + ManagementBaseObject SaveExternalKeyToFileMethodInvocationResult = VolumeInfo.InvokeMethod("SaveExternalKeyToFile", saveExternalKeyArgs, null); - #region Output handling - uint? MethodInvocationResultCode2 = null; - - if (SaveExternalKeyToFileMethodInvocationResult is not null) - { - MethodInvocationResultCode2 = Convert.ToUInt32(SaveExternalKeyToFileMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (MethodInvocationResultCode2 is not null && MethodInvocationResultCode2 == 0) - { - Logger.LogMessage($"Successfully backed up the Startup key to {StartupKeyPath}", LogTypeIntel.Information); - } - else - { - // If the key wasn't saved successfully, remove the protector as a safety measure - - ManagementBaseObject deleteKeyProtectorArgs = VolumeInfo.GetMethodParameters("DeleteKeyProtector"); - deleteKeyProtectorArgs["VolumeKeyProtectorID"] = ProtectKeyWithExternalKeyMethodInvocationResult["VolumeKeyProtectorID"]; - _ = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); + #region Output handling + uint? MethodInvocationResultCode2 = null; + + if (SaveExternalKeyToFileMethodInvocationResult is not null) + { + MethodInvocationResultCode2 = Convert.ToUInt32(SaveExternalKeyToFileMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (MethodInvocationResultCode2 is not null && MethodInvocationResultCode2 == 0) + { + Logger.LogMessage($"Successfully backed up the Startup key to {StartupKeyPath}", LogTypeIntel.Information); + } + else + { + // If the key wasn't saved successfully, remove the protector as a safety measure + + ManagementBaseObject deleteKeyProtectorArgs = VolumeInfo.GetMethodParameters("DeleteKeyProtector"); + deleteKeyProtectorArgs["VolumeKeyProtectorID"] = ProtectKeyWithExternalKeyMethodInvocationResult["VolumeKeyProtectorID"]; + _ = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode2); + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode2); - Logger.LogMessage($"Error saving the Startup key in the defined path, removing the Startup key KeyProtector.", LogTypeIntel.Error); + Logger.LogMessage($"Error saving the Startup key in the defined path, removing the Startup key KeyProtector.", LogTypeIntel.Error); - return; - } - #endregion + return; + } + #endregion - } + } - /// - /// Adds the SidProtector to the drive - /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithadsid-win32-encryptablevolume - /// More info: https://learn.microsoft.com/en-us/windows/security/operating-system-security/data-protection/bitlocker/operations-guide?tabs=powershell#add-a-password-protector - /// - /// - /// - /// - /// - internal static void AddSidProtector(string DriveLetter, string SID, bool ServiceAccount) - { - if (string.IsNullOrWhiteSpace(SID)) - { - throw new InvalidOperationException("SID cannot be null or empty"); - } + /// + /// Adds the SidProtector to the drive + /// https://learn.microsoft.com/en-us/windows/win32/secprov/protectkeywithadsid-win32-encryptablevolume + /// More info: https://learn.microsoft.com/en-us/windows/security/operating-system-security/data-protection/bitlocker/operations-guide?tabs=powershell#add-a-password-protector + /// + /// + /// + /// + /// + internal static void AddSidProtector(string DriveLetter, string SID, bool ServiceAccount) + { + if (string.IsNullOrWhiteSpace(SID)) + { + throw new InvalidOperationException("SID cannot be null or empty"); + } - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - // 1 means FVE_DPAPI_NG_FLAG_UNLOCK_AS_SERVICE_ACCOUNT - uint flags = ServiceAccount ? 1 : (uint)0; + // 1 means FVE_DPAPI_NG_FLAG_UNLOCK_AS_SERVICE_ACCOUNT + uint flags = ServiceAccount ? 1 : (uint)0; - // Convert the SID string to a SecurityIdentifier object - SecurityIdentifier SIDResult = new(SID); + // Convert the SID string to a SecurityIdentifier object + SecurityIdentifier SIDResult = new(SID); - // Prepare the method with arguments - ManagementBaseObject protectWithSidArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithAdSid"); - protectWithSidArgs["FriendlyName"] = null; - protectWithSidArgs["SidString"] = SIDResult.Value; - protectWithSidArgs["Flags"] = flags; + // Prepare the method with arguments + ManagementBaseObject protectWithSidArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithAdSid"); + protectWithSidArgs["FriendlyName"] = null; + protectWithSidArgs["SidString"] = SIDResult.Value; + protectWithSidArgs["Flags"] = flags; - // Invoke the method to add the key protector - ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithAdSid", protectWithSidArgs, null); + // Invoke the method to add the key protector + ManagementBaseObject MethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithAdSid", protectWithSidArgs, null); - #region Output handling - uint? MethodInvocationResultCode = null; - - if (MethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } + #region Output handling + uint? MethodInvocationResultCode = null; + + if (MethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(MethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("Successfully added the SID key protector.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("Successfully added the SID key protector.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion - } + } - } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-DataCollection.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-DataCollection.cs index c387a931e..92108107a 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-DataCollection.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-DataCollection.cs @@ -15,473 +15,473 @@ namespace HardenWindowsSecurity; - internal partial class BitLocker - { - - // Class that stores the information about each key protector - internal sealed class KeyProtector - { - internal KeyProtectorType? KeyProtectorType { get; set; } - internal string? KeyProtectorID { get; set; } - internal bool AutoUnlockProtector { get; set; } - internal string? KeyFileName { get; set; } - internal string? RecoveryPassword { get; set; } - internal string? KeyCertificateType { get; set; } - internal string? Thumbprint { get; set; } - } - - // class that stores the information about BitLocker protected volumes - internal sealed class BitLockerVolume - { - internal string? MountPoint { get; set; } - internal EncryptionMethod? EncryptionMethod { get; set; } - internal string? EncryptionMethodFlags { get; set; } - internal bool AutoUnlockEnabled { get; set; } - internal bool AutoUnlockKeyStored { get; set; } - - // https://learn.microsoft.com/en-us/windows/win32/secprov/getversion-win32-encryptablevolume#parameters - internal uint MetadataVersion { get; set; } - - internal ConversionStatus? ConversionStatus { get; set; } - internal ProtectionStatus? ProtectionStatus { get; set; } - internal LockStatus? LockStatus { get; set; } - internal string? EncryptionPercentage { get; set; } - internal string? WipePercentage { get; set; } - internal WipingStatus? WipingStatus { get; set; } - internal VolumeType? VolumeType { get; set; } - internal string? CapacityGB { get; set; } - internal FileSystemType? FileSystemType { get; set; } - internal string? FriendlyName { get; set; } - internal string? AllocationUnitSize { get; set; } - internal ReFSDedupMode? ReFSDedupMode { get; set; } - internal List? KeyProtector { get; set; } - } - - // Different types of the key protectors - // https://learn.microsoft.com/en-us/windows/win32/secprov/getkeyprotectortype-win32-encryptablevolume - internal enum KeyProtectorType : uint - { - Unknown = 0, - Tpm = 1, - ExternalKey = 2, - RecoveryPassword = 3, - TpmPin = 4, - TpmStartupKey = 5, - TpmPinStartupKey = 6, - PublicKey = 7, - Password = 8, - TpmNetworkKey = 9, - AdAccountOrGroup = 10 - } - - // https://learn.microsoft.com/en-us/windows/win32/secprov/getencryptionmethod-win32-encryptablevolume - internal enum EncryptionMethod : uint - { - None = 0, - AES_128_WITH_DIFFUSER = 1, - AES_256_WITH_DIFFUSER = 2, - AES_128 = 3, - AES_256 = 4, - HARDWARE_ENCRYPTION = 5, - XTS_AES_128 = 6, - XTS_AES_256 = 7 - } - - // https://learn.microsoft.com/en-us/windows/win32/secprov/getprotectionstatus-win32-encryptablevolume - internal enum ProtectionStatus : uint - { - Unprotected = 0, - Protected = 1, - Unknown = 2 - } - - // https://learn.microsoft.com/en-us/windows/win32/secprov/getlockstatus-win32-encryptablevolume - internal enum LockStatus - { - Unlocked = 0, - Locked = 1 - } - - // https://learn.microsoft.com/en-us/windows/win32/secprov/win32-encryptablevolume#properties - internal enum VolumeType - { - OperationSystem = 0, - FixedDisk = 1, - Removable = 2 - } - - // https://learn.microsoft.com/en-us/windows/win32/secprov/getconversionstatus-win32-encryptablevolume - internal enum ConversionStatus : uint - { - FullyDecrypted = 0, - FullyEncrypted = 1, - EncryptionInProgress = 2, - DecryptionInProgress = 3, - EncryptionPaused = 4, - DecryptionPaused = 5 - } - - // https://learn.microsoft.com/en-us/windows/win32/secprov/getconversionstatus-win32-encryptablevolume - internal enum WipingStatus : uint - { - FreeSpaceNotWiped = 0, - FreeSpaceWiped = 1, - FreeSpaceWipingInProgress = 2, - FreeSpaceWipingPaused = 3 - } - - // https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/msft-volume#properties - internal enum FileSystemType : ushort - { - Unknown = 0, - UFS = 2, - HFS = 3, - FAT = 4, - FAT16 = 5, - FAT32 = 6, - NTFS4 = 7, - NTFS5 = 8, - XFS = 9, - AFS = 10, - EXT2 = 11, - EXT3 = 12, - ReiserFS = 13, - NTFS = 14, - ReFS = 15 - } - - // https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/msft-volume#properties - internal enum ReFSDedupMode : uint - { - Disabled = 0, - GeneralPurpose = 1, - HyperV = 2, - Backup = 3, - NotAvailable = 4 - } - - - // The main method that will generate as much useful info as possible about every BitLocker volume - internal static BitLockerVolume GetEncryptedVolumeInfo(string targetVolume) - { - // The MSFT_Volume class requires the volume name without the colon - string targetVolumeVer2 = targetVolume.Replace(":", "", StringComparison.OrdinalIgnoreCase); - - // Create a new instance of the BitLockerVolume class - BitLockerVolume newInstance = new(); - - // Get the information about the volume using Win32_EncryptableVolume class - // This is used a lot as the main input object to get information from other classes - ManagementBaseObject? volume = GetCimInstance("Root\\CIMV2\\Security\\MicrosoftVolumeEncryption", "Win32_EncryptableVolume", $"DriveLetter = '{targetVolume}'"); - - // Make sure there is data - if (volume is not null) - { - // Set the MountPoint property of the final object to the drive letter - newInstance.MountPoint = volume["DriveLetter"]?.ToString(); - - try - { - // Set the ProtectionStatus property if it exists - newInstance.ProtectionStatus = (ProtectionStatus)Convert.ToUInt32(volume["ProtectionStatus"], CultureInfo.InvariantCulture); - } - catch { /* ignore */ } - - try - { - // Set the VolumeType property if it exists - newInstance.VolumeType = (VolumeType)Convert.ToUInt32(volume["VolumeType"], CultureInfo.InvariantCulture); - } - catch { /* ignore */ } - - try - { - // Try to use the GetLockStatus method to get the CurrentLockStatus - ManagementBaseObject currentLockStatus = InvokeCimMethod(volume, "GetLockStatus", null); - if (currentLockStatus is not null && Convert.ToUInt32(currentLockStatus["ReturnValue"], CultureInfo.InvariantCulture) == 0) - { - // Set the LockStatus property if it exists - newInstance.LockStatus = (LockStatus)Convert.ToUInt32(currentLockStatus["LockStatus"], CultureInfo.InvariantCulture); - } - } - catch { /* ignore */ } - - try - { - ManagementBaseObject currentVolConversionStatus = InvokeCimMethod(volume, "GetConversionStatus", null); - if (currentVolConversionStatus is not null && Convert.ToUInt32(currentVolConversionStatus["ReturnValue"], CultureInfo.InvariantCulture) == 0) - { - newInstance.EncryptionPercentage = currentVolConversionStatus["EncryptionPercentage"]?.ToString(); - newInstance.WipePercentage = currentVolConversionStatus["WipingPercentage"]?.ToString(); - newInstance.ConversionStatus = (ConversionStatus)Convert.ToUInt32(currentVolConversionStatus["ConversionStatus"], CultureInfo.InvariantCulture); - newInstance.WipingStatus = (WipingStatus)Convert.ToUInt32(currentVolConversionStatus["WipingStatus"], CultureInfo.InvariantCulture); - } - } - catch { /* ignore */ } - - try - { - // Try to use the GetEncryptionMethod method to get the EncryptionMethod and EncryptionMethodFlags properties - ManagementBaseObject? currentEncryptionMethod = InvokeCimMethod(volume, "GetEncryptionMethod", null); - if (currentEncryptionMethod is not null && Convert.ToUInt32(currentEncryptionMethod["ReturnValue"], CultureInfo.InvariantCulture) == 0) - { - uint EncryptionMethodNum = Convert.ToUInt32(currentEncryptionMethod["EncryptionMethod"], CultureInfo.InvariantCulture); - - // Cast the uint to the EncryptionMethod enum - newInstance.EncryptionMethod = (EncryptionMethod)EncryptionMethodNum; - - newInstance.EncryptionMethodFlags = currentEncryptionMethod["EncryptionMethodFlags"]?.ToString(); - } - } - catch { /* ignore */ } - - try - { - // Use the GetVersion method - ManagementBaseObject currentVolVersion = InvokeCimMethod(volume, "GetVersion", null); - if (currentVolVersion is not null && Convert.ToUInt32(currentVolVersion["ReturnValue"], CultureInfo.InvariantCulture) == 0) - { - newInstance.MetadataVersion = Convert.ToUInt32(currentVolVersion["Version"], CultureInfo.InvariantCulture); - } - } - catch { /* ignore */ } - - try - { - // Use the GetKeyProtectors method - ManagementBaseObject keyProtectors = InvokeCimMethod(volume, "GetKeyProtectors", null); - - // If there are any key protectors - if (keyProtectors is not null) - { - // Create a new list of KeyProtector objects to store the results of processing each key protector in the loop below - newInstance.KeyProtector = []; - - // Iterate through all of the key protectors' IDs - foreach (string keyProtectorID in (string[])keyProtectors["VolumeKeyProtectorID"]) - { - // Set them all to null initially so we don't accidentally use them for the wrong key protector type - KeyProtectorType? type = null; - string? recoveryPassword = null; - bool autoUnlockProtector = false; - string? keyProtectorFileName = null; - string? keyProtectorThumbprint = null; - string? keyProtectorCertificateType = null; - - try - { - // Use the GetKeyProtectorType method - ManagementBaseObject keyProtectorTypeResult = InvokeCimMethod(volume, "GetKeyProtectorType", new Dictionary { { "VolumeKeyProtectorID", keyProtectorID } }); - if (keyProtectorTypeResult is not null) - { - uint keyProtectorType = Convert.ToUInt32(keyProtectorTypeResult["KeyProtectorType"], CultureInfo.InvariantCulture); - // Cast the uint value to the KeyProtectorType enum - type = (KeyProtectorType)keyProtectorType; - - // if the current key protector is RecoveryPassword / Numerical password - if (keyProtectorType == 3) - { - ManagementBaseObject numericalPassword = InvokeCimMethod(volume, "GetKeyProtectorNumericalPassword", new Dictionary { { "VolumeKeyProtectorID", keyProtectorID } }); - if (numericalPassword is not null && Convert.ToUInt32(numericalPassword["ReturnValue"], CultureInfo.InvariantCulture) == 0) - { - recoveryPassword = numericalPassword["NumericalPassword"]?.ToString(); - } - } - - // if the current key protector is ExternalKey - if (keyProtectorType == 2) - { - ManagementBaseObject autoUnlockEnabledResult = InvokeCimMethod(volume, "IsAutoUnlockEnabled", null); - if (autoUnlockEnabledResult is not null && Convert.ToUInt32(autoUnlockEnabledResult["ReturnValue"], CultureInfo.InvariantCulture) == 0) - { - bool isAutoUnlockEnabled = Convert.ToBoolean(autoUnlockEnabledResult["IsAutoUnlockEnabled"], CultureInfo.InvariantCulture); - string? volumeKeyProtectorID = autoUnlockEnabledResult["VolumeKeyProtectorID"]?.ToString(); - - if (isAutoUnlockEnabled && string.Equals(volumeKeyProtectorID, keyProtectorID, StringComparison.Ordinal)) - { - autoUnlockProtector = true; - } - } - - ManagementBaseObject keyProtectorFileNameResult = InvokeCimMethod(volume, "GetExternalKeyFileName", new Dictionary { { "VolumeKeyProtectorID", keyProtectorID } }); - if (keyProtectorFileNameResult is not null && Convert.ToUInt32(keyProtectorFileNameResult["ReturnValue"], CultureInfo.InvariantCulture) == 0) - { - keyProtectorFileName = keyProtectorFileNameResult["FileName"]?.ToString(); - } - } - - // if the current key protector is PublicKey or TpmNetworkKey - if (keyProtectorType is 7 or 9) - { - ManagementBaseObject keyProtectorCertificateResult = InvokeCimMethod(volume, "GetKeyProtectorCertificate", new Dictionary { { "VolumeKeyProtectorID", keyProtectorID } }); - if (keyProtectorCertificateResult is not null && Convert.ToUInt32(keyProtectorCertificateResult["ReturnValue"], CultureInfo.InvariantCulture) == 0) - { - keyProtectorThumbprint = keyProtectorCertificateResult["CertThumbprint"]?.ToString(); - keyProtectorCertificateType = keyProtectorCertificateResult["CertType"]?.ToString(); - } - } - - // Create a new KeyProtector class instance and add it to the KeyProtector property of the output object as an array member - newInstance.KeyProtector.Add(new KeyProtector - { - KeyProtectorID = keyProtectorID, - KeyProtectorType = type, - RecoveryPassword = recoveryPassword, - AutoUnlockProtector = autoUnlockProtector, - KeyFileName = keyProtectorFileName, - KeyCertificateType = keyProtectorCertificateType, - Thumbprint = keyProtectorThumbprint - }); - } - } - catch { /* ignore */ } - } - } - } - catch { /* ignore */ } - } - - // Get volume information using the MSFT_Volume class - ManagementBaseObject? currentStorage = GetCimInstance("Root\\Microsoft\\Windows\\Storage", "MSFT_Volume", $"DriveLetter = '{targetVolumeVer2}'"); - if (currentStorage is not null) - { - try - { - newInstance.CapacityGB = Math.Round(Convert.ToDouble(currentStorage["Size"], CultureInfo.InvariantCulture) / (1024 * 1024 * 1024), 4).ToString(CultureInfo.InvariantCulture); - } - catch { /* ignore */ } - - try - { - newInstance.FileSystemType = (FileSystemType)Convert.ToUInt16(currentStorage["FileSystemType"], CultureInfo.InvariantCulture); - } - catch { /* ignore */ } - - try - { - newInstance.FriendlyName = currentStorage["FileSystemLabel"]?.ToString(); - } - catch { /* ignore */ } - - try - { - newInstance.AllocationUnitSize = currentStorage["AllocationUnitSize"]?.ToString(); - } - catch { /* ignore */ } - - try - { - newInstance.ReFSDedupMode = (ReFSDedupMode)Convert.ToUInt32(currentStorage["ReFSDedupMode"], CultureInfo.InvariantCulture); - } - catch { /* ignore */ } - } - - return newInstance; - } - - - // Helper method to get the information from the WMI classes - private static ManagementBaseObject? GetCimInstance(string @namespace, string className, string filter) - { - SelectQuery query = new(className, filter); - using ManagementObjectSearcher searcher = new(@namespace, query.QueryString); - - return searcher.Get().Cast().FirstOrDefault(); - } - - // Helper method to invoke a method on a WMI class - private static ManagementBaseObject InvokeCimMethod(ManagementBaseObject instance, string methodName, Dictionary? parameters) - { - using ManagementClass managementClass = new(instance.ClassPath); - - ManagementBaseObject inParams = managementClass.GetMethodParameters(methodName); - if (parameters is not null) - { - foreach (KeyValuePair param in parameters) - { - inParams[param.Key] = param.Value; - } - } - return ((ManagementObject)instance).InvokeMethod(methodName, inParams, null); - } - - // Method to get the drive letters of all volumes on the system, encrypted or not - internal static string[] GetAllDriveLetters() - { - List driveLetters = []; - - ManagementObjectCollection storages = GetCimInstances("Root\\Microsoft\\Windows\\Storage", "MSFT_Volume", string.Empty); - - foreach (ManagementBaseObject storage in storages) - { - // Iterate through the properties of the storage object - foreach (PropertyData property in storage.Properties) - { - if (string.Equals(property.Name, "DriveLetter", StringComparison.OrdinalIgnoreCase) && property.Value is not null) - { - driveLetters.Add(property.Value?.ToString() ?? string.Empty); - } - } - } - - return [.. driveLetters]; - } - - - private static ManagementObjectCollection GetCimInstances(string namespacePath, string className, string filter) - { - ManagementScope scope = new(namespacePath); - string queryString = string.IsNullOrEmpty(filter) ? $"SELECT * FROM {className}" : $"SELECT * FROM {className} WHERE {filter}"; - ObjectQuery query = new(queryString); - - // Declare the collection to return - ManagementObjectCollection result; - - using (ManagementObjectSearcher searcher = new(scope, query)) - { - // Get the collection from the searcher - result = searcher.Get(); - } - - return result; - } - - - /// - /// Gets the BitLocker info of all of the volumes on the system - /// - /// Will only return Removable Drives - /// Will only return Non-OSDrives, excluding Removable Drives - /// - internal static List GetAllEncryptedVolumeInfo(bool OnlyNonOSDrives, bool OnlyRemovableDrives) - { - // Create a new list of BitLockerVolume objects - List volumes = []; - - // Call the GetAllDriveLetters method to get all of the drive letters - string[] driveLetters = GetAllDriveLetters(); - - // Iterate through all of the drive letters - foreach (string driveLetter in driveLetters) - { - // the method requires the drive letter with the colon - BitLockerVolume volume = GetEncryptedVolumeInfo(driveLetter + ":"); - - // If only Non-OS Drives are requested, skip any other drive types - if (OnlyNonOSDrives && volume.VolumeType is not VolumeType.FixedDisk) - { - continue; - } - - // If only Removable Drives are requested, skip any other drive types - if (OnlyRemovableDrives && volume.VolumeType is not VolumeType.Removable) - { - continue; - } - - volumes.Add(volume); - } - - return volumes; - } - } +internal partial class BitLocker +{ + + // Class that stores the information about each key protector + internal sealed class KeyProtector + { + internal KeyProtectorType? KeyProtectorType { get; set; } + internal string? KeyProtectorID { get; set; } + internal bool AutoUnlockProtector { get; set; } + internal string? KeyFileName { get; set; } + internal string? RecoveryPassword { get; set; } + internal string? KeyCertificateType { get; set; } + internal string? Thumbprint { get; set; } + } + + // class that stores the information about BitLocker protected volumes + internal sealed class BitLockerVolume + { + internal string? MountPoint { get; set; } + internal EncryptionMethod? EncryptionMethod { get; set; } + internal string? EncryptionMethodFlags { get; set; } + internal bool AutoUnlockEnabled { get; set; } + internal bool AutoUnlockKeyStored { get; set; } + + // https://learn.microsoft.com/en-us/windows/win32/secprov/getversion-win32-encryptablevolume#parameters + internal uint MetadataVersion { get; set; } + + internal ConversionStatus? ConversionStatus { get; set; } + internal ProtectionStatus? ProtectionStatus { get; set; } + internal LockStatus? LockStatus { get; set; } + internal string? EncryptionPercentage { get; set; } + internal string? WipePercentage { get; set; } + internal WipingStatus? WipingStatus { get; set; } + internal VolumeType? VolumeType { get; set; } + internal string? CapacityGB { get; set; } + internal FileSystemType? FileSystemType { get; set; } + internal string? FriendlyName { get; set; } + internal string? AllocationUnitSize { get; set; } + internal ReFSDedupMode? ReFSDedupMode { get; set; } + internal List? KeyProtector { get; set; } + } + + // Different types of the key protectors + // https://learn.microsoft.com/en-us/windows/win32/secprov/getkeyprotectortype-win32-encryptablevolume + internal enum KeyProtectorType : uint + { + Unknown = 0, + Tpm = 1, + ExternalKey = 2, + RecoveryPassword = 3, + TpmPin = 4, + TpmStartupKey = 5, + TpmPinStartupKey = 6, + PublicKey = 7, + Password = 8, + TpmNetworkKey = 9, + AdAccountOrGroup = 10 + } + + // https://learn.microsoft.com/en-us/windows/win32/secprov/getencryptionmethod-win32-encryptablevolume + internal enum EncryptionMethod : uint + { + None = 0, + AES_128_WITH_DIFFUSER = 1, + AES_256_WITH_DIFFUSER = 2, + AES_128 = 3, + AES_256 = 4, + HARDWARE_ENCRYPTION = 5, + XTS_AES_128 = 6, + XTS_AES_256 = 7 + } + + // https://learn.microsoft.com/en-us/windows/win32/secprov/getprotectionstatus-win32-encryptablevolume + internal enum ProtectionStatus : uint + { + Unprotected = 0, + Protected = 1, + Unknown = 2 + } + + // https://learn.microsoft.com/en-us/windows/win32/secprov/getlockstatus-win32-encryptablevolume + internal enum LockStatus + { + Unlocked = 0, + Locked = 1 + } + + // https://learn.microsoft.com/en-us/windows/win32/secprov/win32-encryptablevolume#properties + internal enum VolumeType + { + OperationSystem = 0, + FixedDisk = 1, + Removable = 2 + } + + // https://learn.microsoft.com/en-us/windows/win32/secprov/getconversionstatus-win32-encryptablevolume + internal enum ConversionStatus : uint + { + FullyDecrypted = 0, + FullyEncrypted = 1, + EncryptionInProgress = 2, + DecryptionInProgress = 3, + EncryptionPaused = 4, + DecryptionPaused = 5 + } + + // https://learn.microsoft.com/en-us/windows/win32/secprov/getconversionstatus-win32-encryptablevolume + internal enum WipingStatus : uint + { + FreeSpaceNotWiped = 0, + FreeSpaceWiped = 1, + FreeSpaceWipingInProgress = 2, + FreeSpaceWipingPaused = 3 + } + + // https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/msft-volume#properties + internal enum FileSystemType : ushort + { + Unknown = 0, + UFS = 2, + HFS = 3, + FAT = 4, + FAT16 = 5, + FAT32 = 6, + NTFS4 = 7, + NTFS5 = 8, + XFS = 9, + AFS = 10, + EXT2 = 11, + EXT3 = 12, + ReiserFS = 13, + NTFS = 14, + ReFS = 15 + } + + // https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/msft-volume#properties + internal enum ReFSDedupMode : uint + { + Disabled = 0, + GeneralPurpose = 1, + HyperV = 2, + Backup = 3, + NotAvailable = 4 + } + + + // The main method that will generate as much useful info as possible about every BitLocker volume + internal static BitLockerVolume GetEncryptedVolumeInfo(string targetVolume) + { + // The MSFT_Volume class requires the volume name without the colon + string targetVolumeVer2 = targetVolume.Replace(":", "", StringComparison.OrdinalIgnoreCase); + + // Create a new instance of the BitLockerVolume class + BitLockerVolume newInstance = new(); + + // Get the information about the volume using Win32_EncryptableVolume class + // This is used a lot as the main input object to get information from other classes + ManagementBaseObject? volume = GetCimInstance("Root\\CIMV2\\Security\\MicrosoftVolumeEncryption", "Win32_EncryptableVolume", $"DriveLetter = '{targetVolume}'"); + + // Make sure there is data + if (volume is not null) + { + // Set the MountPoint property of the final object to the drive letter + newInstance.MountPoint = volume["DriveLetter"]?.ToString(); + + try + { + // Set the ProtectionStatus property if it exists + newInstance.ProtectionStatus = (ProtectionStatus)Convert.ToUInt32(volume["ProtectionStatus"], CultureInfo.InvariantCulture); + } + catch { /* ignore */ } + + try + { + // Set the VolumeType property if it exists + newInstance.VolumeType = (VolumeType)Convert.ToUInt32(volume["VolumeType"], CultureInfo.InvariantCulture); + } + catch { /* ignore */ } + + try + { + // Try to use the GetLockStatus method to get the CurrentLockStatus + ManagementBaseObject currentLockStatus = InvokeCimMethod(volume, "GetLockStatus", null); + if (currentLockStatus is not null && Convert.ToUInt32(currentLockStatus["ReturnValue"], CultureInfo.InvariantCulture) == 0) + { + // Set the LockStatus property if it exists + newInstance.LockStatus = (LockStatus)Convert.ToUInt32(currentLockStatus["LockStatus"], CultureInfo.InvariantCulture); + } + } + catch { /* ignore */ } + + try + { + ManagementBaseObject currentVolConversionStatus = InvokeCimMethod(volume, "GetConversionStatus", null); + if (currentVolConversionStatus is not null && Convert.ToUInt32(currentVolConversionStatus["ReturnValue"], CultureInfo.InvariantCulture) == 0) + { + newInstance.EncryptionPercentage = currentVolConversionStatus["EncryptionPercentage"]?.ToString(); + newInstance.WipePercentage = currentVolConversionStatus["WipingPercentage"]?.ToString(); + newInstance.ConversionStatus = (ConversionStatus)Convert.ToUInt32(currentVolConversionStatus["ConversionStatus"], CultureInfo.InvariantCulture); + newInstance.WipingStatus = (WipingStatus)Convert.ToUInt32(currentVolConversionStatus["WipingStatus"], CultureInfo.InvariantCulture); + } + } + catch { /* ignore */ } + + try + { + // Try to use the GetEncryptionMethod method to get the EncryptionMethod and EncryptionMethodFlags properties + ManagementBaseObject? currentEncryptionMethod = InvokeCimMethod(volume, "GetEncryptionMethod", null); + if (currentEncryptionMethod is not null && Convert.ToUInt32(currentEncryptionMethod["ReturnValue"], CultureInfo.InvariantCulture) == 0) + { + uint EncryptionMethodNum = Convert.ToUInt32(currentEncryptionMethod["EncryptionMethod"], CultureInfo.InvariantCulture); + + // Cast the uint to the EncryptionMethod enum + newInstance.EncryptionMethod = (EncryptionMethod)EncryptionMethodNum; + + newInstance.EncryptionMethodFlags = currentEncryptionMethod["EncryptionMethodFlags"]?.ToString(); + } + } + catch { /* ignore */ } + + try + { + // Use the GetVersion method + ManagementBaseObject currentVolVersion = InvokeCimMethod(volume, "GetVersion", null); + if (currentVolVersion is not null && Convert.ToUInt32(currentVolVersion["ReturnValue"], CultureInfo.InvariantCulture) == 0) + { + newInstance.MetadataVersion = Convert.ToUInt32(currentVolVersion["Version"], CultureInfo.InvariantCulture); + } + } + catch { /* ignore */ } + + try + { + // Use the GetKeyProtectors method + ManagementBaseObject keyProtectors = InvokeCimMethod(volume, "GetKeyProtectors", null); + + // If there are any key protectors + if (keyProtectors is not null) + { + // Create a new list of KeyProtector objects to store the results of processing each key protector in the loop below + newInstance.KeyProtector = []; + + // Iterate through all of the key protectors' IDs + foreach (string keyProtectorID in (string[])keyProtectors["VolumeKeyProtectorID"]) + { + // Set them all to null initially so we don't accidentally use them for the wrong key protector type + KeyProtectorType? type = null; + string? recoveryPassword = null; + bool autoUnlockProtector = false; + string? keyProtectorFileName = null; + string? keyProtectorThumbprint = null; + string? keyProtectorCertificateType = null; + + try + { + // Use the GetKeyProtectorType method + ManagementBaseObject keyProtectorTypeResult = InvokeCimMethod(volume, "GetKeyProtectorType", new Dictionary { { "VolumeKeyProtectorID", keyProtectorID } }); + if (keyProtectorTypeResult is not null) + { + uint keyProtectorType = Convert.ToUInt32(keyProtectorTypeResult["KeyProtectorType"], CultureInfo.InvariantCulture); + // Cast the uint value to the KeyProtectorType enum + type = (KeyProtectorType)keyProtectorType; + + // if the current key protector is RecoveryPassword / Numerical password + if (keyProtectorType == 3) + { + ManagementBaseObject numericalPassword = InvokeCimMethod(volume, "GetKeyProtectorNumericalPassword", new Dictionary { { "VolumeKeyProtectorID", keyProtectorID } }); + if (numericalPassword is not null && Convert.ToUInt32(numericalPassword["ReturnValue"], CultureInfo.InvariantCulture) == 0) + { + recoveryPassword = numericalPassword["NumericalPassword"]?.ToString(); + } + } + + // if the current key protector is ExternalKey + if (keyProtectorType == 2) + { + ManagementBaseObject autoUnlockEnabledResult = InvokeCimMethod(volume, "IsAutoUnlockEnabled", null); + if (autoUnlockEnabledResult is not null && Convert.ToUInt32(autoUnlockEnabledResult["ReturnValue"], CultureInfo.InvariantCulture) == 0) + { + bool isAutoUnlockEnabled = Convert.ToBoolean(autoUnlockEnabledResult["IsAutoUnlockEnabled"], CultureInfo.InvariantCulture); + string? volumeKeyProtectorID = autoUnlockEnabledResult["VolumeKeyProtectorID"]?.ToString(); + + if (isAutoUnlockEnabled && string.Equals(volumeKeyProtectorID, keyProtectorID, StringComparison.Ordinal)) + { + autoUnlockProtector = true; + } + } + + ManagementBaseObject keyProtectorFileNameResult = InvokeCimMethod(volume, "GetExternalKeyFileName", new Dictionary { { "VolumeKeyProtectorID", keyProtectorID } }); + if (keyProtectorFileNameResult is not null && Convert.ToUInt32(keyProtectorFileNameResult["ReturnValue"], CultureInfo.InvariantCulture) == 0) + { + keyProtectorFileName = keyProtectorFileNameResult["FileName"]?.ToString(); + } + } + + // if the current key protector is PublicKey or TpmNetworkKey + if (keyProtectorType is 7 or 9) + { + ManagementBaseObject keyProtectorCertificateResult = InvokeCimMethod(volume, "GetKeyProtectorCertificate", new Dictionary { { "VolumeKeyProtectorID", keyProtectorID } }); + if (keyProtectorCertificateResult is not null && Convert.ToUInt32(keyProtectorCertificateResult["ReturnValue"], CultureInfo.InvariantCulture) == 0) + { + keyProtectorThumbprint = keyProtectorCertificateResult["CertThumbprint"]?.ToString(); + keyProtectorCertificateType = keyProtectorCertificateResult["CertType"]?.ToString(); + } + } + + // Create a new KeyProtector class instance and add it to the KeyProtector property of the output object as an array member + newInstance.KeyProtector.Add(new KeyProtector + { + KeyProtectorID = keyProtectorID, + KeyProtectorType = type, + RecoveryPassword = recoveryPassword, + AutoUnlockProtector = autoUnlockProtector, + KeyFileName = keyProtectorFileName, + KeyCertificateType = keyProtectorCertificateType, + Thumbprint = keyProtectorThumbprint + }); + } + } + catch { /* ignore */ } + } + } + } + catch { /* ignore */ } + } + + // Get volume information using the MSFT_Volume class + ManagementBaseObject? currentStorage = GetCimInstance("Root\\Microsoft\\Windows\\Storage", "MSFT_Volume", $"DriveLetter = '{targetVolumeVer2}'"); + if (currentStorage is not null) + { + try + { + newInstance.CapacityGB = Math.Round(Convert.ToDouble(currentStorage["Size"], CultureInfo.InvariantCulture) / (1024 * 1024 * 1024), 4).ToString(CultureInfo.InvariantCulture); + } + catch { /* ignore */ } + + try + { + newInstance.FileSystemType = (FileSystemType)Convert.ToUInt16(currentStorage["FileSystemType"], CultureInfo.InvariantCulture); + } + catch { /* ignore */ } + + try + { + newInstance.FriendlyName = currentStorage["FileSystemLabel"]?.ToString(); + } + catch { /* ignore */ } + + try + { + newInstance.AllocationUnitSize = currentStorage["AllocationUnitSize"]?.ToString(); + } + catch { /* ignore */ } + + try + { + newInstance.ReFSDedupMode = (ReFSDedupMode)Convert.ToUInt32(currentStorage["ReFSDedupMode"], CultureInfo.InvariantCulture); + } + catch { /* ignore */ } + } + + return newInstance; + } + + + // Helper method to get the information from the WMI classes + private static ManagementBaseObject? GetCimInstance(string @namespace, string className, string filter) + { + SelectQuery query = new(className, filter); + using ManagementObjectSearcher searcher = new(@namespace, query.QueryString); + + return searcher.Get().Cast().FirstOrDefault(); + } + + // Helper method to invoke a method on a WMI class + private static ManagementBaseObject InvokeCimMethod(ManagementBaseObject instance, string methodName, Dictionary? parameters) + { + using ManagementClass managementClass = new(instance.ClassPath); + + ManagementBaseObject inParams = managementClass.GetMethodParameters(methodName); + if (parameters is not null) + { + foreach (KeyValuePair param in parameters) + { + inParams[param.Key] = param.Value; + } + } + return ((ManagementObject)instance).InvokeMethod(methodName, inParams, null); + } + + // Method to get the drive letters of all volumes on the system, encrypted or not + internal static string[] GetAllDriveLetters() + { + List driveLetters = []; + + ManagementObjectCollection storages = GetCimInstances("Root\\Microsoft\\Windows\\Storage", "MSFT_Volume", string.Empty); + + foreach (ManagementBaseObject storage in storages) + { + // Iterate through the properties of the storage object + foreach (PropertyData property in storage.Properties) + { + if (string.Equals(property.Name, "DriveLetter", StringComparison.OrdinalIgnoreCase) && property.Value is not null) + { + driveLetters.Add(property.Value?.ToString() ?? string.Empty); + } + } + } + + return [.. driveLetters]; + } + + + private static ManagementObjectCollection GetCimInstances(string namespacePath, string className, string filter) + { + ManagementScope scope = new(namespacePath); + string queryString = string.IsNullOrEmpty(filter) ? $"SELECT * FROM {className}" : $"SELECT * FROM {className} WHERE {filter}"; + ObjectQuery query = new(queryString); + + // Declare the collection to return + ManagementObjectCollection result; + + using (ManagementObjectSearcher searcher = new(scope, query)) + { + // Get the collection from the searcher + result = searcher.Get(); + } + + return result; + } + + + /// + /// Gets the BitLocker info of all of the volumes on the system + /// + /// Will only return Removable Drives + /// Will only return Non-OSDrives, excluding Removable Drives + /// + internal static List GetAllEncryptedVolumeInfo(bool OnlyNonOSDrives, bool OnlyRemovableDrives) + { + // Create a new list of BitLockerVolume objects + List volumes = []; + + // Call the GetAllDriveLetters method to get all of the drive letters + string[] driveLetters = GetAllDriveLetters(); + + // Iterate through all of the drive letters + foreach (string driveLetter in driveLetters) + { + // the method requires the drive letter with the colon + BitLockerVolume volume = GetEncryptedVolumeInfo(driveLetter + ":"); + + // If only Non-OS Drives are requested, skip any other drive types + if (OnlyNonOSDrives && volume.VolumeType is not VolumeType.FixedDisk) + { + continue; + } + + // If only Removable Drives are requested, skip any other drive types + if (OnlyRemovableDrives && volume.VolumeType is not VolumeType.Removable) + { + continue; + } + + volumes.Add(volume); + } + + return volumes; + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Disable.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Disable.cs index d7d9fe310..0f94f007b 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Disable.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Disable.cs @@ -4,121 +4,121 @@ namespace HardenWindowsSecurity; - internal partial class BitLocker - { +internal partial class BitLocker +{ - /// - /// Decrypts a BitLocker encrypted drive - /// If the drive is OS drive, it will check if it has auto-unlock keys that belong to other data drives. - /// - /// - internal static void Disable(string DriveLetter) - { + /// + /// Decrypts a BitLocker encrypted drive + /// If the drive is OS drive, it will check if it has auto-unlock keys that belong to other data drives. + /// + /// + internal static void Disable(string DriveLetter) + { - // Get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + // Get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Get the extended volume info based on the drive letter - BitLockerVolume VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); + // Get the extended volume info based on the drive letter + BitLockerVolume VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyDecrypted) - { - Logger.LogMessage($"The drive {DriveLetter} is already decrypted", LogTypeIntel.InformationInteractionRequired); - return; - } + if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyDecrypted) + { + Logger.LogMessage($"The drive {DriveLetter} is already decrypted", LogTypeIntel.InformationInteractionRequired); + return; + } - if (VolumeInfoExtended.ConversionStatus is ConversionStatus.DecryptionInProgress) - { - Logger.LogMessage($"The drive {DriveLetter} is being decrypted, please wait.", LogTypeIntel.InformationInteractionRequired); - return; - } + if (VolumeInfoExtended.ConversionStatus is ConversionStatus.DecryptionInProgress) + { + Logger.LogMessage($"The drive {DriveLetter} is being decrypted, please wait.", LogTypeIntel.InformationInteractionRequired); + return; + } - if (VolumeInfoExtended.VolumeType is VolumeType.OperationSystem) - { + if (VolumeInfoExtended.VolumeType is VolumeType.OperationSystem) + { - Logger.LogMessage($"Operation system drive detected during BitLocker disablement", LogTypeIntel.Information); + Logger.LogMessage($"Operation system drive detected during BitLocker disablement", LogTypeIntel.Information); - Logger.LogMessage("Checking whether The Operation System drive has auto-unlock keys that belong to other data drives.", LogTypeIntel.Information); + Logger.LogMessage("Checking whether The Operation System drive has auto-unlock keys that belong to other data drives.", LogTypeIntel.Information); - // https://learn.microsoft.com/en-us/windows/win32/secprov/isautounlockkeystored-win32-encryptablevolume + // https://learn.microsoft.com/en-us/windows/win32/secprov/isautounlockkeystored-win32-encryptablevolume - // Get the method parameters for IsAutoUnlockKeyStored (even if they are empty) - ManagementBaseObject IsAutoUnlockKeyStoredArgs = VolumeInfo.GetMethodParameters("IsAutoUnlockKeyStored"); + // Get the method parameters for IsAutoUnlockKeyStored (even if they are empty) + ManagementBaseObject IsAutoUnlockKeyStoredArgs = VolumeInfo.GetMethodParameters("IsAutoUnlockKeyStored"); - // Invoke the method with an empty argument object - ManagementBaseObject IsAutoUnlockKeyStoredMethodInvocationResult = VolumeInfo.InvokeMethod("IsAutoUnlockKeyStored", IsAutoUnlockKeyStoredArgs, null); + // Invoke the method with an empty argument object + ManagementBaseObject IsAutoUnlockKeyStoredMethodInvocationResult = VolumeInfo.InvokeMethod("IsAutoUnlockKeyStored", IsAutoUnlockKeyStoredArgs, null); - #region Output handling - uint? MethodInvocationResultCode = null; + #region Output handling + uint? MethodInvocationResultCode = null; - if (IsAutoUnlockKeyStoredMethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(IsAutoUnlockKeyStoredMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } + if (IsAutoUnlockKeyStoredMethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(IsAutoUnlockKeyStoredMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("Successfully checked the OS Drive for any stored auto-unlock keys.", LogTypeIntel.Information); - // Will move forward to the next step - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("Successfully checked the OS Drive for any stored auto-unlock keys.", LogTypeIntel.Information); + // Will move forward to the next step + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion - if (IsAutoUnlockKeyStoredMethodInvocationResult!["IsAutoUnlockKeyStored"] is true) - { - // https://learn.microsoft.com/en-us/windows/win32/secprov/decrypt-win32-encryptablevolume#return-value - HResultHelper.HandleHresultAndLog(2150694953); - return; - } + if (IsAutoUnlockKeyStoredMethodInvocationResult!["IsAutoUnlockKeyStored"] is true) + { + // https://learn.microsoft.com/en-us/windows/win32/secprov/decrypt-win32-encryptablevolume#return-value + HResultHelper.HandleHresultAndLog(2150694953); + return; + } - // Get the volume info based on the drive letter again (Just in case if up to date info is required) - VolumeInfo = GetVolumeFromLetter(DriveLetter); + // Get the volume info based on the drive letter again (Just in case if up to date info is required) + VolumeInfo = GetVolumeFromLetter(DriveLetter); - if (HasErrorsOccurred) { return; } - } + if (HasErrorsOccurred) { return; } + } - // The following sections happen regardless of whether the DriveLetter belongs to an OS Drive or not + // The following sections happen regardless of whether the DriveLetter belongs to an OS Drive or not - // https://learn.microsoft.com/en-us/windows/win32/secprov/decrypt-win32-encryptablevolume - // Get the method parameters for Decrypt (even if they are empty) - ManagementBaseObject DecryptArgs = VolumeInfo.GetMethodParameters("Decrypt"); + // https://learn.microsoft.com/en-us/windows/win32/secprov/decrypt-win32-encryptablevolume + // Get the method parameters for Decrypt (even if they are empty) + ManagementBaseObject DecryptArgs = VolumeInfo.GetMethodParameters("Decrypt"); - // Invoke the method with an empty argument object - ManagementBaseObject DecryptMethodInvocationResult = VolumeInfo.InvokeMethod("Decrypt", DecryptArgs, null); + // Invoke the method with an empty argument object + ManagementBaseObject DecryptMethodInvocationResult = VolumeInfo.InvokeMethod("Decrypt", DecryptArgs, null); - #region Output handling - uint? DecryptMethodInvocationResultCode = null; + #region Output handling + uint? DecryptMethodInvocationResultCode = null; - if (DecryptMethodInvocationResult is not null) - { - DecryptMethodInvocationResultCode = Convert.ToUInt32(DecryptMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } + if (DecryptMethodInvocationResult is not null) + { + DecryptMethodInvocationResultCode = Convert.ToUInt32(DecryptMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (DecryptMethodInvocationResultCode is not null && DecryptMethodInvocationResultCode == 0) - { - Logger.LogMessage($"Successfully Decrypted the drive {DriveLetter}", LogTypeIntel.InformationInteractionRequired); - } - else - { - HResultHelper.HandleHresultAndLog(DecryptMethodInvocationResultCode); - return; - } - #endregion + if (DecryptMethodInvocationResultCode is not null && DecryptMethodInvocationResultCode == 0) + { + Logger.LogMessage($"Successfully Decrypted the drive {DriveLetter}", LogTypeIntel.InformationInteractionRequired); + } + else + { + HResultHelper.HandleHresultAndLog(DecryptMethodInvocationResultCode); + return; + } + #endregion - } + } - } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Enable.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Enable.cs index 0b61240ca..8a98529ee 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Enable.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-Enable.cs @@ -7,695 +7,695 @@ namespace HardenWindowsSecurity; - internal partial class BitLocker - { - - // A variable that keeps track of errors if they occur during BitLocker workflows - internal static bool HasErrorsOccurred; - - // A variable that keeps track of BitLocker group policies whether they are applied or not - internal static bool PoliciesApplied; - - // Encryption types of the OS Drive supported by the Harden Windows Security App - internal enum OSEncryptionType - { - Normal, - Enhanced - } - - - /// - /// Enables BitLocker encryption for the OS Drive - /// Note: Password Protector cannot/should not be used for OS the drive. Secure TPM-Based key protectors should be used for the OS drive. - /// https://learn.microsoft.com/en-us/windows/win32/secprov/preparevolume-win32-encryptablevolume - /// 1) Full Space (instead of Used-space only) - /// 2) Skip hardware test - /// 3) Unspecified encryption between hardware/software - /// 4) Encryption Method = XTS-AES-256 - /// - /// - /// - /// - /// - /// if true, both used and free space will be encrypted - internal static void Enable(string DriveLetter, OSEncryptionType OSEncryptionType, string? PIN, string? StartupKeyPath, bool FreePlusUsedSpace) - { - #region TPM Status Check - TpmResult TPMResult = TpmStatus.GetV2(); - - if (!TPMResult.IsEnabled || !TPMResult.IsActivated) - { - Logger.LogMessage("TPM is not enabled or activated, BitLocker cannot be enabled.", LogTypeIntel.Error); - return; - } - #endregion - - // Get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - - if (HasErrorsOccurred) { return; } - - // Get the extended volume info based on the drive letter - BitLockerVolume VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); - - if (HasErrorsOccurred) { return; } - - // If the drive is fully encrypted, check its key protectors - if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyEncrypted) - { - Logger.LogMessage($"The OS drive is fully encrypted, will check if it conforms to the selected {OSEncryptionType} level.", LogTypeIntel.Information); - - if (VolumeInfoExtended.EncryptionMethod is not EncryptionMethod.XTS_AES_256) - { - Logger.LogMessage($"The OS drive is encrypted but with {VolumeInfoExtended.EncryptionMethod} instead of the more secure {EncryptionMethod.XTS_AES_256}. This is an informational notice.", LogTypeIntel.WarningInteractionRequired); - } - - - // Get the key protectors of the OS Drive after making sure it is fully encrypted - List KeyProtectors = [.. VolumeInfoExtended.KeyProtector!.Select(kp => kp.KeyProtectorType)]; - - if (KeyProtectors is null || KeyProtectors.Count == 0) - { - Logger.LogMessage("The OS drive is encrypted but it has no key protectors", LogTypeIntel.ErrorInteractionRequired); - HasErrorsOccurred = true; - return; - } - - // If Normal security level was selected - if (OSEncryptionType is OSEncryptionType.Normal) - { - // If all the required key protectors for Normal security level are present, then return from the method - if (KeyProtectors.Contains(KeyProtectorType.RecoveryPassword) && KeyProtectors.Contains(KeyProtectorType.TpmPin)) - { - Logger.LogMessage("The OS Drive is already fully encrypted with Normal Security level.", LogTypeIntel.InformationInteractionRequired); - HasErrorsOccurred = true; - return; - } - - // If Recovery password is not present, add it - if (!KeyProtectors.Contains(KeyProtectorType.RecoveryPassword)) - { - - Logger.LogMessage($"OS drive is encrypted, selected encryption is {OSEncryptionType} but there is no {KeyProtectorType.RecoveryPassword} key protector, adding it now.", LogTypeIntel.Information); - - AddRecoveryPassword(DriveLetter, null); - if (HasErrorsOccurred) { return; } - } - - // At this point we are sure the drive is fully encrypted, has Recovery Password - // And Normal security level is being used, so check if the drive is encrypted with Enhanced security level already - if (KeyProtectors.Contains(KeyProtectorType.TpmPinStartupKey)) - { - Logger.LogMessage("For OS Drive encryption, Normal level was selected by the user but Enhanced level already detected, displaying MessageBox to the user for confirmation.", LogTypeIntel.Information); - - MessageBoxResult result = MessageBox.Show( - "The OS Drive is already encrypted with the Enhanced Security level. Do you want to proceed with changing it to Normal Security level?", - "Confirmation", // Title - MessageBoxButton.YesNoCancel, // Buttons - MessageBoxImage.Question // Icon - ); - - // If user selected no, cancel or closed the dialog box, then return from the method - // Otherwise proceed with replacing the TpmPinStartupKey with TpmPin key protector - if (result is MessageBoxResult.No or MessageBoxResult.Cancel or MessageBoxResult.None) - { - Logger.LogMessage("User cancelled changing Enhanced to Normal encryption level for the OS Drive.", LogTypeIntel.Information); - - HasErrorsOccurred = true; - return; - } - else - { - Logger.LogMessage("User chose to proceed with changing Enhanced to Normal encryption level for the OS Drive.", LogTypeIntel.Information); - } - } - - // If TpmPin is not present, add it - if (!KeyProtectors.Contains(KeyProtectorType.TpmPin)) - { - Logger.LogMessage($"OS drive is encrypted, selected encryption is {OSEncryptionType} but there is no {KeyProtectorType.TpmPin} key protector, adding it now.", LogTypeIntel.Information); - - if (string.IsNullOrWhiteSpace(PIN)) - { - Logger.LogMessage("No PIN was specified for the NormalSecurity Level, exiting", LogTypeIntel.Error); - return; - } - - AddTpmAndPinProtector(DriveLetter, PIN); - if (HasErrorsOccurred) { return; } - } - - } - // If Enhanced security level was selected - else - { - // If all the key protectors required for the Enhanced security level are present then return from the method - if (KeyProtectors.Contains(KeyProtectorType.RecoveryPassword) && KeyProtectors.Contains(KeyProtectorType.TpmPinStartupKey)) - { - Logger.LogMessage("The OS Drive is already fully encrypted with Enhanced Security level.", LogTypeIntel.InformationInteractionRequired); - HasErrorsOccurred = true; - return; - } - - // If Recovery password is not present, add it - if (!KeyProtectors.Contains(KeyProtectorType.RecoveryPassword)) - { - - Logger.LogMessage($"OS drive is encrypted, selected encryption is {OSEncryptionType} but there is no {KeyProtectorType.RecoveryPassword} key protector, adding it now.", LogTypeIntel.Information); - - AddRecoveryPassword(DriveLetter, null); - if (HasErrorsOccurred) { return; } - } - - // If TpmPinStartupKey is not present, add it - if (!KeyProtectors.Contains(KeyProtectorType.TpmPinStartupKey)) - { - - Logger.LogMessage($"OS drive is encrypted, selected encryption is {OSEncryptionType} but there is no {KeyProtectorType.TpmPinStartupKey} key protector, adding it now.", LogTypeIntel.Information); - - if (string.IsNullOrWhiteSpace(PIN) || string.IsNullOrWhiteSpace(StartupKeyPath)) - { - Logger.LogMessage("No PIN or Startup Key was specified for the Enhanced Security Level, exiting", LogTypeIntel.Error); - return; - } - AddTpmAndPinAndStartupKeyProtector(DriveLetter, StartupKeyPath, PIN); - if (HasErrorsOccurred) { return; } - } - } - } - - // Continue with full encryption if the drive is fully decrypted - else if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyDecrypted) - { - - // Prepare the method with arguments - ManagementBaseObject PrepareVolumeArgs = VolumeInfo.GetMethodParameters("PrepareVolume"); - PrepareVolumeArgs["DiscoveryVolumeType"] = ""; - PrepareVolumeArgs["ForceEncryptionType"] = (uint)0; // Unspecified Type is the right default if hardware encryption is not explicitly requested - - if (HasErrorsOccurred) { return; } - - // Invoke the method to prepare the volume - // If the drive is fully or partially encrypted, this method would return result: FVE_E_NOT_DECRYPTED 2150694969(0x80310039), which is unhandled by the HResult method. - // And that error won't happen since the check for drive being fully decrypted already happens earlier - // And also if that happens, it is gracefully handled. - // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume - // See note below for further error handling - ManagementBaseObject PrepareVolumeMethodInvocationResult = VolumeInfo.InvokeMethod("PrepareVolume", PrepareVolumeArgs, null); - - if (HasErrorsOccurred) { return; } - - #region Output handling - uint? PrepareVolumeResultCode = null; - - if (PrepareVolumeMethodInvocationResult is not null) - { - PrepareVolumeResultCode = Convert.ToUInt32(PrepareVolumeMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (PrepareVolumeResultCode is not null && PrepareVolumeResultCode == 0) - { - Logger.LogMessage($"Successfully prepared the drive {DriveLetter} for encryption.", LogTypeIntel.Information); - } - // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume - // If the prepare method was previously used or if Add key protector methods were used, the preparation would happen - // and it shouldn't terminate the method if a 2nd preparation is attempted, the method should just proceed to the next step - // FVE_E_NOT_DECRYPTED - else if (PrepareVolumeResultCode == 2150694969) - { - Logger.LogMessage($"The volume with the drive letter {DriveLetter} has already been prepared, continuing...", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(PrepareVolumeResultCode); - return; - } - #endregion - - - if (OSEncryptionType is OSEncryptionType.Normal) - { - - if (string.IsNullOrWhiteSpace(PIN)) - { - Logger.LogMessage("No PIN was specified for the NormalSecurity Level, exiting", LogTypeIntel.Error); - return; - } - - AddTpmAndPinProtector(DriveLetter, PIN); - - if (HasErrorsOccurred) { return; } - - AddRecoveryPassword(DriveLetter, null); - - if (HasErrorsOccurred) { return; } - - } - else - { - if (string.IsNullOrWhiteSpace(PIN) || string.IsNullOrWhiteSpace(StartupKeyPath)) - { - Logger.LogMessage("No PIN or Startup Key was specified for the Enhanced Security Level, exiting", LogTypeIntel.Error); - return; - } +internal partial class BitLocker +{ + + // A variable that keeps track of errors if they occur during BitLocker workflows + internal static bool HasErrorsOccurred; + + // A variable that keeps track of BitLocker group policies whether they are applied or not + internal static bool PoliciesApplied; + + // Encryption types of the OS Drive supported by the Harden Windows Security App + internal enum OSEncryptionType + { + Normal, + Enhanced + } + + + /// + /// Enables BitLocker encryption for the OS Drive + /// Note: Password Protector cannot/should not be used for OS the drive. Secure TPM-Based key protectors should be used for the OS drive. + /// https://learn.microsoft.com/en-us/windows/win32/secprov/preparevolume-win32-encryptablevolume + /// 1) Full Space (instead of Used-space only) + /// 2) Skip hardware test + /// 3) Unspecified encryption between hardware/software + /// 4) Encryption Method = XTS-AES-256 + /// + /// + /// + /// + /// + /// if true, both used and free space will be encrypted + internal static void Enable(string DriveLetter, OSEncryptionType OSEncryptionType, string? PIN, string? StartupKeyPath, bool FreePlusUsedSpace) + { + #region TPM Status Check + TpmResult TPMResult = TpmStatus.GetV2(); + + if (!TPMResult.IsEnabled || !TPMResult.IsActivated) + { + Logger.LogMessage("TPM is not enabled or activated, BitLocker cannot be enabled.", LogTypeIntel.Error); + return; + } + #endregion + + // Get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + + if (HasErrorsOccurred) { return; } + + // Get the extended volume info based on the drive letter + BitLockerVolume VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); + + if (HasErrorsOccurred) { return; } + + // If the drive is fully encrypted, check its key protectors + if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyEncrypted) + { + Logger.LogMessage($"The OS drive is fully encrypted, will check if it conforms to the selected {OSEncryptionType} level.", LogTypeIntel.Information); + + if (VolumeInfoExtended.EncryptionMethod is not EncryptionMethod.XTS_AES_256) + { + Logger.LogMessage($"The OS drive is encrypted but with {VolumeInfoExtended.EncryptionMethod} instead of the more secure {EncryptionMethod.XTS_AES_256}. This is an informational notice.", LogTypeIntel.WarningInteractionRequired); + } + + + // Get the key protectors of the OS Drive after making sure it is fully encrypted + List KeyProtectors = [.. VolumeInfoExtended.KeyProtector!.Select(kp => kp.KeyProtectorType)]; + + if (KeyProtectors is null || KeyProtectors.Count == 0) + { + Logger.LogMessage("The OS drive is encrypted but it has no key protectors", LogTypeIntel.ErrorInteractionRequired); + HasErrorsOccurred = true; + return; + } + + // If Normal security level was selected + if (OSEncryptionType is OSEncryptionType.Normal) + { + // If all the required key protectors for Normal security level are present, then return from the method + if (KeyProtectors.Contains(KeyProtectorType.RecoveryPassword) && KeyProtectors.Contains(KeyProtectorType.TpmPin)) + { + Logger.LogMessage("The OS Drive is already fully encrypted with Normal Security level.", LogTypeIntel.InformationInteractionRequired); + HasErrorsOccurred = true; + return; + } + + // If Recovery password is not present, add it + if (!KeyProtectors.Contains(KeyProtectorType.RecoveryPassword)) + { + + Logger.LogMessage($"OS drive is encrypted, selected encryption is {OSEncryptionType} but there is no {KeyProtectorType.RecoveryPassword} key protector, adding it now.", LogTypeIntel.Information); + + AddRecoveryPassword(DriveLetter, null); + if (HasErrorsOccurred) { return; } + } + + // At this point we are sure the drive is fully encrypted, has Recovery Password + // And Normal security level is being used, so check if the drive is encrypted with Enhanced security level already + if (KeyProtectors.Contains(KeyProtectorType.TpmPinStartupKey)) + { + Logger.LogMessage("For OS Drive encryption, Normal level was selected by the user but Enhanced level already detected, displaying MessageBox to the user for confirmation.", LogTypeIntel.Information); + + MessageBoxResult result = MessageBox.Show( + "The OS Drive is already encrypted with the Enhanced Security level. Do you want to proceed with changing it to Normal Security level?", + "Confirmation", // Title + MessageBoxButton.YesNoCancel, // Buttons + MessageBoxImage.Question // Icon + ); + + // If user selected no, cancel or closed the dialog box, then return from the method + // Otherwise proceed with replacing the TpmPinStartupKey with TpmPin key protector + if (result is MessageBoxResult.No or MessageBoxResult.Cancel or MessageBoxResult.None) + { + Logger.LogMessage("User cancelled changing Enhanced to Normal encryption level for the OS Drive.", LogTypeIntel.Information); + + HasErrorsOccurred = true; + return; + } + else + { + Logger.LogMessage("User chose to proceed with changing Enhanced to Normal encryption level for the OS Drive.", LogTypeIntel.Information); + } + } + + // If TpmPin is not present, add it + if (!KeyProtectors.Contains(KeyProtectorType.TpmPin)) + { + Logger.LogMessage($"OS drive is encrypted, selected encryption is {OSEncryptionType} but there is no {KeyProtectorType.TpmPin} key protector, adding it now.", LogTypeIntel.Information); + + if (string.IsNullOrWhiteSpace(PIN)) + { + Logger.LogMessage("No PIN was specified for the NormalSecurity Level, exiting", LogTypeIntel.Error); + return; + } + + AddTpmAndPinProtector(DriveLetter, PIN); + if (HasErrorsOccurred) { return; } + } + + } + // If Enhanced security level was selected + else + { + // If all the key protectors required for the Enhanced security level are present then return from the method + if (KeyProtectors.Contains(KeyProtectorType.RecoveryPassword) && KeyProtectors.Contains(KeyProtectorType.TpmPinStartupKey)) + { + Logger.LogMessage("The OS Drive is already fully encrypted with Enhanced Security level.", LogTypeIntel.InformationInteractionRequired); + HasErrorsOccurred = true; + return; + } + + // If Recovery password is not present, add it + if (!KeyProtectors.Contains(KeyProtectorType.RecoveryPassword)) + { + + Logger.LogMessage($"OS drive is encrypted, selected encryption is {OSEncryptionType} but there is no {KeyProtectorType.RecoveryPassword} key protector, adding it now.", LogTypeIntel.Information); + + AddRecoveryPassword(DriveLetter, null); + if (HasErrorsOccurred) { return; } + } + + // If TpmPinStartupKey is not present, add it + if (!KeyProtectors.Contains(KeyProtectorType.TpmPinStartupKey)) + { + + Logger.LogMessage($"OS drive is encrypted, selected encryption is {OSEncryptionType} but there is no {KeyProtectorType.TpmPinStartupKey} key protector, adding it now.", LogTypeIntel.Information); + + if (string.IsNullOrWhiteSpace(PIN) || string.IsNullOrWhiteSpace(StartupKeyPath)) + { + Logger.LogMessage("No PIN or Startup Key was specified for the Enhanced Security Level, exiting", LogTypeIntel.Error); + return; + } + AddTpmAndPinAndStartupKeyProtector(DriveLetter, StartupKeyPath, PIN); + if (HasErrorsOccurred) { return; } + } + } + } + + // Continue with full encryption if the drive is fully decrypted + else if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyDecrypted) + { + + // Prepare the method with arguments + ManagementBaseObject PrepareVolumeArgs = VolumeInfo.GetMethodParameters("PrepareVolume"); + PrepareVolumeArgs["DiscoveryVolumeType"] = ""; + PrepareVolumeArgs["ForceEncryptionType"] = (uint)0; // Unspecified Type is the right default if hardware encryption is not explicitly requested + + if (HasErrorsOccurred) { return; } + + // Invoke the method to prepare the volume + // If the drive is fully or partially encrypted, this method would return result: FVE_E_NOT_DECRYPTED 2150694969(0x80310039), which is unhandled by the HResult method. + // And that error won't happen since the check for drive being fully decrypted already happens earlier + // And also if that happens, it is gracefully handled. + // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume + // See note below for further error handling + ManagementBaseObject PrepareVolumeMethodInvocationResult = VolumeInfo.InvokeMethod("PrepareVolume", PrepareVolumeArgs, null); + + if (HasErrorsOccurred) { return; } + + #region Output handling + uint? PrepareVolumeResultCode = null; + + if (PrepareVolumeMethodInvocationResult is not null) + { + PrepareVolumeResultCode = Convert.ToUInt32(PrepareVolumeMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (PrepareVolumeResultCode is not null && PrepareVolumeResultCode == 0) + { + Logger.LogMessage($"Successfully prepared the drive {DriveLetter} for encryption.", LogTypeIntel.Information); + } + // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume + // If the prepare method was previously used or if Add key protector methods were used, the preparation would happen + // and it shouldn't terminate the method if a 2nd preparation is attempted, the method should just proceed to the next step + // FVE_E_NOT_DECRYPTED + else if (PrepareVolumeResultCode == 2150694969) + { + Logger.LogMessage($"The volume with the drive letter {DriveLetter} has already been prepared, continuing...", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(PrepareVolumeResultCode); + return; + } + #endregion + + + if (OSEncryptionType is OSEncryptionType.Normal) + { + + if (string.IsNullOrWhiteSpace(PIN)) + { + Logger.LogMessage("No PIN was specified for the NormalSecurity Level, exiting", LogTypeIntel.Error); + return; + } + + AddTpmAndPinProtector(DriveLetter, PIN); + + if (HasErrorsOccurred) { return; } + + AddRecoveryPassword(DriveLetter, null); + + if (HasErrorsOccurred) { return; } + + } + else + { + if (string.IsNullOrWhiteSpace(PIN) || string.IsNullOrWhiteSpace(StartupKeyPath)) + { + Logger.LogMessage("No PIN or Startup Key was specified for the Enhanced Security Level, exiting", LogTypeIntel.Error); + return; + } - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - AddTpmAndPinAndStartupKeyProtector(DriveLetter, StartupKeyPath, PIN); + AddTpmAndPinAndStartupKeyProtector(DriveLetter, StartupKeyPath, PIN); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - AddRecoveryPassword(DriveLetter, null); + AddRecoveryPassword(DriveLetter, null); - if (HasErrorsOccurred) { return; } - } + if (HasErrorsOccurred) { return; } + } - // Get these again after prep and key protector addition - - // Get the volume info based on the drive letter - VolumeInfo = GetVolumeFromLetter(DriveLetter); - - if (HasErrorsOccurred) { return; } - - // Prepare the method with arguments - ManagementBaseObject EncryptArgs = VolumeInfo.GetMethodParameters("Encrypt"); - EncryptArgs["EncryptionMethod"] = 7; // XTS-AEX-256 - EncryptArgs["EncryptionFlags"] = FreePlusUsedSpace ? 0 : (uint)1; // 0 = Used + Free space | 1 = Used Space only + // Get these again after prep and key protector addition + + // Get the volume info based on the drive letter + VolumeInfo = GetVolumeFromLetter(DriveLetter); + + if (HasErrorsOccurred) { return; } + + // Prepare the method with arguments + ManagementBaseObject EncryptArgs = VolumeInfo.GetMethodParameters("Encrypt"); + EncryptArgs["EncryptionMethod"] = 7; // XTS-AEX-256 + EncryptArgs["EncryptionFlags"] = FreePlusUsedSpace ? 0 : (uint)1; // 0 = Used + Free space | 1 = Used Space only - // Invoke the method to Encrypt the volume - ManagementBaseObject EncryptMethodInvocationResult = VolumeInfo.InvokeMethod("Encrypt", EncryptArgs, null); + // Invoke the method to Encrypt the volume + ManagementBaseObject EncryptMethodInvocationResult = VolumeInfo.InvokeMethod("Encrypt", EncryptArgs, null); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - #region Output handling - uint? EncryptResultCode = null; + #region Output handling + uint? EncryptResultCode = null; - if (EncryptMethodInvocationResult is not null) - { - EncryptResultCode = Convert.ToUInt32(EncryptMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } + if (EncryptMethodInvocationResult is not null) + { + EncryptResultCode = Convert.ToUInt32(EncryptMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (EncryptResultCode is not null && EncryptResultCode == 0) - { - Logger.LogMessage($"Successfully Encrypted the drive {DriveLetter}.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(EncryptResultCode); - return; - } - #endregion + if (EncryptResultCode is not null && EncryptResultCode == 0) + { + Logger.LogMessage($"Successfully Encrypted the drive {DriveLetter}.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(EncryptResultCode); + return; + } + #endregion - // Enabling key protectors - EnableKeyProtectors(DriveLetter); - } + // Enabling key protectors + EnableKeyProtectors(DriveLetter); + } - // Do this if the disk is neither fully encrypted nor fully decrypted - else - { - Logger.LogMessage($"For full disk encryption, the drive's conversion status must be {ConversionStatus.FullyDecrypted}, and for security level change it must be {ConversionStatus.FullyEncrypted}, but it is {VolumeInfoExtended.ConversionStatus} at the moment.", LogTypeIntel.ErrorInteractionRequired); - return; - } - } + // Do this if the disk is neither fully encrypted nor fully decrypted + else + { + Logger.LogMessage($"For full disk encryption, the drive's conversion status must be {ConversionStatus.FullyDecrypted}, and for security level change it must be {ConversionStatus.FullyEncrypted}, but it is {VolumeInfoExtended.ConversionStatus} at the moment.", LogTypeIntel.ErrorInteractionRequired); + return; + } + } - /// - /// Enables BitLocker encryption for Fixed drives (Non-OS drives) - /// 1) Full Space (instead of Used-space only) - /// 2) Skip hardware test - /// 3) Unspecified encryption between hardware/software - /// 4) Encryption Method = XTS-AES-256 - /// - /// - /// if true, both used and free space will be encrypted - internal static void Enable(string DriveLetter, bool FreePlusUsedSpace) - { + /// + /// Enables BitLocker encryption for Fixed drives (Non-OS drives) + /// 1) Full Space (instead of Used-space only) + /// 2) Skip hardware test + /// 3) Unspecified encryption between hardware/software + /// 4) Encryption Method = XTS-AES-256 + /// + /// + /// if true, both used and free space will be encrypted + internal static void Enable(string DriveLetter, bool FreePlusUsedSpace) + { - // Get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + // Get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Get the extended volume info based on the drive letter - BitLockerVolume VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); + // Get the extended volume info based on the drive letter + BitLockerVolume VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Make sure the OS Drive is encrypted first, or else we would add recovery password key protector and then get error about the same problem during auto-unlock key protector enablement - BitLockerVolume OSDriveVolumeInfo = GetEncryptedVolumeInfo(Environment.GetEnvironmentVariable("SystemDrive") ?? "C:\\"); - if (OSDriveVolumeInfo.ProtectionStatus is not ProtectionStatus.Protected) - { - Logger.LogMessage($"Operation System drive must be encrypted first before encrypting Non-OS drives.", LogTypeIntel.ErrorInteractionRequired); - HasErrorsOccurred = true; - return; - } + // Make sure the OS Drive is encrypted first, or else we would add recovery password key protector and then get error about the same problem during auto-unlock key protector enablement + BitLockerVolume OSDriveVolumeInfo = GetEncryptedVolumeInfo(Environment.GetEnvironmentVariable("SystemDrive") ?? "C:\\"); + if (OSDriveVolumeInfo.ProtectionStatus is not ProtectionStatus.Protected) + { + Logger.LogMessage($"Operation System drive must be encrypted first before encrypting Non-OS drives.", LogTypeIntel.ErrorInteractionRequired); + HasErrorsOccurred = true; + return; + } - // If the drive is already fully encrypted, check its key protectors - if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyEncrypted) - { + // If the drive is already fully encrypted, check its key protectors + if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyEncrypted) + { - Logger.LogMessage($"The drive {DriveLetter} is fully encrypted, will check its key protectors.", LogTypeIntel.Information); + Logger.LogMessage($"The drive {DriveLetter} is fully encrypted, will check its key protectors.", LogTypeIntel.Information); - if (VolumeInfoExtended.EncryptionMethod is not EncryptionMethod.XTS_AES_256) - { - Logger.LogMessage($"The drive {DriveLetter} is encrypted but with {VolumeInfoExtended.EncryptionMethod} instead of the more secure {EncryptionMethod.XTS_AES_256}. This is an informational notice.", LogTypeIntel.WarningInteractionRequired); - } + if (VolumeInfoExtended.EncryptionMethod is not EncryptionMethod.XTS_AES_256) + { + Logger.LogMessage($"The drive {DriveLetter} is encrypted but with {VolumeInfoExtended.EncryptionMethod} instead of the more secure {EncryptionMethod.XTS_AES_256}. This is an informational notice.", LogTypeIntel.WarningInteractionRequired); + } - // Get the key protectors of the Drive after making sure it is fully encrypted - List KeyProtectors = [.. VolumeInfoExtended.KeyProtector!.Select(kp => kp.KeyProtectorType)]; + // Get the key protectors of the Drive after making sure it is fully encrypted + List KeyProtectors = [.. VolumeInfoExtended.KeyProtector!.Select(kp => kp.KeyProtectorType)]; - if (KeyProtectors is null || KeyProtectors.Count == 0) - { - Logger.LogMessage($"The drive {DriveLetter} is encrypted but it has no key protectors", LogTypeIntel.ErrorInteractionRequired); - HasErrorsOccurred = true; - return; - } + if (KeyProtectors is null || KeyProtectors.Count == 0) + { + Logger.LogMessage($"The drive {DriveLetter} is encrypted but it has no key protectors", LogTypeIntel.ErrorInteractionRequired); + HasErrorsOccurred = true; + return; + } - // If the drive is already fully encrypted with the required key protectors then return from the method - if (KeyProtectors.Contains(KeyProtectorType.RecoveryPassword) && KeyProtectors.Contains(KeyProtectorType.ExternalKey)) - { + // If the drive is already fully encrypted with the required key protectors then return from the method + if (KeyProtectors.Contains(KeyProtectorType.RecoveryPassword) && KeyProtectors.Contains(KeyProtectorType.ExternalKey)) + { - #region - // Delete any possible old leftover ExternalKey key protectors - List ExternalKeys = [.. VolumeInfoExtended.KeyProtector!.Where(kp => kp.KeyProtectorType is KeyProtectorType.ExternalKey)]; + #region + // Delete any possible old leftover ExternalKey key protectors + List ExternalKeys = [.. VolumeInfoExtended.KeyProtector!.Where(kp => kp.KeyProtectorType is KeyProtectorType.ExternalKey)]; - // This step ensures any leftover or unbound external key key protectors will be removed and a working one will be added - // If the current one is working and bound, it won't be removed and will be gracefully skipped over. - foreach (KeyProtector ExKp in ExternalKeys) - { - if (ExKp.KeyProtectorID is not null) - { - Logger.LogMessage($"Removing ExternalKey key protector with the ID {ExKp.KeyProtectorID} for the drive {DriveLetter}. Will set a new one bound to the OS drive in the next step.", LogTypeIntel.Information); + // This step ensures any leftover or unbound external key key protectors will be removed and a working one will be added + // If the current one is working and bound, it won't be removed and will be gracefully skipped over. + foreach (KeyProtector ExKp in ExternalKeys) + { + if (ExKp.KeyProtectorID is not null) + { + Logger.LogMessage($"Removing ExternalKey key protector with the ID {ExKp.KeyProtectorID} for the drive {DriveLetter}. Will set a new one bound to the OS drive in the next step.", LogTypeIntel.Information); - RemoveKeyProtector(DriveLetter, ExKp.KeyProtectorID, true); - } - } + RemoveKeyProtector(DriveLetter, ExKp.KeyProtectorID, true); + } + } - // Get the extended volume info based on the drive letter again - // Because if the ExternalKey key protectors were deleted in the previous steps, - // The extended drive info must be updated to reflect that change - VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); + // Get the extended volume info based on the drive letter again + // Because if the ExternalKey key protectors were deleted in the previous steps, + // The extended drive info must be updated to reflect that change + VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Get the key protectors of the Drive again for the reason mentioned above - KeyProtectors = [.. VolumeInfoExtended.KeyProtector!.Select(kp => kp.KeyProtectorType)]; + // Get the key protectors of the Drive again for the reason mentioned above + KeyProtectors = [.. VolumeInfoExtended.KeyProtector!.Select(kp => kp.KeyProtectorType)]; - // If the Auto-unlock (aka ExternalKey) key protector is not present, add it - // This only runs if all the ExternalKey key protectors were deleted in the previous step - // Indicating that none of them were bound to the OS Drive and were leftovers of previous OS Installations - if (!KeyProtectors.Contains(KeyProtectorType.ExternalKey)) - { - Logger.LogMessage($"Adding a new {KeyProtectorType.ExternalKey} key protector for Auto-unlock to the drive {DriveLetter}.", LogTypeIntel.Information); + // If the Auto-unlock (aka ExternalKey) key protector is not present, add it + // This only runs if all the ExternalKey key protectors were deleted in the previous step + // Indicating that none of them were bound to the OS Drive and were leftovers of previous OS Installations + if (!KeyProtectors.Contains(KeyProtectorType.ExternalKey)) + { + Logger.LogMessage($"Adding a new {KeyProtectorType.ExternalKey} key protector for Auto-unlock to the drive {DriveLetter}.", LogTypeIntel.Information); - EnableBitLockerAutoUnlock(DriveLetter); + EnableBitLockerAutoUnlock(DriveLetter); - if (HasErrorsOccurred) { return; } - } + if (HasErrorsOccurred) { return; } + } - #endregion + #endregion - #region - // Check for presence of multiple recovery password key protectors + #region + // Check for presence of multiple recovery password key protectors - List PasswordProtectors = [.. VolumeInfoExtended.KeyProtector!.Where(kp => kp.KeyProtectorType is KeyProtectorType.RecoveryPassword)]; + List PasswordProtectors = [.. VolumeInfoExtended.KeyProtector!.Where(kp => kp.KeyProtectorType is KeyProtectorType.RecoveryPassword)]; - if (PasswordProtectors.Count > 1) - { - Logger.LogMessage($"drive {DriveLetter} has {PasswordProtectors.Count} recovery password key protectors. Usually only one is enough.", LogTypeIntel.Information); - } - #endregion + if (PasswordProtectors.Count > 1) + { + Logger.LogMessage($"drive {DriveLetter} has {PasswordProtectors.Count} recovery password key protectors. Usually only one is enough.", LogTypeIntel.Information); + } + #endregion - Logger.LogMessage($"The drive {DriveLetter} is fully encrypted with all the required key protectors.", LogTypeIntel.InformationInteractionRequired); + Logger.LogMessage($"The drive {DriveLetter} is fully encrypted with all the required key protectors.", LogTypeIntel.InformationInteractionRequired); - // Exit the method and do not proceed further if the drive was already encrypted - // And key protector checks have been performed - HasErrorsOccurred = true; - return; - } + // Exit the method and do not proceed further if the drive was already encrypted + // And key protector checks have been performed + HasErrorsOccurred = true; + return; + } - // If Recovery password is not present, add it - if (!KeyProtectors.Contains(KeyProtectorType.RecoveryPassword)) - { - Logger.LogMessage($"Drive {DriveLetter} is encrypted, but there is no {KeyProtectorType.RecoveryPassword} key protector, adding it now.", LogTypeIntel.Information); + // If Recovery password is not present, add it + if (!KeyProtectors.Contains(KeyProtectorType.RecoveryPassword)) + { + Logger.LogMessage($"Drive {DriveLetter} is encrypted, but there is no {KeyProtectorType.RecoveryPassword} key protector, adding it now.", LogTypeIntel.Information); - AddRecoveryPassword(DriveLetter, null); - if (HasErrorsOccurred) { return; } - } + AddRecoveryPassword(DriveLetter, null); + if (HasErrorsOccurred) { return; } + } - // If the Auto-unlock (aka ExternalKey) key protector is not present, add it - if (!KeyProtectors.Contains(KeyProtectorType.ExternalKey)) - { + // If the Auto-unlock (aka ExternalKey) key protector is not present, add it + if (!KeyProtectors.Contains(KeyProtectorType.ExternalKey)) + { - Logger.LogMessage($"Drive {DriveLetter} is encrypted, but there is no {KeyProtectorType.ExternalKey} key protector for Auto-unlock, adding it now.", LogTypeIntel.Information); + Logger.LogMessage($"Drive {DriveLetter} is encrypted, but there is no {KeyProtectorType.ExternalKey} key protector for Auto-unlock, adding it now.", LogTypeIntel.Information); - EnableBitLockerAutoUnlock(DriveLetter); + EnableBitLockerAutoUnlock(DriveLetter); - if (HasErrorsOccurred) { return; } - } - } + if (HasErrorsOccurred) { return; } + } + } - // If the drive is fully decrypted, begin full drive encryption - else if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyDecrypted) - { + // If the drive is fully decrypted, begin full drive encryption + else if (VolumeInfoExtended.ConversionStatus is ConversionStatus.FullyDecrypted) + { - // Prepare the method with arguments - ManagementBaseObject PrepareVolumeArgs = VolumeInfo.GetMethodParameters("PrepareVolume"); - PrepareVolumeArgs["DiscoveryVolumeType"] = ""; - PrepareVolumeArgs["ForceEncryptionType"] = (uint)0; // Unspecified Type is the right default if hardware encryption is not explicitly requested + // Prepare the method with arguments + ManagementBaseObject PrepareVolumeArgs = VolumeInfo.GetMethodParameters("PrepareVolume"); + PrepareVolumeArgs["DiscoveryVolumeType"] = ""; + PrepareVolumeArgs["ForceEncryptionType"] = (uint)0; // Unspecified Type is the right default if hardware encryption is not explicitly requested - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Invoke the method to prepare the volume - // If the drive is fully or partially encrypted, this method would return result: FVE_E_NOT_DECRYPTED 2150694969(0x80310039), which is unhandled by the HResult method. - // And that error won't happen since the check for drive being fully decrypted already happens earlier - // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume - // See note below for further error handling - ManagementBaseObject PrepareVolumeMethodInvocationResult = VolumeInfo.InvokeMethod("PrepareVolume", PrepareVolumeArgs, null); + // Invoke the method to prepare the volume + // If the drive is fully or partially encrypted, this method would return result: FVE_E_NOT_DECRYPTED 2150694969(0x80310039), which is unhandled by the HResult method. + // And that error won't happen since the check for drive being fully decrypted already happens earlier + // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume + // See note below for further error handling + ManagementBaseObject PrepareVolumeMethodInvocationResult = VolumeInfo.InvokeMethod("PrepareVolume", PrepareVolumeArgs, null); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - #region Output handling - uint? PrepareVolumeResultCode = null; + #region Output handling + uint? PrepareVolumeResultCode = null; - if (PrepareVolumeMethodInvocationResult is not null) - { - PrepareVolumeResultCode = Convert.ToUInt32(PrepareVolumeMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } + if (PrepareVolumeMethodInvocationResult is not null) + { + PrepareVolumeResultCode = Convert.ToUInt32(PrepareVolumeMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (PrepareVolumeResultCode is not null && PrepareVolumeResultCode == 0) - { - Logger.LogMessage($"Successfully prepared the drive {DriveLetter} for encryption.", LogTypeIntel.Information); - } - // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume - // If the prepare method was previously used or if Add key protector methods were used, the preparation would happen - // and it shouldn't terminate the method if a 2nd preparation is attempted, the method should just proceed to the next step - // FVE_E_NOT_DECRYPTED - else if (PrepareVolumeResultCode == 2150694969) - { - Logger.LogMessage($"The volume with the drive letter {DriveLetter} has already been prepared, continuing...", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(PrepareVolumeResultCode); - return; - } - #endregion + if (PrepareVolumeResultCode is not null && PrepareVolumeResultCode == 0) + { + Logger.LogMessage($"Successfully prepared the drive {DriveLetter} for encryption.", LogTypeIntel.Information); + } + // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume + // If the prepare method was previously used or if Add key protector methods were used, the preparation would happen + // and it shouldn't terminate the method if a 2nd preparation is attempted, the method should just proceed to the next step + // FVE_E_NOT_DECRYPTED + else if (PrepareVolumeResultCode == 2150694969) + { + Logger.LogMessage($"The volume with the drive letter {DriveLetter} has already been prepared, continuing...", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(PrepareVolumeResultCode); + return; + } + #endregion - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - AddRecoveryPassword(DriveLetter, null); + AddRecoveryPassword(DriveLetter, null); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - EnableBitLockerAutoUnlock(DriveLetter); + EnableBitLockerAutoUnlock(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Get these again after prep and key protector addition + // Get these again after prep and key protector addition - // Get the volume info based on the drive letter - VolumeInfo = GetVolumeFromLetter(DriveLetter); + // Get the volume info based on the drive letter + VolumeInfo = GetVolumeFromLetter(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Prepare the method with arguments - ManagementBaseObject EncryptArgs = VolumeInfo.GetMethodParameters("Encrypt"); - EncryptArgs["EncryptionMethod"] = 7; // XTS-AEX-256 - EncryptArgs["EncryptionFlags"] = FreePlusUsedSpace ? 0 : (uint)1; // 0 = Used + Free space | 1 = Used Space only - - // Invoke the method to Encrypt the volume - ManagementBaseObject EncryptMethodInvocationResult = VolumeInfo.InvokeMethod("Encrypt", EncryptArgs, null); - - if (HasErrorsOccurred) { return; } - - #region Output handling - uint? EncryptResultCode = null; - - if (EncryptMethodInvocationResult is not null) - { - EncryptResultCode = Convert.ToUInt32(EncryptMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (EncryptResultCode is not null && EncryptResultCode == 0) - { - Logger.LogMessage($"Successfully Encrypted the drive {DriveLetter}.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(EncryptResultCode); - return; - } - #endregion - } + // Prepare the method with arguments + ManagementBaseObject EncryptArgs = VolumeInfo.GetMethodParameters("Encrypt"); + EncryptArgs["EncryptionMethod"] = 7; // XTS-AEX-256 + EncryptArgs["EncryptionFlags"] = FreePlusUsedSpace ? 0 : (uint)1; // 0 = Used + Free space | 1 = Used Space only + + // Invoke the method to Encrypt the volume + ManagementBaseObject EncryptMethodInvocationResult = VolumeInfo.InvokeMethod("Encrypt", EncryptArgs, null); + + if (HasErrorsOccurred) { return; } + + #region Output handling + uint? EncryptResultCode = null; + + if (EncryptMethodInvocationResult is not null) + { + EncryptResultCode = Convert.ToUInt32(EncryptMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (EncryptResultCode is not null && EncryptResultCode == 0) + { + Logger.LogMessage($"Successfully Encrypted the drive {DriveLetter}.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(EncryptResultCode); + return; + } + #endregion + } - // Do this if the disk is neither fully encrypted nor fully decrypted - else - { - Logger.LogMessage($"For full disk encryption, the drive's conversion status must be {ConversionStatus.FullyDecrypted}, and for key protector check it must be {ConversionStatus.FullyEncrypted}, but it is {VolumeInfoExtended.ConversionStatus} at the moment.", LogTypeIntel.ErrorInteractionRequired); - return; - } - } + // Do this if the disk is neither fully encrypted nor fully decrypted + else + { + Logger.LogMessage($"For full disk encryption, the drive's conversion status must be {ConversionStatus.FullyDecrypted}, and for key protector check it must be {ConversionStatus.FullyEncrypted}, but it is {VolumeInfoExtended.ConversionStatus} at the moment.", LogTypeIntel.ErrorInteractionRequired); + return; + } + } - /// - /// Enables BitLocker encryption for Removable drives - /// 1) Full Space (instead of Used-space only) - /// 2) Skip hardware test - /// 3) Unspecified encryption between hardware/software - /// 4) Encryption Method = XTS-AES-256 - /// - /// - /// - /// if true, both used and free space will be encrypted - internal static void Enable(string DriveLetter, string? Password, bool FreePlusUsedSpace) - { + /// + /// Enables BitLocker encryption for Removable drives + /// 1) Full Space (instead of Used-space only) + /// 2) Skip hardware test + /// 3) Unspecified encryption between hardware/software + /// 4) Encryption Method = XTS-AES-256 + /// + /// + /// + /// if true, both used and free space will be encrypted + internal static void Enable(string DriveLetter, string? Password, bool FreePlusUsedSpace) + { - // Get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + // Get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Get the extended volume info based on the drive letter - BitLockerVolume VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); + // Get the extended volume info based on the drive letter + BitLockerVolume VolumeInfoExtended = GetEncryptedVolumeInfo(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Exit the method if the volume is not Fully Decrypted - if (VolumeInfoExtended.ConversionStatus is not ConversionStatus.FullyDecrypted) - { - Logger.LogMessage($"In order to encrypt a volume with this method, its Conversion Status must be {ConversionStatus.FullyDecrypted}, but it is {VolumeInfoExtended.ConversionStatus} at the moment.", LogTypeIntel.ErrorInteractionRequired); - return; - } + // Exit the method if the volume is not Fully Decrypted + if (VolumeInfoExtended.ConversionStatus is not ConversionStatus.FullyDecrypted) + { + Logger.LogMessage($"In order to encrypt a volume with this method, its Conversion Status must be {ConversionStatus.FullyDecrypted}, but it is {VolumeInfoExtended.ConversionStatus} at the moment.", LogTypeIntel.ErrorInteractionRequired); + return; + } - // Prepare the method with arguments - ManagementBaseObject PrepareVolumeArgs = VolumeInfo.GetMethodParameters("PrepareVolume"); - PrepareVolumeArgs["DiscoveryVolumeType"] = ""; - PrepareVolumeArgs["ForceEncryptionType"] = (uint)0; // Unspecified Type is the right default if hardware encryption is not explicitly requested + // Prepare the method with arguments + ManagementBaseObject PrepareVolumeArgs = VolumeInfo.GetMethodParameters("PrepareVolume"); + PrepareVolumeArgs["DiscoveryVolumeType"] = ""; + PrepareVolumeArgs["ForceEncryptionType"] = (uint)0; // Unspecified Type is the right default if hardware encryption is not explicitly requested - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Invoke the method to prepare the volume - // If the drive is fully or partially encrypted, this method would return result: FVE_E_NOT_DECRYPTED 2150694969(0x80310039), which is unhandled by the HResult method. - // And that error won't happen since the check for drive being fully decrypted already happens earlier - // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume - // See note below for further error handling - ManagementBaseObject PrepareVolumeMethodInvocationResult = VolumeInfo.InvokeMethod("PrepareVolume", PrepareVolumeArgs, null); + // Invoke the method to prepare the volume + // If the drive is fully or partially encrypted, this method would return result: FVE_E_NOT_DECRYPTED 2150694969(0x80310039), which is unhandled by the HResult method. + // And that error won't happen since the check for drive being fully decrypted already happens earlier + // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume + // See note below for further error handling + ManagementBaseObject PrepareVolumeMethodInvocationResult = VolumeInfo.InvokeMethod("PrepareVolume", PrepareVolumeArgs, null); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - #region Output handling - uint? PrepareVolumeResultCode = null; + #region Output handling + uint? PrepareVolumeResultCode = null; - if (PrepareVolumeMethodInvocationResult is not null) - { - PrepareVolumeResultCode = Convert.ToUInt32(PrepareVolumeMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (PrepareVolumeResultCode is not null && PrepareVolumeResultCode == 0) - { - Logger.LogMessage($"Successfully prepared the drive {DriveLetter} for encryption.", LogTypeIntel.Information); - } - // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume - // If the prepare method was previously used or if Add key protector methods were used, the preparation would happen - // and it shouldn't terminate the method if a 2nd preparation is attempted, the method should just proceed to the next step - // FVE_E_NOT_DECRYPTED - else if (PrepareVolumeResultCode == 2150694969) - { - Logger.LogMessage($"The volume with the drive letter {DriveLetter} has already been prepared, continuing...", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(PrepareVolumeResultCode); - return; - } - #endregion - - - - if (string.IsNullOrEmpty(Password)) - { - Logger.LogMessage("No Password was specified for the Removable Drive Encryption, exiting", LogTypeIntel.Error); - return; - } - - if (HasErrorsOccurred) { return; } - - AddPasswordProtector(DriveLetter, Password); - - if (HasErrorsOccurred) { return; } - - AddRecoveryPassword(DriveLetter, null); - - if (HasErrorsOccurred) { return; } - - // Get these again after prep and key protector addition - - // Get the volume info based on the drive letter - VolumeInfo = GetVolumeFromLetter(DriveLetter); + if (PrepareVolumeMethodInvocationResult is not null) + { + PrepareVolumeResultCode = Convert.ToUInt32(PrepareVolumeMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (PrepareVolumeResultCode is not null && PrepareVolumeResultCode == 0) + { + Logger.LogMessage($"Successfully prepared the drive {DriveLetter} for encryption.", LogTypeIntel.Information); + } + // https://learn.microsoft.com/en-us/windows/win32/secprov/encryptafterhardwaretest-win32-encryptablevolume + // If the prepare method was previously used or if Add key protector methods were used, the preparation would happen + // and it shouldn't terminate the method if a 2nd preparation is attempted, the method should just proceed to the next step + // FVE_E_NOT_DECRYPTED + else if (PrepareVolumeResultCode == 2150694969) + { + Logger.LogMessage($"The volume with the drive letter {DriveLetter} has already been prepared, continuing...", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(PrepareVolumeResultCode); + return; + } + #endregion + + + + if (string.IsNullOrEmpty(Password)) + { + Logger.LogMessage("No Password was specified for the Removable Drive Encryption, exiting", LogTypeIntel.Error); + return; + } + + if (HasErrorsOccurred) { return; } + + AddPasswordProtector(DriveLetter, Password); + + if (HasErrorsOccurred) { return; } + + AddRecoveryPassword(DriveLetter, null); + + if (HasErrorsOccurred) { return; } + + // Get these again after prep and key protector addition + + // Get the volume info based on the drive letter + VolumeInfo = GetVolumeFromLetter(DriveLetter); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - // Prepare the method with arguments - ManagementBaseObject EncryptArgs = VolumeInfo.GetMethodParameters("Encrypt"); - EncryptArgs["EncryptionMethod"] = 7; // XTS-AEX-256 - EncryptArgs["EncryptionFlags"] = FreePlusUsedSpace ? 0 : (uint)1; // 0 = Used + Free space | 1 = Used Space only + // Prepare the method with arguments + ManagementBaseObject EncryptArgs = VolumeInfo.GetMethodParameters("Encrypt"); + EncryptArgs["EncryptionMethod"] = 7; // XTS-AEX-256 + EncryptArgs["EncryptionFlags"] = FreePlusUsedSpace ? 0 : (uint)1; // 0 = Used + Free space | 1 = Used Space only - // Invoke the method to Encrypt the volume - ManagementBaseObject EncryptMethodInvocationResult = VolumeInfo.InvokeMethod("Encrypt", EncryptArgs, null); + // Invoke the method to Encrypt the volume + ManagementBaseObject EncryptMethodInvocationResult = VolumeInfo.InvokeMethod("Encrypt", EncryptArgs, null); - if (HasErrorsOccurred) { return; } + if (HasErrorsOccurred) { return; } - #region Output handling - uint? EncryptResultCode = null; + #region Output handling + uint? EncryptResultCode = null; - if (EncryptMethodInvocationResult is not null) - { - EncryptResultCode = Convert.ToUInt32(EncryptMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } + if (EncryptMethodInvocationResult is not null) + { + EncryptResultCode = Convert.ToUInt32(EncryptMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (EncryptResultCode is not null && EncryptResultCode == 0) - { - Logger.LogMessage($"Successfully Encrypted the drive {DriveLetter}.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(EncryptResultCode); - return; - } - #endregion - } + if (EncryptResultCode is not null && EncryptResultCode == 0) + { + Logger.LogMessage($"Successfully Encrypted the drive {DriveLetter}.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(EncryptResultCode); + return; + } + #endregion + } - } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableBitLockerAutoUnlock.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableBitLockerAutoUnlock.cs index e2d58d89b..e2a5ff985 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableBitLockerAutoUnlock.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableBitLockerAutoUnlock.cs @@ -4,120 +4,120 @@ namespace HardenWindowsSecurity; - internal partial class BitLocker - { - /// - /// Enables Auto unlock | Suitable for Non-OS Drives - /// https://learn.microsoft.com/en-us/windows/win32/secprov/isautounlockenabled-win32-encryptablevolume - /// https://learn.microsoft.com/en-us/windows/win32/secprov/enableautounlock-win32-encryptablevolume - /// - /// Drive letter in the following format: "C:" - internal static void EnableBitLockerAutoUnlock(string DriveLetter) - { +internal partial class BitLocker +{ + /// + /// Enables Auto unlock | Suitable for Non-OS Drives + /// https://learn.microsoft.com/en-us/windows/win32/secprov/isautounlockenabled-win32-encryptablevolume + /// https://learn.microsoft.com/en-us/windows/win32/secprov/enableautounlock-win32-encryptablevolume + /// + /// Drive letter in the following format: "C:" + internal static void EnableBitLockerAutoUnlock(string DriveLetter) + { - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - // Invoke the method to enable the key protectors - // The first null indicates that the method does not require any input parameters. - // The second null indicates that there are no special options being passed for this WMI operation. - ManagementBaseObject IsAutoUnlockEnabledResult = VolumeInfo.InvokeMethod("IsAutoUnlockEnabled", null, null); + // Invoke the method to enable the key protectors + // The first null indicates that the method does not require any input parameters. + // The second null indicates that there are no special options being passed for this WMI operation. + ManagementBaseObject IsAutoUnlockEnabledResult = VolumeInfo.InvokeMethod("IsAutoUnlockEnabled", null, null); - #region Output handling - uint? IsAutoUnlockEnabledResultCode = null; + #region Output handling + uint? IsAutoUnlockEnabledResultCode = null; - if (IsAutoUnlockEnabledResult is not null) - { - IsAutoUnlockEnabledResultCode = Convert.ToUInt32(IsAutoUnlockEnabledResult["ReturnValue"], CultureInfo.InvariantCulture); - } + if (IsAutoUnlockEnabledResult is not null) + { + IsAutoUnlockEnabledResultCode = Convert.ToUInt32(IsAutoUnlockEnabledResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (IsAutoUnlockEnabledResultCode is not null && IsAutoUnlockEnabledResultCode == 0) - { - Logger.LogMessage($"Successfully queried the Auto-unlock status of the drive {DriveLetter}.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(IsAutoUnlockEnabledResultCode); - return; - } - #endregion + if (IsAutoUnlockEnabledResultCode is not null && IsAutoUnlockEnabledResultCode == 0) + { + Logger.LogMessage($"Successfully queried the Auto-unlock status of the drive {DriveLetter}.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(IsAutoUnlockEnabledResultCode); + return; + } + #endregion - if (!Convert.ToBoolean(IsAutoUnlockEnabledResult?["IsAutoUnlockEnabled"], CultureInfo.InvariantCulture)) - { - Logger.LogMessage($"Auto-unlock is not enabled on the drive {DriveLetter}, enabling it now.", LogTypeIntel.Information); + if (!Convert.ToBoolean(IsAutoUnlockEnabledResult?["IsAutoUnlockEnabled"], CultureInfo.InvariantCulture)) + { + Logger.LogMessage($"Auto-unlock is not enabled on the drive {DriveLetter}, enabling it now.", LogTypeIntel.Information); - // Get the method parameters for ProtectKeyWithExternalKey (even if they are empty) - ManagementBaseObject ProtectKeyArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithExternalKey"); + // Get the method parameters for ProtectKeyWithExternalKey (even if they are empty) + ManagementBaseObject ProtectKeyArgs = VolumeInfo.GetMethodParameters("ProtectKeyWithExternalKey"); - // Invoke the method with an empty argument object - // This is required because using ("ProtectKeyWithExternalKey", null, null) would result in a COM error unhandled by HResult method. - ManagementBaseObject ProtectKeyWithExternalKeyMethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithExternalKey", ProtectKeyArgs, null); + // Invoke the method with an empty argument object + // This is required because using ("ProtectKeyWithExternalKey", null, null) would result in a COM error unhandled by HResult method. + ManagementBaseObject ProtectKeyWithExternalKeyMethodInvocationResult = VolumeInfo.InvokeMethod("ProtectKeyWithExternalKey", ProtectKeyArgs, null); - #region Output handling - uint? MethodInvocationResultCode = null; + #region Output handling + uint? MethodInvocationResultCode = null; - if (ProtectKeyWithExternalKeyMethodInvocationResult is not null) - { - MethodInvocationResultCode = Convert.ToUInt32(ProtectKeyWithExternalKeyMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } + if (ProtectKeyWithExternalKeyMethodInvocationResult is not null) + { + MethodInvocationResultCode = Convert.ToUInt32(ProtectKeyWithExternalKeyMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) - { - Logger.LogMessage("The ExternalKey key protector was successfully added.", LogTypeIntel.Information); - // Will move forward to the next step - } - else - { - HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); - return; - } - #endregion + if (MethodInvocationResultCode is not null && MethodInvocationResultCode == 0) + { + Logger.LogMessage("The ExternalKey key protector was successfully added.", LogTypeIntel.Information); + // Will move forward to the next step + } + else + { + HResultHelper.HandleHresultAndLog(MethodInvocationResultCode); + return; + } + #endregion - // Prepare the method with arguments - ManagementBaseObject EnableAutoUnlockArgs = VolumeInfo.GetMethodParameters("EnableAutoUnlock"); - EnableAutoUnlockArgs["VolumeKeyProtectorID"] = ProtectKeyWithExternalKeyMethodInvocationResult?["VolumeKeyProtectorID"]; + // Prepare the method with arguments + ManagementBaseObject EnableAutoUnlockArgs = VolumeInfo.GetMethodParameters("EnableAutoUnlock"); + EnableAutoUnlockArgs["VolumeKeyProtectorID"] = ProtectKeyWithExternalKeyMethodInvocationResult?["VolumeKeyProtectorID"]; - // Invoke the method to enable Auto-unlock - ManagementBaseObject EnableAutoUnlockMethodInvocationResult = VolumeInfo.InvokeMethod("EnableAutoUnlock", EnableAutoUnlockArgs, null); + // Invoke the method to enable Auto-unlock + ManagementBaseObject EnableAutoUnlockMethodInvocationResult = VolumeInfo.InvokeMethod("EnableAutoUnlock", EnableAutoUnlockArgs, null); - #region Output handling - uint? EnableAutoUnlockMethodInvocationResultCode = null; + #region Output handling + uint? EnableAutoUnlockMethodInvocationResultCode = null; - if (EnableAutoUnlockMethodInvocationResult is not null) - { - EnableAutoUnlockMethodInvocationResultCode = Convert.ToUInt32(EnableAutoUnlockMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); - } + if (EnableAutoUnlockMethodInvocationResult is not null) + { + EnableAutoUnlockMethodInvocationResultCode = Convert.ToUInt32(EnableAutoUnlockMethodInvocationResult["ReturnValue"], CultureInfo.InvariantCulture); + } - if (EnableAutoUnlockMethodInvocationResultCode is not null && EnableAutoUnlockMethodInvocationResultCode == 0) - { - Logger.LogMessage($"Auto-Unlock has been successfully enabled for the drive: {DriveLetter}", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(EnableAutoUnlockMethodInvocationResultCode); + if (EnableAutoUnlockMethodInvocationResultCode is not null && EnableAutoUnlockMethodInvocationResultCode == 0) + { + Logger.LogMessage($"Auto-Unlock has been successfully enabled for the drive: {DriveLetter}", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(EnableAutoUnlockMethodInvocationResultCode); - Logger.LogMessage($"Error enabling Auto-Unlock for the drive {DriveLetter}: {EnableAutoUnlockMethodInvocationResultCode} . Removing the previously set ExternalKey Key Protector.", LogTypeIntel.Error); + Logger.LogMessage($"Error enabling Auto-Unlock for the drive {DriveLetter}: {EnableAutoUnlockMethodInvocationResultCode} . Removing the previously set ExternalKey Key Protector.", LogTypeIntel.Error); - RemoveKeyProtector(DriveLetter, ProtectKeyWithExternalKeyMethodInvocationResult?["VolumeKeyProtectorID"].ToString()!, false); + RemoveKeyProtector(DriveLetter, ProtectKeyWithExternalKeyMethodInvocationResult?["VolumeKeyProtectorID"].ToString()!, false); - return; - } - #endregion + return; + } + #endregion - } - else - { - Logger.LogMessage($"Auto-unlock is already enabled on the drive {DriveLetter}.", LogTypeIntel.Information); - } - } - } + } + else + { + Logger.LogMessage($"Auto-unlock is already enabled on the drive {DriveLetter}.", LogTypeIntel.Information); + } + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableKeyProtectors.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableKeyProtectors.cs index 42d0fac92..f1c944b3a 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableKeyProtectors.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-EnableKeyProtectors.cs @@ -4,47 +4,47 @@ namespace HardenWindowsSecurity; - internal partial class BitLocker - { - /// - /// Enables the key protectors of an encrypted volume, doesn't decrypt or encrypt the drive. - /// The drive can remain encrypted and you use Suspend-BitLocker cmdlet to turn the protection off. - /// After using this method, the "Protection Status" will be on. - /// Same as Resume-BitLocker PowerShell cmdlet. - /// This method must run at the end of the operation when turning on (enabling) BitLocker for the OS drive when it's fully decrypted and has no key protectors. - /// It can run on a drive where key protectors are already enabled, won't change anything. - /// https://learn.microsoft.com/en-us/windows/win32/secprov/enablekeyprotectors-win32-encryptablevolume - /// - /// - internal static void EnableKeyProtectors(string DriveLetter) - { - - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - - // Invoke the method to enable the key protectors - // The first null indicates that the method does not require any input parameters. - // The second null indicates that there are no special options being passed for this WMI operation. - ManagementBaseObject KeyProtectorEnablementResult = VolumeInfo.InvokeMethod("EnableKeyProtectors", null, null); - - - #region Output handling - uint? KeyProtectorEnablementResultCode = null; - - if (KeyProtectorEnablementResult is not null) - { - KeyProtectorEnablementResultCode = Convert.ToUInt32(KeyProtectorEnablementResult["ReturnValue"], CultureInfo.InvariantCulture); - } - - if (KeyProtectorEnablementResultCode is not null && KeyProtectorEnablementResultCode == 0) - { - Logger.LogMessage($"Successfully enabled the key protectors of the drive {DriveLetter}.", LogTypeIntel.Information); - } - else - { - HResultHelper.HandleHresultAndLog(KeyProtectorEnablementResultCode); - return; - } - #endregion - } - } +internal partial class BitLocker +{ + /// + /// Enables the key protectors of an encrypted volume, doesn't decrypt or encrypt the drive. + /// The drive can remain encrypted and you use Suspend-BitLocker cmdlet to turn the protection off. + /// After using this method, the "Protection Status" will be on. + /// Same as Resume-BitLocker PowerShell cmdlet. + /// This method must run at the end of the operation when turning on (enabling) BitLocker for the OS drive when it's fully decrypted and has no key protectors. + /// It can run on a drive where key protectors are already enabled, won't change anything. + /// https://learn.microsoft.com/en-us/windows/win32/secprov/enablekeyprotectors-win32-encryptablevolume + /// + /// + internal static void EnableKeyProtectors(string DriveLetter) + { + + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + + // Invoke the method to enable the key protectors + // The first null indicates that the method does not require any input parameters. + // The second null indicates that there are no special options being passed for this WMI operation. + ManagementBaseObject KeyProtectorEnablementResult = VolumeInfo.InvokeMethod("EnableKeyProtectors", null, null); + + + #region Output handling + uint? KeyProtectorEnablementResultCode = null; + + if (KeyProtectorEnablementResult is not null) + { + KeyProtectorEnablementResultCode = Convert.ToUInt32(KeyProtectorEnablementResult["ReturnValue"], CultureInfo.InvariantCulture); + } + + if (KeyProtectorEnablementResultCode is not null && KeyProtectorEnablementResultCode == 0) + { + Logger.LogMessage($"Successfully enabled the key protectors of the drive {DriveLetter}.", LogTypeIntel.Information); + } + else + { + HResultHelper.HandleHresultAndLog(KeyProtectorEnablementResultCode); + return; + } + #endregion + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-RemoveKeyProtectors.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-RemoveKeyProtectors.cs index aba78b701..6e50898b7 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-RemoveKeyProtectors.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/BitLocker-RemoveKeyProtectors.cs @@ -5,121 +5,121 @@ namespace HardenWindowsSecurity; - internal partial class BitLocker - { +internal partial class BitLocker +{ - // https://learn.microsoft.com/en-us/windows/win32/secprov/deletekeyprotector-win32-encryptablevolume#return-value - private const uint FVE_E_KEY_REQUIRED = 2150694941; - private const uint FVE_E_VOLUME_BOUND_ALREADY = 2150694943; + // https://learn.microsoft.com/en-us/windows/win32/secprov/deletekeyprotector-win32-encryptablevolume#return-value + private const uint FVE_E_KEY_REQUIRED = 2150694941; + private const uint FVE_E_VOLUME_BOUND_ALREADY = 2150694943; - /// - /// Removes a key protector of an encrypted volume based on the key protector ID - /// - /// - /// - /// - /// If the key protector being deleted is bound to the volume and used to keep the drive unlocked then do not throw errors. - /// This usually happens when trying to remove all ExternalKey key protectors of a Non-OS Drive when it is detected to have more than 1. - /// - internal static void RemoveKeyProtector(string DriveLetter, string KeyProtectorID, bool NoErrorIfBound) - { + /// + /// Removes a key protector of an encrypted volume based on the key protector ID + /// + /// + /// + /// + /// If the key protector being deleted is bound to the volume and used to keep the drive unlocked then do not throw errors. + /// This usually happens when trying to remove all ExternalKey key protectors of a Non-OS Drive when it is detected to have more than 1. + /// + internal static void RemoveKeyProtector(string DriveLetter, string KeyProtectorID, bool NoErrorIfBound) + { - // First get the volume info based on the drive letter - ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); + // First get the volume info based on the drive letter + ManagementObject VolumeInfo = GetVolumeFromLetter(DriveLetter); - // Get all other info about the drive - BitLockerVolume VolumeExtendedInfo = GetEncryptedVolumeInfo(DriveLetter); + // Get all other info about the drive + BitLockerVolume VolumeExtendedInfo = GetEncryptedVolumeInfo(DriveLetter); - // Get the key protector from the drive based on the user supplied ID - KeyProtector? DetectedKeyProtector = VolumeExtendedInfo?.KeyProtector?.Where(KeyProtector => KeyProtector.KeyProtectorID == KeyProtectorID).FirstOrDefault(); + // Get the key protector from the drive based on the user supplied ID + KeyProtector? DetectedKeyProtector = VolumeExtendedInfo?.KeyProtector?.Where(KeyProtector => KeyProtector.KeyProtectorID == KeyProtectorID).FirstOrDefault(); - if (DetectedKeyProtector is null) - { - Logger.LogMessage($"Key protector with the ID {KeyProtectorID} not found on the volume {DriveLetter}", LogTypeIntel.Warning); - return; - } + if (DetectedKeyProtector is null) + { + Logger.LogMessage($"Key protector with the ID {KeyProtectorID} not found on the volume {DriveLetter}", LogTypeIntel.Warning); + return; + } - if (DetectedKeyProtector.KeyProtectorType is KeyProtectorType.TpmNetworkKey) - { - Logger.LogMessage($"The detected Key Protector type is TpmNetworkKey, it must be disabled and removed using group policies.", LogTypeIntel.Warning); - return; - } + if (DetectedKeyProtector.KeyProtectorType is KeyProtectorType.TpmNetworkKey) + { + Logger.LogMessage($"The detected Key Protector type is TpmNetworkKey, it must be disabled and removed using group policies.", LogTypeIntel.Warning); + return; + } - if (DetectedKeyProtector.KeyProtectorType is KeyProtectorType.PublicKey) - { - Logger.LogMessage($"Removal of PublicKey type key protector not supported yet.", LogTypeIntel.Warning); - return; - } + if (DetectedKeyProtector.KeyProtectorType is KeyProtectorType.PublicKey) + { + Logger.LogMessage($"Removal of PublicKey type key protector not supported yet.", LogTypeIntel.Warning); + return; + } - // Prepare arguments for DeleteKeyProtector method. - ManagementBaseObject deleteKeyProtectorArgs = VolumeInfo.GetMethodParameters("DeleteKeyProtector"); + // Prepare arguments for DeleteKeyProtector method. + ManagementBaseObject deleteKeyProtectorArgs = VolumeInfo.GetMethodParameters("DeleteKeyProtector"); - // Set the VolumeKeyProtectorID argument to the current KeyProtectorID in the loop - deleteKeyProtectorArgs["VolumeKeyProtectorID"] = KeyProtectorID; + // Set the VolumeKeyProtectorID argument to the current KeyProtectorID in the loop + deleteKeyProtectorArgs["VolumeKeyProtectorID"] = KeyProtectorID; - // Invoke DeleteKeyProtector method to remove the key protector - // https://learn.microsoft.com/en-us/windows/win32/secprov/deletekeyprotectors-win32-encryptablevolume - ManagementBaseObject deletionResult = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); + // Invoke DeleteKeyProtector method to remove the key protector + // https://learn.microsoft.com/en-us/windows/win32/secprov/deletekeyprotectors-win32-encryptablevolume + ManagementBaseObject deletionResult = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); - #region Output handling + #region Output handling - uint? deletionResultCode = null; + uint? deletionResultCode = null; - deletionResultCode = Convert.ToUInt32(deletionResult["ReturnValue"], CultureInfo.InvariantCulture); + deletionResultCode = Convert.ToUInt32(deletionResult["ReturnValue"], CultureInfo.InvariantCulture); - if (deletionResultCode == FVE_E_KEY_REQUIRED) - { + if (deletionResultCode == FVE_E_KEY_REQUIRED) + { - Logger.LogMessage($"The key protectors need to be disabled first, disabling now.", LogTypeIntel.Information); + Logger.LogMessage($"The key protectors need to be disabled first, disabling now.", LogTypeIntel.Information); - // https://learn.microsoft.com/en-us/windows/win32/secprov/disablekeyprotectors-win32-encryptablevolume - ManagementBaseObject disableKeyProtectorsResult = VolumeInfo.InvokeMethod("DisableKeyProtectors", null, null); + // https://learn.microsoft.com/en-us/windows/win32/secprov/disablekeyprotectors-win32-encryptablevolume + ManagementBaseObject disableKeyProtectorsResult = VolumeInfo.InvokeMethod("DisableKeyProtectors", null, null); - uint? disablementResultCode = null; + uint? disablementResultCode = null; - disablementResultCode = Convert.ToUInt32(disableKeyProtectorsResult["ReturnValue"], CultureInfo.InvariantCulture); + disablementResultCode = Convert.ToUInt32(disableKeyProtectorsResult["ReturnValue"], CultureInfo.InvariantCulture); - if (disablementResultCode == 0) - { - Logger.LogMessage("Successfully disabled the key protectors, attempting the deletion again.", LogTypeIntel.Information); + if (disablementResultCode == 0) + { + Logger.LogMessage("Successfully disabled the key protectors, attempting the deletion again.", LogTypeIntel.Information); - // Invoke DeleteKeyProtector method, Again, to remove the key protector - deletionResult = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); + // Invoke DeleteKeyProtector method, Again, to remove the key protector + deletionResult = VolumeInfo.InvokeMethod("DeleteKeyProtector", deleteKeyProtectorArgs, null); - deletionResultCode = Convert.ToUInt32(deletionResult["ReturnValue"], CultureInfo.InvariantCulture); + deletionResultCode = Convert.ToUInt32(deletionResult["ReturnValue"], CultureInfo.InvariantCulture); - } - else - { - HResultHelper.HandleHresultAndLog(disablementResultCode); - return; - } - } + } + else + { + HResultHelper.HandleHresultAndLog(disablementResultCode); + return; + } + } - // Check the deletion result code at the end, whether the key protector required disablement or not - if (deletionResultCode == 0) - { - Logger.LogMessage("Successfully deleted the key protector.", LogTypeIntel.Information); - } - else if (NoErrorIfBound && deletionResultCode == FVE_E_VOLUME_BOUND_ALREADY) - { - Logger.LogMessage("The key protector is bound to the volume and used to keep the drive unlocked, skipping the deletion.", LogTypeIntel.Information); - return; - } - else - { - HResultHelper.HandleHresultAndLog(deletionResultCode); - return; - } + // Check the deletion result code at the end, whether the key protector required disablement or not + if (deletionResultCode == 0) + { + Logger.LogMessage("Successfully deleted the key protector.", LogTypeIntel.Information); + } + else if (NoErrorIfBound && deletionResultCode == FVE_E_VOLUME_BOUND_ALREADY) + { + Logger.LogMessage("The key protector is bound to the volume and used to keep the drive unlocked, skipping the deletion.", LogTypeIntel.Information); + return; + } + else + { + HResultHelper.HandleHresultAndLog(deletionResultCode); + return; + } - #endregion + #endregion - } - } + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/ConfigDefenderHelper.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/ConfigDefenderHelper.cs index 5a716b712..01183e75d 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/ConfigDefenderHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/ConfigDefenderHelper.cs @@ -6,161 +6,161 @@ namespace HardenWindowsSecurity; - internal static class ConfigDefenderHelper - { - // Get the MpComputerStatus from the MSFT_MpComputerStatus WMI class and returns it as a dynamic object - internal static dynamic GetMpComputerStatus() - { - try - { - // Define the WMI query to retrieve the MpComputerStatus - string namespaceName = "ROOT\\Microsoft\\Windows\\Defender"; - string className = "MSFT_MpComputerStatus"; - string queryString = $"SELECT * FROM {className}"; - - // Execute the query - using ManagementObjectSearcher searcher = new(namespaceName, queryString); - ManagementObjectCollection results = searcher.Get(); - - // Make sure the results isn't empty - if (results.Count > 0) - { - ManagementBaseObject? result = results.Cast().FirstOrDefault(); - - if (result is not null) - { - - return ConvertToDynamic(result); - } - else - { - throw new InvalidOperationException("Failed to get MpComputerStatus!"); - } - } - else - { - throw new PowerShellExecutionException("WMI query for 'MSFT_MpComputerStatus' failed"); - } - } - catch (ManagementException ex) - { - string errorMessage = $"WMI query for 'MSFT_MpComputerStatus' failed: {ex.Message}"; - throw new PowerShellExecutionException(errorMessage, ex); - } - } - - // Convert the ManagementBaseObject to a dynamic object - private static dynamic ConvertToDynamic(ManagementBaseObject managementObject) - { - // Creating a dynamic object to store the properties of the ManagementBaseObject - dynamic expandoObject = new ExpandoObject(); - - IDictionary dictionary = expandoObject; - - foreach (PropertyData property in managementObject.Properties) - { - if (property.Type == CimType.DateTime && property.Value is string dmtfTime) - { - dictionary[property.Name] = ConvertDmtfToDateTime(dmtfTime); - } - else - { - dictionary[property.Name] = property.Value; - } - } - - return expandoObject; - } - - // Convert DMTF datetime format to DateTime - private static DateTime ConvertDmtfToDateTime(string dmtfTime) - { - // DMTF datetime format: yyyymmddHHMMSS.mmmmmmsUUU - if (ManagementDateTimeConverter.ToDateTime(dmtfTime) is DateTime dateTime) - { - return dateTime; - } - - throw new FormatException($"Invalid DMTF datetime format: {dmtfTime}"); - } - - - /// - /// The Set-MpPreference and Add-MpPreference commands but implemented from scratch for the Harden Windows Security application - /// - /// The type of the value to set the Microsoft Defender feature to - /// The name of the Microsoft Defender feature to configure - /// The value to set the Microsoft Defender feature to - /// Bool. If true, Set will be used, if false, Add will be used. - internal static void ManageMpPreference(string preferenceName, T preferenceValue, bool Set) - { - - // The name of the method - string MethodName = Set ? "Set" : "Add"; - - try - { - // Connect to the WMI namespace - ManagementScope scope = new(@"\\.\ROOT\Microsoft\Windows\Defender"); - scope.Connect(); - - // Create an instance of the MSFT_MpPreference class - using ManagementClass mpPreferenceClass = new(scope, new ManagementPath("MSFT_MpPreference"), null); - - // Get the available methods for the class - ManagementBaseObject methodParams = mpPreferenceClass.GetMethodParameters(MethodName); - - if (preferenceValue is null) - { - throw new ArgumentNullException(nameof(preferenceValue)); - } - - // Set the preference based on the type T - if (typeof(T) == typeof(string)) - { - methodParams[preferenceName] = (string)(object)preferenceValue; - } - else if (typeof(T) == typeof(bool)) - { - methodParams[preferenceName] = (bool)(object)preferenceValue; - } - else if (typeof(T) == typeof(int)) - { - methodParams[preferenceName] = (int)(object)preferenceValue; - } - else if (typeof(T) == typeof(double)) - { - methodParams[preferenceName] = (double)(object)preferenceValue; - } - else if (typeof(T) == typeof(float)) - { - methodParams[preferenceName] = (float)(object)preferenceValue; - } - else if (typeof(T) == typeof(string[])) - { - methodParams[preferenceName] = (string[])(object)preferenceValue; - } - else if (typeof(T) == typeof(byte)) - { - methodParams[preferenceName] = (byte)(object)preferenceValue; - } - else if (typeof(T) == typeof(ushort)) - { - methodParams[preferenceName] = (ushort)(object)preferenceValue; - } - else - { - throw new ArgumentException($"Unsupported type {typeof(T)} for preference value"); - } - - // Invoke the method to apply the settings - _ = mpPreferenceClass.InvokeMethod(MethodName, methodParams, null); - - Logger.LogMessage($"{preferenceName} set to {preferenceValue} (Type: {typeof(T).Name}) successfully.", LogTypeIntel.Information); - } - catch (Exception ex) - { - Logger.LogMessage($"Error setting {preferenceName}: {ex.Message}- You might need to update your OS first.", LogTypeIntel.Warning); - } - } - } +internal static class ConfigDefenderHelper +{ + // Get the MpComputerStatus from the MSFT_MpComputerStatus WMI class and returns it as a dynamic object + internal static dynamic GetMpComputerStatus() + { + try + { + // Define the WMI query to retrieve the MpComputerStatus + string namespaceName = "ROOT\\Microsoft\\Windows\\Defender"; + string className = "MSFT_MpComputerStatus"; + string queryString = $"SELECT * FROM {className}"; + + // Execute the query + using ManagementObjectSearcher searcher = new(namespaceName, queryString); + ManagementObjectCollection results = searcher.Get(); + + // Make sure the results isn't empty + if (results.Count > 0) + { + ManagementBaseObject? result = results.Cast().FirstOrDefault(); + + if (result is not null) + { + + return ConvertToDynamic(result); + } + else + { + throw new InvalidOperationException("Failed to get MpComputerStatus!"); + } + } + else + { + throw new PowerShellExecutionException("WMI query for 'MSFT_MpComputerStatus' failed"); + } + } + catch (ManagementException ex) + { + string errorMessage = $"WMI query for 'MSFT_MpComputerStatus' failed: {ex.Message}"; + throw new PowerShellExecutionException(errorMessage, ex); + } + } + + // Convert the ManagementBaseObject to a dynamic object + private static dynamic ConvertToDynamic(ManagementBaseObject managementObject) + { + // Creating a dynamic object to store the properties of the ManagementBaseObject + dynamic expandoObject = new ExpandoObject(); + + IDictionary dictionary = expandoObject; + + foreach (PropertyData property in managementObject.Properties) + { + if (property.Type == CimType.DateTime && property.Value is string dmtfTime) + { + dictionary[property.Name] = ConvertDmtfToDateTime(dmtfTime); + } + else + { + dictionary[property.Name] = property.Value; + } + } + + return expandoObject; + } + + // Convert DMTF datetime format to DateTime + private static DateTime ConvertDmtfToDateTime(string dmtfTime) + { + // DMTF datetime format: yyyymmddHHMMSS.mmmmmmsUUU + if (ManagementDateTimeConverter.ToDateTime(dmtfTime) is DateTime dateTime) + { + return dateTime; + } + + throw new FormatException($"Invalid DMTF datetime format: {dmtfTime}"); + } + + + /// + /// The Set-MpPreference and Add-MpPreference commands but implemented from scratch for the Harden Windows Security application + /// + /// The type of the value to set the Microsoft Defender feature to + /// The name of the Microsoft Defender feature to configure + /// The value to set the Microsoft Defender feature to + /// Bool. If true, Set will be used, if false, Add will be used. + internal static void ManageMpPreference(string preferenceName, T preferenceValue, bool Set) + { + + // The name of the method + string MethodName = Set ? "Set" : "Add"; + + try + { + // Connect to the WMI namespace + ManagementScope scope = new(@"\\.\ROOT\Microsoft\Windows\Defender"); + scope.Connect(); + + // Create an instance of the MSFT_MpPreference class + using ManagementClass mpPreferenceClass = new(scope, new ManagementPath("MSFT_MpPreference"), null); + + // Get the available methods for the class + ManagementBaseObject methodParams = mpPreferenceClass.GetMethodParameters(MethodName); + + if (preferenceValue is null) + { + throw new ArgumentNullException(nameof(preferenceValue)); + } + + // Set the preference based on the type T + if (typeof(T) == typeof(string)) + { + methodParams[preferenceName] = (string)(object)preferenceValue; + } + else if (typeof(T) == typeof(bool)) + { + methodParams[preferenceName] = (bool)(object)preferenceValue; + } + else if (typeof(T) == typeof(int)) + { + methodParams[preferenceName] = (int)(object)preferenceValue; + } + else if (typeof(T) == typeof(double)) + { + methodParams[preferenceName] = (double)(object)preferenceValue; + } + else if (typeof(T) == typeof(float)) + { + methodParams[preferenceName] = (float)(object)preferenceValue; + } + else if (typeof(T) == typeof(string[])) + { + methodParams[preferenceName] = (string[])(object)preferenceValue; + } + else if (typeof(T) == typeof(byte)) + { + methodParams[preferenceName] = (byte)(object)preferenceValue; + } + else if (typeof(T) == typeof(ushort)) + { + methodParams[preferenceName] = (ushort)(object)preferenceValue; + } + else + { + throw new ArgumentException($"Unsupported type {typeof(T)} for preference value"); + } + + // Invoke the method to apply the settings + _ = mpPreferenceClass.InvokeMethod(MethodName, methodParams, null); + + Logger.LogMessage($"{preferenceName} set to {preferenceValue} (Type: {typeof(T).Name}) successfully.", LogTypeIntel.Information); + } + catch (Exception ex) + { + Logger.LogMessage($"Error setting {preferenceName}: {ex.Message}- You might need to update your OS first.", LogTypeIntel.Warning); + } + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/FirewallHelper.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/FirewallHelper.cs index cefcb7768..3a1d2f65c 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/FirewallHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/FirewallHelper.cs @@ -1,301 +1,301 @@ -using Microsoft.Management.Infrastructure; -using Microsoft.Management.Infrastructure.Options; using System; using System.Collections.Generic; using System.Linq; using System.Management; using System.Net.Http; +using Microsoft.Management.Infrastructure; +using Microsoft.Management.Infrastructure.Options; namespace HardenWindowsSecurity; - internal static class FirewallHelper - { - // Method to get firewall rules based on RuleGroup and Direction - public static List GetFirewallRules(string ruleGroup, ushort direction) - { - string namespacePath = @"root\standardcimv2"; - string className = "MSFT_NetFirewallRule"; - - // List to store results - List results = []; - - try - { - // Create management scope and connect - ManagementScope scope = new(namespacePath); - scope.Connect(); - - // Ensure the connection is established - if (!scope.IsConnected) - { - throw new InvalidOperationException("Failed to connect to WMI namespace."); - } - - // Retrieve all firewall rules - ObjectQuery query = new($"SELECT * FROM {className}"); - - using ManagementObjectSearcher searcher = new(scope, query); - using ManagementObjectCollection queryCollection = searcher.Get(); - - foreach (ManagementObject mObject in queryCollection.Cast()) - { - // Filter results based on RuleGroup and Direction - // supplying the RuleGroup directly wouldn't work - // This however works in PowerShell: - // Get-CimInstance -Namespace 'root/standardcimv2' -ClassName 'MSFT_NetFirewallRule' | - // Where-Object { - // ($_.RuleGroup -eq '@%SystemRoot%\system32\firewallapi.dll,-37302') -and - // ($_.Direction -eq '1') - // } - // OR this - // Get-NetFirewallRule | Where-Object -FilterScript { - // ($_.RuleGroup -eq '@%SystemRoot%\system32\firewallapi.dll,-37302') -and - // ($_.Direction -eq 'inbound') - // } - if (mObject["RuleGroup"]?.ToString() == ruleGroup && (ushort)mObject["Direction"] == direction) - { - results.Add(mObject); - } - } - } - // catch exceptions specific to WMI - catch (ManagementException mex) - { - Logger.LogMessage($"WMI ManagementException: {mex.Message}", LogTypeIntel.Error); - } - // Catch block for unauthorized access exceptions - catch (UnauthorizedAccessException uex) - { - Logger.LogMessage($"UnauthorizedAccessException: {uex.Message}", LogTypeIntel.Error); - } - // General catch block for any other exceptions - catch (Exception ex) - { - Logger.LogMessage($"An error occurred: {ex.Message}", LogTypeIntel.Error); - } - - return results; - } - - - internal enum NetSecurityEnabled : ushort - { - True = 1, - False = 2 - } - - internal enum NetSecurityProfile : ushort - { - Any = 0, - Public = 4, - Private = 2, - Domain = 1, - NotApplicable = 65535 - } - - internal enum NetSecurityDirection : ushort - { - Inbound = 1, - Outbound = 2 - } - - internal enum NetSecurityAction : ushort - { - NotConfigured = 0, - Allow = 2, - Block = 4 - } - - internal enum NetSecurityEdgeTraversal : ushort - { - Block = 0, - Allow = 1, - DeferToUser = 2, - DeferToApp = 3 - } - - internal enum NetSecurityPrimaryStatus : ushort - { - Unknown = 0, - OK = 1, - Inactive = 2, - Error = 3 - } - - internal enum NetSecurityPolicyStoreType : ushort - { - None = 0, - Local = 1, - GroupPolicy = 2, - Dynamic = 3, - Generated = 4, - Hardcoded = 5, - MDM = 6, - HostFirewallLocal = 8, - HostFirewallGroupPolicy = 9, - HostFirewallDynamic = 10, - HostFirewallMDM = 11 - } - - [Flags] - internal enum NetSecurityDynamicTransport : uint - { - Any = 0, - ProximityApps = 1, - ProximitySharing = 2, - WifiDirectPrinting = 4, - WifiDirectDisplay = 8, - WifiDirectDevices = 16 - } - - [Flags] - internal enum NetSecurityInterfaceType : uint - { - Any = 0, - Wired = 1, - Wireless = 2, - RemoteAccess = 4 - } - - internal enum NetSecurityAuthentication : ushort - { - NotRequired = 0, - Required = 1, - NoEncap = 2 - } - - internal enum NetSecurityEncryption : ushort - { - NotRequired = 0, - Required = 1, - Dynamic = 2 - } - - - internal enum FirewallRuleAction - { - Enable, - Disable - } - - private static readonly string[] separator = ["\r\n", "\n"]; - - - /// - /// This method can Add or Remove Firewall rules added to the Group Policy store that are responsible for blocking pre-defined country IP Addresses. - /// If the same rules already exist, the method will delete the old ones and recreate new ones in order to let the system have up to date IP ranges. - /// Group Policy is idempotent so it will actively maintain the policies set in it. - /// Another benefit of using LocalStore is that it supports large arrays of IP addresses. - /// The default store which goes to Windows firewall store does not support large arrays and throws: "The array bounds are invalid" error. - /// - /// The DisplayName of the Firewall rule - /// Link to the GitHub file that contains the IP Addresses - /// If true, the firewall rules will be added. If false, the firewall rules will only be deleted. - public static void BlockIPAddressListsInGroupPolicy(string DisplayName, Uri? ListDownloadURL, bool ToAdd) - { - // An array to hold the IP Address ranges - string[] ipList = []; - - if (ToAdd) - { - if (ListDownloadURL is null) - { - throw new InvalidOperationException("ListDownloadURL cannot be null when creating Firewall rules."); - } - - Logger.LogMessage("Downloading the IP Address list", LogTypeIntel.Information); - // Download the IP Addresses list - ipList = DownloadIPList(ListDownloadURL); - } - - // Establish a CIM session to localhost - using (CimSession cimSession = CimSession.Create(null)) - { - - // Define options to specify the policy store - using CimOperationOptions options = new(); - - options.SetCustomOption("PolicyStore", "localhost", mustComply: true); - - // Delete existing rules with the same name - // it is thorough, any number of firewall rules that match the same name in both inbound and outbound sections of the Group policy firewall rules will be included - DeleteFirewallRules(cimSession, DisplayName, "localhost"); - - if (ToAdd) - { - // Create inbound and outbound rules - CreateFirewallRule(cimSession, DisplayName, ipList, isInbound: true); - CreateFirewallRule(cimSession, DisplayName, ipList, isInbound: false); - } - } - - #region Helper Methods - - // Downloads the IP Address list from the GitHub URLs and converts them into string arrays - string[] DownloadIPList(Uri URL) - { - // Download the fresh list of IPs - using HttpClient client = new(); - HttpResponseMessage response = client.GetAsync(URL).Result; - string content = response.Content.ReadAsStringAsync().Result; - - // Converts the list from string to string array - return content.Split(separator, StringSplitOptions.RemoveEmptyEntries); - } - - // Deletes the Firewall rules - void DeleteFirewallRules(CimSession cimSession, string ruleName, string policyStore) - { - // Define custom options for the operation - using CimOperationOptions options = new(); - - options.SetCustomOption("PolicyStore", policyStore, mustComply: true); - - // Check for existing rules with the same name and delete them - IEnumerable existingRules = cimSession.EnumerateInstances("root/StandardCimv2", "MSFT_NetFirewallRule", options) - .Where(instance => instance.CimInstanceProperties["ElementName"].Value.ToString() == ruleName); - - foreach (CimInstance rule in existingRules) - { - cimSession.DeleteInstance("root/StandardCimv2", rule, options); - Logger.LogMessage($"Deleted existing firewall rule: {ruleName}", LogTypeIntel.Information); - } - } - - // Creates the Firewall rules - void CreateFirewallRule(CimSession cimSession, string name, string[] ipList, bool isInbound) - { - // Define custom options for the operation - using CimOperationOptions options = new(); - - options.SetCustomOption("PolicyStore", "localhost", mustComply: true); - - // The LocalAddress and RemoteAddress accept String[] type - // SetCustomOption doesn't support string arrays using 3 overloads variations - // so we have to use the 4 overload variation that allows us to explicitly define the type - string[] emptyArray = []; - // Empty array will set it to "Any" - options.SetCustomOption("LocalAddress", emptyArray, Microsoft.Management.Infrastructure.CimType.StringArray, mustComply: true); - options.SetCustomOption("RemoteAddress", ipList, Microsoft.Management.Infrastructure.CimType.StringArray, mustComply: true); - - // Define properties for the new firewall rule - using CimInstance newFirewallRule = new("MSFT_NetFirewallRule", "root/StandardCimv2"); - - newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("ElementName", name, CimFlags.None)); // ElementName is the same as DisplayName - newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Description", name, CimFlags.None)); // Setting the Description the same value as the DisplayName - newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Direction", (ushort)(isInbound ? 1 : 2), CimFlags.None)); // 1 for Inbound, 2 for Outbound - newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Action", (ushort)4, CimFlags.None)); // Block - newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Enabled", (ushort)1, CimFlags.None)); // Enable - newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Profiles", (ushort)0, CimFlags.None)); // Any - newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("EdgeTraversalPolicy", (ushort)0, CimFlags.None)); // Block - - // Create the instance - _ = cimSession.CreateInstance("root/StandardCimv2", newFirewallRule, options); - - Logger.LogMessage($"Successfully created a Firewall rule with the name {name} and the direction {(isInbound ? "Inbound" : "Outbound")}.", LogTypeIntel.Information); - } - - #endregion - - } - } +internal static class FirewallHelper +{ + // Method to get firewall rules based on RuleGroup and Direction + public static List GetFirewallRules(string ruleGroup, ushort direction) + { + string namespacePath = @"root\standardcimv2"; + string className = "MSFT_NetFirewallRule"; + + // List to store results + List results = []; + + try + { + // Create management scope and connect + ManagementScope scope = new(namespacePath); + scope.Connect(); + + // Ensure the connection is established + if (!scope.IsConnected) + { + throw new InvalidOperationException("Failed to connect to WMI namespace."); + } + + // Retrieve all firewall rules + ObjectQuery query = new($"SELECT * FROM {className}"); + + using ManagementObjectSearcher searcher = new(scope, query); + using ManagementObjectCollection queryCollection = searcher.Get(); + + foreach (ManagementObject mObject in queryCollection.Cast()) + { + // Filter results based on RuleGroup and Direction + // supplying the RuleGroup directly wouldn't work + // This however works in PowerShell: + // Get-CimInstance -Namespace 'root/standardcimv2' -ClassName 'MSFT_NetFirewallRule' | + // Where-Object { + // ($_.RuleGroup -eq '@%SystemRoot%\system32\firewallapi.dll,-37302') -and + // ($_.Direction -eq '1') + // } + // OR this + // Get-NetFirewallRule | Where-Object -FilterScript { + // ($_.RuleGroup -eq '@%SystemRoot%\system32\firewallapi.dll,-37302') -and + // ($_.Direction -eq 'inbound') + // } + if (mObject["RuleGroup"]?.ToString() == ruleGroup && (ushort)mObject["Direction"] == direction) + { + results.Add(mObject); + } + } + } + // catch exceptions specific to WMI + catch (ManagementException mex) + { + Logger.LogMessage($"WMI ManagementException: {mex.Message}", LogTypeIntel.Error); + } + // Catch block for unauthorized access exceptions + catch (UnauthorizedAccessException uex) + { + Logger.LogMessage($"UnauthorizedAccessException: {uex.Message}", LogTypeIntel.Error); + } + // General catch block for any other exceptions + catch (Exception ex) + { + Logger.LogMessage($"An error occurred: {ex.Message}", LogTypeIntel.Error); + } + + return results; + } + + + internal enum NetSecurityEnabled : ushort + { + True = 1, + False = 2 + } + + internal enum NetSecurityProfile : ushort + { + Any = 0, + Public = 4, + Private = 2, + Domain = 1, + NotApplicable = 65535 + } + + internal enum NetSecurityDirection : ushort + { + Inbound = 1, + Outbound = 2 + } + + internal enum NetSecurityAction : ushort + { + NotConfigured = 0, + Allow = 2, + Block = 4 + } + + internal enum NetSecurityEdgeTraversal : ushort + { + Block = 0, + Allow = 1, + DeferToUser = 2, + DeferToApp = 3 + } + + internal enum NetSecurityPrimaryStatus : ushort + { + Unknown = 0, + OK = 1, + Inactive = 2, + Error = 3 + } + + internal enum NetSecurityPolicyStoreType : ushort + { + None = 0, + Local = 1, + GroupPolicy = 2, + Dynamic = 3, + Generated = 4, + Hardcoded = 5, + MDM = 6, + HostFirewallLocal = 8, + HostFirewallGroupPolicy = 9, + HostFirewallDynamic = 10, + HostFirewallMDM = 11 + } + + [Flags] + internal enum NetSecurityDynamicTransport : uint + { + Any = 0, + ProximityApps = 1, + ProximitySharing = 2, + WifiDirectPrinting = 4, + WifiDirectDisplay = 8, + WifiDirectDevices = 16 + } + + [Flags] + internal enum NetSecurityInterfaceType : uint + { + Any = 0, + Wired = 1, + Wireless = 2, + RemoteAccess = 4 + } + + internal enum NetSecurityAuthentication : ushort + { + NotRequired = 0, + Required = 1, + NoEncap = 2 + } + + internal enum NetSecurityEncryption : ushort + { + NotRequired = 0, + Required = 1, + Dynamic = 2 + } + + + internal enum FirewallRuleAction + { + Enable, + Disable + } + + private static readonly string[] separator = ["\r\n", "\n"]; + + + /// + /// This method can Add or Remove Firewall rules added to the Group Policy store that are responsible for blocking pre-defined country IP Addresses. + /// If the same rules already exist, the method will delete the old ones and recreate new ones in order to let the system have up to date IP ranges. + /// Group Policy is idempotent so it will actively maintain the policies set in it. + /// Another benefit of using LocalStore is that it supports large arrays of IP addresses. + /// The default store which goes to Windows firewall store does not support large arrays and throws: "The array bounds are invalid" error. + /// + /// The DisplayName of the Firewall rule + /// Link to the GitHub file that contains the IP Addresses + /// If true, the firewall rules will be added. If false, the firewall rules will only be deleted. + public static void BlockIPAddressListsInGroupPolicy(string DisplayName, Uri? ListDownloadURL, bool ToAdd) + { + // An array to hold the IP Address ranges + string[] ipList = []; + + if (ToAdd) + { + if (ListDownloadURL is null) + { + throw new InvalidOperationException("ListDownloadURL cannot be null when creating Firewall rules."); + } + + Logger.LogMessage("Downloading the IP Address list", LogTypeIntel.Information); + // Download the IP Addresses list + ipList = DownloadIPList(ListDownloadURL); + } + + // Establish a CIM session to localhost + using (CimSession cimSession = CimSession.Create(null)) + { + + // Define options to specify the policy store + using CimOperationOptions options = new(); + + options.SetCustomOption("PolicyStore", "localhost", mustComply: true); + + // Delete existing rules with the same name + // it is thorough, any number of firewall rules that match the same name in both inbound and outbound sections of the Group policy firewall rules will be included + DeleteFirewallRules(cimSession, DisplayName, "localhost"); + + if (ToAdd) + { + // Create inbound and outbound rules + CreateFirewallRule(cimSession, DisplayName, ipList, isInbound: true); + CreateFirewallRule(cimSession, DisplayName, ipList, isInbound: false); + } + } + + #region Helper Methods + + // Downloads the IP Address list from the GitHub URLs and converts them into string arrays + string[] DownloadIPList(Uri URL) + { + // Download the fresh list of IPs + using HttpClient client = new(); + HttpResponseMessage response = client.GetAsync(URL).Result; + string content = response.Content.ReadAsStringAsync().Result; + + // Converts the list from string to string array + return content.Split(separator, StringSplitOptions.RemoveEmptyEntries); + } + + // Deletes the Firewall rules + void DeleteFirewallRules(CimSession cimSession, string ruleName, string policyStore) + { + // Define custom options for the operation + using CimOperationOptions options = new(); + + options.SetCustomOption("PolicyStore", policyStore, mustComply: true); + + // Check for existing rules with the same name and delete them + IEnumerable existingRules = cimSession.EnumerateInstances("root/StandardCimv2", "MSFT_NetFirewallRule", options) + .Where(instance => instance.CimInstanceProperties["ElementName"].Value.ToString() == ruleName); + + foreach (CimInstance rule in existingRules) + { + cimSession.DeleteInstance("root/StandardCimv2", rule, options); + Logger.LogMessage($"Deleted existing firewall rule: {ruleName}", LogTypeIntel.Information); + } + } + + // Creates the Firewall rules + void CreateFirewallRule(CimSession cimSession, string name, string[] ipList, bool isInbound) + { + // Define custom options for the operation + using CimOperationOptions options = new(); + + options.SetCustomOption("PolicyStore", "localhost", mustComply: true); + + // The LocalAddress and RemoteAddress accept String[] type + // SetCustomOption doesn't support string arrays using 3 overloads variations + // so we have to use the 4 overload variation that allows us to explicitly define the type + string[] emptyArray = []; + // Empty array will set it to "Any" + options.SetCustomOption("LocalAddress", emptyArray, Microsoft.Management.Infrastructure.CimType.StringArray, mustComply: true); + options.SetCustomOption("RemoteAddress", ipList, Microsoft.Management.Infrastructure.CimType.StringArray, mustComply: true); + + // Define properties for the new firewall rule + using CimInstance newFirewallRule = new("MSFT_NetFirewallRule", "root/StandardCimv2"); + + newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("ElementName", name, CimFlags.None)); // ElementName is the same as DisplayName + newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Description", name, CimFlags.None)); // Setting the Description the same value as the DisplayName + newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Direction", (ushort)(isInbound ? 1 : 2), CimFlags.None)); // 1 for Inbound, 2 for Outbound + newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Action", (ushort)4, CimFlags.None)); // Block + newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Enabled", (ushort)1, CimFlags.None)); // Enable + newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("Profiles", (ushort)0, CimFlags.None)); // Any + newFirewallRule.CimInstanceProperties.Add(CimProperty.Create("EdgeTraversalPolicy", (ushort)0, CimFlags.None)); // Block + + // Create the instance + _ = cimSession.CreateInstance("root/StandardCimv2", newFirewallRule, options); + + Logger.LogMessage($"Successfully created a Firewall rule with the name {name} and the direction {(isInbound ? "Inbound" : "Outbound")}.", LogTypeIntel.Information); + } + + #endregion + + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/MDM.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/MDM.cs index bb8f3ee7b..2b6452466 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/MDM.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/MDM.cs @@ -9,174 +9,174 @@ /// https://learn.microsoft.com/en-us/windows/win32/wmisdk/common-information-model namespace HardenWindowsSecurity; - /// - /// Class that deals with MDM/CSPs/Intune - /// - internal static class MDM - { - /// - /// Gets the results of all of the Intune policies from the system - /// - /// - internal static Dictionary>> Get() - { - // Running the asynchronous method synchronously and returning the result - return Task.Run(GetAsync).GetAwaiter().GetResult(); - } - - // Asynchronous method to get the results - private static async Task>>> GetAsync() - { - // Set the location of the CSV file containing the MDM list - string path = GlobalVars.path ?? throw new InvalidOperationException("GlobalVars.path is null"); - string csvFilePath = Path.Combine(path, "Resources", "MDMResultClasses.csv"); - - // Create a dictionary where keys are the class names and values are lists of dictionaries - Dictionary>> results = []; - - try - { - // Read class names and namespaces from CSV file asynchronously - List records = await ReadCsvFileAsync(csvFilePath); - - // Create a list of tasks for querying each class - List tasks = []; - - // Iterate through records - foreach (MdmRecord record in records) - { - // Process only authorized records - if (record.Authorized?.Equals("TRUE", StringComparison.OrdinalIgnoreCase) == true) - { - - // Debugging output - // Logger.LogMessage($"Namespace: {record.Namespace}, Class: {record.Class}"); - - // Add a new task for each class query - tasks.Add(Task.Run(() => - { - // List to store results for the current class - List> classResults = []; - - // Create management scope object - ManagementScope scope = new(record.Namespace); - // Connect to the WMI namespace - try - { - scope.Connect(); - } - catch (ManagementException e) - { - // Write verbose error message if connection fails - Logger.LogMessage($"Error connecting to namespace {record.Namespace}: {e.Message}", LogTypeIntel.Error); - } - - // Create object query for the current class - string classQuery = record.Class?.Trim() ?? throw new InvalidOperationException("Record.Class is null"); - ObjectQuery query = new("SELECT * FROM " + classQuery); - - // Create management object searcher for the query - using ManagementObjectSearcher searcher = new(scope, query); - - try - { - // Execute the query and iterate through the results - foreach (ManagementObject obj in searcher.Get().Cast()) - { - // Dictionary to store properties of the current class instance - Dictionary classInstance = []; - - // Iterate through properties of the current object - foreach (PropertyData prop in obj.Properties) - { - // Store property name and its value - classInstance[prop.Name] = GetPropertyOriginalValue(prop); - } - - // Add class instance to results - classResults.Add(classInstance); - } - } - catch (ManagementException e) - { - // Write verbose error message if query fails - Logger.LogMessage($"Error querying {record.Class}: {e.Message}", LogTypeIntel.Error); - } - - // Add class results to main results dictionary in a thread-safe manner - lock (results) - { - results[record.Class] = classResults; - } - })); - } - } - - // Wait for all tasks to complete - await Task.WhenAll(tasks); - } - catch (IOException ex) - { - // Throw exception with error message if reading CSV file fails - throw new InvalidOperationException($"Error reading CSV file: {ex.Message}"); - } - - // Return dictionary containing results for each class - return results; - } - - // Helper method to get property value as original type - private static object GetPropertyOriginalValue(PropertyData prop) - { - // Return the value of the property - return prop.Value; - } - - // Helper method to read CSV file asynchronously - private static async Task> ReadCsvFileAsync(string filePath) - { - List records = []; - - using (StreamReader reader = new(filePath)) - { - string? line; // Explicitly declare line as nullable - bool isFirstLine = true; - while ((line = await reader.ReadLineAsync()) is not null) - { - if (isFirstLine) - { - isFirstLine = false; - continue; // Skip the header line - } - - // This check is redundant but shows explicit handling - if (line is null) - continue; - - string[] values = line.Split(','); - - // because of using "Comment" column in the CSV file optionally for certain MDM CIMs - if (values.Length >= 3) - { - records.Add(new MdmRecord - { - Namespace = values[0].Trim(), - Class = values[1].Trim(), - Authorized = values[2].Trim() - }); - } - } - } - - return records; - } - - - // Class to represent a record in the CSV file - private sealed class MdmRecord - { - internal string? Namespace { get; set; } - internal string? Class { get; set; } - internal string? Authorized { get; set; } - } - } +/// +/// Class that deals with MDM/CSPs/Intune +/// +internal static class MDM +{ + /// + /// Gets the results of all of the Intune policies from the system + /// + /// + internal static Dictionary>> Get() + { + // Running the asynchronous method synchronously and returning the result + return Task.Run(GetAsync).GetAwaiter().GetResult(); + } + + // Asynchronous method to get the results + private static async Task>>> GetAsync() + { + // Set the location of the CSV file containing the MDM list + string path = GlobalVars.path ?? throw new InvalidOperationException("GlobalVars.path is null"); + string csvFilePath = Path.Combine(path, "Resources", "MDMResultClasses.csv"); + + // Create a dictionary where keys are the class names and values are lists of dictionaries + Dictionary>> results = []; + + try + { + // Read class names and namespaces from CSV file asynchronously + List records = await ReadCsvFileAsync(csvFilePath); + + // Create a list of tasks for querying each class + List tasks = []; + + // Iterate through records + foreach (MdmRecord record in records) + { + // Process only authorized records + if (record.Authorized?.Equals("TRUE", StringComparison.OrdinalIgnoreCase) == true) + { + + // Debugging output + // Logger.LogMessage($"Namespace: {record.Namespace}, Class: {record.Class}"); + + // Add a new task for each class query + tasks.Add(Task.Run(() => + { + // List to store results for the current class + List> classResults = []; + + // Create management scope object + ManagementScope scope = new(record.Namespace); + // Connect to the WMI namespace + try + { + scope.Connect(); + } + catch (ManagementException e) + { + // Write verbose error message if connection fails + Logger.LogMessage($"Error connecting to namespace {record.Namespace}: {e.Message}", LogTypeIntel.Error); + } + + // Create object query for the current class + string classQuery = record.Class?.Trim() ?? throw new InvalidOperationException("Record.Class is null"); + ObjectQuery query = new("SELECT * FROM " + classQuery); + + // Create management object searcher for the query + using ManagementObjectSearcher searcher = new(scope, query); + + try + { + // Execute the query and iterate through the results + foreach (ManagementObject obj in searcher.Get().Cast()) + { + // Dictionary to store properties of the current class instance + Dictionary classInstance = []; + + // Iterate through properties of the current object + foreach (PropertyData prop in obj.Properties) + { + // Store property name and its value + classInstance[prop.Name] = GetPropertyOriginalValue(prop); + } + + // Add class instance to results + classResults.Add(classInstance); + } + } + catch (ManagementException e) + { + // Write verbose error message if query fails + Logger.LogMessage($"Error querying {record.Class}: {e.Message}", LogTypeIntel.Error); + } + + // Add class results to main results dictionary in a thread-safe manner + lock (results) + { + results[record.Class] = classResults; + } + })); + } + } + + // Wait for all tasks to complete + await Task.WhenAll(tasks); + } + catch (IOException ex) + { + // Throw exception with error message if reading CSV file fails + throw new InvalidOperationException($"Error reading CSV file: {ex.Message}"); + } + + // Return dictionary containing results for each class + return results; + } + + // Helper method to get property value as original type + private static object GetPropertyOriginalValue(PropertyData prop) + { + // Return the value of the property + return prop.Value; + } + + // Helper method to read CSV file asynchronously + private static async Task> ReadCsvFileAsync(string filePath) + { + List records = []; + + using (StreamReader reader = new(filePath)) + { + string? line; // Explicitly declare line as nullable + bool isFirstLine = true; + while ((line = await reader.ReadLineAsync()) is not null) + { + if (isFirstLine) + { + isFirstLine = false; + continue; // Skip the header line + } + + // This check is redundant but shows explicit handling + if (line is null) + continue; + + string[] values = line.Split(','); + + // because of using "Comment" column in the CSV file optionally for certain MDM CIMs + if (values.Length >= 3) + { + records.Add(new MdmRecord + { + Namespace = values[0].Trim(), + Class = values[1].Trim(), + Authorized = values[2].Trim() + }); + } + } + } + + return records; + } + + + // Class to represent a record in the CSV file + private sealed class MdmRecord + { + internal string? Namespace { get; set; } + internal string? Class { get; set; } + internal string? Authorized { get; set; } + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/MpPreferenceHelper.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/MpPreferenceHelper.cs index 4badbbf68..e68ec1ae6 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/MpPreferenceHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/MpPreferenceHelper.cs @@ -7,90 +7,90 @@ namespace HardenWindowsSecurity; - internal static class MpPreferenceHelper - { - // Get the MpPreference from the MSFT_MpPreference WMI class and returns it as a dynamic object - internal static dynamic GetMpPreference() - { - try - { - // Defining the WMI query to retrieve the MpPreference - string namespaceName = "ROOT\\Microsoft\\Windows\\Defender"; - string className = "MSFT_MpPreference"; - string queryString = $"SELECT * FROM {className}"; +internal static class MpPreferenceHelper +{ + // Get the MpPreference from the MSFT_MpPreference WMI class and returns it as a dynamic object + internal static dynamic GetMpPreference() + { + try + { + // Defining the WMI query to retrieve the MpPreference + string namespaceName = "ROOT\\Microsoft\\Windows\\Defender"; + string className = "MSFT_MpPreference"; + string queryString = $"SELECT * FROM {className}"; - // Execute the query - using ManagementObjectSearcher searcher = new(namespaceName, queryString); + // Execute the query + using ManagementObjectSearcher searcher = new(namespaceName, queryString); - ManagementObjectCollection results = searcher.Get(); + ManagementObjectCollection results = searcher.Get(); - // Return the first result if there are any - if (results.Count > 0) - { - ManagementBaseObject? result = results.Cast().FirstOrDefault(); + // Return the first result if there are any + if (results.Count > 0) + { + ManagementBaseObject? result = results.Cast().FirstOrDefault(); - if (result is not null) - { + if (result is not null) + { - return ConvertToDynamic(result); - } - else - { - throw new InvalidOperationException("Failed to get MpComputerPreference"); - } - } - else - { - throw new InvalidOperationException("Failed to get MpComputerPreference"); - } - } - catch (ManagementException ex) - { - string errorMessage = $"WMI query for 'MSFT_MpPreference' failed: {ex.Message}"; - throw new PowerShellExecutionException(errorMessage, ex); - } - } + return ConvertToDynamic(result); + } + else + { + throw new InvalidOperationException("Failed to get MpComputerPreference"); + } + } + else + { + throw new InvalidOperationException("Failed to get MpComputerPreference"); + } + } + catch (ManagementException ex) + { + string errorMessage = $"WMI query for 'MSFT_MpPreference' failed: {ex.Message}"; + throw new PowerShellExecutionException(errorMessage, ex); + } + } - // Convert the ManagementBaseObject to a dynamic object - private static dynamic ConvertToDynamic(ManagementBaseObject managementObject) - { - // Creating a dynamic object to store the properties of the ManagementBaseObject - dynamic expandoObject = new ExpandoObject(); + // Convert the ManagementBaseObject to a dynamic object + private static dynamic ConvertToDynamic(ManagementBaseObject managementObject) + { + // Creating a dynamic object to store the properties of the ManagementBaseObject + dynamic expandoObject = new ExpandoObject(); - IDictionary dictionary = expandoObject; + IDictionary dictionary = expandoObject; - // Iterating through the properties of the ManagementBaseObject and adding them to the dynamic object - foreach (PropertyData property in managementObject.Properties) - { - // Check if the value of the property is in DMTF datetime format - // Properties such as SignatureScheduleTime use that format - if (property.Type is CimType.DateTime && property.Value is string dmtfTime) - { - // Convert DMTF datetime format to TimeSpan - dictionary[property.Name] = ConvertDmtfToTimeSpan(dmtfTime); - } - else - { - // Add the property to the dynamic object as is if it's not DMTF - dictionary[property.Name] = property.Value; - } - } + // Iterating through the properties of the ManagementBaseObject and adding them to the dynamic object + foreach (PropertyData property in managementObject.Properties) + { + // Check if the value of the property is in DMTF datetime format + // Properties such as SignatureScheduleTime use that format + if (property.Type is CimType.DateTime && property.Value is string dmtfTime) + { + // Convert DMTF datetime format to TimeSpan + dictionary[property.Name] = ConvertDmtfToTimeSpan(dmtfTime); + } + else + { + // Add the property to the dynamic object as is if it's not DMTF + dictionary[property.Name] = property.Value; + } + } - return expandoObject; - } + return expandoObject; + } - private static TimeSpan ConvertDmtfToTimeSpan(string dmtfTime) - { - // DMTF datetime format: yyyymmddHHMMSS.mmmmmmsUUU - // We only need HHMMSS part for this case - if (dmtfTime.Length >= 15) - { - string hhmmss = dmtfTime.Substring(8, 6); - if (TimeSpan.TryParseExact(hhmmss, "HHmmss", CultureInfo.InvariantCulture, out TimeSpan timeSpan)) - { - return timeSpan; - } - } - return TimeSpan.Zero; - } - } + private static TimeSpan ConvertDmtfToTimeSpan(string dmtfTime) + { + // DMTF datetime format: yyyymmddHHMMSS.mmmmmmsUUU + // We only need HHMMSS part for this case + if (dmtfTime.Length >= 15) + { + string hhmmss = dmtfTime.Substring(8, 6); + if (TimeSpan.TryParseExact(hhmmss, "HHmmss", CultureInfo.InvariantCulture, out TimeSpan timeSpan)) + { + return timeSpan; + } + } + return TimeSpan.Zero; + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/NetConnectionProfiles.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/NetConnectionProfiles.cs index 045115d36..5993d1eae 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/NetConnectionProfiles.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/NetConnectionProfiles.cs @@ -5,145 +5,145 @@ namespace HardenWindowsSecurity; - public static class NetConnectionProfiles - { - /// - /// This method outputs a list of all network connection profiles. - /// The output is precisely the same as the output of the Get-NetConnectionProfile cmdlet in PowerShell. - /// - /// - public static List Get() - { - // Create a list to store the profiles - List profiles = []; - - try - { - // Define the namespace, class, and query string - string namespaceName = @"root\StandardCimv2"; - string className = "MSFT_NetConnectionProfile"; - string queryString = $"SELECT * FROM {className}"; - - // Create a ManagementScope object and connect to it - ManagementScope scope = new(namespaceName); - scope.Connect(); - - // Create a ManagementObjectQuery object and a ManagementObjectSearcher object - ObjectQuery query = new(queryString); - - using ManagementObjectSearcher searcher = new(scope, query); - - // Execute the query and store the results in a ManagementObjectCollection object - ManagementObjectCollection queryCollection = searcher.Get(); - - // Add each profile to the list - foreach (ManagementObject m in queryCollection.Cast()) - { - profiles.Add(m); - } - } - catch (Exception e) - { - Logger.LogMessage($"An error occurred: {e.Message}", LogTypeIntel.Error); - } - - // Return the list of profiles - return profiles; - } - - /// - /// This method sets the NetworkCategory of network connection profiles based on InterfaceIndex or InterfaceAlias. - /// - /// Array of InterfaceIndex values of the network connection profiles. - /// Array of InterfaceAlias values of the network connection profiles. - /// The new NetworkCategory to set. - /// PS Example: [HardenWindowsSecurity.NetConnectionProfiles]::Set((3, 22), $null, [HardenWindowsSecurity.NetConnectionProfiles+NetworkCategory]::public) - /// PS Example: [HardenWindowsSecurity.NetConnectionProfiles]::Set($null, ('Ethernet', 'Wi-Fi'), [HardenWindowsSecurity.NetConnectionProfiles+NetworkCategory]::private) - /// True if successful, otherwise false. - public static bool Set(NetworkCategory networkCategory, int[]? interfaceIndices = null, string[]? interfaceAliases = null) - { - try - { - // Define the namespace and class - string namespaceName = @"root\StandardCimv2"; - string className = "MSFT_NetConnectionProfile"; - ManagementScope scope = new(namespaceName); - scope.Connect(); - - // Process interface indices - if (interfaceIndices is not null) - { - foreach (int index in interfaceIndices) - { - string queryString = $"SELECT * FROM {className} WHERE InterfaceIndex = {index}"; - UpdateNetworkCategory(scope, queryString, networkCategory); - } - } - - // Process interface aliases - if (interfaceAliases is not null) - { - foreach (string alias in interfaceAliases) - { - string queryString = $"SELECT * FROM {className} WHERE InterfaceAlias = '{alias}'"; - UpdateNetworkCategory(scope, queryString, networkCategory); - } - } - - return true; - } - catch (Exception e) - { - Logger.LogMessage($"An error occurred: {e.Message}", LogTypeIntel.Error); - return false; - } - } - - private static void UpdateNetworkCategory(ManagementScope scope, string queryString, NetworkCategory networkCategory) - { - ObjectQuery query = new(queryString); - - using ManagementObjectSearcher searcher = new(scope, query); - - ManagementObjectCollection queryCollection = searcher.Get(); - - foreach (ManagementObject m in queryCollection.Cast()) - { - m["NetworkCategory"] = (uint)networkCategory; - _ = m.Put(); - } - } - - // The following enums are used to represent the properties of the MSFT_NetConnectionProfile class - public enum NetworkCategory : uint - { - Public = 0, - Private = 1, - DomainAuthenticated = 2 - } - - public enum DomainAuthenticationKind : uint - { - None = 0, - Ldap = 1, - Tls = 2 - } - - public enum IPv4Connectivity : uint - { - Disconnected = 0, - NoTraffic = 1, - Subnet = 2, - LocalNetwork = 3, - Internet = 4 - } - - public enum IPv6Connectivity : uint - { - Disconnected = 0, - NoTraffic = 1, - Subnet = 2, - LocalNetwork = 3, - Internet = 4 - } - } +public static class NetConnectionProfiles +{ + /// + /// This method outputs a list of all network connection profiles. + /// The output is precisely the same as the output of the Get-NetConnectionProfile cmdlet in PowerShell. + /// + /// + public static List Get() + { + // Create a list to store the profiles + List profiles = []; + + try + { + // Define the namespace, class, and query string + string namespaceName = @"root\StandardCimv2"; + string className = "MSFT_NetConnectionProfile"; + string queryString = $"SELECT * FROM {className}"; + + // Create a ManagementScope object and connect to it + ManagementScope scope = new(namespaceName); + scope.Connect(); + + // Create a ManagementObjectQuery object and a ManagementObjectSearcher object + ObjectQuery query = new(queryString); + + using ManagementObjectSearcher searcher = new(scope, query); + + // Execute the query and store the results in a ManagementObjectCollection object + ManagementObjectCollection queryCollection = searcher.Get(); + + // Add each profile to the list + foreach (ManagementObject m in queryCollection.Cast()) + { + profiles.Add(m); + } + } + catch (Exception e) + { + Logger.LogMessage($"An error occurred: {e.Message}", LogTypeIntel.Error); + } + + // Return the list of profiles + return profiles; + } + + /// + /// This method sets the NetworkCategory of network connection profiles based on InterfaceIndex or InterfaceAlias. + /// + /// Array of InterfaceIndex values of the network connection profiles. + /// Array of InterfaceAlias values of the network connection profiles. + /// The new NetworkCategory to set. + /// PS Example: [HardenWindowsSecurity.NetConnectionProfiles]::Set((3, 22), $null, [HardenWindowsSecurity.NetConnectionProfiles+NetworkCategory]::public) + /// PS Example: [HardenWindowsSecurity.NetConnectionProfiles]::Set($null, ('Ethernet', 'Wi-Fi'), [HardenWindowsSecurity.NetConnectionProfiles+NetworkCategory]::private) + /// True if successful, otherwise false. + public static bool Set(NetworkCategory networkCategory, int[]? interfaceIndices = null, string[]? interfaceAliases = null) + { + try + { + // Define the namespace and class + string namespaceName = @"root\StandardCimv2"; + string className = "MSFT_NetConnectionProfile"; + ManagementScope scope = new(namespaceName); + scope.Connect(); + + // Process interface indices + if (interfaceIndices is not null) + { + foreach (int index in interfaceIndices) + { + string queryString = $"SELECT * FROM {className} WHERE InterfaceIndex = {index}"; + UpdateNetworkCategory(scope, queryString, networkCategory); + } + } + + // Process interface aliases + if (interfaceAliases is not null) + { + foreach (string alias in interfaceAliases) + { + string queryString = $"SELECT * FROM {className} WHERE InterfaceAlias = '{alias}'"; + UpdateNetworkCategory(scope, queryString, networkCategory); + } + } + + return true; + } + catch (Exception e) + { + Logger.LogMessage($"An error occurred: {e.Message}", LogTypeIntel.Error); + return false; + } + } + + private static void UpdateNetworkCategory(ManagementScope scope, string queryString, NetworkCategory networkCategory) + { + ObjectQuery query = new(queryString); + + using ManagementObjectSearcher searcher = new(scope, query); + + ManagementObjectCollection queryCollection = searcher.Get(); + + foreach (ManagementObject m in queryCollection.Cast()) + { + m["NetworkCategory"] = (uint)networkCategory; + _ = m.Put(); + } + } + + // The following enums are used to represent the properties of the MSFT_NetConnectionProfile class + public enum NetworkCategory : uint + { + Public = 0, + Private = 1, + DomainAuthenticated = 2 + } + + public enum DomainAuthenticationKind : uint + { + None = 0, + Ldap = 1, + Tls = 2 + } + + public enum IPv4Connectivity : uint + { + Disconnected = 0, + NoTraffic = 1, + Subnet = 2, + LocalNetwork = 3, + Internet = 4 + } + + public enum IPv6Connectivity : uint + { + Disconnected = 0, + NoTraffic = 1, + Subnet = 2, + LocalNetwork = 3, + Internet = 4 + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/CimInstances/TaskSchedulerHelper.cs b/Harden-Windows-Security Module/Main files/C#/CimInstances/TaskSchedulerHelper.cs index d1cbada76..f34effaa0 100644 --- a/Harden-Windows-Security Module/Main files/C#/CimInstances/TaskSchedulerHelper.cs +++ b/Harden-Windows-Security Module/Main files/C#/CimInstances/TaskSchedulerHelper.cs @@ -6,295 +6,295 @@ namespace HardenWindowsSecurity; - public static class TaskSchedulerHelper - { - - // Enums for ScheduledTask - public enum State - { - Unknown = 0, - Disabled = 1, - Queued = 2, - Ready = 3, - Running = 4 - } - - public enum Compatibility - { - At = 0, - V1 = 1, - Vista = 2, - Win7 = 3, - Win8 = 4 - } - - public enum RunLevel - { - Limited = 0, - Highest = 1 - } - - public enum ProcessTokenSidType - { - None = 0, - Unrestricted = 1, - Default = 2 - } - - public enum LogonType - { - None = 0, - Password = 1, - S4U = 2, - Interactive = 3, - Group = 4, - ServiceAccount = 5, - InteractiveOrPassword = 6 - } - - public enum MultipleInstances - { - Parallel = 0, - Queue = 1, - IgnoreNew = 2 - } - - public enum ClusterTaskType - { - None = 0, - ResourceSpecific = 1, - AnyNode = 2, - ClusterWide = 3 - } - - - // Enumeration to specify the type of output - public enum OutputType - { - Boolean, // Returns true/false based on task existence - TaskList // Returns a list of ManagementObject tasks - } - - /// - /// Retrieves scheduled tasks from the Task Scheduler based on specified criteria. - /// - /// Optional. The name of the task to filter by. - /// Optional. The path of the task to filter by. - /// Specifies whether to return a boolean or a list of tasks. - /// If outputType is Boolean: Returns true if tasks matching the criteria are found, otherwise false. - /// If outputType is TaskList: Returns a list of ManagementObject containing the matching tasks. - /// PowerShell equivalent: - /// $taskName = 'MSFT Driver Block list update' - /// $taskPath = '\MSFT Driver Block list update\' - /// Get-CimInstance -Namespace Root/Microsoft/Windows/TaskScheduler -ClassName MSFT_ScheduledTask | Where-Object { $_.TaskName -eq $taskName -and $_.TaskPath -eq $taskPath } - public static object Get(string taskName, string taskPath, OutputType outputType) - { - try - { - // Define the WMI query to select all instances of MSFT_ScheduledTask - string query = $"SELECT * FROM MSFT_ScheduledTask"; - - // Define the WMI namespace - string scope = @"\\.\Root\Microsoft\Windows\TaskScheduler"; - - // Create a ManagementObjectSearcher instance with the query and scope - using ManagementObjectSearcher searcher = new(scope, query); - - // Execute the WMI query and retrieve the results - using ManagementObjectCollection results = searcher.Get(); - - // Initialize a list to store matching tasks - List matchingTasks = []; - - // Iterate through each ManagementObject in the results - foreach (ManagementObject obj in results.Cast()) - { - // Retrieve the TaskName and TaskPath properties from the ManagementObject - string? name = obj["TaskName"]?.ToString(); - string? path = obj["TaskPath"]?.ToString(); - - // Check if the TaskName matches the provided taskName (if specified) - // and TaskPath matches the provided taskPath (if specified) - bool nameMatches = string.IsNullOrEmpty(taskName) || string.Equals(name, taskName, StringComparison.OrdinalIgnoreCase); - bool pathMatches = string.IsNullOrEmpty(taskPath) || string.Equals(path, taskPath, StringComparison.OrdinalIgnoreCase); - - // If both TaskName and TaskPath match the provided criteria, add the task to the matchingTasks list - if (nameMatches && pathMatches) - { - matchingTasks.Add(obj); - } - } - - // Depending on the outputType parameter, return either a boolean or a list of tasks - if (outputType == OutputType.Boolean) - { - return matchingTasks.Count > 0; // Return true if any matching tasks were found, otherwise false - } - else if (outputType == OutputType.TaskList) - { - return matchingTasks; // Return the list of matching tasks - } - } - catch (ManagementException e) - { - // Handle any ManagementException that may occur during the WMI query execution - Logger.LogMessage($"An error occurred while querying for WMI data: {e.Message}", LogTypeIntel.Error); - - // Depending on the outputType parameter, return either false or an empty list - if (outputType == OutputType.Boolean) - { - return false; // Return false indicating no tasks found (error occurred) - } - else - { - // Return an empty list of tasks - return new List(); - } - } - - // Default return statement (should not be reached) - if (outputType == OutputType.Boolean) - { - return false; // Return false indicating no tasks found - } - else - { - // Return an empty list of tasks - return new List(); - } - } - - - - /// - /// Deletes a scheduled task if it exists - /// - /// The task name to be deleted - /// The path where the task is located - /// The folder name of the task must not have and back slashes in it - /// - public static bool Delete(string taskName, string taskPath, string taskFolderName) - { - try - { - // The WMI query to select the specific instance of MSFT_ScheduledTask - string query = "SELECT * FROM MSFT_ScheduledTask"; - - // Defining the WMI namespace - string scope = @"\\.\Root\Microsoft\Windows\TaskScheduler"; - - // Creating a ManagementObjectSearcher instance with the query and scope - using ManagementObjectSearcher searcher = new(scope, query); - - // Execute the WMI query and retrieve the results - using ManagementObjectCollection results = searcher.Get(); - - // If no tasks were found, return false - if (results.Count == 0) - { - Logger.LogMessage($"No tasks found in Task Scheduler.", LogTypeIntel.Warning); - return false; - } - - // Iterate through each ManagementObject in the results - foreach (ManagementObject obj in results.Cast()) - { - string? name = obj["TaskName"]?.ToString(); - string? path = obj["TaskPath"]?.ToString(); - - // Match based on taskName and taskPath - if (string.Equals(name, taskName, StringComparison.OrdinalIgnoreCase) && - string.Equals(path, taskPath, StringComparison.OrdinalIgnoreCase)) - { - try - { - // Call DeleteInstance to delete the task - obj.Delete(); - - Logger.LogMessage($"Task '{taskName}' with path '{taskPath}' was deleted successfully.", LogTypeIntel.Information); - - // Return true indicating the task was deleted - return true; - } - catch (ManagementException ex) - { - Logger.LogMessage($"Failed to delete task '{taskName}' with path '{taskPath}': {ex.Message}", LogTypeIntel.Error); - - // Return false indicating failure to delete the task - return false; - } - } - } - - Logger.LogMessage($"No task found with the name '{taskName}' and path '{taskPath}'.", LogTypeIntel.Information); - return false; // Task not found - } - catch (ManagementException e) - { - // for any ManagementException that may occur during the WMI query execution - Logger.LogMessage($"An error occurred while querying for WMI data: {e.Message}", LogTypeIntel.Error); - - // Return false indicating no task was deleted (error occurred) - return false; - } - finally - { - // Attempt to delete the task folder whether or not the task itself exists - DeleteTaskFolder(taskFolderName); - } - } - - /// - /// Deletes the folder of a scheduled task - /// same as: (schtasks.exe /Delete /TN "Task Folder Name" /F) - /// - /// - private static void DeleteTaskFolder(string FolderName) - { - - // Initialize some variables - dynamic? rootFolder = null; - dynamic? scheduleObject = null; - - try - { - - // Create COM object for Schedule.Service - Type? schedulerType = Type.GetTypeFromProgID("Schedule.Service"); - scheduleObject = Activator.CreateInstance(schedulerType!); - - // Connect to the service - scheduleObject!.Connect(); - - // Get the root folder - rootFolder = scheduleObject.GetFolder("\\"); - - // Delete the folder with the name - rootFolder.DeleteFolder(FolderName, null); - - Logger.LogMessage($"Folder named {FolderName} was successfully deleted.", LogTypeIntel.Information); - } - catch - { - Logger.LogMessage("Couldn't create/connect to Schedule.Service COM Object or the folder could not be deleted.", LogTypeIntel.Error); - } - finally - { - try - { - // Cleanup (Release the COM objects) - if (rootFolder is not null) - { - Marshal.ReleaseComObject(rootFolder); - } - - if (scheduleObject is not null) - { - Marshal.ReleaseComObject(scheduleObject); - } - } - // suppress any errors that might occur during resource clean up - catch { } - } - } - } +public static class TaskSchedulerHelper +{ + + // Enums for ScheduledTask + public enum State + { + Unknown = 0, + Disabled = 1, + Queued = 2, + Ready = 3, + Running = 4 + } + + public enum Compatibility + { + At = 0, + V1 = 1, + Vista = 2, + Win7 = 3, + Win8 = 4 + } + + public enum RunLevel + { + Limited = 0, + Highest = 1 + } + + public enum ProcessTokenSidType + { + None = 0, + Unrestricted = 1, + Default = 2 + } + + public enum LogonType + { + None = 0, + Password = 1, + S4U = 2, + Interactive = 3, + Group = 4, + ServiceAccount = 5, + InteractiveOrPassword = 6 + } + + public enum MultipleInstances + { + Parallel = 0, + Queue = 1, + IgnoreNew = 2 + } + + public enum ClusterTaskType + { + None = 0, + ResourceSpecific = 1, + AnyNode = 2, + ClusterWide = 3 + } + + + // Enumeration to specify the type of output + public enum OutputType + { + Boolean, // Returns true/false based on task existence + TaskList // Returns a list of ManagementObject tasks + } + + /// + /// Retrieves scheduled tasks from the Task Scheduler based on specified criteria. + /// + /// Optional. The name of the task to filter by. + /// Optional. The path of the task to filter by. + /// Specifies whether to return a boolean or a list of tasks. + /// If outputType is Boolean: Returns true if tasks matching the criteria are found, otherwise false. + /// If outputType is TaskList: Returns a list of ManagementObject containing the matching tasks. + /// PowerShell equivalent: + /// $taskName = 'MSFT Driver Block list update' + /// $taskPath = '\MSFT Driver Block list update\' + /// Get-CimInstance -Namespace Root/Microsoft/Windows/TaskScheduler -ClassName MSFT_ScheduledTask | Where-Object { $_.TaskName -eq $taskName -and $_.TaskPath -eq $taskPath } + public static object Get(string taskName, string taskPath, OutputType outputType) + { + try + { + // Define the WMI query to select all instances of MSFT_ScheduledTask + string query = $"SELECT * FROM MSFT_ScheduledTask"; + + // Define the WMI namespace + string scope = @"\\.\Root\Microsoft\Windows\TaskScheduler"; + + // Create a ManagementObjectSearcher instance with the query and scope + using ManagementObjectSearcher searcher = new(scope, query); + + // Execute the WMI query and retrieve the results + using ManagementObjectCollection results = searcher.Get(); + + // Initialize a list to store matching tasks + List matchingTasks = []; + + // Iterate through each ManagementObject in the results + foreach (ManagementObject obj in results.Cast()) + { + // Retrieve the TaskName and TaskPath properties from the ManagementObject + string? name = obj["TaskName"]?.ToString(); + string? path = obj["TaskPath"]?.ToString(); + + // Check if the TaskName matches the provided taskName (if specified) + // and TaskPath matches the provided taskPath (if specified) + bool nameMatches = string.IsNullOrEmpty(taskName) || string.Equals(name, taskName, StringComparison.OrdinalIgnoreCase); + bool pathMatches = string.IsNullOrEmpty(taskPath) || string.Equals(path, taskPath, StringComparison.OrdinalIgnoreCase); + + // If both TaskName and TaskPath match the provided criteria, add the task to the matchingTasks list + if (nameMatches && pathMatches) + { + matchingTasks.Add(obj); + } + } + + // Depending on the outputType parameter, return either a boolean or a list of tasks + if (outputType == OutputType.Boolean) + { + return matchingTasks.Count > 0; // Return true if any matching tasks were found, otherwise false + } + else if (outputType == OutputType.TaskList) + { + return matchingTasks; // Return the list of matching tasks + } + } + catch (ManagementException e) + { + // Handle any ManagementException that may occur during the WMI query execution + Logger.LogMessage($"An error occurred while querying for WMI data: {e.Message}", LogTypeIntel.Error); + + // Depending on the outputType parameter, return either false or an empty list + if (outputType == OutputType.Boolean) + { + return false; // Return false indicating no tasks found (error occurred) + } + else + { + // Return an empty list of tasks + return new List(); + } + } + + // Default return statement (should not be reached) + if (outputType == OutputType.Boolean) + { + return false; // Return false indicating no tasks found + } + else + { + // Return an empty list of tasks + return new List(); + } + } + + + + /// + /// Deletes a scheduled task if it exists + /// + /// The task name to be deleted + /// The path where the task is located + /// The folder name of the task must not have and back slashes in it + /// + public static bool Delete(string taskName, string taskPath, string taskFolderName) + { + try + { + // The WMI query to select the specific instance of MSFT_ScheduledTask + string query = "SELECT * FROM MSFT_ScheduledTask"; + + // Defining the WMI namespace + string scope = @"\\.\Root\Microsoft\Windows\TaskScheduler"; + + // Creating a ManagementObjectSearcher instance with the query and scope + using ManagementObjectSearcher searcher = new(scope, query); + + // Execute the WMI query and retrieve the results + using ManagementObjectCollection results = searcher.Get(); + + // If no tasks were found, return false + if (results.Count == 0) + { + Logger.LogMessage($"No tasks found in Task Scheduler.", LogTypeIntel.Warning); + return false; + } + + // Iterate through each ManagementObject in the results + foreach (ManagementObject obj in results.Cast()) + { + string? name = obj["TaskName"]?.ToString(); + string? path = obj["TaskPath"]?.ToString(); + + // Match based on taskName and taskPath + if (string.Equals(name, taskName, StringComparison.OrdinalIgnoreCase) && + string.Equals(path, taskPath, StringComparison.OrdinalIgnoreCase)) + { + try + { + // Call DeleteInstance to delete the task + obj.Delete(); + + Logger.LogMessage($"Task '{taskName}' with path '{taskPath}' was deleted successfully.", LogTypeIntel.Information); + + // Return true indicating the task was deleted + return true; + } + catch (ManagementException ex) + { + Logger.LogMessage($"Failed to delete task '{taskName}' with path '{taskPath}': {ex.Message}", LogTypeIntel.Error); + + // Return false indicating failure to delete the task + return false; + } + } + } + + Logger.LogMessage($"No task found with the name '{taskName}' and path '{taskPath}'.", LogTypeIntel.Information); + return false; // Task not found + } + catch (ManagementException e) + { + // for any ManagementException that may occur during the WMI query execution + Logger.LogMessage($"An error occurred while querying for WMI data: {e.Message}", LogTypeIntel.Error); + + // Return false indicating no task was deleted (error occurred) + return false; + } + finally + { + // Attempt to delete the task folder whether or not the task itself exists + DeleteTaskFolder(taskFolderName); + } + } + + /// + /// Deletes the folder of a scheduled task + /// same as: (schtasks.exe /Delete /TN "Task Folder Name" /F) + /// + /// + private static void DeleteTaskFolder(string FolderName) + { + + // Initialize some variables + dynamic? rootFolder = null; + dynamic? scheduleObject = null; + + try + { + + // Create COM object for Schedule.Service + Type? schedulerType = Type.GetTypeFromProgID("Schedule.Service"); + scheduleObject = Activator.CreateInstance(schedulerType!); + + // Connect to the service + scheduleObject!.Connect(); + + // Get the root folder + rootFolder = scheduleObject.GetFolder("\\"); + + // Delete the folder with the name + rootFolder.DeleteFolder(FolderName, null); + + Logger.LogMessage($"Folder named {FolderName} was successfully deleted.", LogTypeIntel.Information); + } + catch + { + Logger.LogMessage("Couldn't create/connect to Schedule.Service COM Object or the folder could not be deleted.", LogTypeIntel.Error); + } + finally + { + try + { + // Cleanup (Release the COM objects) + if (rootFolder is not null) + { + Marshal.ReleaseComObject(rootFolder); + } + + if (scheduleObject is not null) + { + Marshal.ReleaseComObject(scheduleObject); + } + } + // suppress any errors that might occur during resource clean up + catch { } + } + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/Confirm Methods/InvokeConfirmation.cs b/Harden-Windows-Security Module/Main files/C#/Confirm Methods/InvokeConfirmation.cs index e6291b23f..a0c2cf78f 100644 --- a/Harden-Windows-Security Module/Main files/C#/Confirm Methods/InvokeConfirmation.cs +++ b/Harden-Windows-Security Module/Main files/C#/Confirm Methods/InvokeConfirmation.cs @@ -5,69 +5,69 @@ namespace HardenWindowsSecurity; - public static class InvokeConfirmation - { - /// - /// This method will perform the system compliance checking and verification - /// - /// - public static void Invoke(string[] Categories) - { - ControlledFolderAccessHandler.Start(true, false); +public static class InvokeConfirmation +{ + /// + /// This method will perform the system compliance checking and verification + /// + /// + public static void Invoke(string[] Categories) + { + ControlledFolderAccessHandler.Start(true, false); - SYSTEMScheduledTasks.Invoke(); + SYSTEMScheduledTasks.Invoke(); - // Collect the JSON File Paths - string MDM_Firewall_DomainProfile02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Firewall_DomainProfile02.json"); - string MDM_Firewall_PrivateProfile02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Firewall_PrivateProfile02.json"); - string MDM_Firewall_PublicProfile02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Firewall_PublicProfile02.json"); - string MDM_Policy_Result01_Update02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Policy_Result01_Update02.json"); - string MDM_Policy_Result01_System02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Policy_Result01_System02.json"); + // Collect the JSON File Paths + string MDM_Firewall_DomainProfile02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Firewall_DomainProfile02.json"); + string MDM_Firewall_PrivateProfile02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Firewall_PrivateProfile02.json"); + string MDM_Firewall_PublicProfile02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Firewall_PublicProfile02.json"); + string MDM_Policy_Result01_Update02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Policy_Result01_Update02.json"); + string MDM_Policy_Result01_System02_Path = Path.Combine(GlobalVars.WorkingDir, "MDM_Policy_Result01_System02.json"); - // Wait until all files are created, this is necessary because sometimes it takes a second or two for the scheduled task to create the files - // Initialize a stopwatch to track the elapsed time so we don't wait indefinitely - Stopwatch stopwatch = Stopwatch.StartNew(); + // Wait until all files are created, this is necessary because sometimes it takes a second or two for the scheduled task to create the files + // Initialize a stopwatch to track the elapsed time so we don't wait indefinitely + Stopwatch stopwatch = Stopwatch.StartNew(); - while (true) - { - try - { - // Check if all files exist - if (File.Exists(MDM_Firewall_DomainProfile02_Path) && - File.Exists(MDM_Firewall_PrivateProfile02_Path) && - File.Exists(MDM_Firewall_PublicProfile02_Path) && - File.Exists(MDM_Policy_Result01_Update02_Path) && - File.Exists(MDM_Policy_Result01_System02_Path)) - { - break; // Exit the loop if all files exist - } - } - catch (IOException) - { - // Ignore IOException and continue waiting - // Because the scheduled task will probably be accessing the file at the same time as well - } + while (true) + { + try + { + // Check if all files exist + if (File.Exists(MDM_Firewall_DomainProfile02_Path) && + File.Exists(MDM_Firewall_PrivateProfile02_Path) && + File.Exists(MDM_Firewall_PublicProfile02_Path) && + File.Exists(MDM_Policy_Result01_Update02_Path) && + File.Exists(MDM_Policy_Result01_System02_Path)) + { + break; // Exit the loop if all files exist + } + } + catch (IOException) + { + // Ignore IOException and continue waiting + // Because the scheduled task will probably be accessing the file at the same time as well + } - // Check if the timeout has been exceeded - if (stopwatch.ElapsedMilliseconds > 30000) // 30 seconds in milliseconds - { - throw new TimeoutException("Timeout exceeded while waiting for the MDM policy files to be created."); - } + // Check if the timeout has been exceeded + if (stopwatch.ElapsedMilliseconds > 30000) // 30 seconds in milliseconds + { + throw new TimeoutException("Timeout exceeded while waiting for the MDM policy files to be created."); + } - // Sleep for a short period before checking again - Thread.Sleep(500); - } + // Sleep for a short period before checking again + Thread.Sleep(500); + } - // Parse the JSON Files and store the results in global variables - GlobalVars.MDM_Firewall_DomainProfile02 = JsonToHashTable.ProcessJsonFile(MDM_Firewall_DomainProfile02_Path); - GlobalVars.MDM_Firewall_PrivateProfile02 = JsonToHashTable.ProcessJsonFile(MDM_Firewall_PrivateProfile02_Path); - GlobalVars.MDM_Firewall_PublicProfile02 = JsonToHashTable.ProcessJsonFile(MDM_Firewall_PublicProfile02_Path); - GlobalVars.MDM_Policy_Result01_Update02 = JsonToHashTable.ProcessJsonFile(MDM_Policy_Result01_Update02_Path); - GlobalVars.MDM_Policy_Result01_System02 = JsonToHashTable.ProcessJsonFile(MDM_Policy_Result01_System02_Path); + // Parse the JSON Files and store the results in global variables + GlobalVars.MDM_Firewall_DomainProfile02 = JsonToHashTable.ProcessJsonFile(MDM_Firewall_DomainProfile02_Path); + GlobalVars.MDM_Firewall_PrivateProfile02 = JsonToHashTable.ProcessJsonFile(MDM_Firewall_PrivateProfile02_Path); + GlobalVars.MDM_Firewall_PublicProfile02 = JsonToHashTable.ProcessJsonFile(MDM_Firewall_PublicProfile02_Path); + GlobalVars.MDM_Policy_Result01_Update02 = JsonToHashTable.ProcessJsonFile(MDM_Policy_Result01_Update02_Path); + GlobalVars.MDM_Policy_Result01_System02 = JsonToHashTable.ProcessJsonFile(MDM_Policy_Result01_System02_Path); - Logger.LogMessage("Verifying the security settings", LogTypeIntel.Information); - ConfirmSystemComplianceMethods.OrchestrateComplianceChecks(Categories); + Logger.LogMessage("Verifying the security settings", LogTypeIntel.Information); + ConfirmSystemComplianceMethods.OrchestrateComplianceChecks(Categories); - } - } + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/Confirm Methods/SYSTEMScheduledTasks.cs b/Harden-Windows-Security Module/Main files/C#/Confirm Methods/SYSTEMScheduledTasks.cs index f55e7ebb0..311b3e6c3 100644 --- a/Harden-Windows-Security Module/Main files/C#/Confirm Methods/SYSTEMScheduledTasks.cs +++ b/Harden-Windows-Security Module/Main files/C#/Confirm Methods/SYSTEMScheduledTasks.cs @@ -3,22 +3,22 @@ namespace HardenWindowsSecurity; - internal static class SYSTEMScheduledTasks - { - internal static void Invoke() - { - Logger.LogMessage("Collecting Intune applied policy details from the System", LogTypeIntel.Information); +internal static class SYSTEMScheduledTasks +{ + internal static void Invoke() + { + Logger.LogMessage("Collecting Intune applied policy details from the System", LogTypeIntel.Information); - // Path to the PowerShell script - string scriptPath = Path.Combine(GlobalVars.path!, "Shared", "SYSTEMInfoGathering.ps1"); + // Path to the PowerShell script + string scriptPath = Path.Combine(GlobalVars.path!, "Shared", "SYSTEMInfoGathering.ps1"); - // Load the PowerShell script into a string - string script = File.ReadAllText(scriptPath); + // Load the PowerShell script into a string + string script = File.ReadAllText(scriptPath); - // Replace the BaseDirectory placeholder with the actual value - script = script.Replace("[System.String]$BaseDirectory = [HardenWindowsSecurity.GlobalVars]::WorkingDir", $"[System.String]$BaseDirectory = '{GlobalVars.WorkingDir}'", StringComparison.OrdinalIgnoreCase); + // Replace the BaseDirectory placeholder with the actual value + script = script.Replace("[System.String]$BaseDirectory = [HardenWindowsSecurity.GlobalVars]::WorkingDir", $"[System.String]$BaseDirectory = '{GlobalVars.WorkingDir}'", StringComparison.OrdinalIgnoreCase); - // Run the PowerShell script - _ = PowerShellExecutor.ExecuteScript(script); - } - } + // Run the PowerShell script + _ = PowerShellExecutor.ExecuteScript(script); + } +} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/Variables.cs b/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/Variables.cs index 75b748403..264cc6bab 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/Variables.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/Variables.cs @@ -2,9 +2,9 @@ namespace HardenWindowsSecurity; - internal static class GUIASRRules - { - internal static UserControl? View; +internal static class GUIASRRules +{ + internal static UserControl? View; - internal static Grid? ParentGrid; - } + internal static Grid? ParentGrid; +} diff --git a/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/View.cs b/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/View.cs index 9b7c9d326..53597c83c 100644 --- a/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/View.cs +++ b/Harden-Windows-Security Module/Main files/C#/GUI/ASRRules/View.cs @@ -10,397 +10,397 @@ namespace HardenWindowsSecurity; - public static partial class GUIMain - { - - // Partial class definition for handling navigation and view models - public partial class NavigationVM : ViewModelBase - { - - // Method to handle the ASRRules view, including loading - private void ASRRulesView(object obj) - { - // Check if the view is already cached - if (_viewCache.TryGetValue("ASRRulesView", out var cachedView)) - { - CurrentView = cachedView; - return; - } - - if (GlobalVars.path is null) - { - throw new InvalidOperationException("GlobalVars.path cannot be null."); - } - - // if Admin privileges are not available, return and do not proceed any further - // Will prevent the page from being loaded since the CurrentView won't be set/changed - if (!UserPrivCheck.IsAdmin()) - { - Logger.LogMessage("ASR Rules page can only be used when running the Harden Windows Security Application with Administrator privileges", LogTypeIntel.ErrorInteractionRequired); - return; - } - - // Construct the file path for the ASRRules view XAML - string xamlPath = Path.Combine(GlobalVars.path, "Resources", "XAML", "ASRRules.xaml"); - - // Read the XAML content from the file - string xamlContent = File.ReadAllText(xamlPath); - - // Parse the XAML content to create a UserControl - GUIASRRules.View = (UserControl)XamlReader.Parse(xamlContent); - - // Find the Parent Grid - GUIASRRules.ParentGrid = (Grid)GUIASRRules.View.FindName("ParentGrid"); - - #region finding elements - - // Finding the Execute Button Grid - Grid? ExecuteButtonGrid = GUIASRRules.ParentGrid.FindName("ExecuteButtonGrid") as Grid ?? throw new InvalidOperationException("ExecuteButtonGrid is null in the ASRRules View"); - - // Finding the Execute Button - if (ExecuteButtonGrid.FindName("ExecuteButton") is not ToggleButton ExecuteButton) - { - throw new InvalidOperationException("Couldn't find the ExecuteButton in ASRRules view"); - } - - // Apply the template to make sure it's available - _ = ExecuteButton.ApplyTemplate(); - - // Access the image within the Execute Button's template - if (ExecuteButton.Template.FindName("RefreshIconImage", ExecuteButton) is not Image RefreshIconImage) - { - throw new InvalidOperationException("RefreshIconImage could not be found in the ASRRules view"); - } - - // Update the image source for the Refresh button - // Load the Refresh icon image into memory and set it as the source - BitmapImage RefreshIconBitmapImage = new(); - RefreshIconBitmapImage.BeginInit(); - RefreshIconBitmapImage.UriSource = new Uri(Path.Combine(GlobalVars.path!, "Resources", "Media", "ExecuteButton.png")); - RefreshIconBitmapImage.CacheOption = BitmapCacheOption.OnLoad; // Load the image data into memory - RefreshIconBitmapImage.EndInit(); - - RefreshIconImage.Source = RefreshIconBitmapImage; - - Button RetrieveASRStatusButton = GUIASRRules.ParentGrid.FindName("RetrieveASRStatus") as Button ?? throw new InvalidOperationException("RetrieveASRStatus could not be found in the ASRRules view"); - - #endregion - - - // Register button to be disabled/enabled based on global activity - ActivityTracker.RegisterUIElement(RetrieveASRStatusButton); - - // Create a dictionary to store the ComboBox Names as keys and their corresponding SelectedIndex as Values so that we will loop over this dictionary instead of access UI elements and won't need to use UI Dispatcher - Dictionary comboBoxDictionary = []; - - // Method to process ListView items - void ProcessListViewItems(ListView listView) - { - foreach (ListViewItem item in listView.Items.Cast()) - { - // Find the StackPanel inside the ListViewItem - if (item.Content is StackPanel stackPanel) - { - // Find the Label inside the StackPanel - // Label label = stackPanel.Children.OfType