computer-use-ootb-internal 0.0.164__py3-none-any.whl → 0.0.165__py3-none-any.whl

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.
@@ -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 second argument for cmd.exe /K, precisely matching the working command
35
- # Format: "<quoted_exe_path>" --port <port> --target_user ''<username>''
36
- # Note: PowerShell handles escaping within double quotes differently.
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
- # Construct the argument list array for Start-Process launching cmd.exe
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 cmd.exe -ArgumentList @('/K', '$cmdKSecondArg') -WorkingDirectory '$WorkingDirectory' -Verb RunAs"
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 cmd elevated, which runs the target app
50
- Start-Process -FilePath cmd.exe -ArgumentList $startProcessArgs -WorkingDirectory $WorkingDirectory -Verb RunAs
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.
@@ -6,11 +6,14 @@ import subprocess
6
6
  import ctypes
7
7
  import platform
8
8
  import time
9
+ import json
10
+ import shutil
9
11
 
10
12
  # Constants need to match guard_service.py
11
13
  _SERVICE_NAME = "OOTBGuardService"
12
14
  _SERVICE_DISPLAY_NAME = "OOTB Guard Service"
13
15
  _TASK_NAME_PREFIX = "OOTB_UserLogon_" # Must match guard_service.py
16
+ _SHORTCUT_NAME = "OOTB AutoStart Signal.lnk" # Name for the startup shortcut
14
17
 
15
18
  def is_admin():
16
19
  """Check if the script is running with administrative privileges."""
@@ -51,142 +54,280 @@ def get_service_module_path():
51
54
  except Exception as fallback_e:
52
55
  raise FileNotFoundError(f"Could not find guard_service.py using inspect ({e}) or sys.prefix ({fallback_e}). Check installation.")
53
56
 
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
-
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
62
  try:
63
- python_exe = sys.executable # Use the same python that's running this script
64
- service_script = get_service_module_path()
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)
65
75
  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}"'
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
74
90
 
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)}")
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
78
113
 
114
+ def _find_pythonw_executable():
115
+ """Finds pythonw.exe in the same directory as sys.executable."""
79
116
  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
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
104
125
  except Exception as e:
105
- print(f"An unexpected error occurred running service command: {e}", file=sys.stderr)
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:
106
137
  return False
107
138
 
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}")
139
+ shortcut_path = os.path.join(startup_dir, _SHORTCUT_NAME)
140
+ python_launcher = _find_pythonw_executable()
141
+ signal_script = None
113
142
  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
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
122
149
  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
- }}
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.'
140
182
  """
141
- _run_powershell_cleanup_command(command)
142
- # --- End cleanup helpers ---
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
143
212
 
144
213
  def install_and_start():
145
214
  """Installs and starts the Guard Service."""
146
215
  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)
216
+ # Step 1: Run the Python script to register the service class with SCM
217
+ install_success = False
218
+ try:
219
+ python_exe = sys.executable
220
+ service_script = get_service_module_path()
221
+ # Quote paths
222
+ python_exe_quoted = f'"{python_exe}"' if " " in python_exe else python_exe
223
+ service_script_quoted = f'"{service_script}"' if " " in service_script else service_script
224
+ # Use list for subprocess
225
+ install_cmd = [sys.executable, service_script, '--startup', 'auto', 'install']
226
+ print(f"Executing registration command: {' '.join(install_cmd)}")
227
+ # We need to check output/return code carefully
228
+ result = subprocess.run(install_cmd, capture_output=True, text=True, check=False, encoding='utf-8')
229
+ if result.stdout: print(f" Registration STDOUT: {result.stdout.strip()}")
230
+ if result.stderr: print(f" Registration STDERR: {result.stderr.strip()}")
231
+ # Check common success/already-installed messages or just return code 0?
232
+ # win32serviceutil often returns 0 even if service exists. Let's assume 0 is okay.
233
+ if result.returncode == 0:
234
+ print("Service registration command executed (might indicate success or already installed).")
235
+ install_success = True
236
+ else:
237
+ print(f"Service registration command failed (Exit Code {result.returncode}).", file=sys.stderr)
238
+ install_success = False
239
+
240
+ except FileNotFoundError as e:
241
+ print(f"Error finding Python or service script for registration: {e}", file=sys.stderr)
242
+ install_success = False
243
+ except Exception as e:
244
+ print(f"Unexpected error during service registration: {e}", file=sys.stderr)
245
+ install_success = False
150
246
 
151
247
  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.")
248
+ print(f"\nRegistration command finished. Attempting to start service using 'sc start'...")
249
+ time.sleep(2) # Give SCM time
250
+ # Step 2: Use sc start
251
+ start_cmd = ['sc', 'start', _SERVICE_NAME]
252
+ start_success = _run_command(start_cmd, check_errors=False) # Don't fail script if start fails
253
+
254
+ # Optional: Query status after attempting start
255
+ time.sleep(3) # Wait a bit longer
256
+ query_cmd = ['sc', 'query', _SERVICE_NAME]
257
+ query_result = _run_command(query_cmd, capture_output=True, check_errors=False, verbose=False)
258
+ service_running = False
259
+ if query_result and query_result.stdout:
260
+ if "RUNNING" in query_result.stdout:
261
+ service_running = True
262
+ print(f"Service '{_SERVICE_NAME}' confirmed running.")
263
+ else:
264
+ print(f"Service '{_SERVICE_NAME}' status check returned:\n{query_result.stdout.strip()}")
162
265
  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)
266
+ print("Warning: Could not query service status after start attempt.")
267
+
268
+ if start_success and service_running:
269
+ print(f"\nService '{_SERVICE_NAME}' installed/updated and started successfully.")
270
+ # Step 3: Create startup shortcut only if service started
271
+ print("Creating startup shortcut...")
272
+ _create_startup_shortcut()
273
+ elif start_success and not service_running:
274
+ print(f"\nService '{_SERVICE_NAME}' installed/updated. 'sc start' command succeeded but service is not in RUNNING state.", file=sys.stderr)
275
+ print(" Check logs or try starting manually.", file=sys.stderr)
276
+ else: # start_success was False
277
+ print(f"\nService '{_SERVICE_NAME}' installed/updated but 'sc start' command failed.", file=sys.stderr)
165
278
  print(f" Check output above, service logs ('C:\ProgramData\OOTBGuardService\guard_post_mode.log'), or Windows Event Viewer.", file=sys.stderr)
166
279
  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
-
280
+ # This path is taken if the initial registration command failed critically
281
+ print(f"\nService '{_SERVICE_NAME}' registration failed critically. See errors above.", file=sys.stderr)
170
282
 
171
283
  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)")
284
+ """Stops and removes the Guard Service and associated resources."""
285
+ print(f"Attempting to remove Startup shortcut...")
286
+ _remove_startup_shortcut()
287
+
288
+ print(f"\nAttempting to stop service using 'sc stop'...")
174
289
  # 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
290
+ # run_service_command(['stop'], check_errors=False)
291
+ stop_cmd = ['sc', 'stop', _SERVICE_NAME]
292
+ _run_command(stop_cmd, check_errors=False)
293
+ time.sleep(3) # Give service time to stop
177
294
 
178
- print(f"\nAttempting to remove service: '{_SERVICE_NAME}'")
179
- remove_success = run_service_command(['remove']) # Check if removal command itself failed
295
+ # Optional: Check if stopped
296
+ query_cmd = ['sc', 'query', _SERVICE_NAME]
297
+ query_result = _run_command(query_cmd, capture_output=True, check_errors=False, verbose=False)
298
+ service_exists = True # Assume it exists unless query fails specifically
299
+ if query_result:
300
+ if query_result.stderr and ("failed" in query_result.stderr.lower() or "does not exist" in query_result.stderr.lower()):
301
+ service_exists = False
302
+ print("Service does not appear to exist before removal attempt.")
303
+ elif query_result.stdout and "STOPPED" in query_result.stdout:
304
+ print("Service confirmed stopped.")
305
+ elif query_result.stdout:
306
+ print(f"Warning: Service state after stop attempt: {query_result.stdout.strip()}")
307
+ else:
308
+ print("Warning: Could not query service state after stop attempt.")
309
+
310
+ print(f"\nAttempting to remove service using 'sc delete'...")
311
+ # remove_success = run_service_command(['remove']) # Check if removal command itself failed
312
+ delete_cmd = ['sc', 'delete', _SERVICE_NAME]
313
+ delete_success = _run_command(delete_cmd, check_errors=False) # Ignore error if not found
180
314
 
181
315
  # Always attempt task cleanup, even if service removal had issues
182
316
  _cleanup_scheduled_tasks()
183
317
 
184
- if remove_success:
185
- print(f"\nService '{_SERVICE_NAME}' stopped (if running) and removed successfully. Associated logon tasks cleanup attempted.")
318
+ if delete_success:
319
+ # Check if it really doesn't exist now
320
+ time.sleep(1)
321
+ query_result_after = _run_command(query_cmd, capture_output=True, check_errors=False, verbose=False)
322
+ 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()):
323
+ print(f"\nService '{_SERVICE_NAME}' stopped (if running), removed successfully. Startup shortcut and logon tasks cleanup attempted.")
324
+ else:
325
+ print(f"\nService '{_SERVICE_NAME}' stop attempted. 'sc delete' command ran but service might still exist. Please check manually.", file=sys.stderr)
326
+ print(f" Startup shortcut and logon tasks cleanup attempted.", file=sys.stderr)
186
327
  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)
328
+ # This might happen if sc delete failed for permission reasons etc.
329
+ print(f"\n'sc delete {_SERVICE_NAME}' command failed to execute properly.", file=sys.stderr)
330
+ print(f" Startup shortcut and logon tasks cleanup attempted.", file=sys.stderr)
190
331
  print(f" Ensure the service was stopped first, or check permissions.", file=sys.stderr)
191
332
 
192
333
  if __name__ == '__main__':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: computer-use-ootb-internal
3
- Version: 0.0.164
3
+ Version: 0.0.165
4
4
  Summary: Computer Use OOTB
5
5
  Author-email: Siyuan Hu <siyuan.hu.sg@gmail.com>
6
6
  Requires-Python: >=3.11
@@ -2,11 +2,11 @@ computer_use_ootb_internal/README.md,sha256=FxpW95lyub2iX73ZDfK6ML7SdEKg060H5I6G
2
2
  computer_use_ootb_internal/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
3
3
  computer_use_ootb_internal/app_teachmode.py,sha256=hiUTiX4jl1-5yqs3AwrOjNmToL5LbUb42o5XS4fiKAA,23805
4
4
  computer_use_ootb_internal/dependency_check.py,sha256=y8RMEP6RXQzTgU1MS_1piBLtz4J-Hfn9RjUZg59dyvo,1333
5
- computer_use_ootb_internal/guard_service.py,sha256=Ejfg3kXSirAN7XjVq4KlCblpwc5huJxqFN1iiDuP-68,54840
6
- computer_use_ootb_internal/launch_ootb_elevated.ps1,sha256=h6CnpDd8pRwDqFu42E5GUuLdPrCHJWDuc_zOXaE9mtQ,2793
5
+ computer_use_ootb_internal/guard_service.py,sha256=sJRd4uYLkmWoD9UoAMKwCLAC771ScoUCY4l-O4gDB9I,48459
6
+ computer_use_ootb_internal/launch_ootb_elevated.ps1,sha256=cAigroRaV4CW1gw0SNaPemmeIBRM7bCCwNDHSN8KHkw,2364
7
7
  computer_use_ootb_internal/requirements-lite.txt,sha256=5DAHomz4A_P2BmTIXNkNqkHbnIF0AyZ4_1XAlb1LaYs,290
8
8
  computer_use_ootb_internal/run_teachmode_ootb_args.py,sha256=eUPpfA7bB3bdBBiIBIxKJSS-Jpz2G6R46fpDO440Jyo,7687
9
- computer_use_ootb_internal/service_manager.py,sha256=SD8jzfn0VVXBOr_nP6zmBWSC2TzrU_sp2e5JJkSlQFU,9734
9
+ computer_use_ootb_internal/service_manager.py,sha256=7BcZBjGDvtuZq5DlPtRI0mxxT26V1llcSucH9p_E6y4,17088
10
10
  computer_use_ootb_internal/signal_connection.py,sha256=8jPLOj0WSBXI_NElm5A-F146DTAE5LdL07lov7YXTNQ,1774
11
11
  computer_use_ootb_internal/computer_use_demo/animation/click_animation.py,sha256=tP1gsayFy-CKk10UlrE9RlexwlHWiHQUe5Ogg4vQvSg,3234
12
12
  computer_use_ootb_internal/computer_use_demo/animation/icons8-select-cursor-transparent-96.gif,sha256=4LfwsfFQnREXrNRs32aJU2jO65JXianJoL_8q7-8elg,30966
@@ -35,7 +35,7 @@ computer_use_ootb_internal/computer_use_demo/tools/run.py,sha256=xhXdnBK1di9muaO
35
35
  computer_use_ootb_internal/computer_use_demo/tools/screen_capture.py,sha256=L8qfvtUkPPQGt92N-2Zfw5ZTDBzLsDps39uMnX3_uSA,6857
36
36
  computer_use_ootb_internal/preparation/__init__.py,sha256=AgtGHcBpiTkxJjF0xwcs3yyQ6SyUvhL3G0vD2XO-zJw,63
37
37
  computer_use_ootb_internal/preparation/star_rail_prepare.py,sha256=r0b19M_c1sXkN3_MRFjql8w_ThC9nZUe8zbSLYUvKS8,4635
38
- computer_use_ootb_internal-0.0.164.dist-info/METADATA,sha256=IYKzsXP34pDKBd92-DrsuLIQBmtqysJI1cihfZI3bzU,1048
39
- computer_use_ootb_internal-0.0.164.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
40
- computer_use_ootb_internal-0.0.164.dist-info/entry_points.txt,sha256=bXfyAU_qq-G1EiEgAQEioXvgEdRCFxaTooqdDD9Y4OA,258
41
- computer_use_ootb_internal-0.0.164.dist-info/RECORD,,
38
+ computer_use_ootb_internal-0.0.165.dist-info/METADATA,sha256=onOiMtt-IQ2Eolx5dSaK0DJS9cDmQmfbFLoEsgKVhuk,1048
39
+ computer_use_ootb_internal-0.0.165.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
40
+ computer_use_ootb_internal-0.0.165.dist-info/entry_points.txt,sha256=bXfyAU_qq-G1EiEgAQEioXvgEdRCFxaTooqdDD9Y4OA,258
41
+ computer_use_ootb_internal-0.0.165.dist-info/RECORD,,