computer-use-ootb-internal 0.0.164__tar.gz → 0.0.166__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/PKG-INFO +1 -1
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/pyproject.toml +1 -1
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/guard_service.py +0 -112
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/launch_ootb_elevated.ps1 +7 -13
- computer_use_ootb_internal-0.0.166/src/computer_use_ootb_internal/service_manager.py +354 -0
- computer_use_ootb_internal-0.0.164/src/computer_use_ootb_internal/service_manager.py +0 -195
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/.gitignore +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/README.md +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/app_teachmode.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/animation/click_animation.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/animation/icons8-select-cursor-transparent-96.gif +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/animation/test_animation.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/executor/teachmode_executor.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/gui_capture.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/utils.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/uia_tools/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/uia_tools/screenshot_cli.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/uia_tools/screenshot_service.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/llm_utils.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/oai.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/run_litellm.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/run_llm.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/aws_request.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/base.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/bash.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/collection.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/colorful_text.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/computer.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/computer_marbot.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/edit.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/run.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/computer_use_demo/tools/screen_capture.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/dependency_check.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/preparation/__init__.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/preparation/star_rail_prepare.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/requirements-lite.txt +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/run_teachmode_ootb_args.py +0 -0
- {computer_use_ootb_internal-0.0.164 → computer_use_ootb_internal-0.0.166}/src/computer_use_ootb_internal/signal_connection.py +0 -0
@@ -144,7 +144,6 @@ class GuardService(win32serviceutil.ServiceFramework):
|
|
144
144
|
_svc_name_ = _SERVICE_NAME
|
145
145
|
_svc_display_name_ = _SERVICE_DISPLAY_NAME
|
146
146
|
_svc_description_ = _SERVICE_DESCRIPTION
|
147
|
-
_task_name_prefix = "OOTB_UserLogon_" # Class attribute for task prefix
|
148
147
|
|
149
148
|
# --- Instance Logging Methods ---
|
150
149
|
def log_info(self, msg):
|
@@ -850,117 +849,6 @@ class GuardService(win32serviceutil.ServiceFramework):
|
|
850
849
|
return "failed_trigger_exception"
|
851
850
|
|
852
851
|
|
853
|
-
def create_or_update_logon_task(self, username):
|
854
|
-
"""Creates/updates task to trigger the internal signal script on session connect."""
|
855
|
-
if not self.signal_script_path:
|
856
|
-
self.log_error(f"Cannot create task for {username}: Signal script path is not set.")
|
857
|
-
return False
|
858
|
-
if not sys.executable:
|
859
|
-
self.log_error(f"Cannot create task for {username}: sys.executable is not found.")
|
860
|
-
return False
|
861
|
-
|
862
|
-
# Use the python executable that the service itself is running under
|
863
|
-
python_exe = sys.executable
|
864
|
-
if ' ' in python_exe and not python_exe.startswith('"'):
|
865
|
-
python_exe = f'"{python_exe}"'
|
866
|
-
|
867
|
-
task_name = f"OOTB_UserConnect_{username}"
|
868
|
-
# Action: Run python.exe with the signal script and username argument
|
869
|
-
action_executable = python_exe
|
870
|
-
# Ensure script path is quoted if needed
|
871
|
-
script_arg = self.signal_script_path # Should be quoted already by _find_signal_script
|
872
|
-
# Username might need quoting if it contains spaces, though unlikely
|
873
|
-
user_arg = username # Keep simple for now
|
874
|
-
action_arguments = f'{script_arg} "{user_arg}"' # Pass username as quoted arg
|
875
|
-
safe_action_executable = action_executable.replace("'", "''") # Escape for PS
|
876
|
-
safe_action_arguments = action_arguments.replace("'", "''") # Escape for PS
|
877
|
-
|
878
|
-
# Working directory for the script (likely its own directory)
|
879
|
-
try:
|
880
|
-
script_dir = os.path.dirname(self.signal_script_path.strip('"'))
|
881
|
-
if not script_dir: script_dir = "."
|
882
|
-
safe_working_directory = script_dir.replace("'", "''")
|
883
|
-
working_directory_setting = f"$action.WorkingDirectory = '{safe_working_directory}'"
|
884
|
-
except Exception as e:
|
885
|
-
self.log_error(f"Error determining working directory for signal script task: {e}. WD will not be set.")
|
886
|
-
working_directory_setting = "# Could not set WorkingDirectory"
|
887
|
-
|
888
|
-
# PowerShell command construction
|
889
|
-
ps_command = f"""
|
890
|
-
$taskName = "{task_name}"
|
891
|
-
$principal = New-ScheduledTaskPrincipal -UserId "{username}" -LogonType Interactive
|
892
|
-
|
893
|
-
# Action: Run python signal script
|
894
|
-
$action = New-ScheduledTaskAction -Execute '{safe_action_executable}' -Argument '{safe_action_arguments}'
|
895
|
-
{working_directory_setting}
|
896
|
-
|
897
|
-
# Trigger: On session connect (Event ID 21)
|
898
|
-
$logName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'
|
899
|
-
$source = 'Microsoft-Windows-TerminalServices-LocalSessionManager'
|
900
|
-
$eventIDs = @(21, 25)
|
901
|
-
$trigger = New-ScheduledTaskTrigger -Event -LogName $logName -Source $source -EventId $eventIDs[0]
|
902
|
-
# Optional Delay: -Delay 'PT15S'
|
903
|
-
# $trigger.Delay = 'PT15S'
|
904
|
-
|
905
|
-
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit (New-TimeSpan -Days 9999) -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
|
906
|
-
$description = "Triggers OOTB Guard Service for user {username} upon session connect via internal signal." # Updated description
|
907
|
-
|
908
|
-
# Unregister existing task first (force)
|
909
|
-
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
910
|
-
|
911
|
-
# Register the new task
|
912
|
-
Register-ScheduledTask -TaskName $taskName -Principal $principal -Action $action -Trigger $trigger -Settings $settings -Description $description -Force
|
913
|
-
"""
|
914
|
-
self.log_info(f"Attempting to create/update task '{task_name}' for user '{username}' to run signal script.")
|
915
|
-
try:
|
916
|
-
success = self.run_powershell_command(ps_command)
|
917
|
-
if success:
|
918
|
-
self.log_info(f"Successfully ran PowerShell command to create/update task '{task_name}'.")
|
919
|
-
return True
|
920
|
-
else:
|
921
|
-
self.log_error(f"PowerShell command failed to create/update task '{task_name}'. See previous logs.")
|
922
|
-
return False
|
923
|
-
except Exception as e:
|
924
|
-
self.log_error(f"Failed to create/update scheduled task '{task_name}' for user '{username}': {e}", exc_info=True)
|
925
|
-
return False
|
926
|
-
|
927
|
-
def run_powershell_command(self, command, log_output=True):
|
928
|
-
"""Executes a PowerShell command and handles output/errors. Returns True on success."""
|
929
|
-
self.log_info(f"Executing PowerShell: {command}")
|
930
|
-
try:
|
931
|
-
result = subprocess.run(
|
932
|
-
["powershell.exe", "-NoProfile", "-NonInteractive", "-Command", command],
|
933
|
-
capture_output=True, text=True, check=True, encoding='utf-8', errors='ignore'
|
934
|
-
)
|
935
|
-
if log_output and result.stdout:
|
936
|
-
self.log_info(f"PowerShell STDOUT:\n{result.stdout.strip()}")
|
937
|
-
if log_output and result.stderr:
|
938
|
-
# Log stderr as info, as some commands write status here (like unregister task not found)
|
939
|
-
self.log_info(f"PowerShell STDERR:\n{result.stderr.strip()}")
|
940
|
-
return True
|
941
|
-
except FileNotFoundError:
|
942
|
-
self.log_error("'powershell.exe' not found. Cannot manage scheduled tasks.")
|
943
|
-
return False
|
944
|
-
except subprocess.CalledProcessError as e:
|
945
|
-
# Log error but still return False, handled by caller
|
946
|
-
self.log_error(f"PowerShell command failed (Exit Code {e.returncode}):")
|
947
|
-
self.log_error(f" Command: {e.cmd}")
|
948
|
-
if e.stdout: self.log_error(f" STDOUT: {e.stdout.strip()}")
|
949
|
-
if e.stderr: self.log_error(f" STDERR: {e.stderr.strip()}")
|
950
|
-
return False
|
951
|
-
except Exception as e:
|
952
|
-
self.log_error(f"Unexpected error running PowerShell: {e}", exc_info=True)
|
953
|
-
return False
|
954
|
-
|
955
|
-
def remove_logon_task(self, username):
|
956
|
-
"""Removes the logon scheduled task for a user."""
|
957
|
-
task_name = f"{self._task_name_prefix}{username}"
|
958
|
-
safe_task_name = task_name.replace("'", "''")
|
959
|
-
command = f"Unregister-ScheduledTask -TaskName '{safe_task_name}' -Confirm:$false -ErrorAction SilentlyContinue"
|
960
|
-
self.run_powershell_command(command, log_output=False)
|
961
|
-
self.log_info(f"Attempted removal of scheduled task '{task_name}' for user '{username}'.")
|
962
|
-
return True
|
963
|
-
|
964
852
|
def _find_signal_script(self):
|
965
853
|
"""Finds the signal_connection.py script relative to this service file."""
|
966
854
|
return self._find_helper_script("signal_connection.py") # Reuse helper finding logic
|
@@ -31,23 +31,17 @@ try {
|
|
31
31
|
throw "Working directory not found at '$WorkingDirectory'"
|
32
32
|
}
|
33
33
|
|
34
|
-
# Construct the
|
35
|
-
#
|
36
|
-
|
37
|
-
# Using backticks ` before inner quotes is safer here.
|
38
|
-
$cmdKSecondArg = "`"`"$TargetExePath`"`" --port $Port --target_user ''$TargetUser''"
|
34
|
+
# Construct the argument list string for the target executable
|
35
|
+
# Ensure target user is single-quoted for the argument parser
|
36
|
+
$argumentList = "--port $Port --target_user '$TargetUser'"
|
39
37
|
|
40
|
-
|
41
|
-
$startProcessArgs = @('/K', $cmdKSecondArg)
|
42
|
-
|
43
|
-
Write-Host "Constructed cmd.exe /K arguments: $cmdKSecondArg"
|
44
|
-
Write-Host "Constructed Start-Process arguments array: $($startProcessArgs -join ' ')" # For logging
|
38
|
+
Write-Host "Constructed ArgumentList for Target Exe: $argumentList"
|
45
39
|
Write-Host "Executing elevated process..."
|
46
|
-
Write-Host "Command: Start-Process -FilePath
|
40
|
+
Write-Host "Command: Start-Process -FilePath `$TargetExePath` -ArgumentList `$argumentList` -WorkingDirectory `$WorkingDirectory` -Verb RunAs"
|
47
41
|
Write-Host "--- Waiting for UAC prompt if necessary ---"
|
48
42
|
|
49
|
-
# Execute the command to launch
|
50
|
-
Start-Process -FilePath
|
43
|
+
# Execute the command to launch the target exe elevated directly
|
44
|
+
Start-Process -FilePath $TargetExePath -ArgumentList $argumentList -WorkingDirectory $WorkingDirectory -Verb RunAs
|
51
45
|
|
52
46
|
Write-Host "--- OOTB Elevation Helper: Start-Process command executed. ---"
|
53
47
|
# The calling powershell window (started by CreateProcessAsUser with -NoExit) will remain open.
|
@@ -0,0 +1,354 @@
|
|
1
|
+
# src/computer_use_ootb_internal/service_manager.py
|
2
|
+
import sys
|
3
|
+
import os
|
4
|
+
import inspect
|
5
|
+
import subprocess
|
6
|
+
import ctypes
|
7
|
+
import platform
|
8
|
+
import time
|
9
|
+
import json
|
10
|
+
import shutil
|
11
|
+
|
12
|
+
# Constants need to match guard_service.py
|
13
|
+
_SERVICE_NAME = "OOTBGuardService"
|
14
|
+
_SERVICE_DISPLAY_NAME = "OOTB Guard Service"
|
15
|
+
_TASK_NAME_PREFIX = "OOTB_UserLogon_" # Must match guard_service.py
|
16
|
+
_SHORTCUT_NAME = "OOTB AutoStart Signal.lnk" # Name for the startup shortcut
|
17
|
+
|
18
|
+
def is_admin():
|
19
|
+
"""Check if the script is running with administrative privileges."""
|
20
|
+
if platform.system() != "Windows":
|
21
|
+
return False # Only applicable on Windows
|
22
|
+
try:
|
23
|
+
return ctypes.windll.shell32.IsUserAnAdmin()
|
24
|
+
except:
|
25
|
+
return False
|
26
|
+
|
27
|
+
def get_service_module_path():
|
28
|
+
"""Gets the absolute path to the guard_service.py module."""
|
29
|
+
# Find the path relative to this script's location
|
30
|
+
# This assumes service_manager.py and guard_service.py are in the same installed package directory
|
31
|
+
try:
|
32
|
+
current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
33
|
+
service_module = os.path.join(current_dir, "guard_service.py")
|
34
|
+
if not os.path.exists(service_module):
|
35
|
+
raise FileNotFoundError(f"guard_service.py not found adjacent to service_manager.py in {current_dir}")
|
36
|
+
return service_module
|
37
|
+
except Exception as e:
|
38
|
+
# Fallback if inspect fails (e.g., in some frozen environments)
|
39
|
+
# Try finding it relative to the script itself? Unreliable.
|
40
|
+
# Let's try sys.prefix - might work in standard venv/conda installs
|
41
|
+
try:
|
42
|
+
# sys.prefix points to the environment root (e.g., C:\path\to\env)
|
43
|
+
# Package likely installed in Lib\site-packages\<package_name>
|
44
|
+
# This depends heavily on installation layout
|
45
|
+
package_name = __name__.split('.')[0] # Should be 'computer_use_ootb_internal'
|
46
|
+
site_packages_path = os.path.join(sys.prefix, 'Lib', 'site-packages')
|
47
|
+
module_dir = os.path.join(site_packages_path, package_name)
|
48
|
+
service_module = os.path.join(module_dir, "guard_service.py")
|
49
|
+
if os.path.exists(service_module):
|
50
|
+
print(f"Warning: Found service module via sys.prefix fallback: {service_module}")
|
51
|
+
return service_module
|
52
|
+
else:
|
53
|
+
raise FileNotFoundError(f"guard_service.py not found via inspect or sys.prefix fallback (checked {module_dir})")
|
54
|
+
except Exception as fallback_e:
|
55
|
+
raise FileNotFoundError(f"Could not find guard_service.py using inspect ({e}) or sys.prefix ({fallback_e}). Check installation.")
|
56
|
+
|
57
|
+
def _run_command(cmd_list, check_errors=True, capture_output=False, verbose=True):
|
58
|
+
"""Helper to run an external command (like sc.exe)."""
|
59
|
+
if verbose:
|
60
|
+
# Safely join for printing, handle potential non-string elements just in case
|
61
|
+
print(f"Executing command: {' '.join(map(str, cmd_list))}")
|
62
|
+
try:
|
63
|
+
result = subprocess.run(
|
64
|
+
cmd_list,
|
65
|
+
capture_output=capture_output,
|
66
|
+
text=True,
|
67
|
+
check=check_errors,
|
68
|
+
encoding='utf-8',
|
69
|
+
errors='ignore'
|
70
|
+
)
|
71
|
+
if capture_output and verbose:
|
72
|
+
if result.stdout: print(f" CMD STDOUT: {result.stdout.strip()}")
|
73
|
+
if result.stderr: print(f" CMD STDERR: {result.stderr.strip()}")
|
74
|
+
return result if capture_output else (result.returncode == 0)
|
75
|
+
except FileNotFoundError as e:
|
76
|
+
print(f"Error: Command not found during execution: {cmd_list[0]}", file=sys.stderr)
|
77
|
+
print(f" Details: {e}", file=sys.stderr)
|
78
|
+
return None if capture_output else False
|
79
|
+
except subprocess.CalledProcessError as e:
|
80
|
+
# Don't print error if check_errors was False and it failed
|
81
|
+
if check_errors and verbose:
|
82
|
+
print(f"Error executing command {' '.join(map(str, cmd_list))} (Exit Code {e.returncode}).", file=sys.stderr)
|
83
|
+
if e.stdout: print(f"Subprocess STDOUT:", file=sys.stderr); print(e.stdout, file=sys.stderr)
|
84
|
+
if e.stderr: print(f"Subprocess STDERR:", file=sys.stderr); print(e.stderr, file=sys.stderr)
|
85
|
+
return None if capture_output else False
|
86
|
+
except Exception as e:
|
87
|
+
if verbose:
|
88
|
+
print(f"An unexpected error occurred running command: {e}", file=sys.stderr)
|
89
|
+
return None if capture_output else False
|
90
|
+
|
91
|
+
def _get_startup_folder():
|
92
|
+
"""Gets the current user's Startup folder path."""
|
93
|
+
try:
|
94
|
+
# Use CSIDL value for Startup folder
|
95
|
+
# Requires pywin32
|
96
|
+
import win32com.client
|
97
|
+
shell = win32com.client.Dispatch("WScript.Shell")
|
98
|
+
# SHGetSpecialFolderPath requires integer CSIDL, Startup=7
|
99
|
+
# Using shell.SpecialFolders is usually easier
|
100
|
+
startup_path = shell.SpecialFolders("Startup")
|
101
|
+
if startup_path and os.path.isdir(startup_path):
|
102
|
+
print(f"Found Startup folder: {startup_path}")
|
103
|
+
return startup_path
|
104
|
+
else:
|
105
|
+
print("Error: Could not resolve Startup folder path via WScript.Shell.", file=sys.stderr)
|
106
|
+
return None
|
107
|
+
except ImportError:
|
108
|
+
print("Error: pywin32com is required to find Startup folder. Cannot manage startup shortcut.", file=sys.stderr)
|
109
|
+
return None
|
110
|
+
except Exception as e:
|
111
|
+
print(f"Error finding Startup folder: {e}", file=sys.stderr)
|
112
|
+
return None
|
113
|
+
|
114
|
+
def _find_pythonw_executable():
|
115
|
+
"""Finds pythonw.exe in the same directory as sys.executable."""
|
116
|
+
try:
|
117
|
+
python_dir = os.path.dirname(sys.executable)
|
118
|
+
pythonw_path = os.path.join(python_dir, "pythonw.exe")
|
119
|
+
if os.path.exists(pythonw_path):
|
120
|
+
return pythonw_path
|
121
|
+
else:
|
122
|
+
print(f"Warning: pythonw.exe not found next to sys.executable ({sys.executable}). Console window might flash on login.", file=sys.stderr)
|
123
|
+
# Fallback to python.exe if pythonw not found
|
124
|
+
return sys.executable
|
125
|
+
except Exception as e:
|
126
|
+
print(f"Error finding pythonw.exe: {e}. Using sys.executable as fallback.", file=sys.stderr)
|
127
|
+
return sys.executable
|
128
|
+
|
129
|
+
def _create_startup_shortcut():
|
130
|
+
"""Creates a shortcut in the Startup folder to run signal_connection.py."""
|
131
|
+
if not is_admin(): # Should already be checked, but double-check
|
132
|
+
print("Admin privileges needed to potentially write shortcut.")
|
133
|
+
return False
|
134
|
+
|
135
|
+
startup_dir = _get_startup_folder()
|
136
|
+
if not startup_dir:
|
137
|
+
return False
|
138
|
+
|
139
|
+
shortcut_path = os.path.join(startup_dir, _SHORTCUT_NAME)
|
140
|
+
python_launcher = _find_pythonw_executable()
|
141
|
+
signal_script = None
|
142
|
+
try:
|
143
|
+
# Find signal_connection.py relative to this script (service_manager.py)
|
144
|
+
script_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
145
|
+
signal_script = os.path.join(script_dir, "signal_connection.py")
|
146
|
+
if not os.path.exists(signal_script):
|
147
|
+
print(f"Error: signal_connection.py not found in {script_dir}", file=sys.stderr)
|
148
|
+
return False
|
149
|
+
except Exception as e:
|
150
|
+
print(f"Error finding signal_connection.py: {e}", file=sys.stderr)
|
151
|
+
return False
|
152
|
+
|
153
|
+
# Target command for the shortcut
|
154
|
+
target_cmd = f'"{python_launcher}"' # Quote launcher path
|
155
|
+
# Quote script path
|
156
|
+
target_cmd += f' "{signal_script}"'
|
157
|
+
# Username argument - %USERNAME% will be expanded by shell when shortcut runs
|
158
|
+
target_cmd += ' %USERNAME%'
|
159
|
+
|
160
|
+
print(f"Creating Startup shortcut:")
|
161
|
+
print(f" Shortcut : {shortcut_path}")
|
162
|
+
print(f" Target : {target_cmd}")
|
163
|
+
|
164
|
+
# Use PowerShell to create the shortcut
|
165
|
+
# Escape paths and arguments for the PowerShell command string
|
166
|
+
ps_shortcut_path = shortcut_path.replace("'", "''")
|
167
|
+
ps_target_cmd = target_cmd.replace("'", "''")
|
168
|
+
ps_working_dir = os.path.dirname(signal_script).replace("'", "''") # Use script's dir as working dir
|
169
|
+
ps_icon_location = python_launcher.replace("'", "''") # Use python icon
|
170
|
+
|
171
|
+
ps_command = f"""
|
172
|
+
$ws = New-Object -ComObject WScript.Shell
|
173
|
+
$s = $ws.CreateShortcut('{ps_shortcut_path}')
|
174
|
+
$s.TargetPath = '{ps_target_cmd.split()[0]}' # Executable part
|
175
|
+
$s.Arguments = '{ps_target_cmd.split(' ', 1)[1] if ' ' in ps_target_cmd else ''}' # Arguments part
|
176
|
+
$s.WorkingDirectory = '{ps_working_dir}'
|
177
|
+
$s.IconLocation = '{ps_icon_location}'
|
178
|
+
$s.WindowStyle = 7 # Minimized
|
179
|
+
$s.Description = 'Triggers OOTB Guard Service connection check on login'
|
180
|
+
$s.Save()
|
181
|
+
Write-Host 'Shortcut created successfully.'
|
182
|
+
"""
|
183
|
+
|
184
|
+
return _run_command([sys.executable, "-NoProfile", "-NonInteractive", "-Command", ps_command])
|
185
|
+
|
186
|
+
def _remove_startup_shortcut():
|
187
|
+
"""Removes the OOTB startup shortcut if it exists."""
|
188
|
+
if not is_admin(): return False # Need admin to potentially delete
|
189
|
+
startup_dir = _get_startup_folder()
|
190
|
+
if not startup_dir:
|
191
|
+
return False
|
192
|
+
|
193
|
+
shortcut_path = os.path.join(startup_dir, _SHORTCUT_NAME)
|
194
|
+
print(f"Attempting to remove Startup shortcut: {shortcut_path}")
|
195
|
+
if os.path.exists(shortcut_path):
|
196
|
+
try:
|
197
|
+
os.remove(shortcut_path)
|
198
|
+
print("Shortcut removed successfully.")
|
199
|
+
return True
|
200
|
+
except OSError as e:
|
201
|
+
print(f"Error removing shortcut: {e}", file=sys.stderr)
|
202
|
+
# Fallback attempt with PowerShell just in case of permission issues
|
203
|
+
ps_shortcut_path = shortcut_path.replace("'", "''")
|
204
|
+
ps_command = f"Remove-Item -Path '{ps_shortcut_path}' -Force -ErrorAction SilentlyContinue"
|
205
|
+
return _run_command([sys.executable, "-NoProfile", "-NonInteractive", "-Command", ps_command], verbose=False)
|
206
|
+
except Exception as e:
|
207
|
+
print(f"Unexpected error removing shortcut: {e}", file=sys.stderr)
|
208
|
+
return False
|
209
|
+
else:
|
210
|
+
print("Shortcut not found, no removal needed.")
|
211
|
+
return True
|
212
|
+
|
213
|
+
def _cleanup_scheduled_tasks():
|
214
|
+
"""Removes all OOTB user logon scheduled tasks (legacy cleanup)."""
|
215
|
+
print("Attempting legacy cleanup of OOTB user logon scheduled tasks...")
|
216
|
+
# Use -like operator and wildcard
|
217
|
+
# Need _TASK_NAME_PREFIX defined at module level
|
218
|
+
command = f"""
|
219
|
+
$tasks = Get-ScheduledTask | Where-Object {{ $_.TaskName -like '{_TASK_NAME_PREFIX}*' }}
|
220
|
+
if ($tasks) {{
|
221
|
+
Write-Host "Found $($tasks.Count) legacy OOTB logon tasks to remove."
|
222
|
+
$tasks | Unregister-ScheduledTask -Confirm:$false -ErrorAction SilentlyContinue
|
223
|
+
Write-Host "Legacy OOTB logon task removal attempted."
|
224
|
+
}} else {{
|
225
|
+
Write-Host "No legacy OOTB logon tasks found to remove."
|
226
|
+
}}
|
227
|
+
"""
|
228
|
+
# Use the generic _run_command helper, specifying powershell.exe
|
229
|
+
_run_command(['powershell.exe', '-NoProfile', '-NonInteractive', '-Command', command], check_errors=False, verbose=False)
|
230
|
+
|
231
|
+
def install_and_start():
|
232
|
+
"""Installs and starts the Guard Service."""
|
233
|
+
print(f"Attempting to install service: '{_SERVICE_NAME}' ('{_SERVICE_DISPLAY_NAME}')")
|
234
|
+
# Step 1: Run the Python script to register the service class with SCM
|
235
|
+
install_success = False
|
236
|
+
try:
|
237
|
+
python_exe = sys.executable
|
238
|
+
service_script = get_service_module_path()
|
239
|
+
# Quote paths
|
240
|
+
python_exe_quoted = f'"{python_exe}"' if " " in python_exe else python_exe
|
241
|
+
service_script_quoted = f'"{service_script}"' if " " in service_script else service_script
|
242
|
+
# Use list for subprocess
|
243
|
+
install_cmd = [sys.executable, service_script, '--startup', 'auto', 'install']
|
244
|
+
print(f"Executing registration command: {' '.join(install_cmd)}")
|
245
|
+
# We need to check output/return code carefully
|
246
|
+
result = subprocess.run(install_cmd, capture_output=True, text=True, check=False, encoding='utf-8')
|
247
|
+
if result.stdout: print(f" Registration STDOUT: {result.stdout.strip()}")
|
248
|
+
if result.stderr: print(f" Registration STDERR: {result.stderr.strip()}")
|
249
|
+
# Check common success/already-installed messages or just return code 0?
|
250
|
+
# win32serviceutil often returns 0 even if service exists. Let's assume 0 is okay.
|
251
|
+
if result.returncode == 0:
|
252
|
+
print("Service registration command executed (might indicate success or already installed).")
|
253
|
+
install_success = True
|
254
|
+
else:
|
255
|
+
print(f"Service registration command failed (Exit Code {result.returncode}).", file=sys.stderr)
|
256
|
+
install_success = False
|
257
|
+
|
258
|
+
except FileNotFoundError as e:
|
259
|
+
print(f"Error finding Python or service script for registration: {e}", file=sys.stderr)
|
260
|
+
install_success = False
|
261
|
+
except Exception as e:
|
262
|
+
print(f"Unexpected error during service registration: {e}", file=sys.stderr)
|
263
|
+
install_success = False
|
264
|
+
|
265
|
+
if install_success:
|
266
|
+
print(f"\nRegistration command finished. Attempting to start service using 'sc start'...")
|
267
|
+
time.sleep(2) # Give SCM time
|
268
|
+
# Step 2: Use sc start
|
269
|
+
start_cmd = ['sc', 'start', _SERVICE_NAME]
|
270
|
+
start_success = _run_command(start_cmd, check_errors=False) # Don't fail script if start fails
|
271
|
+
|
272
|
+
# Optional: Query status after attempting start
|
273
|
+
time.sleep(3) # Wait a bit longer
|
274
|
+
query_cmd = ['sc', 'query', _SERVICE_NAME]
|
275
|
+
query_result = _run_command(query_cmd, capture_output=True, check_errors=False, verbose=False)
|
276
|
+
service_running = False
|
277
|
+
if query_result and query_result.stdout:
|
278
|
+
if "RUNNING" in query_result.stdout:
|
279
|
+
service_running = True
|
280
|
+
print(f"Service '{_SERVICE_NAME}' confirmed running.")
|
281
|
+
else:
|
282
|
+
print(f"Service '{_SERVICE_NAME}' status check returned:\n{query_result.stdout.strip()}")
|
283
|
+
else:
|
284
|
+
print("Warning: Could not query service status after start attempt.")
|
285
|
+
|
286
|
+
if start_success and service_running:
|
287
|
+
print(f"\nService '{_SERVICE_NAME}' installed/updated and started successfully.")
|
288
|
+
# Step 3: Create startup shortcut only if service started
|
289
|
+
print("Creating startup shortcut...")
|
290
|
+
_create_startup_shortcut()
|
291
|
+
elif start_success and not service_running:
|
292
|
+
print(f"\nService '{_SERVICE_NAME}' installed/updated. 'sc start' command succeeded but service is not in RUNNING state.", file=sys.stderr)
|
293
|
+
print(" Check logs or try starting manually.", file=sys.stderr)
|
294
|
+
else: # start_success was False
|
295
|
+
print(f"\nService '{_SERVICE_NAME}' installed/updated but 'sc start' command failed.", file=sys.stderr)
|
296
|
+
print(f" Check output above, service logs ('C:\ProgramData\OOTBGuardService\guard_post_mode.log'), or Windows Event Viewer.", file=sys.stderr)
|
297
|
+
else:
|
298
|
+
# This path is taken if the initial registration command failed critically
|
299
|
+
print(f"\nService '{_SERVICE_NAME}' registration failed critically. See errors above.", file=sys.stderr)
|
300
|
+
|
301
|
+
def stop_and_remove():
|
302
|
+
"""Stops and removes the Guard Service and associated resources."""
|
303
|
+
print(f"Attempting to remove Startup shortcut...")
|
304
|
+
_remove_startup_shortcut()
|
305
|
+
|
306
|
+
print(f"\nAttempting to stop service using 'sc stop'...")
|
307
|
+
# Run stop first, ignore errors (check_errors=False)
|
308
|
+
# run_service_command(['stop'], check_errors=False)
|
309
|
+
stop_cmd = ['sc', 'stop', _SERVICE_NAME]
|
310
|
+
_run_command(stop_cmd, check_errors=False)
|
311
|
+
time.sleep(3) # Give service time to stop
|
312
|
+
|
313
|
+
# Optional: Check if stopped
|
314
|
+
query_cmd = ['sc', 'query', _SERVICE_NAME]
|
315
|
+
query_result = _run_command(query_cmd, capture_output=True, check_errors=False, verbose=False)
|
316
|
+
service_exists = True # Assume it exists unless query fails specifically
|
317
|
+
if query_result:
|
318
|
+
if query_result.stderr and ("failed" in query_result.stderr.lower() or "does not exist" in query_result.stderr.lower()):
|
319
|
+
service_exists = False
|
320
|
+
print("Service does not appear to exist before removal attempt.")
|
321
|
+
elif query_result.stdout and "STOPPED" in query_result.stdout:
|
322
|
+
print("Service confirmed stopped.")
|
323
|
+
elif query_result.stdout:
|
324
|
+
print(f"Warning: Service state after stop attempt: {query_result.stdout.strip()}")
|
325
|
+
else:
|
326
|
+
print("Warning: Could not query service state after stop attempt.")
|
327
|
+
|
328
|
+
print(f"\nAttempting to remove service using 'sc delete'...")
|
329
|
+
# remove_success = run_service_command(['remove']) # Check if removal command itself failed
|
330
|
+
delete_cmd = ['sc', 'delete', _SERVICE_NAME]
|
331
|
+
delete_success = _run_command(delete_cmd, check_errors=False) # Ignore error if not found
|
332
|
+
|
333
|
+
# Always attempt task cleanup, even if service removal had issues
|
334
|
+
_cleanup_scheduled_tasks()
|
335
|
+
|
336
|
+
if delete_success:
|
337
|
+
# Check if it really doesn't exist now
|
338
|
+
time.sleep(1)
|
339
|
+
query_result_after = _run_command(query_cmd, capture_output=True, check_errors=False, verbose=False)
|
340
|
+
if query_result_after and query_result_after.stderr and ("failed" in query_result_after.stderr.lower() or "does not exist" in query_result_after.stderr.lower()):
|
341
|
+
print(f"\nService '{_SERVICE_NAME}' stopped (if running), removed successfully. Startup shortcut and logon tasks cleanup attempted.")
|
342
|
+
else:
|
343
|
+
print(f"\nService '{_SERVICE_NAME}' stop attempted. 'sc delete' command ran but service might still exist. Please check manually.", file=sys.stderr)
|
344
|
+
print(f" Startup shortcut and logon tasks cleanup attempted.", file=sys.stderr)
|
345
|
+
else:
|
346
|
+
# This might happen if sc delete failed for permission reasons etc.
|
347
|
+
print(f"\n'sc delete {_SERVICE_NAME}' command failed to execute properly.", file=sys.stderr)
|
348
|
+
print(f" Startup shortcut and logon tasks cleanup attempted.", file=sys.stderr)
|
349
|
+
print(f" Ensure the service was stopped first, or check permissions.", file=sys.stderr)
|
350
|
+
|
351
|
+
if __name__ == '__main__':
|
352
|
+
# Allow calling functions directly for testing if needed
|
353
|
+
print("This script provides service management commands.")
|
354
|
+
print("Use 'ootb-install-service' or 'ootb-remove-service' as Administrator.")
|
@@ -1,195 +0,0 @@
|
|
1
|
-
# src/computer_use_ootb_internal/service_manager.py
|
2
|
-
import sys
|
3
|
-
import os
|
4
|
-
import inspect
|
5
|
-
import subprocess
|
6
|
-
import ctypes
|
7
|
-
import platform
|
8
|
-
import time
|
9
|
-
|
10
|
-
# Constants need to match guard_service.py
|
11
|
-
_SERVICE_NAME = "OOTBGuardService"
|
12
|
-
_SERVICE_DISPLAY_NAME = "OOTB Guard Service"
|
13
|
-
_TASK_NAME_PREFIX = "OOTB_UserLogon_" # Must match guard_service.py
|
14
|
-
|
15
|
-
def is_admin():
|
16
|
-
"""Check if the script is running with administrative privileges."""
|
17
|
-
if platform.system() != "Windows":
|
18
|
-
return False # Only applicable on Windows
|
19
|
-
try:
|
20
|
-
return ctypes.windll.shell32.IsUserAnAdmin()
|
21
|
-
except:
|
22
|
-
return False
|
23
|
-
|
24
|
-
def get_service_module_path():
|
25
|
-
"""Gets the absolute path to the guard_service.py module."""
|
26
|
-
# Find the path relative to this script's location
|
27
|
-
# This assumes service_manager.py and guard_service.py are in the same installed package directory
|
28
|
-
try:
|
29
|
-
current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
30
|
-
service_module = os.path.join(current_dir, "guard_service.py")
|
31
|
-
if not os.path.exists(service_module):
|
32
|
-
raise FileNotFoundError(f"guard_service.py not found adjacent to service_manager.py in {current_dir}")
|
33
|
-
return service_module
|
34
|
-
except Exception as e:
|
35
|
-
# Fallback if inspect fails (e.g., in some frozen environments)
|
36
|
-
# Try finding it relative to the script itself? Unreliable.
|
37
|
-
# Let's try sys.prefix - might work in standard venv/conda installs
|
38
|
-
try:
|
39
|
-
# sys.prefix points to the environment root (e.g., C:\path\to\env)
|
40
|
-
# Package likely installed in Lib\site-packages\<package_name>
|
41
|
-
# This depends heavily on installation layout
|
42
|
-
package_name = __name__.split('.')[0] # Should be 'computer_use_ootb_internal'
|
43
|
-
site_packages_path = os.path.join(sys.prefix, 'Lib', 'site-packages')
|
44
|
-
module_dir = os.path.join(site_packages_path, package_name)
|
45
|
-
service_module = os.path.join(module_dir, "guard_service.py")
|
46
|
-
if os.path.exists(service_module):
|
47
|
-
print(f"Warning: Found service module via sys.prefix fallback: {service_module}")
|
48
|
-
return service_module
|
49
|
-
else:
|
50
|
-
raise FileNotFoundError(f"guard_service.py not found via inspect or sys.prefix fallback (checked {module_dir})")
|
51
|
-
except Exception as fallback_e:
|
52
|
-
raise FileNotFoundError(f"Could not find guard_service.py using inspect ({e}) or sys.prefix ({fallback_e}). Check installation.")
|
53
|
-
|
54
|
-
|
55
|
-
def run_service_command(command_args, check_errors=True):
|
56
|
-
"""Runs the guard_service.py script with specified command-line args."""
|
57
|
-
if not is_admin():
|
58
|
-
print("Error: Administrative privileges are required to manage the service.", file=sys.stderr)
|
59
|
-
print("Please run this command from an Administrator Command Prompt or PowerShell.", file=sys.stderr)
|
60
|
-
return False
|
61
|
-
|
62
|
-
try:
|
63
|
-
python_exe = sys.executable # Use the same python that's running this script
|
64
|
-
service_script = get_service_module_path()
|
65
|
-
except FileNotFoundError as e:
|
66
|
-
print(f"Error: {e}", file=sys.stderr)
|
67
|
-
return False
|
68
|
-
|
69
|
-
# Quote paths if they contain spaces
|
70
|
-
if " " in python_exe and not python_exe.startswith('"'):
|
71
|
-
python_exe = f'"{python_exe}"'
|
72
|
-
if " " in service_script and not service_script.startswith('"'):
|
73
|
-
service_script = f'"{service_script}"'
|
74
|
-
|
75
|
-
# Construct command using list to avoid shell quoting issues
|
76
|
-
cmd = [sys.executable, get_service_module_path()] + command_args
|
77
|
-
print(f"Executing command: {' '.join(cmd)}")
|
78
|
-
|
79
|
-
try:
|
80
|
-
# Run the command. Use shell=False with list of args.
|
81
|
-
# Capture output to check for specific errors if needed, but print it too.
|
82
|
-
result = subprocess.run(cmd, capture_output=True, text=True, check=check_errors, encoding='utf-8')
|
83
|
-
if result.stdout:
|
84
|
-
print("Command STDOUT:")
|
85
|
-
print(result.stdout)
|
86
|
-
if result.stderr:
|
87
|
-
print("Command STDERR:")
|
88
|
-
print(result.stderr)
|
89
|
-
print(f"Command {' '.join(command_args)} executed successfully.")
|
90
|
-
return True
|
91
|
-
except FileNotFoundError as e:
|
92
|
-
print(f"Error: Could not find Python executable or service script during execution.", file=sys.stderr)
|
93
|
-
print(f" Details: {e}", file=sys.stderr)
|
94
|
-
return False
|
95
|
-
except subprocess.CalledProcessError as e:
|
96
|
-
print(f"Error executing service command {' '.join(command_args)} (Exit Code {e.returncode}).", file=sys.stderr)
|
97
|
-
if e.stdout:
|
98
|
-
print("Subprocess STDOUT:")
|
99
|
-
print(e.stdout)
|
100
|
-
if e.stderr:
|
101
|
-
print("Subprocess STDERR:")
|
102
|
-
print(e.stderr)
|
103
|
-
return False
|
104
|
-
except Exception as e:
|
105
|
-
print(f"An unexpected error occurred running service command: {e}", file=sys.stderr)
|
106
|
-
return False
|
107
|
-
|
108
|
-
# --- Add cleanup helpers ---
|
109
|
-
def _run_powershell_cleanup_command(command):
|
110
|
-
"""Executes a PowerShell command specifically for cleanup, ignoring most errors."""
|
111
|
-
if platform.system() != "Windows": return True # Skip on non-windows
|
112
|
-
print(f"Executing PowerShell Cleanup: {command}")
|
113
|
-
try:
|
114
|
-
# Use check=False, don't capture output unless needed for debug
|
115
|
-
subprocess.run(
|
116
|
-
["powershell.exe", "-NoProfile", "-NonInteractive", "-Command", command],
|
117
|
-
check=False, # Don't throw error if command fails (e.g., no tasks found)
|
118
|
-
stdout=subprocess.DEVNULL, # Suppress stdout
|
119
|
-
stderr=subprocess.DEVNULL # Suppress stderr
|
120
|
-
)
|
121
|
-
return True # Assume success for cleanup flow
|
122
|
-
except Exception as e:
|
123
|
-
print(f"Warning: PowerShell cleanup command failed: {e}", file=sys.stderr)
|
124
|
-
return False # Indicate potential issue
|
125
|
-
|
126
|
-
def _cleanup_scheduled_tasks():
|
127
|
-
"""Removes all OOTB user logon scheduled tasks."""
|
128
|
-
print("Attempting to remove any existing OOTB user logon scheduled tasks...")
|
129
|
-
# Use -like operator and wildcard
|
130
|
-
# Use try-catch within PowerShell for robustness
|
131
|
-
command = f"""
|
132
|
-
$tasks = Get-ScheduledTask | Where-Object {{ $_.TaskName -like '{_TASK_NAME_PREFIX}*' }}
|
133
|
-
if ($tasks) {{
|
134
|
-
Write-Host "Found $($tasks.Count) OOTB logon tasks to remove."
|
135
|
-
$tasks | Unregister-ScheduledTask -Confirm:$false -ErrorAction SilentlyContinue
|
136
|
-
Write-Host "OOTB logon task removal attempted."
|
137
|
-
}} else {{
|
138
|
-
Write-Host "No OOTB logon tasks found to remove."
|
139
|
-
}}
|
140
|
-
"""
|
141
|
-
_run_powershell_cleanup_command(command)
|
142
|
-
# --- End cleanup helpers ---
|
143
|
-
|
144
|
-
def install_and_start():
|
145
|
-
"""Installs and starts the Guard Service."""
|
146
|
-
print(f"Attempting to install service: '{_SERVICE_NAME}' ('{_SERVICE_DISPLAY_NAME}')")
|
147
|
-
# Call 'install' command first.
|
148
|
-
# We pass check_errors=True to stop if installation fails fundamentally.
|
149
|
-
install_success = run_service_command(['--startup', 'auto', 'install'], check_errors=True)
|
150
|
-
|
151
|
-
if install_success:
|
152
|
-
# Note: Even if install_success is True, pywin32 might have printed internal errors
|
153
|
-
# like 'service already installed'. We proceed to start anyway in that case.
|
154
|
-
print(f"\nInstallation command finished. Attempting to start service: '{_SERVICE_NAME}' (waiting a few seconds first)")
|
155
|
-
time.sleep(3) # Give SCM time to register the install/update
|
156
|
-
start_success = run_service_command(['start'], check_errors=True)
|
157
|
-
|
158
|
-
if start_success:
|
159
|
-
# Similar caveat: start might succeed according to subprocess, but pywin32 could print internal errors.
|
160
|
-
print(f"\nService '{_SERVICE_NAME}' install command executed and start command executed.")
|
161
|
-
print(f"Please verify service status in 'services.msc' and check logs.")
|
162
|
-
else:
|
163
|
-
# This path is taken if run_service_command returned False (subprocess error occurred)
|
164
|
-
print(f"\nService '{_SERVICE_NAME}' installed/updated but the 'start' command failed with an error.", file=sys.stderr)
|
165
|
-
print(f" Check output above, service logs ('C:\ProgramData\OOTBGuardService\guard_post_mode.log'), or Windows Event Viewer.", file=sys.stderr)
|
166
|
-
else:
|
167
|
-
# This path is taken if the initial 'install' command failed critically (subprocess error)
|
168
|
-
print(f"\nService '{_SERVICE_NAME}' installation failed critically. See errors above.", file=sys.stderr)
|
169
|
-
|
170
|
-
|
171
|
-
def stop_and_remove():
|
172
|
-
"""Stops and removes the Guard Service and associated scheduled tasks."""
|
173
|
-
print(f"Attempting to stop service: '{_SERVICE_NAME}' (will ignore errors if not running)")
|
174
|
-
# Run stop first, ignore errors (check_errors=False)
|
175
|
-
run_service_command(['stop'], check_errors=False)
|
176
|
-
time.sleep(2) # Give service time to stop
|
177
|
-
|
178
|
-
print(f"\nAttempting to remove service: '{_SERVICE_NAME}'")
|
179
|
-
remove_success = run_service_command(['remove']) # Check if removal command itself failed
|
180
|
-
|
181
|
-
# Always attempt task cleanup, even if service removal had issues
|
182
|
-
_cleanup_scheduled_tasks()
|
183
|
-
|
184
|
-
if remove_success:
|
185
|
-
print(f"\nService '{_SERVICE_NAME}' stopped (if running) and removed successfully. Associated logon tasks cleanup attempted.")
|
186
|
-
else:
|
187
|
-
print(f"\nService '{_SERVICE_NAME}' removal command failed.", file=sys.stderr)
|
188
|
-
# Make sure to mention cleanup was still attempted
|
189
|
-
print(f" Associated logon tasks cleanup attempted.", file=sys.stderr)
|
190
|
-
print(f" Ensure the service was stopped first, or check permissions.", file=sys.stderr)
|
191
|
-
|
192
|
-
if __name__ == '__main__':
|
193
|
-
# Allow calling functions directly for testing if needed
|
194
|
-
print("This script provides service management commands.")
|
195
|
-
print("Use 'ootb-install-service' or 'ootb-remove-service' as Administrator.")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|