mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 20:54:32 +02:00
Merge branch 'bugfix/IDFGH-2036' into 'master'
Fix for Windows Defender PS task hanging (IDF tools installation) Closes IDFGH-2036 See merge request espressif/esp-idf!6796
This commit is contained in:
@@ -229,14 +229,14 @@ end;
|
|||||||
|
|
||||||
{ ------------------------------ Start menu shortcut ------------------------------ }
|
{ ------------------------------ Start menu shortcut ------------------------------ }
|
||||||
|
|
||||||
procedure CreateIDFCommandPromptShortcut();
|
procedure CreateIDFCommandPromptShortcut(LnkString: String);
|
||||||
var
|
var
|
||||||
Destination: String;
|
Destination: String;
|
||||||
Description: String;
|
Description: String;
|
||||||
Command: String;
|
Command: String;
|
||||||
begin
|
begin
|
||||||
ForceDirectories(ExpandConstant('{group}'));
|
ForceDirectories(ExpandConstant(LnkString));
|
||||||
Destination := ExpandConstant('{group}\{#IDFCmdExeShortcutFile}');
|
Destination := ExpandConstant(LnkString + '\{#IDFCmdExeShortcutFile}');
|
||||||
Description := '{#IDFCmdExeShortcutDescription}';
|
Description := '{#IDFCmdExeShortcutDescription}';
|
||||||
{ If cmd.exe command argument starts with a quote, the first and last quote chars in the command
|
{ If cmd.exe command argument starts with a quote, the first and last quote chars in the command
|
||||||
will be removed by cmd.exe; each argument needs to be surrounded by quotes as well. }
|
will be removed by cmd.exe; each argument needs to be surrounded by quotes as well. }
|
||||||
@@ -267,3 +267,42 @@ begin
|
|||||||
Log('Registering IDF Tools executables in Windows Defender: ' + CmdLine);
|
Log('Registering IDF Tools executables in Windows Defender: ' + CmdLine);
|
||||||
DoCmdlineInstall('Finishing ESP-IDF installation', 'Registering IDF Tools executables in Windows Defender', CmdLine);
|
DoCmdlineInstall('Finishing ESP-IDF installation', 'Registering IDF Tools executables in Windows Defender', CmdLine);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
<event('CurPageChanged')>
|
||||||
|
procedure CheckWinDefenderAvailable(CurPageID: Integer);
|
||||||
|
var
|
||||||
|
bHasWD: Boolean;
|
||||||
|
szHasWD: String;
|
||||||
|
szWDPath: String;
|
||||||
|
listPSModulePath: TStringList;
|
||||||
|
x: Integer;
|
||||||
|
begin
|
||||||
|
if CurPageID = wpSelectTasks then
|
||||||
|
begin
|
||||||
|
listPSModulePath := TStringList.Create;
|
||||||
|
listPSModulePath.Delimiter := ';';
|
||||||
|
listPSModulePath.StrictDelimiter := True;
|
||||||
|
listPSModulePath.DelimitedText := GetEnv('PsModulePath');
|
||||||
|
|
||||||
|
Log('Checking PSMODULEPATH for Windows Defender module...');
|
||||||
|
|
||||||
|
for x:=0 to (listPSModulePath.Count-1) do
|
||||||
|
begin
|
||||||
|
szWDPath := listPSModulePath[x] + '\Defender'
|
||||||
|
bHasWD := DirExists(szWDPath);
|
||||||
|
if bHasWD then
|
||||||
|
begin
|
||||||
|
szHasWD := 'YES (' + szWDPath + ')';
|
||||||
|
Break;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
szHasWD := 'NO';
|
||||||
|
end;
|
||||||
|
|
||||||
|
Log('CheckWinDefenderAvailable: ' + szHasWD);
|
||||||
|
|
||||||
|
WizardForm.TasksList.ItemEnabled[1] := bHasWD;
|
||||||
|
WizardForm.TasksList.Checked[1] := bHasWD;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
@@ -73,16 +73,18 @@ Type: filesandordirs; Name: "{app}\dist"
|
|||||||
Type: filesandordirs; Name: "{app}\releases"
|
Type: filesandordirs; Name: "{app}\releases"
|
||||||
Type: filesandordirs; Name: "{app}\tools"
|
Type: filesandordirs; Name: "{app}\tools"
|
||||||
Type: filesandordirs; Name: "{app}\python_env"
|
Type: filesandordirs; Name: "{app}\python_env"
|
||||||
|
Type: files; Name: "{autostartmenu}\Programs\ESP-IDF\{#IDFCmdExeShortcutFile}"
|
||||||
|
Type: files; Name: "{autodesktop}\{#IDFCmdExeShortcutFile}"
|
||||||
|
|
||||||
[Tasks]
|
[Tasks]
|
||||||
Name: createlnk; Description: "Create Desktop shortcut for ESP-IDF Tools Command Line";
|
Name: createlnk; Description: "Create Start Menu shortcut for the ESP-IDF Tools Command Prompt";
|
||||||
Name: wdexcl; Description: "Register ESP-IDF Tools executables as Windows Defender exclusions (improves compilation speed, requires elevation)";
|
Name: createdsk; Description: "Create Desktop shortcut for the ESP-IDF Tools Command Prompt";
|
||||||
|
Name: wdexcl; Description: "Register the ESP-IDF Tools executables as Windows Defender exclusions (improves compilation speed, requires elevation)";
|
||||||
|
|
||||||
[Run]
|
[Run]
|
||||||
Filename: "{app}\dist\{#PythonInstallerName}"; Parameters: "/passive PrependPath=1 InstallLauncherAllUsers=0 Include_dev=0 Include_tcltk=0 Include_launcher=0 Include_test=0 Include_doc=0"; Description: "Installing Python"; Check: PythonInstallRequired
|
Filename: "{app}\dist\{#PythonInstallerName}"; Parameters: "/passive PrependPath=1 InstallLauncherAllUsers=0 Include_dev=0 Include_tcltk=0 Include_launcher=0 Include_test=0 Include_doc=0"; Description: "Installing Python"; Check: PythonInstallRequired
|
||||||
Filename: "{app}\dist\{#GitInstallerName}"; Parameters: "/silent /tasks="""" /norestart"; Description: "Installing Git"; Check: GitInstallRequired
|
Filename: "{app}\dist\{#GitInstallerName}"; Parameters: "/silent /tasks="""" /norestart"; Description: "Installing Git"; Check: GitInstallRequired
|
||||||
Filename: "{group}\{#IDFCmdExeShortcutFile}"; Flags: postinstall shellexec; Description: "Run ESP-IDF Command Prompt (cmd.exe)"; Check: InstallationSuccessful
|
Filename: "{autostartmenu}\Programs\ESP-IDF\{#IDFCmdExeShortcutFile}"; Flags: postinstall shellexec; Description: "Run ESP-IDF Command Prompt (cmd.exe)"; Check: InstallationSuccessful
|
||||||
|
|
||||||
|
|
||||||
[UninstallRun]
|
[UninstallRun]
|
||||||
Filename: "powershell.exe"; \
|
Filename: "powershell.exe"; \
|
||||||
|
@@ -122,9 +122,14 @@ begin
|
|||||||
|
|
||||||
if WizardIsTaskSelected('createlnk') then
|
if WizardIsTaskSelected('createlnk') then
|
||||||
begin
|
begin
|
||||||
CreateIDFCommandPromptShortcut();
|
CreateIDFCommandPromptShortcut('{autostartmenu}\Programs\ESP-IDF');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if WizardIsTaskSelected('createdsk') then
|
||||||
|
begin
|
||||||
|
CreateIDFCommandPromptShortcut('{autodesktop}');
|
||||||
|
end;
|
||||||
|
|
||||||
if WizardIsTaskSelected('wdexcl') then
|
if WizardIsTaskSelected('wdexcl') then
|
||||||
begin
|
begin
|
||||||
RegisterIDFToolsExecutablesInWD();
|
RegisterIDFToolsExecutablesInWD();
|
||||||
|
@@ -15,152 +15,165 @@
|
|||||||
|
|
||||||
Param
|
Param
|
||||||
(
|
(
|
||||||
[String]$RmExclPath,
|
[String]$RmExclPath,
|
||||||
[String]$logFile
|
[String]$logFile
|
||||||
)
|
)
|
||||||
|
|
||||||
Import-Module Defender
|
|
||||||
|
|
||||||
function Check-Command($cmdname)
|
function Check-Command($cmdname)
|
||||||
{
|
{
|
||||||
return [bool](Get-Command -Name $cmdname -ErrorAction SilentlyContinue)
|
return [bool](Get-Command -Name $cmdname -ErrorAction SilentlyContinue)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Log-Msg($msg, $logF = $null)
|
function Log-Msg($msg, $logF = $null)
|
||||||
{
|
{
|
||||||
if( ![string]::IsNullOrEmpty($logF) ) { Write-Output $msg *>> $logF }
|
if( ![string]::IsNullOrEmpty($logF) ) { Write-Output $msg *>> $logF }
|
||||||
else { Write-Output $msg }
|
else { Write-Output $msg }
|
||||||
[Console]::Out.Flush()
|
[Console]::Out.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$retVal = 1
|
||||||
|
|
||||||
Try
|
Try
|
||||||
{
|
{
|
||||||
#self-elevation support
|
#check the Defender module availability
|
||||||
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
|
if (!(Get-Module "Defender")) {
|
||||||
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
|
Write-Output "Windows Defender module not available, aborting"
|
||||||
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
|
[Environment]::Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
if( -not $myWindowsPrincipal.IsInRole($adminRole) ) {
|
Import-Module Defender
|
||||||
|
|
||||||
$params = ""
|
|
||||||
foreach($key in $PSBoundParameters.keys) {
|
|
||||||
$params = -join( $params, "-", $key, " `"", $PSBoundParameters[$key], "`"" )
|
|
||||||
}
|
|
||||||
|
|
||||||
#running elevated and logFile not set
|
|
||||||
if( [string]::IsNullOrEmpty($logFile) ) {
|
|
||||||
$tempFileName = Get-Date -UFormat "%Y%m%d%H%M%s"
|
|
||||||
$lf = Join-Path -Path $env:TEMP -ChildPath "WDEspLog$tempFileName.log"
|
|
||||||
#Write-Output "Logfile: $lf"
|
|
||||||
}
|
|
||||||
|
|
||||||
$newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell"
|
|
||||||
$newProcess.Arguments = "-ExecutionPolicy ByPass -File " + $script:MyInvocation.MyCommand.Definition + " " + $params + " -logFile $lf"
|
|
||||||
$newProcess.Verb = "RunAs"
|
|
||||||
$newProcess.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
|
|
||||||
|
|
||||||
$proc = [System.Diagnostics.Process]::Start($newProcess)
|
|
||||||
$proc.WaitForExit()
|
|
||||||
|
|
||||||
if (Test-Path -Path $lf ) {
|
#self-elevation support
|
||||||
foreach($line in Get-Content $lf) {
|
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
Log-Msg -msg $line
|
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
|
||||||
}
|
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
|
||||||
Remove-Item $lf
|
|
||||||
}
|
|
||||||
|
|
||||||
#Write-Output "Process finished with code " $proc.ExitCode
|
|
||||||
exit $proc.ExitCode
|
|
||||||
}
|
|
||||||
|
|
||||||
Log-Msg -msg "Getting Windows Defender process exclusions..." -logF $logFile
|
if( -not $myWindowsPrincipal.IsInRole($adminRole) ) {
|
||||||
|
|
||||||
$Preferences = Get-MpPreference
|
|
||||||
|
|
||||||
#ExclusionProcess
|
$params = ""
|
||||||
$cnt = $Preferences.ExclusionProcess.Count
|
foreach($key in $PSBoundParameters.keys) {
|
||||||
$cntRemoved = 0
|
$params = -join( $params, "-", $key, " `"", $PSBoundParameters[$key], "`"" )
|
||||||
$cntRemovedTotal = 0
|
}
|
||||||
$cntMissed = 0
|
|
||||||
$cntMissedTotal = 0
|
|
||||||
|
|
||||||
$bRmPath = ![string]::IsNullOrEmpty($RmExclPath)
|
#running elevated and logFile not set
|
||||||
if( $bRmPath ) { Log-Msg -msg "Exclusion path: $RmExclPath" -logF $logFile }
|
if( [string]::IsNullOrEmpty($logFile) ) {
|
||||||
|
$tempFileName = Get-Date -UFormat "%Y%m%d%H%M%s"
|
||||||
|
$lf = Join-Path -Path $env:TEMP -ChildPath "WDEspLog$tempFileName.log"
|
||||||
|
#Write-Output "Logfile: $lf"
|
||||||
|
}
|
||||||
|
|
||||||
Log-Msg -msg " Found total $cnt of ExclusionProcess items" -logF $logFile
|
$newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell"
|
||||||
|
$newProcess.Arguments = "-ExecutionPolicy ByPass -File " + $script:MyInvocation.MyCommand.Definition + " " + $params + " -logFile $lf"
|
||||||
|
$newProcess.Verb = "RunAs"
|
||||||
|
$newProcess.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
|
||||||
|
|
||||||
|
$proc = [System.Diagnostics.Process]::Start($newProcess)
|
||||||
|
$proc.WaitForExit()
|
||||||
|
|
||||||
foreach( $pref in $Preferences.ExclusionProcess ) {
|
if (Test-Path -Path $lf ) {
|
||||||
|
foreach($line in Get-Content $lf) {
|
||||||
|
Log-Msg -msg $line
|
||||||
|
}
|
||||||
|
Remove-Item $lf
|
||||||
|
}
|
||||||
|
|
||||||
if( $bRmPath ) { $bGoAhead = $pref.Contains($RmExclPath) }
|
#Write-Output "Process finished with code " $proc.ExitCode
|
||||||
else { $bGoAhead = $true }
|
exit $proc.ExitCode
|
||||||
|
}
|
||||||
if( $bGoAhead ) {
|
|
||||||
Log-Msg -msg " removing $pref" -logF $logFile
|
|
||||||
Try
|
|
||||||
{
|
|
||||||
Remove-MpPreference -ExclusionProcess $pref
|
|
||||||
$cntRemoved++
|
|
||||||
}
|
|
||||||
Catch
|
|
||||||
{
|
|
||||||
if( ![string]::IsNullOrEmpty($logFile) ) { Write-Error -Exception $_.Exception *>> $logFile }
|
|
||||||
Write-Error -Exception $_.Exception
|
|
||||||
$cntMissed++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( $cntMissed -eq 0 ) { Log-Msg -msg " $cntRemoved relevant items removed from ExclusionProcess list" -logF $logFile }
|
|
||||||
else { Log-Msg -msg " WARNING: Only $cntRemoved out of $(cntRemoved+cntMissed) relevant items removed from ExclusionProcess list" -logF $logFile }
|
|
||||||
|
|
||||||
#ExclusionPath
|
Log-Msg -msg "Getting Windows Defender process exclusions..." -logF $logFile
|
||||||
$cnt = $Preferences.ExclusionPath.Count
|
|
||||||
$cntRemovedTotal = $cntRemoved
|
|
||||||
$cntRemoved = 0
|
|
||||||
$cntMissedTotal = $cntMissed
|
|
||||||
$cntMissed = 0
|
|
||||||
|
|
||||||
Log-Msg -msg " Found total $cnt of ExclusionPath items" -logF $logFile
|
$Preferences = Get-MpPreference
|
||||||
|
|
||||||
foreach( $pref in $Preferences.ExclusionPath ) {
|
#ExclusionProcess
|
||||||
|
$cnt = $Preferences.ExclusionProcess.Count
|
||||||
|
$cntRemoved = 0
|
||||||
|
$cntRemovedTotal = 0
|
||||||
|
$cntMissed = 0
|
||||||
|
$cntMissedTotal = 0
|
||||||
|
|
||||||
if( $bRmPath ) { $bGoAhead = $pref.Contains($RmExclPath) }
|
$bRmPath = ![string]::IsNullOrEmpty($RmExclPath)
|
||||||
else { $bGoAhead = $true }
|
if( $bRmPath ) { Log-Msg -msg "Exclusion path: $RmExclPath" -logF $logFile }
|
||||||
|
|
||||||
if( $bGoAhead ) {
|
|
||||||
Log-Msg -msg " removing $pref" -logF $logFile
|
|
||||||
Try
|
|
||||||
{
|
|
||||||
Remove-MpPreference -ExclusionPath $pref
|
|
||||||
$cntRemoved++
|
|
||||||
}
|
|
||||||
Catch
|
|
||||||
{
|
|
||||||
if( ![string]::IsNullOrEmpty($logFile) ) { Write-Error -Exception $_.Exception *>> $logFile }
|
|
||||||
Write-Error -Exception $_.Exception
|
|
||||||
$cntMissed++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( $cntMissed -eq 0 ) { Log-Msg -msg " $cntRemoved relevant items removed from ExclusionPath list" -logF $logFile }
|
Log-Msg -msg " Found total $cnt of ExclusionProcess items" -logF $logFile
|
||||||
else { Log-Msg -msg " WARNING: Only $cntRemoved out of $(cntRemoved+cntMissed) relevant items removed from ExclusionPath list" -logF $logFile }
|
|
||||||
|
|
||||||
#TOTAL
|
foreach( $pref in $Preferences.ExclusionProcess ) {
|
||||||
$cntRemovedTotal += $cntRemoved
|
|
||||||
$cntMissedTotal += $cntMissed
|
|
||||||
|
|
||||||
Log-Msg -msg "============================" -logF $logFile
|
|
||||||
if( $cntMissedTotal -eq 0 ) { Log-Msg -msg "OK: Processed all $cntRemovedTotal items" -logF $logFile }
|
|
||||||
else { Log-Msg -msg "WARNING: Processed only $cntRemovedTotal out of $(cntRemovedTotal+cntMissedTotal) relevat items" -logF $logFile }
|
|
||||||
|
|
||||||
Log-Msg -msg "`nDone" -logF $logFile
|
if( $bRmPath ) { $bGoAhead = $pref.Contains($RmExclPath) }
|
||||||
|
else { $bGoAhead = $true }
|
||||||
|
|
||||||
|
if( $bGoAhead ) {
|
||||||
|
Log-Msg -msg " removing $pref" -logF $logFile
|
||||||
|
Try
|
||||||
|
{
|
||||||
|
Remove-MpPreference -ExclusionProcess $pref
|
||||||
|
$cntRemoved++
|
||||||
|
}
|
||||||
|
Catch
|
||||||
|
{
|
||||||
|
if( ![string]::IsNullOrEmpty($logFile) ) { Write-Error -Exception $_.Exception *>> $logFile }
|
||||||
|
Write-Error -Exception $_.Exception
|
||||||
|
$cntMissed++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $cntMissed -eq 0 ) { Log-Msg -msg " $cntRemoved relevant items removed from ExclusionProcess list" -logF $logFile }
|
||||||
|
else { Log-Msg -msg " WARNING: Only $cntRemoved out of $(cntRemoved+cntMissed) relevant items removed from ExclusionProcess list" -logF $logFile }
|
||||||
|
|
||||||
|
#ExclusionPath
|
||||||
|
$cnt = $Preferences.ExclusionPath.Count
|
||||||
|
$cntRemovedTotal = $cntRemoved
|
||||||
|
$cntRemoved = 0
|
||||||
|
$cntMissedTotal = $cntMissed
|
||||||
|
$cntMissed = 0
|
||||||
|
|
||||||
|
Log-Msg -msg " Found total $cnt of ExclusionPath items" -logF $logFile
|
||||||
|
|
||||||
|
foreach( $pref in $Preferences.ExclusionPath ) {
|
||||||
|
|
||||||
|
if( $bRmPath ) { $bGoAhead = $pref.Contains($RmExclPath) }
|
||||||
|
else { $bGoAhead = $true }
|
||||||
|
|
||||||
|
if( $bGoAhead ) {
|
||||||
|
Log-Msg -msg " removing $pref" -logF $logFile
|
||||||
|
Try
|
||||||
|
{
|
||||||
|
Remove-MpPreference -ExclusionPath $pref
|
||||||
|
$cntRemoved++
|
||||||
|
}
|
||||||
|
Catch
|
||||||
|
{
|
||||||
|
if( ![string]::IsNullOrEmpty($logFile) ) { Write-Error -Exception $_.Exception *>> $logFile }
|
||||||
|
Write-Error -Exception $_.Exception
|
||||||
|
$cntMissed++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $cntMissed -eq 0 ) { Log-Msg -msg " $cntRemoved relevant items removed from ExclusionPath list" -logF $logFile }
|
||||||
|
else { Log-Msg -msg " WARNING: Only $cntRemoved out of $(cntRemoved+cntMissed) relevant items removed from ExclusionPath list" -logF $logFile }
|
||||||
|
|
||||||
|
#TOTAL
|
||||||
|
$cntRemovedTotal += $cntRemoved
|
||||||
|
$cntMissedTotal += $cntMissed
|
||||||
|
|
||||||
|
Log-Msg -msg "============================" -logF $logFile
|
||||||
|
if( $cntMissedTotal -eq 0 ) { Log-Msg -msg "OK: Processed all $cntRemovedTotal items" -logF $logFile }
|
||||||
|
else { Log-Msg -msg "WARNING: Processed only $cntRemovedTotal out of $(cntRemovedTotal+cntMissedTotal) relevat items" -logF $logFile }
|
||||||
|
|
||||||
|
Log-Msg -msg "`nDone" -logF $logFile
|
||||||
|
|
||||||
|
$retVal = 0
|
||||||
}
|
}
|
||||||
Catch
|
Catch
|
||||||
{
|
{
|
||||||
if( ![string]::IsNullOrEmpty($logFile) ) { Write-Error -Exception $_.Exception *>> $logFile }
|
if( ![string]::IsNullOrEmpty($logFile) ) { Write-Error -Exception $_.Exception *>> $logFile }
|
||||||
Write-Error -Exception $_.Exception
|
Write-Error -Exception $_.Exception
|
||||||
exit -1
|
[Environment]::Exit($retVal)
|
||||||
|
}
|
||||||
|
Finally
|
||||||
|
{
|
||||||
|
[Environment]::Exit($retVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,235 +4,261 @@
|
|||||||
# Espressif Systems, 2019
|
# Espressif Systems, 2019
|
||||||
#
|
#
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
|
||||||
# PS utility to add/remove PROCESS exceptions to/from MS WD real-time
|
|
||||||
# scanning. Files (referenced by 'path' or 'path\filemask') are expected
|
|
||||||
# to be Windows process executables, for obvious reasons.
|
|
||||||
#
|
#
|
||||||
# The script requires Administrator privileges to succeed -> self-elevation procedure is involved
|
# PS utility to add/remove PROCESS exceptions to/from MS WD real-time
|
||||||
|
# scanning. Files (referenced by 'path' or 'path\filemask') are expected
|
||||||
|
# to be Windows process executables, for obvious reasons.
|
||||||
|
#
|
||||||
|
# The script requires Administrator privileges to succeed -> self-elevation procedure is involved
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
#
|
#
|
||||||
# PowerShell -ExecutionPolicy ByPass -File tools_WD_excl.ps1 <ARGUMENTS>
|
# PowerShell -ExecutionPolicy ByPass -File tools_WD_excl.ps1 <ARGUMENTS>
|
||||||
#
|
#
|
||||||
# ARGUMENTS:
|
# ARGUMENTS:
|
||||||
# -AddExclPath <path | path\*.filemask>
|
# -AddExclPath <path | path\*.filemask>
|
||||||
# add all matching files in the path (recursive) to the WD exception list
|
# add all matching files in the path (recursive) to the WD exception list
|
||||||
#
|
|
||||||
# -AddExclFile <filepath>
|
|
||||||
# adds file to the WD exception list exactly as specified by 'filepath'
|
|
||||||
#
|
#
|
||||||
# -RmExclPath <path | path\*.filemask>
|
# -AddExclFile <filepath>
|
||||||
# remove all matching files in the path (recursive) from WD exclusions
|
# adds file to the WD exception list exactly as specified by 'filepath'
|
||||||
#
|
#
|
||||||
# -RmExclFile <filepath>
|
# -RmExclPath <path | path\*.filemask>
|
||||||
# adds file to the WD exception list exactly as specified by 'filepath'
|
# remove all matching files in the path (recursive) from WD exclusions
|
||||||
#
|
#
|
||||||
# -logFile <filepath>
|
# -RmExclFile <filepath>
|
||||||
# stdout/stderr redirection file. Used internally for elevated process (generated in tempdir, deleted after the script finishing)
|
# adds file to the WD exception list exactly as specified by 'filepath'
|
||||||
# use manually at your own risk
|
|
||||||
#
|
#
|
||||||
# Returns 0 on success or -1 on failure
|
# -logFile <filepath>
|
||||||
|
# stdout/stderr redirection file. Used internally for elevated process (generated in tempdir, deleted after the script finishing)
|
||||||
|
# use manually at your own risk
|
||||||
|
#
|
||||||
|
# Returns 0 on success or -1 on failure
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
# PowerShell -ExecutionPolicy ByPass -File tools_WD_excl.ps1 -AddExclPath "C:\Program Files\Espressif\ESP-IDF Tools\*.exe"
|
# PowerShell -ExecutionPolicy ByPass -File tools_WD_excl.ps1 -AddExclPath "C:\Program Files\Espressif\ESP-IDF Tools\*.exe"
|
||||||
#
|
#
|
||||||
# Notes:
|
# Notes:
|
||||||
# - default scenario is set to the following
|
# - default scenario is set to the following
|
||||||
# -AddExclPath "$Env:ProgramFiles\Espressif\ESP-IDF Tools\*.exe"
|
# -AddExclPath "$Env:ProgramFiles\Espressif\ESP-IDF Tools\*.exe"
|
||||||
# (eg when called with no params)
|
# (eg when called with no params)
|
||||||
# - only named parameters are supported, any other use-cases redirect to the default
|
# - only named parameters are supported, any other use-cases redirect to the default
|
||||||
# - multiple paths/files in 1 parameter are not supported by this version
|
# - multiple paths/files in 1 parameter are not supported by this version
|
||||||
# - minimum requirements: Windows XP SP3, PowerShell 2.0, Windows Defender with relevant PS cmdlets
|
# - minimum requirements: Windows XP SP3, PowerShell 2.0, Windows Defender with relevant PS cmdlets
|
||||||
#
|
#
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
|
||||||
Param
|
Param
|
||||||
(
|
(
|
||||||
[String]$AddExclPath,
|
[String]$AddExclPath,
|
||||||
[String]$AddExclFile,
|
[String]$AddExclFile,
|
||||||
[String]$RmExclPath,
|
[String]$RmExclPath,
|
||||||
[String]$RmExclFile,
|
[String]$RmExclFile,
|
||||||
[String]$logFile
|
[String]$logFile
|
||||||
)
|
)
|
||||||
|
|
||||||
Import-Module Defender
|
|
||||||
|
|
||||||
function Check-Command($cmdname)
|
function Check-Command($cmdname)
|
||||||
{
|
{
|
||||||
return [bool](Get-Command -Name $cmdname -ErrorAction SilentlyContinue)
|
return [bool](Get-Command -Name $cmdname -ErrorAction SilentlyContinue)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Log-Msg($msg, $logF = $null)
|
function Log-Msg($msg, $logF = $null)
|
||||||
{
|
{
|
||||||
if( ![string]::IsNullOrEmpty($logF) ) { Write-Output $msg *>> $logF }
|
if( ![string]::IsNullOrEmpty($logF) ) { Write-Output $msg *>> $logF }
|
||||||
else { Write-Output $msg }
|
else { Write-Output $msg }
|
||||||
[Console]::Out.Flush()
|
[Console]::Out.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$retVal = 1
|
||||||
|
|
||||||
Try
|
Try
|
||||||
{
|
{
|
||||||
#self-elevation support
|
$bDebug = $false
|
||||||
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
|
|
||||||
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
|
#parameter sanity check
|
||||||
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
|
if( $Args.Count -gt 0 ) {
|
||||||
|
if( $Args.Count -eq 1 -And $Args[0] -eq "Debug" ) {
|
||||||
|
$bDebug = $true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$Exception = [ArgumentException]::new("Invalid parameters: $Args")
|
||||||
|
throw $Exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( -not $myWindowsPrincipal.IsInRole($adminRole) ) {
|
#check the Defender module availability
|
||||||
|
$wdModuleDir = Join-Path -Path $env:SystemRoot -ChildPath "System32\WindowsPowerShell\v1.0\Modules\Defender"
|
||||||
$params = ""
|
if( -not (Test-Path -Path $wdModuleDir) ) {
|
||||||
foreach($key in $PSBoundParameters.keys) {
|
Write-Output "Windows Defender module not found, aborting"
|
||||||
$params = -join( $params, "-", $key, " `"", $PSBoundParameters[$key], "`"" )
|
[Environment]::Exit($retVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
#running elevated and logFile not set
|
|
||||||
if( [string]::IsNullOrEmpty($logFile) ) {
|
|
||||||
$tempFileName = Get-Date -UFormat "%Y%m%d%H%M%s"
|
|
||||||
$lf = Join-Path -Path $env:TEMP -ChildPath "WDEspLog$tempFileName.log"
|
|
||||||
#Write-Output "Logfile: $lf"
|
|
||||||
}
|
|
||||||
|
|
||||||
$newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell"
|
|
||||||
$newProcess.Arguments = "-ExecutionPolicy ByPass -File " + $script:MyInvocation.MyCommand.Definition + " " + $params + " -logFile $lf"
|
|
||||||
$newProcess.Verb = "RunAs"
|
|
||||||
$newProcess.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
|
|
||||||
|
|
||||||
$proc = [System.Diagnostics.Process]::Start($newProcess)
|
|
||||||
$proc.WaitForExit()
|
|
||||||
|
|
||||||
if (Test-Path -Path $lf ) {
|
Import-Module Defender
|
||||||
foreach($line in Get-Content $lf) {
|
|
||||||
Log-Msg -msg $line
|
|
||||||
}
|
|
||||||
Remove-Item $lf
|
|
||||||
}
|
|
||||||
|
|
||||||
#Write-Output "Process finished with code " $proc.ExitCode
|
|
||||||
exit $proc.ExitCode
|
|
||||||
}
|
|
||||||
|
|
||||||
#parameter sanity check
|
|
||||||
if( $Args.Count -gt 0 ) {
|
|
||||||
$Exception = [ArgumentException]::new("Only named parameters are supported: $Args")
|
|
||||||
throw $Exception
|
|
||||||
}
|
|
||||||
|
|
||||||
#check WinDefender cmdlets are available
|
#self-elevation support
|
||||||
if (!(Check-Command -cmdname 'Add-MpPreference')) {
|
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
$Exception = [NotSupportedException ]::new("Windows Defender cmdlets not available")
|
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
|
||||||
throw $Exception
|
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
|
||||||
}
|
|
||||||
|
|
||||||
$pathsToExclude = New-Object 'System.Collections.Generic.List[String]'
|
if( -not $myWindowsPrincipal.IsInRole($adminRole) ) {
|
||||||
$filesToExclude = New-Object 'System.Collections.Generic.List[String]'
|
|
||||||
$pathsToInclude = New-Object 'System.Collections.Generic.List[String]'
|
|
||||||
$filesToRemove = New-Object 'System.Collections.Generic.List[String]'
|
|
||||||
|
|
||||||
if( $PSBoundParameters.Count -gt 0 ) {
|
$params = ""
|
||||||
|
foreach($key in $PSBoundParameters.keys) {
|
||||||
|
$params = -join( $params, "-", $key, " `"", $PSBoundParameters[$key], "`"" )
|
||||||
|
}
|
||||||
|
|
||||||
|
$arguments = ""
|
||||||
|
foreach($a in $Args) {
|
||||||
|
$arguments = -join( $arguments, "-", $a )
|
||||||
|
}
|
||||||
|
|
||||||
$bAddPath = ![string]::IsNullOrEmpty($AddExclPath)
|
#running elevated and logFile not set
|
||||||
$bAddFile = ![string]::IsNullOrEmpty($AddExclFile)
|
$bOwnLogFile = [string]::IsNullOrEmpty($logFile)
|
||||||
$bRmPath = ![string]::IsNullOrEmpty($RmExclPath)
|
if( $bOwnLogFile ) {
|
||||||
$bRmFile = ![string]::IsNullOrEmpty($RmExclFile)
|
$tempFileName = Get-Date -UFormat "%Y%m%d%H%M%s"
|
||||||
|
$lf = Join-Path -Path $env:TEMP -ChildPath "WDEspLog$tempFileName.log"
|
||||||
if( !$bAddPath -And !$bAddFile -And !$bRmPath -And !$bRmFile ) {
|
Write-Output "Logfile: $lf"
|
||||||
$Exception = [ArgumentException]::new("Invalid parameter(s): $Args")
|
}
|
||||||
throw $Exception
|
else { $lf = $logFile }
|
||||||
}
|
|
||||||
|
|
||||||
#ADD exclusion paths
|
$newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell"
|
||||||
if( $bAddPath ) {
|
$newProcess.Arguments = "-ExecutionPolicy ByPass -File " + $script:MyInvocation.MyCommand.Definition + " " + $params + " -logFile $lf " + $arguments
|
||||||
#foreach ($wdPath in $AddExclPath) {
|
$newProcess.Verb = "RunAs"
|
||||||
# $pathsToExclude.Add( $wdPath )
|
|
||||||
#}
|
|
||||||
$pathsToExclude.Add( $AddExclPath )
|
|
||||||
}
|
|
||||||
|
|
||||||
#ADD exclusion files
|
#show the process window for -Debug
|
||||||
if( $bAddFile ) {
|
if( !$bDebug ) { $newProcess.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden }
|
||||||
#foreach ($wdFile in $AddExclFile) {
|
|
||||||
# $filesToExclude.Add( $wdFile )
|
$proc = [System.Diagnostics.Process]::Start($newProcess)
|
||||||
#}
|
$proc.WaitForExit()
|
||||||
$filesToExclude.Add( $AddExclFile )
|
|
||||||
}
|
|
||||||
|
|
||||||
#REMOVE exclusion paths
|
if (Test-Path -Path $lf ) {
|
||||||
if( $bRmPath ) {
|
foreach($line in Get-Content $lf) {
|
||||||
#foreach ($wdPath in $RmExclPath) {
|
Log-Msg -msg $line
|
||||||
# $pathsToInclude.Add( $wdPath )
|
}
|
||||||
#}
|
}
|
||||||
$pathsToInclude.Add( $RmExclPath )
|
|
||||||
}
|
if( $bDebug ) { Log-Msg -msg "Process finished with code " + $proc.ExitCode -logF $lf }
|
||||||
|
if( $bOwnLogFile -And !$bDebug) { Remove-Item $lf }
|
||||||
#ADD exclusion file
|
|
||||||
if( $bAddFile ) {
|
[Environment]::Exit($proc.ExitCode)
|
||||||
#foreach ($wdFile in $RmExclFile) {
|
}
|
||||||
# $filesToRemove.Add( $wdFile )
|
|
||||||
#}
|
|
||||||
$filesToRemove.Add( $RmExclFile )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#default: throw exception
|
|
||||||
else {
|
|
||||||
$Exception = [ArgumentException]::new("Mandatory parameter missing")
|
|
||||||
throw $Exception
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#to exclude all files opened by a process including the process' binary, a record must be added to both Exclusions/Paths and Exclusions/Processes configurations, see
|
$pathsToExclude = New-Object 'System.Collections.Generic.List[String]'
|
||||||
# https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-antivirus/configure-process-opened-file-exclusions-windows-defender-antivirus :
|
$filesToExclude = New-Object 'System.Collections.Generic.List[String]'
|
||||||
# "When you add a process to the process exclusion list, Windows Defender Antivirus won't scan files opened by that process, no matter where the files are located. The process itself, however, will be scanned unless it has also been added to the file exclusion list.
|
$pathsToInclude = New-Object 'System.Collections.Generic.List[String]'
|
||||||
#The exclusions only apply to always-on real-time protection and monitoring. They don't apply to scheduled or on-demand scans."
|
$filesToRemove = New-Object 'System.Collections.Generic.List[String]'
|
||||||
|
|
||||||
Log-Msg -msg "Updating Windows Defender real-time scan exclusions:" -logF $logFile
|
if( $PSBoundParameters.Count -gt 0 ) {
|
||||||
|
|
||||||
$itemCount = 0
|
$bAddPath = ![string]::IsNullOrEmpty($AddExclPath)
|
||||||
|
$bAddFile = ![string]::IsNullOrEmpty($AddExclFile)
|
||||||
|
$bRmPath = ![string]::IsNullOrEmpty($RmExclPath)
|
||||||
|
$bRmFile = ![string]::IsNullOrEmpty($RmExclFile)
|
||||||
|
|
||||||
|
if( !$bAddPath -And !$bAddFile -And !$bRmPath -And !$bRmFile ) {
|
||||||
|
throw (New-Object -TypeName System.ArgumentException -ArgumentList "Invalid parameter(s)")
|
||||||
|
}
|
||||||
|
|
||||||
#exclusions
|
#ADD exclusion paths
|
||||||
foreach( $exclPath in $pathsToExclude ) {
|
if( $bAddPath ) {
|
||||||
$exclFiles = Get-ChildItem -Recurse -File -Path $exclPath | % { $_.FullName }
|
#foreach ($wdPath in $AddExclPath) {
|
||||||
foreach ($exfile in $exclFiles) {
|
# $pathsToExclude.Add( $wdPath )
|
||||||
Log-Msg -msg " adding $exfile" -logF $logFile
|
#}
|
||||||
Add-MpPreference -ExclusionProcess $exfile
|
$pathsToExclude.Add( $AddExclPath )
|
||||||
Add-MpPreference -ExclusionPath $exfile
|
}
|
||||||
$itemCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
### ! better run in separate, adding files to exclusion object array from above is very inefficient (forced reallocations)
|
#ADD exclusion files
|
||||||
foreach ($exfile1 in $filesToExclude) {
|
if( $bAddFile ) {
|
||||||
Log-Msg -msg " adding $exfile1" -logF $logFile
|
#foreach ($wdFile in $AddExclFile) {
|
||||||
Add-MpPreference -ExclusionProcess $exfile1
|
# $filesToExclude.Add( $wdFile )
|
||||||
Add-MpPreference -ExclusionPath $exfile1
|
#}
|
||||||
$itemCount++
|
$filesToExclude.Add( $AddExclFile )
|
||||||
}
|
}
|
||||||
|
|
||||||
#inclusions
|
#REMOVE exclusion paths
|
||||||
foreach( $inclPath in $pathsToInclude ) {
|
if( $bRmPath ) {
|
||||||
$inclFiles = Get-ChildItem -Recurse -File -Path $inclPath | % { $_.FullName }
|
#foreach ($wdPath in $RmExclPath) {
|
||||||
foreach ($infile in $inclFiles) {
|
# $pathsToInclude.Add( $wdPath )
|
||||||
Log-Msg -msg " removing $infile" -logF $logFile
|
#}
|
||||||
Remove-MpPreference -ExclusionProcess $infile
|
$pathsToInclude.Add( $RmExclPath )
|
||||||
Remove-MpPreference -ExclusionPath $infile
|
}
|
||||||
$itemCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
### ! see exclusions
|
#ADD exclusion file
|
||||||
foreach ($infile1 in $filesToExclude) {
|
if( $bAddFile ) {
|
||||||
Log-Msg -msg " removing $infile1" -logF $logFile
|
#foreach ($wdFile in $RmExclFile) {
|
||||||
Remove-MpPreference -ExclusionProcess $infile1
|
# $filesToRemove.Add( $wdFile )
|
||||||
Remove-MpPreference -ExclusionPath $infile1
|
#}
|
||||||
$itemCount++
|
$filesToRemove.Add( $RmExclFile )
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#default: throw exception
|
||||||
|
else {
|
||||||
|
throw (New-Object -TypeName System.ArgumentException -ArgumentList "Mandatory parameter(s) missing")
|
||||||
|
}
|
||||||
|
|
||||||
Log-Msg -msg "Done (processed $itemCount items)" -logF $logFile
|
|
||||||
|
#to exclude all files opened by a process including the process' binary, a record must be added to both Exclusions/Paths and Exclusions/Processes configurations, see
|
||||||
|
# https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-antivirus/configure-process-opened-file-exclusions-windows-defender-antivirus :
|
||||||
|
# "When you add a process to the process exclusion list, Windows Defender Antivirus won't scan files opened by that process, no matter where the files are located. The process itself, however, will be scanned unless it has also been added to the file exclusion list.
|
||||||
|
#The exclusions only apply to always-on real-time protection and monitoring. They don't apply to scheduled or on-demand scans."
|
||||||
|
|
||||||
|
Log-Msg -msg "Updating Windows Defender real-time scan exclusions:" -logF $logFile
|
||||||
|
|
||||||
|
$itemCount = 0
|
||||||
|
|
||||||
|
#exclusions
|
||||||
|
foreach( $exclPath in $pathsToExclude ) {
|
||||||
|
$exclFiles = Get-ChildItem -Recurse -File -Path $exclPath | % { $_.FullName }
|
||||||
|
foreach ($exfile in $exclFiles) {
|
||||||
|
Log-Msg -msg " adding $exfile" -logF $logFile
|
||||||
|
Add-MpPreference -ExclusionProcess $exfile
|
||||||
|
Add-MpPreference -ExclusionPath $exfile
|
||||||
|
$itemCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
### ! better run in separate, adding files to exclusion object array from above is very inefficient (forced reallocations)
|
||||||
|
foreach ($exfile1 in $filesToExclude) {
|
||||||
|
Log-Msg -msg " adding $exfile1" -logF $logFile
|
||||||
|
Add-MpPreference -ExclusionProcess $exfile1
|
||||||
|
Add-MpPreference -ExclusionPath $exfile1
|
||||||
|
$itemCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
#inclusions
|
||||||
|
foreach( $inclPath in $pathsToInclude ) {
|
||||||
|
$inclFiles = Get-ChildItem -Recurse -File -Path $inclPath | % { $_.FullName }
|
||||||
|
foreach ($infile in $inclFiles) {
|
||||||
|
Log-Msg -msg " removing $infile" -logF $logFile
|
||||||
|
Remove-MpPreference -ExclusionProcess $infile
|
||||||
|
Remove-MpPreference -ExclusionPath $infile
|
||||||
|
$itemCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
### ! see exclusions
|
||||||
|
foreach ($infile1 in $filesToExclude) {
|
||||||
|
Log-Msg -msg " removing $infile1" -logF $logFile
|
||||||
|
Remove-MpPreference -ExclusionProcess $infile1
|
||||||
|
Remove-MpPreference -ExclusionPath $infile1
|
||||||
|
$itemCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
Log-Msg -msg "Done (processed $itemCount items)" -logF $logFile
|
||||||
|
|
||||||
|
$retVal = 0
|
||||||
|
[Environment]::Exit($retVal)
|
||||||
}
|
}
|
||||||
Catch
|
Catch
|
||||||
{
|
{
|
||||||
if( ![string]::IsNullOrEmpty($logFile) ) { Write-Error -Exception $_.Exception *>> $logFile }
|
if( ![string]::IsNullOrEmpty($logFile) ) { Write-Error -Exception $_.Exception *>> $logFile }
|
||||||
Write-Error -Exception $_.Exception
|
Write-Error -Exception $_.Exception -ErrorAction Stop
|
||||||
exit -1
|
[Environment]::Exit($retVal)
|
||||||
|
}
|
||||||
|
Finally
|
||||||
|
{
|
||||||
|
[Environment]::Exit($retVal)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user