Functions.ps1
# Stop the execution when there is an error $global:ErrorActionPreference = 'Stop' # Function to test if current session has administrator privileges Function Test-IsAdmin { $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object Security.Principal.WindowsPrincipal $identity $principal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) } # Hiding Invoke-WebRequest progress because it creates lingering visual effect on PowerShell console for some reason # https://github.com/PowerShell/PowerShell/issues/14348 # https://stackoverflow.com/questions/18770723/hide-progress-of-Invoke-WebRequest # Create an in-memory module so $ScriptBlock doesn't run in new scope $null = New-Module { function Invoke-WithoutProgress { [CmdletBinding()] param ( [Parameter(Mandatory)][scriptblock]$ScriptBlock ) # Save current progress preference and hide the progress $prevProgressPreference = $global:ProgressPreference $global:ProgressPreference = 'SilentlyContinue' try { # Run the script block in the scope of the caller of this module function . $ScriptBlock } finally { # Restore the original behavior $global:ProgressPreference = $prevProgressPreference } } } # Make sure the latest version of the module is installed and if not, automatically update it, clean up any old versions function Update-self { [version]$CurrentVersion = (Test-ModuleManifest "$psscriptroot\Harden-Windows-Security-Module.psd1").Version try { Invoke-WithoutProgress { [version]$global:LatestVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/HotCakeX/Harden-Windows-Security/main/Harden-Windows-Security%20Module/version.txt' } } catch { Write-Error -Message "Couldn't verify if the latest version of the module is installed, please check your Internet connection." } if ($CurrentVersion -lt $LatestVersion) { Write-Output "$($PSStyle.Foreground.FromRGB(255,105,180))The currently installed module's version is $CurrentVersion while the latest version is $LatestVersion - Auto Updating the module... 💓$($PSStyle.Reset)" # Only attempt to auto update the module if running as Admin, because Controlled Folder Access exclusion modification requires Admin privs if (Test-IsAdmin) { Remove-Module -Name 'Harden-Windows-Security-Module' -Force try { # backup the current allowed apps list in Controlled folder access in order to restore them at the end of the script # doing this so that when we Add and then Remove PowerShell executables in Controlled folder access exclusions # no user customization will be affected [string[]]$CFAAllowedAppsBackup = (Get-MpPreference).ControlledFolderAccessAllowedApplications # Temporarily allow the currently running PowerShell executables to the Controlled Folder Access allowed apps # so that the script can run without interruption. This change is reverted at the end. Get-ChildItem -Path "$PSHOME\*.exe" | ForEach-Object { Add-MpPreference -ControlledFolderAccessAllowedApplications $_.FullName } # Do this if the module was installed properly using Install-moodule cmdlet Uninstall-Module -Name 'Harden-Windows-Security-Module' -AllVersions -Force Install-Module -Name 'Harden-Windows-Security-Module' -RequiredVersion $LatestVersion -Force Import-Module -Name 'Harden-Windows-Security-Module' -RequiredVersion $LatestVersion -Force -Global } # Do this if module files/folder was just copied to Documents folder and not properly installed - Should rarely happen catch { Install-Module -Name 'Harden-Windows-Security-Module' -RequiredVersion $LatestVersion -Force Import-Module -Name 'Harden-Windows-Security-Module' -RequiredVersion $LatestVersion -Force -Global } finally { # Reverting the PowerShell executables allow listings in Controlled folder access Get-ChildItem -Path "$PSHOME\*.exe" | ForEach-Object { Remove-MpPreference -ControlledFolderAccessAllowedApplications $_.FullName } # restoring the original Controlled folder access allow list - if user already had added PowerShell executables to the list # they will be restored as well, so user customization will remain intact if ($null -ne $CFAAllowedAppsBackup) { $CFAAllowedAppsBackup | ForEach-Object { Add-MpPreference -ControlledFolderAccessAllowedApplications $_ } } } # Make sure the old version isn't run after update Write-Output "$($PSStyle.Foreground.FromRGB(152,255,152))Update successful, please run the cmdlet again.$($PSStyle.Reset)" break return } else { Write-Error -Message 'Please run the cmdlet as Admin to update the module.' break } } } # Self update the module Update-self # Requirements Check # check if user's OS is Windows Home edition if ((Get-CimInstance -ClassName Win32_OperatingSystem).OperatingSystemSKU -eq '101') { Write-Error 'Windows Home edition detected, exiting...' break } # check if user's OS is latest version if (-NOT ([System.Environment]::OSVersion.Version -ge [version]'10.0.22621')) { Write-Error "You're not using the latest version of the Windows OS, exiting..." break } if (Test-IsAdmin) { # check to make sure TPM is available and enabled [bool]$TPMFlag1 = (Get-Tpm).tpmpresent [bool]$TPMFlag2 = (Get-Tpm).tpmenabled if (!$TPMFlag1 -or !$TPMFlag2) { Write-Error 'TPM is not available or enabled, please go to your UEFI settings to enable it and then try again.' break } } |