computer-use-ootb-internal 0.0.162__tar.gz → 0.0.163__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.
Files changed (40) hide show
  1. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/PKG-INFO +1 -1
  2. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/pyproject.toml +1 -1
  3. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/guard_service.py +162 -65
  4. computer_use_ootb_internal-0.0.163/src/computer_use_ootb_internal/launch_ootb_elevated.ps1 +69 -0
  5. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/.gitignore +0 -0
  6. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/README.md +0 -0
  7. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/__init__.py +0 -0
  8. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/app_teachmode.py +0 -0
  9. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/animation/click_animation.py +0 -0
  10. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/animation/icons8-select-cursor-transparent-96.gif +0 -0
  11. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/animation/test_animation.py +0 -0
  12. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/executor/teachmode_executor.py +0 -0
  13. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/__init__.py +0 -0
  14. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/gui_capture.py +0 -0
  15. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/utils.py +0 -0
  16. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/uia_tools/__init__.py +0 -0
  17. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/uia_tools/screenshot_cli.py +0 -0
  18. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/uia_tools/screenshot_service.py +0 -0
  19. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/llm_utils.py +0 -0
  20. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/oai.py +0 -0
  21. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/run_litellm.py +0 -0
  22. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/gui_agent/llm_utils/run_llm.py +0 -0
  23. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/__init__.py +0 -0
  24. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/aws_request.py +0 -0
  25. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/base.py +0 -0
  26. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/bash.py +0 -0
  27. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/collection.py +0 -0
  28. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/colorful_text.py +0 -0
  29. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/computer.py +0 -0
  30. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/computer_marbot.py +0 -0
  31. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/edit.py +0 -0
  32. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/run.py +0 -0
  33. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/computer_use_demo/tools/screen_capture.py +0 -0
  34. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/dependency_check.py +0 -0
  35. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/preparation/__init__.py +0 -0
  36. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/preparation/star_rail_prepare.py +0 -0
  37. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/requirements-lite.txt +0 -0
  38. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/run_teachmode_ootb_args.py +0 -0
  39. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/service_manager.py +0 -0
  40. {computer_use_ootb_internal-0.0.162 → computer_use_ootb_internal-0.0.163}/src/computer_use_ootb_internal/signal_connection.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: computer-use-ootb-internal
3
- Version: 0.0.162
3
+ Version: 0.0.163
4
4
  Summary: Computer Use OOTB
5
5
  Author-email: Siyuan Hu <siyuan.hu.sg@gmail.com>
6
6
  Requires-Python: >=3.11
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "computer-use-ootb-internal"
7
- version = "0.0.162"
7
+ version = "0.0.163"
8
8
  description = "Computer Use OOTB"
9
9
  authors = [{ name = "Siyuan Hu", email = "siyuan.hu.sg@gmail.com" }]
10
10
  requires-python = ">=3.11"
@@ -23,6 +23,7 @@ import psutil # For process/user info
23
23
  from flask import Flask, request, jsonify # For embedded server
24
24
  from waitress import serve # For serving Flask app
25
25
  import json # Needed for status reporting
26
+ import shutil # Added for shutil.which
26
27
 
27
28
  # --- Configuration ---
28
29
  _SERVICE_NAME = "OOTBGuardService"
@@ -226,7 +227,9 @@ class GuardService(win32serviceutil.ServiceFramework):
226
227
  self.log_info(f"Using target executable: {self.target_executable_path}")
227
228
 
228
229
  _service_instance = self
229
- self.log_info(f"Service initialized. Target executable: {self.target_executable_path}.")
230
+ # Determine path to the signal script
231
+ self.signal_script_path = self._find_signal_script()
232
+ self.log_info(f"Service initialized. Target executable: {self.target_executable_path}. Signal script: {self.signal_script_path}")
230
233
 
231
234
  def SvcStop(self):
232
235
  self.log_info(f"Service stop requested.")
@@ -708,7 +711,7 @@ class GuardService(win32serviceutil.ServiceFramework):
708
711
  try:
709
712
  # 1. Ensure scheduled task exists (still useful fallback/persistence)
710
713
  try:
711
- task_created = self.create_or_update_logon_task(user, calculated_port)
714
+ task_created = self.create_or_update_logon_task(user)
712
715
  task_created_status = "task_success" if task_created else "task_failed"
713
716
  except Exception as task_err:
714
717
  self.log_error(f"Internal trigger: Exception creating/updating task for {user}: {task_err}", exc_info=True)
@@ -756,58 +759,96 @@ class GuardService(win32serviceutil.ServiceFramework):
756
759
  self.log_error(f"Internal trigger: Error checking existing processes for {user}: {e}")
757
760
  # Continue and attempt start despite error?
758
761
 
759
- # 4. Create/Update and Trigger Scheduled Task
760
- immediate_start_status = "start_attempted_task_trigger"
761
- self.log_info(f"Internal trigger: User '{user}' is active and not running. Attempting start via Task Scheduler...")
762
+ # 4. Attempt immediate start using CreateProcessAsUser to run helper script
763
+ immediate_start_status = "start_attempted_helper_script"
764
+ self.log_info(f"Internal trigger: User '{user}' is active and not running. Attempting start via helper script...")
765
+
766
+ if not self.target_executable_path:
767
+ self.log_error("Internal trigger: Cannot start process - target executable path not found.")
768
+ final_status = "failed_exe_not_found"
769
+ return final_status
762
770
 
763
- # --- Start Task Scheduler logic ---
764
771
  try:
765
- # Step 4a: Ensure the task is created/updated correctly
766
- # Pass calculated port to the task creation function
767
- task_created = self.create_or_update_logon_task(user, calculated_port)
768
- if not task_created:
769
- self.log_error(f"Internal trigger: Failed to create/update scheduled task for user '{user}'. Cannot proceed with start.")
770
- final_status = "failed_task_creation"
772
+ # Find helper script path
773
+ helper_script_path = self._find_helper_script("launch_ootb_elevated.ps1")
774
+ if not helper_script_path:
775
+ self.log_error("Internal trigger: Cannot start process - helper script not found.")
776
+ final_status = "failed_helper_script_not_found"
771
777
  return final_status
772
-
773
- # Step 4b: Trigger the task to run immediately
774
- task_name = f"OOTB_UserConnect_{user}" # Must match the name used in create_or_update_logon_task
775
- trigger_command = ["schtasks", "/Run", "/TN", task_name]
776
- self.log_info(f"Internal trigger: Attempting to run task '{task_name}' immediately using: {trigger_command}")
777
-
778
- result = subprocess.run(
779
- trigger_command,
780
- capture_output=True,
781
- text=True,
782
- check=False, # Check return code manually
783
- encoding='utf-8',
784
- errors='ignore'
778
+
779
+ # Get PowerShell executable path
780
+ powershell_executable = self._find_powershell_executable()
781
+ if not powershell_executable:
782
+ self.log_error("Internal trigger: Cannot start process - powershell.exe not found.")
783
+ final_status = "failed_powershell_not_found"
784
+ return final_status
785
+
786
+ # Prepare arguments for the helper script (paths need quoting if they contain spaces)
787
+ target_exe_unquoted = self.target_executable_path.strip('"')
788
+ target_exe_dir = os.path.dirname(target_exe_unquoted) # Use directory of unquoted path
789
+
790
+ # Quote paths/args for command line - IMPORTANT: Use double quotes for PowerShell args
791
+ helper_script_arg = f'"{helper_script_path}"' if " " in helper_script_path else helper_script_path
792
+ target_exe_arg = f'"{target_exe_unquoted}"' if " " in target_exe_unquoted else target_exe_unquoted
793
+ working_dir_arg = f'"{target_exe_dir}"' if " " in target_exe_dir else target_exe_dir
794
+ # Username might need quoting if it contains special characters, double quote should be safe
795
+ target_user_arg = f'"{user}"'
796
+
797
+ # Construct the command line to execute powershell with the helper script and args
798
+ lpCommandLine = (
799
+ f'"{powershell_executable}" -NoProfile -ExecutionPolicy Bypass -NoExit '
800
+ f'-File {helper_script_arg} '
801
+ f'-TargetExePath {target_exe_arg} '
802
+ f'-Port {calculated_port} '
803
+ f'-TargetUser {target_user_arg} '
804
+ f'-WorkingDirectory {working_dir_arg}'
785
805
  )
786
806
 
787
- if result.stdout:
788
- self.log_info(f"Internal trigger: schtasks /Run STDOUT:\n{result.stdout.strip()}")
789
- if result.stderr:
790
- # schtasks often prints success message to stderr, log as info
791
- self.log_info(f"Internal trigger: schtasks /Run STDERR:\n{result.stderr.strip()}")
792
-
793
- if result.returncode == 0 or "SUCCESS: Attempted to run the scheduled task" in result.stdout or "SUCCESS: Attempted to run the scheduled task" in result.stderr:
794
- self.log_info(f"Internal trigger: Successfully triggered task '{task_name}' for user '{user}'.")
795
- immediate_start_status = "start_success_task_triggered"
796
- final_status = "success_task_triggered"
797
- else:
798
- self.log_error(f"Internal trigger: Failed to trigger task '{task_name}' (Exit Code: {result.returncode}).")
799
- immediate_start_status = f"start_failed_task_trigger_code_{result.returncode}"
800
- final_status = f"failed_task_trigger_code_{result.returncode}"
801
-
802
- except FileNotFoundError:
803
- self.log_error("Internal trigger: 'schtasks.exe' not found.")
804
- immediate_start_status = "start_failed_schtasks_not_found"
805
- final_status = "failed_schtasks_not_found"
806
- except Exception as task_trigger_err:
807
- self.log_error(f"Internal trigger: Exception during task trigger for user '{user}': {task_trigger_err}", exc_info=True)
808
- immediate_start_status = "start_failed_task_trigger_exception"
809
- final_status = "failed_task_trigger_exception"
810
- # --- End Task Scheduler logic ---
807
+ # Use CreateProcessAsUser to launch this command in the user's session
808
+ token = win32ts.WTSQueryUserToken(session_id)
809
+ env = win32profile.CreateEnvironmentBlock(token, False)
810
+ startup = win32process.STARTUPINFO()
811
+ # Ensure the window is visible on the user's desktop
812
+ startup.lpDesktop = "winsta0\\default"
813
+ creation_flags = win32con.CREATE_NEW_CONSOLE | win32con.NORMAL_PRIORITY_CLASS
814
+ lpApplicationName = None # Must be None when using lpCommandLine
815
+ # Working directory for powershell itself? Let it default or use script dir?
816
+ # Let's use the script's directory as CWD for powershell.exe
817
+ cwd = os.path.dirname(helper_script_path) # Use directory of unquoted path
818
+
819
+ self.log_info(f"Internal trigger: Launching helper script via CreateProcessAsUser:")
820
+ self.log_info(f" lpCommandLine: {lpCommandLine}")
821
+ self.log_info(f" lpCurrentDirectory: {cwd}")
822
+
823
+ # Execute the command in the user's session
824
+ hProcess, hThread, dwPid, dwTid = win32process.CreateProcessAsUser(
825
+ token, lpApplicationName, lpCommandLine, None, None, False,
826
+ creation_flags, env, cwd, startup
827
+ )
828
+ self.log_info(f"Internal trigger: CreateProcessAsUser call for helper script succeeded (Launcher PID: {dwPid}). Helper script should now run and trigger elevation.")
829
+ win32api.CloseHandle(hProcess)
830
+ win32api.CloseHandle(hThread)
831
+
832
+ # Assume success if CreateProcessAsUser succeeded.
833
+ # The actual success depends on the user interacting with UAC triggered by the helper.
834
+ immediate_start_status = "start_success_helper_launched"
835
+ final_status = "success_helper_launched"
836
+
837
+ except FileNotFoundError as fnf_err:
838
+ # This might now be powershell.exe OR the helper script
839
+ self.log_error(f"Internal trigger: File not found during helper script launch: {fnf_err}")
840
+ immediate_start_status = "start_failed_file_not_found"
841
+ final_status = "failed_file_not_found"
842
+ except Exception as launch_err:
843
+ self.log_error(f"Internal trigger: Exception during CreateProcessAsUser for helper script (user '{user}'): {launch_err}", exc_info=True)
844
+ immediate_start_status = "start_failed_launch_exception"
845
+ final_status = "failed_launch_exception"
846
+ finally:
847
+ if 'token' in locals() and token: # Ensure token is defined before trying to close
848
+ try:
849
+ win32api.CloseHandle(token)
850
+ except: # Ignore errors closing handle
851
+ pass
811
852
 
812
853
  # Combine results (mostly determined by start attempt now)
813
854
  # Example: final_status = f"{task_created_status}_{immediate_start_status}"
@@ -818,35 +859,48 @@ class GuardService(win32serviceutil.ServiceFramework):
818
859
  return "failed_trigger_exception"
819
860
 
820
861
 
821
- def create_or_update_logon_task(self, username, port):
862
+ def create_or_update_logon_task(self, username):
822
863
  """Creates/updates task to trigger the internal signal script on session connect."""
823
- if not self.target_executable_path:
824
- self.log_error(f"Cannot create task for {username}: Target executable path not found.")
864
+ if not self.signal_script_path:
865
+ self.log_error(f"Cannot create task for {username}: Signal script path is not set.")
825
866
  return False
867
+ if not sys.executable:
868
+ self.log_error(f"Cannot create task for {username}: sys.executable is not found.")
869
+ return False
870
+
871
+ # Use the python executable that the service itself is running under
872
+ python_exe = sys.executable
873
+ if ' ' in python_exe and not python_exe.startswith('"'):
874
+ python_exe = f'"{python_exe}"'
826
875
 
827
876
  task_name = f"OOTB_UserConnect_{username}"
828
- target_exe_unquoted = self.target_executable_path.strip('"')
829
- target_exe_for_ps = target_exe_unquoted.replace("'", "''")
830
- action_arguments = f"--port {port} --target_user '{username}'".replace("'", "''") # Arguments for the target exe
831
-
832
- # Working directory for the executable
877
+ # Action: Run python.exe with the signal script and username argument
878
+ action_executable = python_exe
879
+ # Ensure script path is quoted if needed
880
+ script_arg = self.signal_script_path # Should be quoted already by _find_signal_script
881
+ # Username might need quoting if it contains spaces, though unlikely
882
+ user_arg = username # Keep simple for now
883
+ action_arguments = f'{script_arg} "{user_arg}"' # Pass username as quoted arg
884
+ safe_action_executable = action_executable.replace("'", "''") # Escape for PS
885
+ safe_action_arguments = action_arguments.replace("'", "''") # Escape for PS
886
+
887
+ # Working directory for the script (likely its own directory)
833
888
  try:
834
- target_dir = os.path.dirname(target_exe_unquoted)
835
- if not target_dir: target_dir = "."
836
- safe_working_directory = target_dir.replace("'", "''")
889
+ script_dir = os.path.dirname(self.signal_script_path.strip('"'))
890
+ if not script_dir: script_dir = "."
891
+ safe_working_directory = script_dir.replace("'", "''")
837
892
  working_directory_setting = f"$action.WorkingDirectory = '{safe_working_directory}'"
838
893
  except Exception as e:
839
- self.log_error(f"Error determining working directory for target exe task: {e}. WD will not be set.")
894
+ self.log_error(f"Error determining working directory for signal script task: {e}. WD will not be set.")
840
895
  working_directory_setting = "# Could not set WorkingDirectory"
841
896
 
842
897
  # PowerShell command construction
843
898
  ps_command = f"""
844
899
  $taskName = "{task_name}"
845
- # Principal runs as the user, but with highest privileges
846
- $principal = New-ScheduledTaskPrincipal -UserId "{username}" -LogonType Interactive -RunLevel Highest
900
+ $principal = New-ScheduledTaskPrincipal -UserId "{username}" -LogonType Interactive
847
901
 
848
- # Action: Run the target executable directly with arguments
849
- $action = New-ScheduledTaskAction -Execute '{target_exe_for_ps}' -Argument '{action_arguments}'
902
+ # Action: Run python signal script
903
+ $action = New-ScheduledTaskAction -Execute '{safe_action_executable}' -Argument '{safe_action_arguments}'
850
904
  {working_directory_setting}
851
905
 
852
906
  # Trigger: On session connect (Event ID 21)
@@ -916,6 +970,49 @@ class GuardService(win32serviceutil.ServiceFramework):
916
970
  self.log_info(f"Attempted removal of scheduled task '{task_name}' for user '{username}'.")
917
971
  return True
918
972
 
973
+ def _find_signal_script(self):
974
+ """Finds the signal_connection.py script relative to this service file."""
975
+ return self._find_helper_script("signal_connection.py") # Reuse helper finding logic
976
+
977
+ def _find_helper_script(self, script_name):
978
+ """Finds a helper script relative to this service file."""
979
+ try:
980
+ # Use __file__ which should be reliable when run as a service via pythonservice.exe
981
+ base_dir = os.path.dirname(os.path.abspath(__file__))
982
+ script_path = os.path.join(base_dir, script_name)
983
+ if os.path.exists(script_path):
984
+ self.log_info(f"Found helper script '{script_name}' at: {script_path}")
985
+ # Return unquoted path for potential quoting later
986
+ return script_path
987
+ else:
988
+ self.log_error(f"Helper script '{script_name}' not found near {base_dir}")
989
+ return None
990
+ except Exception as e:
991
+ self.log_error(f"Error finding helper script '{script_name}': {e}")
992
+ return None
993
+
994
+ def _find_powershell_executable(self):
995
+ """Finds powershell.exe, preferring the system path."""
996
+ try:
997
+ # Check System32 first
998
+ system32_path = os.path.join(os.environ.get('SystemRoot', 'C:\\Windows'), 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe')
999
+ if os.path.exists(system32_path):
1000
+ self.log_info(f"Found powershell.exe at: {system32_path}")
1001
+ return system32_path
1002
+ else:
1003
+ # Fallback to checking PATH using shutil.which (requires Python 3.3+)
1004
+ # Make sure to import shutil at the top of the file if not already present
1005
+ powershell_path = shutil.which("powershell.exe")
1006
+ if powershell_path:
1007
+ self.log_info(f"Found powershell.exe via PATH: {powershell_path}")
1008
+ return powershell_path
1009
+ else:
1010
+ self.log_error("powershell.exe not found in System32 or PATH.")
1011
+ return None
1012
+ except Exception as e:
1013
+ self.log_error(f"Error finding powershell.exe: {e}")
1014
+ return None
1015
+
919
1016
  # --- Main Execution Block ---
920
1017
  if __name__ == '__main__':
921
1018
  if len(sys.argv) > 1 and sys.argv[1] == 'debug':
@@ -0,0 +1,69 @@
1
+ # launch_ootb_elevated.ps1
2
+ param(
3
+ [Parameter(Mandatory=$true)]
4
+ [string]$TargetExePath,
5
+
6
+ [Parameter(Mandatory=$true)]
7
+ [string]$Port,
8
+
9
+ [Parameter(Mandatory=$true)]
10
+ [string]$TargetUser,
11
+
12
+ [Parameter(Mandatory=$true)]
13
+ [string]$WorkingDirectory
14
+ )
15
+
16
+ try {
17
+ Write-Host "--- OOTB Elevation Helper ---"
18
+ Write-Host "Timestamp: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
19
+ Write-Host "Received parameters:"
20
+ Write-Host " Target Exe Path : $TargetExePath"
21
+ Write-Host " Port : $Port"
22
+ Write-Host " Target User : $TargetUser"
23
+ Write-Host " Working Dir : $WorkingDirectory"
24
+ Write-Host ""
25
+
26
+ # Validate paths
27
+ if (-not (Test-Path -Path $TargetExePath -PathType Leaf)) {
28
+ throw "Target executable not found at '$TargetExePath'"
29
+ }
30
+ if (-not (Test-Path -Path $WorkingDirectory -PathType Container)) {
31
+ throw "Working directory not found at '$WorkingDirectory'"
32
+ }
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''"
39
+
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
45
+ Write-Host "Executing elevated process..."
46
+ Write-Host "Command: Start-Process -FilePath cmd.exe -ArgumentList @('/K', '$cmdKSecondArg') -WorkingDirectory '$WorkingDirectory' -Verb RunAs"
47
+ Write-Host "--- Waiting for UAC prompt if necessary ---"
48
+
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
51
+
52
+ Write-Host "--- OOTB Elevation Helper: Start-Process command executed. ---"
53
+ # The calling powershell window (started by CreateProcessAsUser with -NoExit) will remain open.
54
+
55
+ } catch {
56
+ Write-Error "--- OOTB Elevation Helper Error ---"
57
+ Write-Error "Error launching elevated process: $($_.Exception.Message)"
58
+ Write-Error "Script Parameters:"
59
+ Write-Error " Target Exe Path : $TargetExePath"
60
+ Write-Error " Port : $Port"
61
+ Write-Error " Target User : $TargetUser"
62
+ Write-Error " Working Dir : $WorkingDirectory"
63
+ Write-Host "Press Enter to exit..."
64
+ Read-Host # Keep window open on error
65
+ Exit 1
66
+ }
67
+
68
+ # Exit gracefully if successful
69
+ Exit 0