argumentum Posted August 1 Posted August 1 am as busy as one can be. I'll look at it on Tuesday. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
sl23 Posted August 1 Author Posted August 1 No worries, thank you. I am just about to update for some fixes and improvements anyway. Thank you for checking it out. argumentum 1
sl23 Posted August 1 Author Posted August 1 (edited) New version 0.0.0.31 in last post. Fixed persistence not working correctly. Added message box for persistence with Yes or No option. Again, clicking one adds it to the White or Blacklist files. Usage at 8.3MB RAM Edited August 1 by sl23 argumentum 1
sl23 Posted August 1 Author Posted August 1 Ok I have an issue wrt the checks. I got a new alert about modified entry, but for some reason it was a long list of mods! So long that it went off the bottom of my screen! What concerns me is that first I couldn't click Yes or No as they were offscreen, but mainly and most importantly, what the hell was it? How do I know if that sort of thing is normal and that I should allow it? That's a lot of mods to allow OR deny! Must've been around 60 or more onscreen, with more below the screen. Some were drivers, some were registry, but I had to end the task as I couldn't shutdown the app. This was why I planned to keep the app simple, I'm getting into unknown territory, besides the programming I mean! I literally don't know whether those mods were safe or not. Was it windows update or something?
argumentum Posted August 2 Posted August 2 lol, good luck with that You'll see the master of the a database ( SQLite, one guy ) or the master of an editor ( Notepad++, one guy ), etc. That one guy, is into it ( whatever that is ) like no one else and, we go and use those. For you to get into what is your curiosity you'll end up becoming a master at it because there is no way around it. And to code it in AutoIt, you'll benefit from forking, and IPC, and hooking. But the title is "Learning using AI to create script" and that is what got you here. I find AutoIt beautiful, but I know how much, and how to squeeze it, to get the most of it. Yet there are those that are better than me. ( No low self esteem, just a fact ) You came with an "AI squeezer" and I guess you'll end up teaching the AI or, you'll learn yourself. All in all is a good experience for you because you really wanna have that, and that will guide you ( your drive ( if you stay driven )). So, back to coding. I'd make a main script as orchestrator and others to collect the info and give it to the orchestrator and a separate GUI with a listview with checkmarks to white list or black list. That way the orchestrator can keep on receiving events and the GUI does not slow down anything. Even the tray icon would be it's own script that would communicate with the orchestrator/main script. And yes, it may be overengineering, but is as non-blocking as possible. And you can close the Tray or the GUI and you can load them back again without loosing track of what is going on. Also, everything would be noted in SQLite. There. That is my approach to your project. Based on that I'd tell you to play around and build experience with SQLite, to find it easy to use. That in the end, is far better than ini files. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
sl23 Posted August 3 Author Posted August 3 (edited) Added GUI with checkboxes. Buttons for Select All, Unselect All, Export list (as INI), OK, Cancel. Single alerts still use the old message box format for simplicity. Fixed repeating alerts for same entries. All created files are now stored within the "Data" folder. Source now consists of two AutoIT files: StartupMonitor64.au3 and GUI.au3 StartupMonitor.au3: expandcollapse popup;***************************************** ; StartupMonitor64.au3 by sl23 ; Created with ISN AutoIt Studio v1.16 ; Compiled with AutoIt v3.3.16.1 ;***************************************** #AutoIt3Wrapper_icon=StartupMonitor.ico #AutoIt3Wrapper_Res_Fileversion_First_Increment=Y ; AutoIncrement: Before (Y); After (N) compile. Default=N #AutoIt3Wrapper_Res_FileVersion_AutoIncrement=y #AutoIt3Wrapper_Res_Fileversion=0.0.0.42 #AutoIt3Wrapper_Res_ProductVersion=3.3.16.1 #AutoIt3Wrapper_Res_Description=StartupMonitor64 #AutoIt3Wrapper_Res_LegalCopyright=sl23 ; Generated by GitHub Copilot AI: #RequireAdmin #include <MsgBoxConstants.au3> #include <File.au3> #include <TrayConstants.au3> #include <Date.au3> #include <Array.au3> #include "GUI.au3" ; ---------------------------------------------------------------------- ; Single Instance check and alert ; ---------------------------------------------------------------------- SingleInstanceForce() Func SingleInstanceForce() Local $instance = "[TITLE:" & @ScriptFullPath & ";CLASS:AutoIt v3;]" If WinExists($instance) Then MsgBox($MB_ICONERROR, "StartupMonitor64", "The application is already running." & @CRLF & "Check the tray or Task Manager." & @CRLF & @CRLF & "Click OK to close new instance...") Exit 4 EndIf AutoItWinSetTitle(@ScriptFullPath) EndFunc ; ---------------------------------------------------------------------- ; Settings and File Paths ; ---------------------------------------------------------------------- DirCreate(@ScriptDir & "\Data") Global Const $g_settingsFile = @ScriptDir & "\Data\Settings.ini" Global Const $g_logFile = @ScriptDir & "\Data\Log.ini" Global Const $g_whitelistFile = @ScriptDir & "\Data\Whitelist.ini" Global Const $g_blacklistFile = @ScriptDir & "\Data\Blacklist.ini" Global Const $g_initialStartupFile = @ScriptDir & "\Data\InitialStartupEntries.ini" Global Const $g_initialTasksFile = @ScriptDir & "\Data\InitialScheduledTasks.ini" If Not DirCreate(@ScriptDir & "\Data") Then MsgBox(16, "Error", "Could not create Data directory!") EndIf ; ---------------------------------------------------------------------- ; Create Settings File With Comments if Needed (add GUI window size settings) ; ---------------------------------------------------------------------- If Not FileExists($g_settingsFile) Then Local $hSet = FileOpen($g_settingsFile, $FO_OVERWRITE) If $hSet <> -1 Then FileWriteLine($hSet, "[Options]") FileWriteLine($hSet, "; Show tray icon in the notification area: Show (1), Hide (0)") FileWriteLine($hSet, "ShowTrayIcon=1") FileWriteLine($hSet, "; New log file on start: New (1), Keep old log (0). Entries older than 30 days will be deleted.") FileWriteLine($hSet, "ClearLogOnStart=0") FileWriteLine($hSet, "; Time in milliseconds between monitoring checks. (Minimum 1500ms / Default 3000).") FileWriteLine($hSet, "MonitorTime=3000") FileWriteLine($hSet, "; Show messagebox for auto-removed blacklist items: Enable (1), Disable (0)") FileWriteLine($hSet, "ShowBlacklistMsgBox=1") FileWriteLine($hSet, "; Save/load persistent baseline snapshot of startup entries and scheduled tasks: Enable (1), Disable (0)") FileWriteLine($hSet, "PersistentBaseline=1") FileWriteLine($hSet, "; Monitor scheduled tasks: Enable (1), Disable (0)") FileWriteLine($hSet, "MonitorTasks=1") FileWriteLine($hSet, "") FileWriteLine($hSet, "[GUI]") FileWriteLine($hSet, "; Review Window Width (pixels). Default 500.") FileWriteLine($hSet, "ReviewWindowWidth=500") FileWriteLine($hSet, "; Review Window Height (pixels). Default 400.") FileWriteLine($hSet, "ReviewWindowHeight=400") FileWriteLine($hSet, "") FileWriteLine($hSet, "[ExtraStartupChecks]") FileWriteLine($hSet, "; Enable (1) or disable (0) each extra startup location.") FileWriteLine($hSet, "HKCU_RunOnce=1") FileWriteLine($hSet, "HKLM_RunOnce=1") FileWriteLine($hSet, "HKCU_Explorer_UserShellFolders=1") FileWriteLine($hSet, "HKCU_Explorer_ShellFolders=1") FileWriteLine($hSet, "HKLM_Explorer_ShellFolders=1") FileWriteLine($hSet, "HKLM_Explorer_UserShellFolders=1") FileWriteLine($hSet, "HKLM_RunServicesOnce=1") FileWriteLine($hSet, "HKCU_RunServicesOnce=1") FileWriteLine($hSet, "HKLM_RunServices=1") FileWriteLine($hSet, "HKCU_RunServices=1") FileWriteLine($hSet, "HKLM_Policies_Explorer_Run=1") FileWriteLine($hSet, "HKCU_Policies_Explorer_Run=1") FileWriteLine($hSet, "HKLM_Winlogon_Userinit=1") FileWriteLine($hSet, "HKLM_Winlogon_Shell=1") FileWriteLine($hSet, "HKCU_Windows=1") FileWriteLine($hSet, "HKLM_SessionManager=1") FileClose($hSet) EndIf EndIf ; ---------------------------------------------------------------------- ; Create Whitelist File if Needed ; ---------------------------------------------------------------------- If Not FileExists($g_whitelistFile) Then Local $hWhite = FileOpen($g_whitelistFile, $FO_OVERWRITE) If $hWhite <> -1 Then FileWriteLine($hWhite, "; Whitelisted startup/task entries for StartupMonitor64") FileClose($hWhite) EndIf EndIf ; ---------------------------------------------------------------------- ; Create Blacklist File if Needed ; ---------------------------------------------------------------------- If Not FileExists($g_blacklistFile) Then Local $hBlack = FileOpen($g_blacklistFile, $FO_OVERWRITE) If $hBlack <> -1 Then FileWriteLine($hBlack, "; Blacklisted startup/task entries for StartupMonitor64") FileWriteLine($hBlack, "; Add entries under [Startup] or [Task] sections, one per line as a key (value can be left blank)") FileWriteLine($hBlack, "[Startup]") FileWriteLine($hBlack, ";Example: badprogram.exe") FileWriteLine($hBlack, "[Task]") FileWriteLine($hBlack, ";Example: bad task name") FileClose($hBlack) EndIf EndIf ; ---------------------------------------------------------------------- ; Read Settings ; ---------------------------------------------------------------------- Global $g_showTray = IniRead($g_settingsFile, "Options", "ShowTrayIcon", "1") Global $g_clearLog = IniRead($g_settingsFile, "Options", "ClearLogOnStart", "0") Global $g_monitorInterval = IniRead($g_settingsFile, "Options", "MonitorTime", "3000") Global $g_showBlacklistMsgBox = IniRead($g_settingsFile, "Options", "ShowBlacklistMsgBox", "1") Global $g_persistentBaseline = IniRead($g_settingsFile, "Options", "PersistentBaseline", "1") Global $g_monitorTasks = IniRead($g_settingsFile, "Options", "MonitorTasks", "1") Global $g_reviewWindowWidth = Number(IniRead($g_settingsFile, "Options", "ReviewWindowWidth", "500")) Global $g_reviewWindowHeight = Number(IniRead($g_settingsFile, "Options", "ReviewWindowHeight", "400")) If Number($g_monitorInterval) < 1500 Then $g_monitorInterval = 1500 If $g_reviewWindowWidth < 300 Then $g_reviewWindowWidth = 500 If $g_reviewWindowHeight < 200 Then $g_reviewWindowHeight = 400 ; Read Extra Checks Global $g_extraChecks = [ _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKCU_RunOnce", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKLM_RunOnce", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKCU_Explorer_UserShellFolders", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKCU_Explorer_ShellFolders", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKLM_Explorer_ShellFolders", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKLM_Explorer_UserShellFolders", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKLM_RunServicesOnce", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKCU_RunServicesOnce", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKLM_RunServices", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKCU_RunServices", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKLM_Policies_Explorer_Run", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKCU_Policies_Explorer_Run", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKLM_Winlogon_Userinit", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKLM_Winlogon_Shell", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKCU_Windows", "1"), _ IniRead($g_settingsFile, "ExtraStartupChecks", "HKLM_SessionManager", "1") _ ] ; ---------------------------------------------------------------------- ; Tray Icon Handling ; ---------------------------------------------------------------------- If $g_showTray = "1" Then TraySetState($TRAY_ICONSTATE_SHOW) Else TraySetState($TRAY_ICONSTATE_HIDE) EndIf ; ---------------------------------------------------------------------- ; Clear Log if Setting Enabled ; ---------------------------------------------------------------------- If $g_clearLog = "1" Then If FileExists($g_logFile) Then FileDelete($g_logFile) EndIf ; ---------------------------------------------------------------------- ; Prune Old Log Entries (Older than 30 days) ; ---------------------------------------------------------------------- _PruneOldLogEntries_LineByLine() ; ---------------------------------------------------------------------- ; Log program start with current tray status ; ---------------------------------------------------------------------- _LogWrite("Startup Monitor started. Tray icon is " & ($g_showTray = "1" ? "visible." : "hidden.")) ; ---------------------------------------------------------------------- ; Persistent Baseline Snapshot Management ; ---------------------------------------------------------------------- Global $g_initialEntries, $g_initialTasks If $g_persistentBaseline = "1" Then ; -- Startup Entries Baseline -- If FileExists($g_initialStartupFile) Then $g_initialEntries = _LoadSnapshotEntries($g_initialStartupFile) Else $g_initialEntries = _GetAllStartupEntries_Map(True) _SaveSnapshotEntries($g_initialEntries, $g_initialStartupFile) EndIf ; -- Scheduled Tasks Baseline -- If $g_monitorTasks = "1" Then If FileExists($g_initialTasksFile) Then $g_initialTasks = _LoadSnapshotEntries($g_initialTasksFile) Else $g_initialTasks = _GetAllScheduledTasks_Map(True) _SaveSnapshotEntries($g_initialTasks, $g_initialTasksFile) EndIf EndIf EndIf ; ---------------------------------------------------------------------- ; Get Initial Startup Entries and Scheduled Tasks (with metadata) ; ---------------------------------------------------------------------- Global $g_oldEntries = _GetAllStartupEntries_Map(True) Global $g_oldTasks If $g_monitorTasks = "1" Then $g_oldTasks = _GetAllScheduledTasks_Map(True) EndIf ; ---------------------------------------------------------------------- ; Baseline diff detection on startup (immediate detection of changes made while not running) ; ---------------------------------------------------------------------- If $g_persistentBaseline = "1" Then _ReportBaselineDiff("Startup", $g_initialEntries, $g_oldEntries) If $g_monitorTasks = "1" Then _ReportBaselineDiff("Task", $g_initialTasks, $g_oldTasks) EndIf EndIf ; ---------------------------------------------------------------------- ; Main Monitoring Loop ; ---------------------------------------------------------------------- While 1 Sleep(Number($g_monitorInterval)) ; --- Startup Entries Monitoring --- Local $newEntries = _GetAllStartupEntries_Map(True) _CheckAndHandleChanges("Startup", $g_oldEntries, $newEntries) If $g_persistentBaseline = "1" Then _ReportBaselineDiff("Startup", $g_initialEntries, $newEntries) EndIf ; Update the old entries after any removals (to avoid repeated alerts) $g_oldEntries = $newEntries ; --- Scheduled Tasks Monitoring --- If $g_monitorTasks = "1" Then Local $newTasks = _GetAllScheduledTasks_Map(True) _CheckAndHandleChanges("Task", $g_oldTasks, $newTasks) If $g_persistentBaseline = "1" Then _ReportBaselineDiff("Task", $g_initialTasks, $newTasks) EndIf ; Update the old tasks after any removals (to avoid repeated alerts) $g_oldTasks = $newTasks EndIf WEnd ; ------------------------------------------------------------------------------ ; Persistent Baseline: Save and Load (for both startup and tasks) ; ------------------------------------------------------------------------------ Func _SaveSnapshotEntries($dict, $file) Local $h = FileOpen($file, $FO_OVERWRITE) If $h = -1 Then Return For $key In $dict.Keys Local $val = $dict.Item($key) FileWriteLine($h, $key & "=" & $val[0]) Next FileClose($h) EndFunc Func _LoadSnapshotEntries($file) Local $dict = ObjCreate("Scripting.Dictionary") If Not FileExists($file) Then Return $dict Local $arr = FileReadToArray($file) If @error Then Return $dict For $i = 0 To UBound($arr)-1 Local $line = $arr[$i] If StringLeft($line, 1) = ";" Or StringStripWS($line, 8) = "" Then ContinueLoop Local $parts = StringSplit($line, "=", 2) If UBound($parts) = 2 Then Local $key = $parts[0] Local $val = $parts[1] Local $meta[2] $meta[0] = $val $meta[1] = _StringHash($val) $dict.Add($key, $meta) EndIf Next Return $dict EndFunc ; ------------------------------------------------------------------------------ ; PATCHED _ReportBaselineDiff to prevent repeating alert for removed entries ; ------------------------------------------------------------------------------ Func _ReportBaselineDiff($type, $baseline, $current) Local $added = _MapDiff($current, $baseline) Local $removed = _MapDiff($baseline, $current) ; Track processed items to show each only once Local $processed = ObjCreate("Scripting.Dictionary") ; Handle "added" entries (present now but not in baseline) For $key In $added.Keys If $processed.Exists($key) Then ContinueLoop Local $meta = $current.Item($key) Local $target = $meta[0] Local $programName = _ExtractProgramName($target) Local $msg = "*** New " & ($type = "Startup" ? "startup entry" : "scheduled task") & " detected since original baseline! ***" & @CRLF & @CRLF & _ "- Program Name: " & @CRLF & $programName & @CRLF & @CRLF & _ "- " & ($type = "Startup" ? "Startup Location" : "Task File Path") & ": " & @CRLF & $key & @CRLF & @CRLF & _ "- " & ($type = "Startup" ? "Startup Target" : "Task Action") & ": " & @CRLF & $target & @CRLF & @CRLF & _ "- Do you wish to allow this change?" Local $response = MsgBox($MB_ICONWARNING + $MB_YESNO + $MB_TOPMOST, "StartupMonitor64: Baseline Difference", $msg) If $response = $IDNO Then _LogWrite("User denied baseline-detected " & ($type = "Startup" ? "entry" : "scheduled task") & ", removing: " & $key & " | Target: " & $target) _AddToBlackList($type, $key, $target) If $type = "Startup" Then _RemoveStartupEntry($key) ElseIf $type = "Task" Then _RemoveScheduledTask($key) EndIf ; Remove from current set to avoid repeated alerts If IsObj($current) And $current.Exists($key) Then $current.Remove($key) Else _LogWrite("User allowed baseline-detected " & ($type = "Startup" ? "entry" : "scheduled task") & ": " & $key & " | Target: " & $target) _AddToWhiteList($type, $key, $target) ; PATCH: Prevent repeated alerts by adding this entry to $baseline If IsObj($baseline) And Not $baseline.Exists($key) Then Local $metaArr[2] $metaArr[0] = $target $metaArr[1] = $meta[1] $baseline.Add($key, $metaArr) EndIf EndIf $processed.Add($key, True) Next ; Handle "removed" entries (present in baseline but missing now) ; PATCH: Prevent repeated alerts by restoring the entry to $current if No is selected For $key In $removed.Keys If $processed.Exists($key) Then ContinueLoop Local $meta = $baseline.Item($key) Local $target = $meta[0] Local $programName = _ExtractProgramName($target) Local $msg = "*** " & ($type = "Startup" ? "Startup entry" : "Scheduled task") & " REMOVED since original baseline! ***" & @CRLF & @CRLF & _ "- Program Name: " & @CRLF & $programName & @CRLF & @CRLF & _ "- " & ($type = "Startup" ? "Startup Location" : "Task File Path") & ": " & @CRLF & $key & @CRLF & @CRLF & _ "- " & ($type = "Startup" ? "Startup Target" : "Task Action") & ": " & @CRLF & $target & @CRLF & @CRLF & _ "- Do you wish to allow this removal?" & @CRLF & "(No = blacklist it from being deleted in future)" Local $response = MsgBox($MB_ICONWARNING + $MB_YESNO + $MB_TOPMOST, "StartupMonitor64: Baseline Removal", $msg) If $response = $IDNO Then _LogWrite("User denied REMOVAL of baseline " & ($type = "Startup" ? "entry" : "scheduled task") & ": " & $key & " | Target: " & $target) _AddToBlackList($type, $key, $target) ; PATCH: Prevent repeated alerts by restoring this entry to $current If IsObj($current) And Not $current.Exists($key) Then Local $metaArr[2] $metaArr[0] = $target $metaArr[1] = $meta[1] $current.Add($key, $metaArr) EndIf Else _LogWrite("User allowed removal of baseline " & ($type = "Startup" ? "entry" : "scheduled task") & ": " & $key & " | Target: " & $target) _AddToWhiteList($type, $key, $target) EndIf $processed.Add($key, True) Next EndFunc ; ------------------------------------------------------------------------------ ; _CheckAndHandleChanges: Adds to Blacklist/Whitelist automatically, shows msgbox for blacklist if enabled. ; Uses MsgBox for single entries, GUI review window for multiples, and passes window size from settings. ; ------------------------------------------------------------------------------ Func _CheckAndHandleChanges($type, $oldDict, ByRef $newDict) Local $processed = ObjCreate("Scripting.Dictionary") ; Detect additions Local $added = _MapDiff($newDict, $oldDict) Local $aReviewEntries[0][3], $reviewCount = 0 For $entry In $added.Keys If $processed.Exists($entry) Then ContinueLoop Local $meta = $newDict.Item($entry) Local $target = $meta[0] Local $programName = _ExtractProgramName($target) ; --- Blacklist check --- If _IsBlackListed($type, $entry, $target) Then If $g_showBlacklistMsgBox = "1" Then Local $alertMsg = "*** BLACKLISTED " & ($type = "Startup" ? "startup entry" : "scheduled task") & " auto-removed! ***" & @CRLF & @CRLF & _ "- Program Name: " & @CRLF & $programName & @CRLF & @CRLF & _ "- " & ($type = "Startup" ? "Startup Location" : "Task File Path") & ": " & @CRLF & $entry & @CRLF & @CRLF & _ "- " & ($type = "Startup" ? "Startup Target" : "Task Action") & ": " & @CRLF & $target MsgBox($MB_ICONWARNING + $MB_TOPMOST, "StartupMonitor64: Blacklist", $alertMsg) EndIf _LogWrite("BLACKLISTED " & ($type = "Startup" ? "entry" : "scheduled task") & ", auto-removing: " & $entry & " | Target: " & $target) If $type = "Startup" Then _RemoveStartupEntry($entry) ElseIf $type = "Task" Then _RemoveScheduledTask($entry) EndIf $processed.Add($entry, True) If IsObj($newDict) And $newDict.Exists($entry) Then $newDict.Remove($entry) ContinueLoop EndIf ; --- Whitelist check --- If _IsWhiteListed($type, $entry, $target) Then ContinueLoop ; --- Add to review batch instead of prompting immediately --- ReDim $aReviewEntries[$reviewCount + 1][3] $aReviewEntries[$reviewCount][0] = $programName $aReviewEntries[$reviewCount][1] = $entry $aReviewEntries[$reviewCount][2] = $target $reviewCount += 1 Next ; Detect modifications (silent for whitelisted, prompt for others) Local $modified = _MapModified($newDict, $oldDict) Local $aReviewModified[0][3], $reviewModCount = 0 For $entry In $modified.Keys If $processed.Exists($entry) Then ContinueLoop Local $meta = $newDict.Item($entry) Local $target = $meta[0] Local $programName = _ExtractProgramName($target) ; --- Blacklist check --- If _IsBlackListed($type, $entry, $target) Then If $g_showBlacklistMsgBox = "1" Then Local $alertMsg = "*** BLACKLISTED MODIFIED " & ($type = "Startup" ? "startup entry" : "scheduled task") & " auto-removed! ***" & @CRLF & @CRLF & _ "- Program Name: " & @CRLF & $programName & @CRLF & @CRLF & _ "- " & ($type = "Startup" ? "Startup Location" : "Task File Path") & ": " & @CRLF & $entry & @CRLF & @CRLF & _ "- " & ($type = "Startup" ? "Startup Target" : "Task Action") & ": " & @CRLF & $target MsgBox($MB_ICONWARNING + $MB_TOPMOST, "StartupMonitor64: Blacklist", $alertMsg) EndIf _LogWrite("BLACKLISTED MODIFIED " & ($type = "Startup" ? "entry" : "scheduled task") & ", auto-removing: " & $entry & " | Target: " & $target) If $type = "Startup" Then _RemoveStartupEntry($entry) ElseIf $type = "Task" Then _RemoveScheduledTask($entry) EndIf $processed.Add($entry, True) If IsObj($newDict) And $newDict.Exists($entry) Then $newDict.Remove($entry) ContinueLoop EndIf ; --- Whitelist check --- If _IsWhiteListed($type, $entry, $target) Then ContinueLoop ; --- Add to review batch instead of prompting immediately --- ReDim $aReviewModified[$reviewModCount + 1][3] $aReviewModified[$reviewModCount][0] = $programName & " (MODIFIED)" $aReviewModified[$reviewModCount][1] = $entry $aReviewModified[$reviewModCount][2] = $target $reviewModCount += 1 Next ; --- Batch review window or MsgBox for new entries --- If $reviewCount = 1 Then ; Only one item - use MsgBox Local $desc = $aReviewEntries[0][0] Local $entryKey = $aReviewEntries[0][1] Local $target = $aReviewEntries[0][2] Local $msg = "*** " & ($type = "Startup" ? "Startup entry" : "Scheduled task") & " detected ***" & @CRLF & _ "- Program Name: " & $desc & @CRLF & _ "- Location/Key: " & $entryKey & @CRLF & _ "- Target: " & $target & @CRLF & _ "- Allow this entry?" Local $response = MsgBox($MB_ICONWARNING + $MB_YESNO + $MB_TOPMOST, "StartupMonitor64", $msg) If $response = $IDYES Then _LogWrite("User allowed new " & ($type = "Startup" ? "entry" : "scheduled task") & ": " & $entryKey & " | Target: " & $target) _AddToWhiteList($type, $entryKey, $target) Else _LogWrite("User denied new " & ($type = "Startup" ? "entry" : "scheduled task") & ", removing: " & $entryKey & " | Target: " & $target) _AddToBlackList($type, $entryKey, $target) If $type = "Startup" Then _RemoveStartupEntry($entryKey) ElseIf $type = "Task" Then _RemoveScheduledTask($entryKey) EndIf If IsObj($newDict) And $newDict.Exists($entryKey) Then $newDict.Remove($entryKey) EndIf ElseIf $reviewCount > 1 Then ; Multiple items - show review window with settings size Local $reviewTitle = "Review new " & ($type = "Startup" ? "startup entries" : "scheduled tasks") Local $aResults = ShowReviewWindow($aReviewEntries, $reviewTitle, $g_reviewWindowWidth, $g_reviewWindowHeight) For $i = 0 To UBound($aResults) - 1 If $aResults[$i][0] = 1 Then ; Allowed _LogWrite("User allowed new " & ($type = "Startup" ? "entry" : "scheduled task") & ": " & $aResults[$i][1] & " | Target: " & $aResults[$i][2]) _AddToWhiteList($type, $aResults[$i][1], $aResults[$i][2]) ElseIf $aResults[$i][0] = 0 Then ; Denied _LogWrite("User denied new " & ($type = "Startup" ? "entry" : "scheduled task") & ", removing: " & $aResults[$i][1] & " | Target: " & $aResults[$i][2]) _AddToBlackList($type, $aResults[$i][1], $aResults[$i][2]) If $type = "Startup" Then _RemoveStartupEntry($aResults[$i][1]) ElseIf $type = "Task" Then _RemoveScheduledTask($aResults[$i][1]) EndIf If IsObj($newDict) And $newDict.Exists($aResults[$i][1]) Then $newDict.Remove($aResults[$i][1]) EndIf Next EndIf ; --- Batch review window or MsgBox for modified entries --- If $reviewModCount = 1 Then ; Only one modified entry - use MsgBox Local $desc = $aReviewModified[0][0] Local $entryKey = $aReviewModified[0][1] Local $target = $aReviewModified[0][2] Local $msg = "*** " & ($type = "Startup" ? "Startup entry" : "Scheduled task") & " MODIFIED ***" & @CRLF & _ "- Program Name: " & $desc & @CRLF & _ "- Location/Key: " & $entryKey & @CRLF & _ "- Target: " & $target & @CRLF & _ "- Allow this MODIFIED entry?" Local $response = MsgBox($MB_ICONWARNING + $MB_YESNO + $MB_TOPMOST, "StartupMonitor64", $msg) If $response = $IDYES Then _LogWrite("User allowed MODIFIED " & ($type = "Startup" ? "entry" : "scheduled task") & ": " & $entryKey & " | Target: " & $target) _AddToWhiteList($type, $entryKey, $target) Else _LogWrite("User denied MODIFIED " & ($type = "Startup" ? "entry" : "scheduled task") & ", removing: " & $entryKey & " | Target: " & $target) _AddToBlackList($type, $entryKey, $target) If $type = "Startup" Then _RemoveStartupEntry($entryKey) ElseIf $type = "Task" Then _RemoveScheduledTask($entryKey) EndIf If IsObj($newDict) And $newDict.Exists($entryKey) Then $newDict.Remove($entryKey) EndIf ElseIf $reviewModCount > 1 Then ; Multiple items - show review window with settings size Local $reviewTitle = "Review MODIFIED " & ($type = "Startup" ? "startup entries" : "scheduled tasks") Local $aResults = ShowReviewWindow($aReviewModified, $reviewTitle, $g_reviewWindowWidth, $g_reviewWindowHeight) For $i = 0 To UBound($aResults) - 1 If $aResults[$i][0] = 1 Then ; Allowed _LogWrite("User allowed MODIFIED " & ($type = "Startup" ? "entry" : "scheduled task") & ": " & $aResults[$i][1] & " | Target: " & $aResults[$i][2]) _AddToWhiteList($type, $aResults[$i][1], $aResults[$i][2]) ElseIf $aResults[$i][0] = 0 Then ; Denied _LogWrite("User denied MODIFIED " & ($type = "Startup" ? "entry" : "scheduled task") & ", removing: " & $aResults[$i][1] & " | Target: " & $aResults[$i][2]) _AddToBlackList($type, $aResults[$i][1], $aResults[$i][2]) If $type = "Startup" Then _RemoveStartupEntry($aResults[$i][1]) ElseIf $type = "Task" Then _RemoveScheduledTask($aResults[$i][1]) EndIf If IsObj($newDict) And $newDict.Exists($aResults[$i][1]) Then $newDict.Remove($aResults[$i][1]) EndIf Next EndIf EndFunc ; ------------------------------------------------------------------------------ ; _GetAllStartupEntries_Map: Collect all current startup entries from registry ; and startup folders, and from optionally enabled extra registry locations ; Returns a dictionary of [entry_path] = [value, hash] ; If $withMeta is true, stores an array: [command/value, timestamp/hash] ; ------------------------------------------------------------------------------ Func _GetAllStartupEntries_Map($withMeta=False) Local $dict = ObjCreate("Scripting.Dictionary") _GetRegEntries_Map("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", $dict, $withMeta) _GetRegEntries_Map("HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", $dict, $withMeta) _GetFolderEntries_Map(@StartupDir, $dict, False, $withMeta) _GetFolderEntries_Map(@StartupCommonDir, $dict, False, $withMeta) ; Extra locations If $g_extraChecks[0] = "1" Then _GetRegEntries_Map("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce", $dict, $withMeta) If $g_extraChecks[1] = "1" Then _GetRegEntries_Map("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce", $dict, $withMeta) If $g_extraChecks[2] = "1" Then _GetRegEntries_Map("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders", $dict, $withMeta) If $g_extraChecks[3] = "1" Then _GetRegEntries_Map("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", $dict, $withMeta) If $g_extraChecks[4] = "1" Then _GetRegEntries_Map("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", $dict, $withMeta) If $g_extraChecks[5] = "1" Then _GetRegEntries_Map("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders", $dict, $withMeta) If $g_extraChecks[6] = "1" Then _GetRegEntries_Map("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce", $dict, $withMeta) If $g_extraChecks[7] = "1" Then _GetRegEntries_Map("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce", $dict, $withMeta) If $g_extraChecks[8] = "1" Then _GetRegEntries_Map("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices", $dict, $withMeta) If $g_extraChecks[9] = "1" Then _GetRegEntries_Map("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices", $dict, $withMeta) If $g_extraChecks[10] = "1" Then _GetRegEntries_Map("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run", $dict, $withMeta) If $g_extraChecks[11] = "1" Then _GetRegEntries_Map("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run", $dict, $withMeta) If $g_extraChecks[12] = "1" Then _GetRegEntries_Map("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit", $dict, $withMeta) If $g_extraChecks[13] = "1" Then _GetRegEntries_Map("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell", $dict, $withMeta) If $g_extraChecks[14] = "1" Then _GetRegEntries_Map("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows", $dict, $withMeta) If $g_extraChecks[15] = "1" Then _GetRegEntries_Map("HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager", $dict, $withMeta) Return $dict EndFunc ; ------------------------------------------------------------------------------ ; _GetRegEntries_Map: Adds value names & content from registry key to the map ; ------------------------------------------------------------------------------ Func _GetRegEntries_Map($key, ByRef $dict, $withMeta=False) Local $i = 1, $val, $v While 1 $val = RegEnumVal($key, $i) If @error Then ExitLoop $v = RegRead($key, $val) If $withMeta Then Local $arr[2] $arr[0] = $v $arr[1] = _StringHash($v) $dict.Add($key & "\" & $val, $arr) Else $dict.Add($key & "\" & $val, $v) EndIf $i += 1 WEnd EndFunc ; ------------------------------------------------------------------------------ ; _GetFolderEntries_Map: Adds all file names (and hash/mtime) from folder to map ; ------------------------------------------------------------------------------ Func _GetFolderEntries_Map($folder, ByRef $dict, $recursive=False, $withMeta=False) Local $search = FileFindFirstFile($folder & "\*") If $search = -1 Then Return While 1 Local $file = FileFindNextFile($search) If @error Then ExitLoop If @extended = 1 Then ; Folder If $recursive Then _GetFolderEntries_Map($folder & "\" & $file, $dict, $recursive, $withMeta) Else Local $path = $folder & "\" & $file If $withMeta Then Local $hash = "" If StringRight($file, 4) = ".lnk" Then $hash = _StringHash(_GetShortcutTarget($path)) Else $hash = FileGetTime($path, 0, 1) ; last write time EndIf Local $arr[2] $arr[0] = $path $arr[1] = $hash $dict.Add($path, $arr) Else $dict.Add($path, $path) EndIf EndIf WEnd FileClose($search) EndFunc ; ------------------------------------------------------------------------------ ; _GetAllScheduledTasks_Map: Collects all current scheduled tasks (recursively) ; Returns a dictionary of [taskfile_path] = [command, hash] ; ------------------------------------------------------------------------------ Func _GetAllScheduledTasks_Map($withMeta=False) Local $dict = ObjCreate("Scripting.Dictionary") _GetFolderEntries_Map("C:\Windows\System32\Tasks", $dict, True, $withMeta) If $withMeta Then For $k In $dict.Keys Local $command = _GetTaskAction($k) Local $arr[2] $arr[0] = $command $arr[1] = _StringHash($command) $dict.Item($k) = $arr Next EndIf Return $dict EndFunc ; ------------------------------------------------------------------------------ ; _MapDiff: Returns keys in dictA not present in dictB as a new map (dictionary) ; ------------------------------------------------------------------------------ Func _MapDiff($dictA, $dictB) Local $diff = ObjCreate("Scripting.Dictionary") For $key In $dictA.Keys If Not $dictB.Exists($key) Then $diff.Add($key, $dictA.Item($key)) Next Return $diff EndFunc ; ------------------------------------------------------------------------------ ; _MapModified: Returns keys in dictA and dictB that have different values/hashes ; ------------------------------------------------------------------------------ Func _MapModified($dictA, $dictB) Local $diff = ObjCreate("Scripting.Dictionary") For $key In $dictA.Keys If $dictB.Exists($key) Then If $dictA.Item($key)[1] <> $dictB.Item($key)[1] Then $diff.Add($key, $dictA.Item($key)) EndIf Next Return $diff EndFunc ; ------------------------------------------------------------------------------ ; Blacklist Management: Add and Check ; ------------------------------------------------------------------------------ Func _IsBlackListed($type, $entry, $target) Local $section = $type Local $arr = IniReadSection($g_blacklistFile, $section) If @error Then Return False For $i = 1 To $arr[0][0] Local $black = $arr[$i][0] If $black = "" Or StringLeft($black, 1) = ";" Then ContinueLoop If StringInStr($entry, $black, 0) Or StringInStr($target, $black, 0) Then Return True Next Return False EndFunc Func _AddToBlackList($type, $entry, $target) If Not _IsBlackListed($type, $entry, $target) Then IniWrite($g_blacklistFile, $type, $entry, $target) EndIf EndFunc ; ------------------------------------------------------------------------------ ; Whitelist Management: Add and Check ; ------------------------------------------------------------------------------ Func _AddToWhiteList($type, $entry, $target) If Not _IsWhiteListed($type, $entry, $target) Then IniWrite($g_whitelistFile, $type, $entry, $target) EndIf EndFunc Func _IsWhiteListed($type, $entry, $target) Local $val = IniRead($g_whitelistFile, $type, $entry, "") Return $val = $target EndFunc ; ------------------------------------------------------------------------------ ; _RemoveStartupEntry: Removes the specified startup entry from registry or folder ; ------------------------------------------------------------------------------ Func _RemoveStartupEntry($entry) If StringLeft($entry, 18) = "HKEY_LOCAL_MACHINE" Then Local $remain = StringTrimLeft($entry, 19) Local $lastSep = StringInStr($remain, "\", 0, -1) Local $key = "HKEY_LOCAL_MACHINE\" & StringLeft($remain, $lastSep - 1) Local $val = StringTrimLeft($remain, $lastSep) RegDelete($key, $val) ElseIf StringLeft($entry, 17) = "HKEY_CURRENT_USER" Then Local $remain = StringTrimLeft($entry, 18) Local $lastSep = StringInStr($remain, "\", 0, -1) Local $key = "HKEY_CURRENT_USER\" & StringLeft($remain, $lastSep - 1) Local $val = StringTrimLeft($remain, $lastSep) RegDelete($key, $val) Else FileDelete($entry) EndIf EndFunc ; ------------------------------------------------------------------------------ ; _RemoveScheduledTask: Safely removes scheduled tasks using schtasks.exe ; ------------------------------------------------------------------------------ Func _RemoveScheduledTask($entry) Local $taskRoot = "C:\Windows\System32\Tasks" If StringLeft($entry, StringLen($taskRoot)) = $taskRoot Then Local $rel = StringTrimLeft($entry, StringLen($taskRoot)) If StringLeft($rel, 1) = "\" Then $rel = StringTrimLeft($rel, 1) $rel = StringReplace($rel, "/", "\") Local $cmd = 'schtasks /Delete /TN "' & $rel & '" /F' RunWait(@ComSpec & " /c " & $cmd, "", @SW_HIDE) EndIf EndFunc ; ------------------------------------------------------------------------------ ; _LogWrite: Appends a timestamped line to the log file, with '=' as separator ; ------------------------------------------------------------------------------ Func _LogWrite($sText) Local $hFile = FileOpen($g_logFile, $FO_APPEND) If $hFile = -1 Then Return FileWriteLine($hFile, @YEAR & "-" & @MON & "-" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & " = " & $sText) FileClose($hFile) EndFunc ; ------------------------------------------------------------------------------ ; _PruneOldLogEntries_LineByLine: Keeps only log entries from the last 30 days ; ------------------------------------------------------------------------------ Func _PruneOldLogEntries_LineByLine() If Not FileExists($g_logFile) Then Return Local $nowTS = _DateToTS(@YEAR & "-" & @MON & "-" & @MDAY) Local $tempFile = @ScriptDir & "\_tmp_log.txt" Local $rfh = FileOpen($g_logFile, $FO_READ) If $rfh = -1 Then Return Local $wfh = FileOpen($tempFile, $FO_OVERWRITE) If $wfh = -1 Then FileClose($rfh) Return EndIf While 1 Local $line = FileReadLine($rfh) If @error Then ExitLoop Local $dateStr = StringLeft($line, 10) If StringRegExp($dateStr, "^\d{4}-\d{2}-\d{2}$") Then Local $lineTS = _DateToTS($dateStr) If $nowTS - $lineTS <= 2592000 Then FileWriteLine($wfh, $line) EndIf Else FileWriteLine($wfh, $line) EndIf WEnd FileClose($rfh) FileClose($wfh) FileDelete($g_logFile) FileMove($tempFile, $g_logFile, 1) EndFunc ; ------------------------------------------------------------------------------ ; _DateToTS: Convert YYYY-MM-DD to timestamp (seconds since epoch) ; ------------------------------------------------------------------------------ Func _DateToTS($sDate) Local $a = StringSplit($sDate, "-") If $a[0] <> 3 Then Return 0 Return _DateDiff("s", "1970/01/01 00:00:00", $a[1] & "/" & $a[2] & "/" & $a[3] & " 00:00:00") EndFunc ; ------------------------------------------------------------------------------ ; _GetStartupEntryTarget: Gets the command/target for a startup entry (reg/file) ; ------------------------------------------------------------------------------ Func _GetStartupEntryTarget($entry) If StringLeft($entry, 18) = "HKEY_LOCAL_MACHINE" Or StringLeft($entry, 17) = "HKEY_CURRENT_USER" Then Local $remain = StringInStr($entry, "\", 0, -1) If $remain = 0 Then Return "" Local $key = StringLeft($entry, $remain - 1) Local $val = StringTrimLeft($entry, $remain) Return RegRead($key, $val) Else If StringRight($entry, 4) = ".lnk" Then Return _GetShortcutTarget($entry) Else Return $entry EndIf EndIf EndFunc ; ------------------------------------------------------------------------------ ; _GetShortcutTarget: Get target path from a Windows shortcut (.lnk) ; ------------------------------------------------------------------------------ Func _GetShortcutTarget($lnkFile) Local $objShell = ObjCreate("WScript.Shell") If Not IsObj($objShell) Then Return "" Local $objShortcut = $objShell.CreateShortcut($lnkFile) If Not IsObj($objShortcut) Then Return "" Return $objShortcut.TargetPath EndFunc ; ------------------------------------------------------------------------------ ; _ExtractProgramName: Extracts program name from a command/target path ; ------------------------------------------------------------------------------ Func _ExtractProgramName($target) If $target = "" Then Return "" Local $re = StringRegExp($target, '[^\\\/]+\.exe', 1) If IsArray($re) Then Return $re[UBound($re) - 1] EndIf Local $lastSlash = StringInStr($target, "\", 0, -1) If $lastSlash > 0 Then Return StringTrimLeft($target, $lastSlash) EndIf Return $target EndFunc ; ------------------------------------------------------------------------------ ; _GetTaskAction: Extracts the "Action" (target) from a Scheduled Task XML file ; ------------------------------------------------------------------------------ Func _GetTaskAction($taskPath) Local $xml = FileRead($taskPath) If @error Or $xml = "" Then Return "" Local $re = StringRegExp($xml, "<Command>(.*?)</Command>", 1) If IsArray($re) Then Return $re[0] EndIf Return "" EndFunc ; ------------------------------------------------------------------------------ ; _StringHash: Returns a simple hash of a string (for change detection, not crypto) ; ------------------------------------------------------------------------------ Func _StringHash($s) Local $i, $h = 0 For $i = 1 To StringLen($s) $h = BitXOR($h, Asc(StringMid($s, $i, 1))) $h = BitAND($h * 31, 0xFFFFFFFF) Next Return $h EndFunc GUI.au3: expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <GuiListView.au3> #include <Array.au3> #include <WinAPI.au3> #include <File.au3> #include <Date.au3> #include <StaticConstants.au3> Func ShowReviewWindow(ByRef $aEntries, $sTitle = "Review Startup/Task Entries", $width = 500, $height = 400) Local $iRows = UBound($aEntries, 1) If $iRows < 1 Then Return SetError(1, 0, 0) Local $iCols = UBound($aEntries, 2) If $iCols < 2 Then $iCols = 2 Local $aResults[$iRows][3 + ($iCols > 2 ? $iCols - 2 : 0)] ; GUI Create Local $hGUI = GUICreate($sTitle, $width, $height, -1, -1, $WS_CAPTION + $WS_SYSMENU, $WS_EX_TOPMOST) ; ListView Local $lvWidth = $width - 20 Local $lvHeight = $height - 120 Local $idListView = GUICtrlCreateListView("Allow|Entry|Location", 10, 10, $lvWidth, $lvHeight, _ BitOR($LVS_REPORT, $LVS_SHOWSELALWAYS, $WS_HSCROLL, $WS_VSCROLL)) _GUICtrlListView_SetExtendedListViewStyle($idListView, BitOR($LVS_EX_CHECKBOXES, $LVS_EX_FULLROWSELECT, $LVS_EX_GRIDLINES)) _GUICtrlListView_SetColumnWidth($idListView, 0, 45) _GUICtrlListView_SetColumnWidth($idListView, 1, 230) _GUICtrlListView_SetColumnWidth($idListView, 2, 400) ; Add entries For $i = 0 To $iRows - 1 Local $desc = $aEntries[$i][0] Local $key = $aEntries[$i][1] Local $info = $iCols > 2 ? $aEntries[$i][2] : "" GUICtrlCreateListViewItem("|" & $desc & "|" & $info, $idListView) Next ; Button layout Local $button_width = 100 Local $button_height = 24 Local $btn_left = 10 Local $btn_gap = 5 ; Bottom button vertical position Local $btnVertTop1 = $height - (2 * $button_height) - $btn_gap - 10 Local $btnVertTop2 = $btnVertTop1 + $button_height + $btn_gap ; Info label Local $labelText = "CHECKED ITEMS: Allow and add to Whitelist." & @CRLF & "UNCHECKED ITEMS: Delete and add to Blacklist." Local $labelInfo = GUICtrlCreateLabel($labelText, 10, $btnVertTop1 - 38, $width - 40, 36) GUICtrlSetFont($labelInfo, 9, -1, -1, "Segoe UI") ; Allow All / Deny All (left) Local $btnAllowAll = GUICtrlCreateButton("Select All", $btn_left, $btnVertTop1, $button_width, $button_height) Local $btnDenyAll = GUICtrlCreateButton("Unselect All", $btn_left, $btnVertTop2, $button_width, $button_height) ; OK and Cancel (right) Local $btn_right = $width - $button_width - 10 Local $btnOK = GUICtrlCreateButton("OK", $btn_right, $btnVertTop1, $button_width, $button_height) Local $btnCancel = GUICtrlCreateButton("Cancel", $btn_right, $btnVertTop2, $button_width, $button_height) ; Export (centered horizontally in the GUI) Local $exportMsgWidth = 120 Local $exportBtnWidth = $button_width Local $exportBtnLeft = Int(($width - $exportBtnWidth) / 2) Local $exportBtnTop = $btnVertTop2 Local $btnExport = GUICtrlCreateButton("Export List", $exportBtnLeft, $exportBtnTop, $exportBtnWidth, $button_height) ; Exported message label (centered above Export INI button) Local $exportMsgLeft = Int(($width - $exportMsgWidth) / 2) Local $exportMsgTop = $exportBtnTop - 22 Local $lblExported = GUICtrlCreateLabel("", $exportMsgLeft, $exportMsgTop, $exportMsgWidth, 20, $SS_CENTER) GUICtrlSetFont($lblExported, 9, 400, 0, "Segoe UI") GUICtrlSetColor($lblExported, 0x008000) GUICtrlSetBkColor($lblExported, $GUI_BKCOLOR_TRANSPARENT) GUISetState(@SW_SHOW, $hGUI) ; Now that the ListView is created, check all by default Local $hListView = GUICtrlGetHandle($idListView) For $i = 0 To $iRows - 1 _GUICtrlListView_SetItemChecked($hListView, $i, True) Next Local $msg, $cancel = False, $exportTime = 0 While 1 $msg = GUIGetMsg() Switch $msg Case $GUI_EVENT_CLOSE, $btnCancel $cancel = True ExitLoop Case $btnAllowAll For $i = 0 To $iRows - 1 _GUICtrlListView_SetItemChecked($hListView, $i, True) Next Case $btnDenyAll For $i = 0 To $iRows - 1 _GUICtrlListView_SetItemChecked($hListView, $i, False) Next Case $btnExport _ExportListViewToINI($hListView, $iRows, $iCols, $aEntries) GUICtrlSetData($lblExported, "Exported!") $exportTime = TimerInit() Case $btnOK ExitLoop EndSwitch ; Hide "Exported!" message after 5 seconds If $exportTime > 0 And TimerDiff($exportTime) > 5000 Then GUICtrlSetData($lblExported, "") $exportTime = 0 EndIf WEnd ; Gather results For $i = 0 To $iRows - 1 $aResults[$i][0] = $cancel ? -1 : _GUICtrlListView_GetItemChecked($hListView, $i) $aResults[$i][1] = $aEntries[$i][1] $aResults[$i][2] = $aEntries[$i][0] If $iCols > 2 Then For $j = 2 To $iCols - 1 $aResults[$i][1 + $j] = $aEntries[$i][$j] Next EndIf Next GUIDelete($hGUI) Return $aResults EndFunc Func _ExportListViewToINI($hListView, $iRows, $iCols, $aEntries) Local $now = _NowCalc() Local $dateTime = StringRegExpReplace($now, "([^\d])", "") Local $date = StringLeft($dateTime, 8) ; YYYYMMDD Local $time = StringMid($dateTime, 9, 6) ; HHMMSS Local $timestamp = StringFormat("%s-%s", $date, $time) Local $filename = @ScriptDir & "\ExportedEntries_" & $timestamp & ".ini" Local $section = "Entries" If FileExists($filename) Then FileDelete($filename) For $i = 0 To $iRows - 1 Local $desc = $aEntries[$i][0] Local $key = $aEntries[$i][1] Local $info = ($iCols > 2) ? $aEntries[$i][2] : "" Local $line = $desc & " | " & $key If $iCols > 2 Then For $j = 2 To $iCols - 1 $line &= " | " & $aEntries[$i][$j] Next EndIf IniWrite($filename, $section, "Entry" & ($i + 1), $line) Next EndFunc Please let me know what needs improving. Though I expect you may want a comprehensive security tool, this is only meant to be a first line of defence, basic program for easy use, not a fully fledged, all powerful, sentinel. Personally, I am happy with it's current functionality, but am a little concerned with the massive lists it detects. But that is probably normal behaviour in windows? I don't know. StartupMonitor.ico Edited August 3 by sl23
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now