Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
SwitchProcessCommand.cs135 linesDownload Raw Back to Modules
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#nullable enable5 6using System;7using System.Collections;8using System.Collections.Generic;9using System.Management.Automation;10using System.Runtime.InteropServices;11 12using Dbg = System.Management.Automation.Diagnostics;13 14#if UNIX15 16namespace Microsoft.PowerShell.Commands17{18    /// <summary>19    /// Implements a cmdlet that allows use of execv API.20    /// </summary>21    [Cmdlet(VerbsCommon.Switch, "Process", HelpUri = "https://go.microsoft.com/fwlink/?linkid=2181448")]22    public sealed class SwitchProcessCommand : PSCmdlet23    {24        /// <summary>25        /// Get or set the command and arguments to replace the current pwsh process.26        /// </summary>27        [Parameter(Position = 0, Mandatory = false, ValueFromRemainingArguments = true)]28        public string[] WithCommand { get; set; } = Array.Empty<string>();29 30        /// <summary>31        /// Execute the command and arguments32        /// </summary>33        protected override void EndProcessing()34        {35            if (WithCommand.Length == 0)36            {37                return;38            }39 40            // execv requires command to be full path so resolve command to first match41            var command = this.SessionState.InvokeCommand.GetCommand(WithCommand[0], CommandTypes.Application);42            if (command is null)43            {44                ThrowTerminatingError(45                    new ErrorRecord(46                        new CommandNotFoundException(47                            string.Format(48                                System.Globalization.CultureInfo.InvariantCulture,49                                CommandBaseStrings.NativeCommandNotFound,50                                WithCommand[0]51                            )52                        ),53                        "CommandNotFound",54                        ErrorCategory.InvalidArgument,55                        WithCommand[0]56                    )57                );58            }59 60            var execArgs = new string?[WithCommand.Length + 1];61 62            // execv convention is the first arg is the program name63            execArgs[0] = command.Name;64 65            for (int i = 1; i < WithCommand.Length; i++)66            {67                execArgs[i] = WithCommand[i];68            }69 70            // need null terminator at end71            execArgs[execArgs.Length - 1] = null;72 73            var env = Environment.GetEnvironmentVariables();74            var envBlock = new string?[env.Count + 1];75            int j = 0;76            foreach (DictionaryEntry entry in env)77            {78                envBlock[j++] = entry.Key + "=" + entry.Value;79            }80 81            envBlock[envBlock.Length - 1] = null;82 83            // setup termios for a child process as .NET modifies termios dynamically for use with ReadKey()84            ConfigureTerminalForChildProcess(true);85            int exitCode = Exec(command.Source, execArgs, envBlock);86            if (exitCode < 0)87            {88                ConfigureTerminalForChildProcess(false);89                ThrowTerminatingError(90                    new ErrorRecord(91                        new Exception(92                            string.Format(93                                System.Globalization.CultureInfo.InvariantCulture,94                                CommandBaseStrings.ExecFailed,95                                Marshal.GetLastPInvokeError(),96                                string.Join(' ', WithCommand)97                            )98                        ),99                        "ExecutionFailed",100                        ErrorCategory.InvalidOperation,101                        WithCommand102                    )103                );104            }105        }106 107        /// <summary>108        /// The `execv` POSIX syscall we use to exec /bin/sh.109        /// </summary>110        /// <param name="path">The path to the executable to exec.</param>111        /// <param name="args">112        /// The arguments to send through to the executable.113        /// Array must have its final element be null.114        /// </param>115        /// <param name="env">116        /// The environment variables to send through to the executable in the form of "key=value".117        /// Array must have its final element be null.118        /// <returns>119        /// An exit code if exec failed, but if successful the calling process will be overwritten.120        /// </returns>121        [DllImport("libc",122            EntryPoint = "execve",123            CallingConvention = CallingConvention.Cdecl,124            CharSet = CharSet.Ansi,125            SetLastError = true)]126        private static extern int Exec(string path, string?[] args, string?[] env);127 128        // leverage .NET runtime's native library which abstracts the need to handle different OS and architectures for termios api129        [DllImport("libSystem.Native", EntryPoint = "SystemNative_ConfigureTerminalForChildProcess")]130        private static extern void ConfigureTerminalForChildProcess([MarshalAs(UnmanagedType.Bool)] bool childUsesTerminal);131    }132}133 134#endif135