param ( [cmdletbinding()] [string]$dir="modules.d", [string]$module, [switch]$debug = $false ) #requires -RunAsAdministrator Import-Module NetSecurity #Useful to manipulate firewall rules Set-StrictMode -Version 2 #$PSDefaultParameterValues=@{$dir = "./modules.d"} $HOST_FILE = "$env:windir\System32\drivers\etc\hosts" $HOST_IP = "0.0.0.0" $FW_RULE_NAME_PREFIX = "CleanW10" $IP4_REGEX = "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" $ProgressPreference = "SilentlyContinue" #Thanks to https://gist.github.com/markembling/173887 function BlockHost { param( [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) if ( $params.ContainsKey('file') ) { if ( -not $params.ContainsKey('firewall') -or $params.firewall -eq "" ) { $params.firewall = $false } Get-Content $params.file | where { $_ -notmatch "^#.*$|^$" } | Foreach{ BlockHost -params @{host=$_;firewall=$params.firewall} } } elseif ( $params.ContainsKey('host') -and $params.host -ne "" ) { Write-Host "`n`tBlock host $($params.host) : " try { if ( $(IsHostAlreadyBlocked $HOST_FILE $params.host) ){ #If host is inhosts.conf, verify that ip is blocked in FW if ( $params.ContainsKey('firewall') -and $params.firewall -eq $true ) { $tmp = Get-Content $HOST_FILE | Where { $_ -ne "$HOST_IP`t`t$($params.host)" } Set-Content $HOST_FILE $tmp BlockHostByIP $params.host $HOST_IP + "`t`t" + $params.host | Out-File -encoding ASCII -append $HOST_FILE } Write-Host -ForegroundColor Yellow "`t`tHost Already blocked" } else { if ( $params.ContainsKey('firewall') -and $params.firewall -eq $true ) { BlockHostByIP $params.host } $HOST_IP + "`t`t" + $params.host | Out-File -encoding ASCII -append $HOST_FILE Write-Host -ForegroundColor Green "`t`tHost blocked" } } catch { Write-Host -NoNewline -ForegroundColor Red "`t`terror`n`t`t" Write-Host -ForegroundColor DarkRed $Error[0].Exception.Message } } else { Write-Host -ForegroundColor Red "`tError : No name or file for action $($MyInvocation.MyCommand.Name)" } } function BlockHostByIP { param( [string]$hostname ) #$resolv = [system.net.Dns]::GetHostAddresses($hostname) | Select IPAddressToString $resolv = Resolve-DnsName $hostname -ErrorAction SilentlyContinue | Where { $_.type -match "^A{1,4}$" } | select Address $resolv | Foreach { Write-Host -NoNewLine "`t" $ip = $_.Address Write-Debug "Found a valid IP $ip" $rule = Get-NetFirewallAddressFilter | Where-Object { $_.RemoteAddress -eq $ip } | Get-NetFirewallRule if ( $rule ) { write-host -NoNewLine "`tFW Rule exist : " write-host -ForegroundColor yellow $rule.name } else { FwBlockOutputIP @{ ip=$ip; name=$hostname } } } } function IsHostAlreadyBlocked { param([string]$filename, [string]$hostname) $c = Get-Content $filename | where { $_ -eq "$HOST_IP`t`t$hostname" } Write-Debug "`tMatch hostname on host file : $c" if ( $c ) { return $true } return $false } function FwBlockOutputIP { param( [object]$params ) if ( $params.ContainsKey('file') ) { Get-Content $params.file | where { $_ -notmatch "^#.*$|^$" } | Foreach { FwBlockOutputIP @{ip=$_} } } elseif ( $params.ContainsKey('ip') ) { if (-not $params.ContainsKey('name') -or $params.name -eq "" ) { $name = $FW_RULE_NAME_PREFIX + "_IP_" + $params.ip } else { $name = $FW_RULE_NAME_PREFIX + "_IP_" + $params.name + "-" + $params.ip } Write-Host -NoNewline "`tAdd FW IP rule $name ($($params.ip)) : " $rule = Get-NetFirewallAddressFilter | Where-Object { $_.RemoteAddress -eq $params.ip } | Get-NetFirewallRule if ( $rule ) { write-host -NoNewLine " exist : " write-host -ForegroundColor yellow $rule.name } else { Try { New-NetFirewallRule -Name "$name" -DisplayName "$name" -Direction Outbound -Protocol any -Enabled True -Profile Any -RemoteAddress $params.ip -Action Block | Out-Null } Catch { Write-Host -ForegroundColor Red "error" return } Write-Host -ForegroundColor Green "done" } } else { Write-Host -ForegroundColor Red "`tError : No name or file for action $($MyInvocation.MyCommand.Name)" } } function FwBlockProgram { param ( [cmdletbinding( DefaultParameterSetName='params' )] [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) if ( $params.ContainsKey('file') ) { Get-Content $params.file | where { $_ -notmatch "^#.*$|^$" } | Foreach { FwBlockProgram @{path=$_} } } elseif ( $params.ContainsKey('path') ) { $path = Invoke-Expression """$($params.path)""" if ( -not $params.ContainsKey('name') -or $params.name -eq "" ) { $name = $FW_RULE_NAME_PREFIX + "_PROG_" + $params.path } $name = $FW_RULE_NAME_PREFIX + "_PROG_" + $params.name Write-Host -NoNewline "`tAdd FW program rule $name ($($path)) : " if ( Get-NetFirewallRule -Name $name -ErrorAction SilentlyContinue) { Write-Host -ForegroundColor Yellow "already exist" return } if ( -not (Test-Path $path) ) { Write-Host -Foregroundcolor Red "Error (path not found)" return } try { New-NetFirewallRule -Name "$name" -DisplayName "$name (program : $($params.path))" -Program "$path" -Direction Outbound -Protocol any -Enabled True -Profile Any -RemoteAddress any -Action Block | Out-Null Write-Host -ForegroundColor Green "done" } catch { Write-Host -ForegroundColor Red "error" } } else { Write-Host -ForegroundColor Red "`tError : No path or file for action $($MyInvocation.MyCommand.Name)" } } function RemoveScheduledTask () { param ( [cmdletbinding( DefaultParameterSetName='params' )] [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) if ( $params.ContainsKey('file') ) { Get-Content $params.file | where { $_ -notmatch "^#.*$|^$" } | foreach { RemoveScheduledTask @{name=$_} } } elseif ( $params.ContainsKey('name') ) { $command = "Get-ScheduledTask -ErrorAction Stop -TaskName `"$($params.name)`"" if ($params.ContainsKey('path') -and $params.path -ne '') { $command += " -TaskPath `"$($params.path)`"" } else { $params.path="" } try { $task = Invoke-Expression $command Write-Host -NoNewline "`tRemove task $($params.name) : " $task | Unregister-ScheduledTask -ErrorAction SilentlyContinue -Confirm:$false Write-Host -ForegroundColor Green "done" } catch [Microsoft.PowerShell.Cmdletization.Cim.CimJobException]{ Write-Host -ForegroundColor Yellow "`tScheduled Task $($params.path)$($params.name) not found" } catch { Write-Host -NoNewLine -ForegroundColor Red "`tError in RemoveSheduledTask`n`t" Write-Host -ForegroundColor DarkRed $Error[0].Exception.Message } } else { Write-Host -ForegroundColor Red "`tError : No name or file for action $($MyInvocation.MyCommand.Name)" } } function AddRegKey { param( [Parameter(Mandatory=$true)] [object]$params ) if ( -not $params.ContainsKey('path') -or -not $params.ContainsKey('key') ) { Write-Host -ForegroundColor Red -NoNewline "Error in AddRegKey : no path, key or value`n" return } if ( -not $params.ContainsKey('value') ) { $params.value = "" } if ( -not $params.ContainsKey('type') -or $params.type -eq "" ){ $params.type="DWord" } #When keypath start with HKCU, we need to apply it ro all users if ( ($params.path).StartsWith("HKCU") ) { $script:users | Foreach { #If so, we need to put the key on all users hives AddRegKey @{ path = (($params.path).replace('HKCU:','HKU:\' + $_.sid)); key = $params.key; value = $params.value; type = $params.type } } #then put key to default user hive AddRegKey @{ path = (($params.path).replace('HKCU:','HKU:\Default')); key = $params.key; value = $params.value; type = $params.type } return } #Let's begin... Write-Host -NoNewline "`t$($params.path.substring(0,30))...$($params.key) reg key to $($params.value) : " if ( -not (Test-Path $params.path) ){ Write-Host -NoNewline -ForegroundColor DarkGreen "creating path " try { New-Item -Path $params.path -Force | Out-Null } catch { Write-Host -NoNewLine -ForegroundColor Red "Error`n`t" Write-Host -ForegroundColor DarkRed $Error[0].Exception.Message return } } # Test if the key already exist try { $current_value = Get-ItemPropertyValue -Path $params.path -Name $params.key if ( $current_value -eq $params.value ) { Write-Host -ForegroundColor Yellow "Already done" return } else { Write-Host -NoNewline -ForegroundColor DarkGreen "old value $current_value " } } catch { Write-Host -NoNewline -ForegroundColor DarkGreen "new key " } # Put the key try { Set-ItemProperty -Path $params.path -Name $params.key -Value $params.value -Type $params.type -Force Write-Host -ForegroundColor Green "done" } catch [System.Security.SecurityException]{ Write-Host -ForegroundColor Red "Error (access denied)" } catch { Write-Host -NoNewLine -ForegroundColor Red "`tError`n`t" Write-Host -ForegroundColor DarkRed $Error[0].Exception.Message } } function DelRegKey { param( [Parameter(Mandatory=$true)] [object]$params ) #When keypath start with HKCU, we need to apply it ro all users if ( ($params.path).StartsWith("HKCU") ) { $script:users | Foreach { #If so, we need to put the key on all users hives DelRegKey @{ path = (($params.path).replace('HKCU:','HKU:\' + $_.sid)); key = $params.key; } } #then put key to default user hive DelRegKey @{ path = (($params.path).replace('HKCU:','HKU:\Default')); key = $params.key; } return } Write-Host -NoNewline "`tDelete registery key $($params.key) : " if ( ! (Test-Path $params.path) ){ Write-Host -ForegroundColor Red " Error (path not found)" return } try { Get-ItemProperty -Path $params.path -Name $params.key } catch { Write-Host -ForegroundColor Yellow "key already deleted" return } try { #Remove-ItemProperty -Path $params.path -Name $params.key Write-host -ForegroundColor Green "done" } catch [System.Security.SecurityException]{ Write-Host -ForegroundColor Red "Error (access denied)" } catch { Write-Host -ForegroundColor Red -NoNewLine "Error`n`t" Write-Host -ForegroundColor DarkRed $Error[0].Exception.Message } } function DisableFeature { param ( [cmdletbinding( DefaultParameterSetName='params' )] [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) if ( $params.ContainsKey('file') ) { Get-Content $params.file | where { $_ -notmatch "^#.*$|^$" } | foreach { DisableFeature @{name=$_} } } elseif ( $params.ContainsKey('name') ) { $feature = $(dism /online /Get-FeatureInfo /FeatureName:$($params.name) /English) $name = $feature | Select-String "Feature Name" | %{($_ -split " : ")[1]} if (-not $name){ Write-Host -ForegroundColor Yellow "`tFeature $params.name not found" return } Write-Host -NoNewline "`tDisable Feature $name : " if ( $($feature | Select-String "state") -match "Disable" ){ Write-Host -ForegroundColor Yellow "already disable" return } try { Dism /online /Disable-Feature /FeatureName:$name /NoRestart | Out-Null Write-Host -ForegroundColor Green "done" } catch { Write-Host -ForegroundColor Red "error" } } else { Write-Host -ForegroundColor Red "`tError : No name or file for action $($MyInvocation.MyCommand.Name)" } } function UninstallModernApp { param( [cmdletbinding( DefaultParameterSetName='params' )] [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) if ( $params.ContainsKey('file') ) { $pkgs = $(Get-AppxPackage -AllUsers).name $uninstall_list = Get-Content $params.file | Where { $_ -notmatch "^#.*$|^$" } $pkgs | Where-Object { $_ -in $uninstall_list } | Foreach { UninstallModernApp @{name=$_} } $uninstall_list | Where-Object { $_ -notin $pkgs } | Foreach { Write-Host -ForegroundColor Yellow "`tModern App $_ not installed" } } elseif ( $params.ContainsKey('name') ) { Write-Host -NoNewLine "`tUninstall $($params.name) : " try { $(Get-AppxPackage -AllUsers | Where-Object { $_.name -like "*$($params.name)*" } | Remove-AppxPackage -AllUsers) Write-Host -ForegroundColor Green "done" } catch { Write-Host -NoNewLine -ForegroundColor Red "Error `n`t" write-Host -ForegroundColor DarkRed $_ } } else { Write-Host -ForegroundColor Red "`tError : No name or file for action $($MyInvocation.MyCommand.Name)" return } if ( $params.ContainsKey('removeProvisionned' ) ) { UninstallModernProvisonnedApp $params } } function UninstallModernProvisonnedApp { param( [cmdletbinding( DefaultParameterSetName='params' )] [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) if ( $params.ContainsKey('file') ) { $pkgs = $(Get-AppxProvisionedPackage -Online).DisplayName $list = Get-Content $params.file | Where { $_ -notmatch "^#.*$|^$" } $pkgs | Where-Object { $_ -in $list } | Foreach { UninstallModernProvisonnedApp @{name=$_} } $list | Where-Object { $_ -notin $pkgs } | Foreach { Write-Host -ForegroundColor Yellow "`tProvisionned App $_ not found" } } elseif ( $params.ContainsKey('name') ){ Write-Host -NoNewLine "`tUninstall Provisonned $($params.name) :" try { $(Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -eq $($params.name) }) | Remove-AppxProvisionedPackage -Online | Out-Null Write-Host -ForegroundColor Green "done" } catch { Write-Host -NoNewLine -ForegroundColor Red "`tError`n`t" write-Host -ForegroundColor DarkRed $Error[0].Exception.Message return } } else { Write-Host -ForegroundColor Red "`tError : No name or file for action $($MyInvocation.MyCommand.Name)" } } function DisableService { param ( [cmdletbinding( DefaultParameterSetName='params' )] [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) if ( $params.ContainsKey('file') ) { $services = $(Get-Service).name $list = Get-Content $params.file | Where { $_ -notmatch "^#.*$|^$" } $services | Where-Object { $_ -in $list } | Foreach { DisableService @{name=$_} } $list | Where-Object { $_ -notin $services } | Foreach { Write-Host -ForegroundColor Yellow "`t Service $_ not found" } } elseif ( $params.ContainsKey('name') ) { $service = Get-Service -Name $params.name if ( -not $service ){ Write-Host -ForegroundColor "`t Service $($params.name) not found" return } Write-Host -NoNewline "`tDisable service $($params.name) : " if ( $service.StartType -eq "Disable") { Write-Host -ForegroundColor Yellow "already disabled" return } try { Stop-Service -InputObject $service $service | Set-Service -StartupType disabled -ErrorAction Stop Write-Host -ForegroundColor Green "done" } catch { Write-Host -NoNewLine -ForegroundColor Red "Error`n`t" write-Host -ForegroundColor DarkRed $Error[0].Exception.Message } finally { if ( $params.ContainsKey('userService') -and $params.userService -eq $true ) { # For this kind of service, we need to add a key t create a user service # Where user log-in. AddRegKey @{ path="HKLM:\SYSTEM\CurrentControlSet\Services\$($params.name)"; key="UserServiceFlags" value="0" } } } } else { Write-Host -ForegroundColor Red "`tError : No name or file for action $($MyInvocation.MyCommand.Name)" } } function KillProcess { param( [cmdletbinding( DefaultParameterSetName='params' )] [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) Write-Host -NoNewLine "`tKilling $($params.name) : " try { Stop-Process $(Get-Process $params.name -ErrorAction SilentlyContinue ) Write-Host -ForegroundColor Green "Done" } catch { Write-host -ForegroundColor Yellow "Not started" } } function DelFile { param ( [cmdletbinding( DefaultParameterSetName='params' )] [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) $path = Invoke-Expression """$($params.path)""" Write-Host -NoNewline "`tDelete $path : " if ( -not (Test-Path $path) ){ Write-Host -ForegroundColor Yellow "not found" return } $command = "Remove-Item -ErrorAction SilentlyContinue -Force -Path `"$path`"" if ( $params.ContainsKey('recurse') -and $params.recurse -eq $true ) { $command += "-Recurse" } try { Invoke-Expression $command Write-Host -ForegroundColor Green "done" } catch { Write-Host -NoNewLine -ForegroundColor Red "`Error`n`t" write-Host -ForegroundColor DarkRed $Error[0].Exception.Message } } function ExecCommand { param ( [cmdletbinding( DefaultParameterSetName='params' )] [Parameter( ValueFromPipeline=$False, ParameterSetName="params", Position = 0 )] [object]$params ) $path = $params.path.Replace("##mod_path##", $script:current_module_path) $args = $params.arguments.Replace("##mod_path##", $script:current_module_path) Write-Host -NoNewline "`tExecute : $path : " $path = Invoke-Expression """$($path)""" if ( -not (Test-Path $path) -or -not $path -eq "powershell" ) { Write-Host -ForegroundColor Yellow "File not found" return } try { Start-Process -wait -filepath $path -ArgumentList $args.split(" ") Write-Host -ForegroundColor Green "done" } catch { Write-Host -NoNewLine -ForegroundColor Red "Error`n`t" write-Host -ForegroundColor DarkRed $Error[0].Exception.Message } } function ProcessModuleFile { param ( [Parameter( Mandatory=$true, ValueFromPipeline=$True, ParameterSetName="path" )] [string]$path ) try { $mod = Get-Content $(Get-ChildItem $path).FullName -Raw | ConvertFrom-Json } catch { Write-Host -ForegroundColor Red "Error While Loading JSON : $path `n`n" #Write-Host -ForegroundColor DarkRed $Error[0].Exception.Message return } Write-Host -ForegroundColor White "`nProcess Module $($mod.name) `n" $mod.actions | Foreach { $action_file = "" $current_action = @{} $script:current_module_path = $(Get-ChildItem $path).DirectoryName + "\" + $(Get-ChildItem $path).BaseName + '\' foreach( $p in $_.psobject.properties.name ){ $current_action[$p] = $_.$p } if ( -not $current_action.ContainsKey('action') ) { Write-Host -ForegroundColor Red "`tError : action not found" return } # If action content a file element, need to test if file exist if ( $current_action.ContainsKey('file')) { $action_file = $script:current_module_path + $current_action.file if ( -not (Test-Path $action_file) ) { Write-Host -ForegroundColor Red "`tError in $($mod.name) : file $action_file not found`n" return } $current_action.file = $action_file } # Invoke function if (Get-Command $($_.action) -ErrorAction SilentlyContinue ){ Invoke-Expression "$($_.action) `$current_action" } else { Write-Host -ForegroundColor Red "`tError in $($mod.name) : action $($_.action) not exist" } } } Write-Output "`nIt's time to kick ass and chew bubble gum" Write-Output "_________________________________________`n" $script:users = @() try { Write-Host -NoNewline "Mount Default user registery hive : " reg load "HKU\Default" "C:\Users\Default\NTUSER.DAT" | Out-Null New-PSDrive -PSProvider Registry -Root HKEY_USERS -Name HKU | Out-Null Write-Host -ForegroundColor Green "done" Write-Host -NoNewline "Mount HK_CLASSES_ROOT registery hive : " New-PSDrive -PSProvider Registry -Root HKEY_CLASSES_ROOT -Name HKCR | Out-Null New-PSDrive -PSProvider Registry -Root HKEY_CURRENT_USER -Name HKCU | Out-Null Write-Host -ForegroundColor Green "done" } catch { Write-Host -NoNewline -ForegroundColor Red "Error while mounting Registery`n`t" Write-Host -ForegroundColor DarkRed $Error[0].Exception.Message #return } #We need access to users registry hive for applying mofidication to existing users $profile_list = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\" Get-LocalUser | Where-Object { $_.Enabled -eq $true } | foreach { $current_user_path = Get-ItemPropertyValue -Path "$profile_list$($_.SID.Value)\" -Name "ProfileImagePath" $script:users += @{name = $_.name;'sid' = $_.SID.Value; 'was_mounted' = $false; 'directory' = $current_user_path} } Write-Host "Mount users registry hives :" $script:users | foreach { Write-Host -NoNewline "`tMount $($_.name) hive : " if ( -not (Test-Path "HKU:\$($_.sid)") ) { try { reg load "HKU\$($_.sid)" "$($_.directory)\NTUSER.DAT" 2>&1 | Out-Null Write-Host -ForegroundColor Green "done" } catch { Write-Host -ForegroundColor Red "Error`n`t" Write-host $Error[0].Exception.Message } } else { $_.was_mounted = $true Write-Host -ForegroundColor Yellow "Already mounted" } } Write-Host "Folder to process : $module" if ( $debug ) { $DebugPreference = "Continue" } if ( $module -and $( Test-Path $module ) ) { $module | ProcessModuleFile } else { Get-ChildItem -Path $dir -Filter "*.conf" | foreach { $_.FullName | ProcessModuleFile } } Write-Host -Nonewline "`nRemove powershell access to HKCR, HKCU and HKU : " try { Remove-PSDrive -Name HKCR Remove-PSDrive -Name HKCU Remove-PSDrive -Name HKU Write-Host -ForegroundColor Green "done" } catch { Write-Host -NoNewline -ForegroundColor Red "Error`n`t" Write-Host -ForegroundColor DarkRed $Error[0].Exception.Message } 0 [gc]::collect() Write-Host "`nUnload Users hives : " #Unmount Registery $script:users | foreach { Write-Host -Nonewline "`tUnmount $($_.name) hive : " #Need to unmount all not-connected users hives" if ($_.was_mounted -eq $false) { try { reg unload "HKU\$($_.sid)" 2>&1 | Out-Null Write-Host -foregroundColor Green "Done" } catch { Write-Host -NoNewline -ForegroundColor Red "Error`n`t" Write-Host -ForegroundColor Red $Error[0].Exception.Message } } else { Write-Host -ForegroundColor Yellow "Was mounted (User connected)" } } Write-Host -nonewline "`nUnload default user hive : " try { reg unload "HKU\Default" 2>&1 | Out-Null Write-Host -ForegroundColor Green "done" } catch { Write-Host -NoNewline -ForegroundColor Red "Error`n`t" Write-Host -ForegroundColor DarkRed $Error[0].Exception.Message }