/********************************************************************++ Copyright (c) Microsoft Corporation. All rights reserved. --********************************************************************/ using System; using System.Text; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; // Process class using System.ComponentModel; // Win32Exception using System.Runtime.Serialization; using System.Threading; using System.Management.Automation; using System.Diagnostics.CodeAnalysis; using System.Net; using System.IO; using System.Runtime.InteropServices; using System.Security; using System.Security.Principal; using Microsoft.Win32.SafeHandles; using System.Management.Automation.Internal; using Microsoft.PowerShell.Commands.Internal; using Microsoft.Management.Infrastructure; using FileNakedHandle = System.IntPtr; using DWORD = System.UInt32; #if CORECLR // Use stubs for SafeHandleZeroOrMinusOneIsInvalid and SerializableAttribute using Microsoft.PowerShell.CoreClr.Stubs; using Environment = System.Management.Automation.Environment; #else using System.Runtime.ConstrainedExecution; using System.Security.Permissions; #endif namespace Microsoft.PowerShell.Commands { // 2004/12/17-JonN ProcessNameGlobAttribute was deeply wrong. // For example, if you pass in a single Process, it will match // all processes with the same name. // I have removed the globbing code. #region ProcessBaseCommand /// /// This class implements the base for process commands /// public abstract class ProcessBaseCommand : Cmdlet { #region Parameters /// /// The various process selection modes /// internal enum MatchMode { /// /// Select all processes /// All, /// /// Select processes matching the supplied names /// ByName, /// /// Select the processes matching the id /// ById, /// /// Select the processes specified as input. /// ByInput }; /// /// The current process selection mode. /// internal MatchMode myMode = MatchMode.All; /// /// The computer from which to retrieve processes. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] protected string[] SuppliedComputerName { get { return computerName; } set { computerName = value; } } private string[] computerName = new string[0]; /// /// The Name parameter is declared in subclasses, /// since it is optional for GetProcess and mandatory for StopProcess. /// internal string[] processNames = null; // The Id parameter is declared in subclasses, // since it is positional for StopProcess but not for GetProcess. internal int[] processIds = null; /// /// If the input is a stream of [collections of] /// Process objects, we bypass the Name and /// Id parameters and read the Process objects /// directly. This allows us to deal with processes which /// have wildcard characters in their name. /// /// Process objects [Parameter( ParameterSetName = "InputObject", Mandatory = true, ValueFromPipeline = true)] public virtual Process[] InputObject { get { return input; } set { myMode = MatchMode.ByInput; input = value; } } Process[] input = null; #endregion Parameters #region Internal // We use a Dictionary to optimize the check whether the object // is already in the list. private List _matchingProcesses = new List(); private Dictionary _keys = new Dictionary(); /// /// Retrieve the list of all processes matching the Name, Id /// and InputObject parameters, sorted by Id. /// /// internal List MatchingProcesses() { _matchingProcesses.Clear(); switch (myMode) { case MatchMode.ById: RetrieveMatchingProcessesById(); break; case MatchMode.ByInput: RetrieveProcessesByInput(); break; default: // Default is "Name": RetrieveMatchingProcessesByProcessName(); break; } // 2004/12/16 Note that the processes will be sorted // before being stopped. PM confirms that this is fine. _matchingProcesses.Sort(ProcessComparison); return _matchingProcesses; } // MatchingProcesses /// /// sort function to sort by Name first, then Id /// /// first Process object /// second Process object /// /// as String.Compare: returns less than zero if x less than y, /// greater than 0 if x greater than y, 0 if x == y /// private static int ProcessComparison(Process x, Process y) { int diff = String.Compare( SafeGetProcessName(x), SafeGetProcessName(y), StringComparison.CurrentCultureIgnoreCase); if (0 != diff) return diff; return SafeGetProcessId(x) - SafeGetProcessId(y); } /// /// Retrieves the list of all processes matching the Name /// parameter. /// Generates a non-terminating error for each specified /// process name which is not found even though it contains /// no wildcards. /// /// private void RetrieveMatchingProcessesByProcessName() { if (null == processNames) { _matchingProcesses = new List(AllProcesses); return; } foreach (string pattern in processNames) { WildcardPattern wildcard = WildcardPattern.Get(pattern, WildcardOptions.IgnoreCase); bool found = false; foreach (Process process in AllProcesses) { if (!wildcard.IsMatch(SafeGetProcessName(process))) continue; found = true; AddIdempotent(process); } if (!found && !WildcardPattern.ContainsWildcardCharacters(pattern)) { WriteNonTerminatingError( pattern, 0, pattern, null, ProcessResources.NoProcessFoundForGivenName, "NoProcessFoundForGivenName", ErrorCategory.ObjectNotFound); } } } // MatchingProcessesByProcessName /// /// Retrieves the list of all processes matching the Id /// parameter. /// Generates a non-terminating error for each specified /// process ID which is not found. /// /// private void RetrieveMatchingProcessesById() { if (null == processIds) { Diagnostics.Assert(false, "null processIds"); throw PSTraceSource.NewInvalidOperationException(); } foreach (int processId in processIds) { Process process; try { if (SuppliedComputerName.Length > 0) { foreach(string computerName in SuppliedComputerName) { process = Process.GetProcessById(processId, computerName); AddIdempotent(process); } } else { process = Process.GetProcessById(processId); AddIdempotent(process); } } catch (ArgumentException) { WriteNonTerminatingError( "", processId, processId, null, ProcessResources.NoProcessFoundForGivenId, "NoProcessFoundForGivenId", ErrorCategory.ObjectNotFound); continue; } } } // MatchingProcessesById /// /// Retrieves the list of all processes matching the InputObject /// parameter. /// /// private void RetrieveProcessesByInput() { if (null == InputObject) { Diagnostics.Assert(false, "null InputObject"); throw PSTraceSource.NewInvalidOperationException(); } foreach (Process process in InputObject) { SafeRefresh(process); AddIdempotent(process); } } // MatchingProcessesByInput /// /// Retrieve the master list of all processes /// /// /// /// MSDN does not document the list of exceptions, /// but it is reasonable to expect that SecurityException is /// among them. Errors here will terminate the cmdlet. /// internal Process[] AllProcesses { get { if (null == allProcesses) { List processes = new List(); if (SuppliedComputerName.Length > 0) { foreach(string computerName in SuppliedComputerName) { processes.AddRange(Process.GetProcesses(computerName)); } } else { processes.AddRange(Process.GetProcesses()); } allProcesses = processes.ToArray(); } return allProcesses; } } private Process[] allProcesses = null; /// /// Add to , /// but only if it is not already on . /// We use a Dictionary to optimize the check whether the object /// is already in the list. /// /// process to add to list private void AddIdempotent( Process process) { int hashCode = SafeGetProcessName(process).GetHashCode() ^ SafeGetProcessId(process); // XOR if (!_keys.ContainsKey(hashCode)) { _keys.Add(hashCode, process); _matchingProcesses.Add(process); } } /// /// Writes a non-terminating error. /// /// /// /// /// /// internal void WriteNonTerminatingError( Process process, Exception innerException, string resourceId, string errorId, ErrorCategory category ) { WriteNonTerminatingError( SafeGetProcessName(process), SafeGetProcessId(process), process, innerException, resourceId, errorId, category); } /// /// Writes a non-terminating error. /// /// /// /// /// /// /// /// internal void WriteNonTerminatingError( string processName, int processId, object targetObject, Exception innerException, string resourceId, string errorId, ErrorCategory category) { string message = StringUtil.Format(resourceId, processName, processId, (null == innerException) ? "" : innerException.Message); ProcessCommandException exception = new ProcessCommandException(message, innerException); exception.ProcessName = processName; WriteError(new ErrorRecord( exception, errorId, category, targetObject)); } // The Name property is not always available, even for // live processes (such as the Idle process). internal static string SafeGetProcessName(Process process) { try { return process.ProcessName; } catch (Win32Exception) { return ""; } catch (InvalidOperationException) { return ""; } } // 2004/12/17-JonN I saw this fail once too, so we'll play it safe internal static int SafeGetProcessId(Process process) { try { return process.Id; } catch (Win32Exception) { return int.MinValue; } catch (InvalidOperationException) { return int.MinValue; } } internal static void SafeRefresh(Process process) { try { process.Refresh(); } catch (Win32Exception) { } catch (InvalidOperationException) { } } /// /// TryHasExited is a helper function used to detect if the process has aready exited or not. /// /// /// Process whose exit status has to be checked. /// /// Tre if the process has exited or else returns false. internal static bool TryHasExited(Process process) { bool hasExited = true; try { hasExited = process.HasExited; } catch (Win32Exception) { hasExited = false; } catch (InvalidOperationException) { hasExited = false; } return hasExited; } #endregion Internal }//ProcessBaseCommand #endregion ProcessBaseCommand #region GetProcessCommand /// /// This class implements the get-process command /// [Cmdlet(VerbsCommon.Get, "Process", DefaultParameterSetName = NameParameterSet, HelpUri = "http://go.microsoft.com/fwlink/?LinkID=113324", RemotingCapability = RemotingCapability.SupportedByCommand)] [OutputType(typeof(ProcessModule), typeof(FileVersionInfo), typeof(Process))] public sealed class GetProcessCommand : ProcessBaseCommand { #region ParameterSetStrings private const string NameParameterSet = "Name"; private const string IdParameterSet = "Id"; private const string InputObjectParameterSet = "InputObject"; private const string NameWithUserNameParameterSet = "NameWithUserName"; private const string IdWithUserNameParameterSet = "IdWithUserName"; private const string InputObjectWithUserNameParameterSet = "InputObjectWithUserName"; #endregion ParameterSetStrings #region Parameters /// /// Has the list of process names on which to this command will work /// // [ProcessNameGlobAttribute] [Parameter(Position = 0, ParameterSetName = NameParameterSet, ValueFromPipelineByPropertyName = true)] [Parameter(Position = 0, ParameterSetName = NameWithUserNameParameterSet, ValueFromPipelineByPropertyName = true)] [Alias("ProcessName")] [ValidateNotNullOrEmpty] public string[] Name { get { return processNames; } set { myMode = MatchMode.ByName; processNames = value; } } /// /// gets/sets an array of process IDs /// [Parameter(ParameterSetName = IdParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Parameter(ParameterSetName = IdWithUserNameParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Alias("PID")] public int[] Id { get { return processIds; } set { myMode = MatchMode.ById; processIds = value; } } /// /// Input is a stream of [collections of] Process objects /// [Parameter(ParameterSetName = InputObjectParameterSet, Mandatory = true, ValueFromPipeline = true)] [Parameter(ParameterSetName = InputObjectWithUserNameParameterSet, Mandatory = true, ValueFromPipeline = true)] public override Process[] InputObject { get { return base.InputObject; } set { base.InputObject = value; } } /// /// Include the UserName /// [Parameter(ParameterSetName = NameWithUserNameParameterSet, Mandatory = true)] [Parameter(ParameterSetName = IdWithUserNameParameterSet, Mandatory = true)] [Parameter(ParameterSetName = InputObjectWithUserNameParameterSet, Mandatory = true)] public SwitchParameter IncludeUserName { get { return _includeUserName; } set { _includeUserName = value; } } private bool _includeUserName = false; /// /// gets/sets the destination computer name /// [Parameter(Mandatory = false, ParameterSetName = NameParameterSet, ValueFromPipelineByPropertyName = true)] [Parameter(Mandatory = false, ParameterSetName = IdParameterSet, ValueFromPipelineByPropertyName = true)] [Parameter(Mandatory = false, ParameterSetName = InputObjectParameterSet, ValueFromPipelineByPropertyName = true)] [Alias("Cn")] [ValidateNotNullOrEmpty()] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] ComputerName { get { return SuppliedComputerName; } set { SuppliedComputerName = value; } } /// ///To display the modules of a process /// [Parameter(ParameterSetName = NameParameterSet)] [Parameter(ParameterSetName = IdParameterSet)] [Parameter(ParameterSetName = InputObjectParameterSet)] [ValidateNotNull] public SwitchParameter Module { get { return _module; } set { _module = value; } } private SwitchParameter _module; /// ///To display the fileversioninfo of the main module of a process /// [Parameter(ParameterSetName = NameParameterSet)] [Parameter(ParameterSetName = IdParameterSet)] [Parameter(ParameterSetName = InputObjectParameterSet)] [Alias("FV","FVI")] [ValidateNotNull] public SwitchParameter FileVersionInfo { get { return _fileversioninfo; } set { _fileversioninfo = value; } } private SwitchParameter _fileversioninfo; #endregion Parameters #region Overrides /// /// Check the elevation mode if IncludeUserName is specified /// protected override void BeginProcessing() { // The parameter 'IncludeUserName' requires administrator privilege if (IncludeUserName.IsPresent && !Utils.IsAdministrator()) { var ex = new InvalidOperationException(ProcessResources.IncludeUserNameRequiresElevation); var er = new ErrorRecord(ex, "IncludeUserNameRequiresElevation", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } } /// /// Write the process objects /// protected override void ProcessRecord() { if (ComputerName.Length > 0 && (_fileversioninfo.IsPresent || _module.IsPresent)) { Exception ex = new InvalidOperationException(ProcessResources.NoComputerNameWithFileVersion); ErrorRecord er = new ErrorRecord(ex, "InvalidOperationException", ErrorCategory.InvalidOperation, ComputerName); ThrowTerminatingError(er); } foreach (Process process in MatchingProcesses()) { //if module and fileversion are to be displayed if (_module.IsPresent && _fileversioninfo.IsPresent) { ProcessModule tempmodule = null; try { ProcessModuleCollection modules = process.Modules; foreach (ProcessModule pmodule in modules) { //assigning to tempmodule to rethrow for exceptions on 64 bit machines tempmodule = pmodule; WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(pmodule), true); } } catch (InvalidOperationException exception) { WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateModuleFileVer, "CouldnotEnumerateModuleFileVer", ErrorCategory.PermissionDenied); } catch (ArgumentException exception) { WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateModuleFileVer, "CouldnotEnumerateModuleFileVer", ErrorCategory.PermissionDenied); } catch (Win32Exception exception) { try { if (exception.HResult == 299) { WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(tempmodule), true); } else { WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateModuleFileVer, "CouldnotEnumerateModuleFileVer", ErrorCategory.PermissionDenied); } } catch (Win32Exception ex) { WriteNonTerminatingError(process, ex, ProcessResources.CouldnotEnumerateModuleFileVer, "CouldnotEnumerateModuleFileVer", ErrorCategory.PermissionDenied); } } catch (Exception exception) { CommandsCommon.CheckForSevereException(this, exception); WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateModuleFileVer, "CouldnotEnumerateModuleFileVer", ErrorCategory.PermissionDenied); } } else if (_module.IsPresent) { //if only modules are to be displayed try { WriteObject(process.Modules, true); } catch (Win32Exception exception) { try { if (exception.HResult == 299) { WriteObject(process.Modules, true); } else { WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateModules, "CouldnotEnumerateModules", ErrorCategory.PermissionDenied); } } catch (Win32Exception ex) { WriteNonTerminatingError(process, ex, ProcessResources.CouldnotEnumerateModules, "CouldnotEnumerateModules", ErrorCategory.PermissionDenied); } } catch (Exception exception) { CommandsCommon.CheckForSevereException(this, exception); WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateModules, "CouldnotEnumerateModules", ErrorCategory.PermissionDenied); } } else if (_fileversioninfo.IsPresent) { //if fileversion of each process is to be displayed try { WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(PsUtils.GetMainModule(process)), true); } catch (InvalidOperationException exception) { WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateFileVer, "CouldnotEnumerateFileVer", ErrorCategory.PermissionDenied); } catch (ArgumentException exception) { WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateFileVer, "CouldnotEnumerateFileVer", ErrorCategory.PermissionDenied); } catch (Win32Exception exception) { try { if (exception.HResult == 299) { WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(PsUtils.GetMainModule(process)), true); } else { WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateFileVer, "CouldnotEnumerateFileVer", ErrorCategory.PermissionDenied); } } catch (Win32Exception ex) { WriteNonTerminatingError(process, ex, ProcessResources.CouldnotEnumerateFileVer, "CouldnotEnumerateFileVer", ErrorCategory.PermissionDenied); } } catch (Exception exception) { CommandsCommon.CheckForSevereException(this, exception); WriteNonTerminatingError(process, exception, ProcessResources.CouldnotEnumerateFileVer, "CouldnotEnumerateFileVer", ErrorCategory.PermissionDenied); } } else { #if CORECLR WriteObject(AddProperties(IncludeUserName.IsPresent, process, this)); #else WriteObject(IncludeUserName.IsPresent ? AddUserNameToProcess(process, this) : process); #endif } }//for loop } // ProcessRecord #endregion Overrides #region IncludeUserName /// /// New PSTypeName added to the process object /// private const string TypeNameForProcessWithUserName = "System.Diagnostics.Process#IncludeUserName"; /// /// Add the 'UserName' NoteProperty to the Process object /// /// /// /// internal object AddUserNameToProcess(Process process, Cmdlet cmdlet) { // Return null if we failed to get the owner information string userName = RetrieveProcessUserName(process, cmdlet); PSObject processAsPsobj = PSObject.AsPSObject(process); PSNoteProperty noteProperty = new PSNoteProperty("UserName", userName); processAsPsobj.Properties.Add(noteProperty, true); processAsPsobj.TypeNames.Insert(0, TypeNameForProcessWithUserName); return processAsPsobj; } #if CORECLR /// /// Add the 'UserName' and 'HandleCount' NoteProperties to the Process object. /// /// /// /// /// internal object AddProperties(bool includeUserName, Process process, Cmdlet cmdlet) { PSObject processAsPsobj = PSObject.AsPSObject(process); if (includeUserName) { // Return null if we failed to get the owner information string userName = RetrieveProcessUserName(process, cmdlet); PSNoteProperty noteProperty = new PSNoteProperty("UserName", userName); processAsPsobj.Properties.Add(noteProperty, true); processAsPsobj.TypeNames.Insert(0, TypeNameForProcessWithUserName); } // In CoreCLR, the System.Diagnostics.Process.HandleCount property does not exist. // I am adding a note property HandleCount and temporarily setting it to zero. // This issue will be fix for RTM and it is tracked by 5024994: Get-process does not populate the Handles field. PSMemberInfo hasHandleCount = processAsPsobj.Properties["HandleCount"]; if (hasHandleCount == null) { PSNoteProperty noteProperty = new PSNoteProperty("HandleCount", 0); processAsPsobj.Properties.Add(noteProperty, true); processAsPsobj.TypeNames.Insert(0, "System.Diagnostics.Process#HandleCount"); } return processAsPsobj; } #endif /// /// Retrieve the UserName through PInvoke /// /// /// /// private static string RetrieveProcessUserName(Process process, Cmdlet cmdlet) { string userName = null; IntPtr tokenUserInfo = IntPtr.Zero; IntPtr processTokenHandler = IntPtr.Zero; const uint TOKEN_QUERY = 0x0008; try { do { int error; if (!Win32Native.OpenProcessToken(ClrFacade.GetSafeProcessHandle(process), TOKEN_QUERY, out processTokenHandler)) { break; } // Set the default length to be 256, so it will be sufficient for most cases int tokenInfoLength = 256; tokenUserInfo = Marshal.AllocHGlobal(tokenInfoLength); if (!Win32Native.GetTokenInformation(processTokenHandler, Win32Native.TOKEN_INFORMATION_CLASS.TokenUser, tokenUserInfo, tokenInfoLength, out tokenInfoLength)) { error = Marshal.GetLastWin32Error(); if (error == Win32Native.ERROR_INSUFFICIENT_BUFFER) { Marshal.FreeHGlobal(tokenUserInfo); tokenUserInfo = Marshal.AllocHGlobal(tokenInfoLength); if (!Win32Native.GetTokenInformation(processTokenHandler, Win32Native.TOKEN_INFORMATION_CLASS.TokenUser, tokenUserInfo, tokenInfoLength, out tokenInfoLength)) { break; } } else { break; } } var tokenUser = ClrFacade.PtrToStructure(tokenUserInfo); // Set the default length to be 256, so it will be sufficient for most cases int userNameLength = 256, domainNameLength = 256; var userNameStr = new StringBuilder(userNameLength); var domainNameStr = new StringBuilder(domainNameLength); Win32Native.SID_NAME_USE accountType; if (!Win32Native.LookupAccountSid(null, tokenUser.User.Sid, userNameStr, ref userNameLength, domainNameStr, ref domainNameLength, out accountType)) { error = Marshal.GetLastWin32Error(); if (error == Win32Native.ERROR_INSUFFICIENT_BUFFER) { userNameStr.EnsureCapacity(userNameLength); domainNameStr.EnsureCapacity(domainNameLength); if (!Win32Native.LookupAccountSid(null, tokenUser.User.Sid, userNameStr, ref userNameLength, domainNameStr, ref domainNameLength, out accountType)) { break; } } else { break; } } userName = domainNameStr + "\\" + userNameStr; } while (false); } catch (NotSupportedException) { // The Process not started yet, or it's a process from a remote machine } catch (InvalidOperationException) { // The Process has exited, Process.Handle will raise this exception } catch (Win32Exception) { // We might get an AccessDenied error } catch (Exception ex) { // I don't expect to get other exceptions, CommandsCommon.CheckForSevereException(cmdlet, ex); } finally { if (tokenUserInfo != IntPtr.Zero) { Marshal.FreeHGlobal(tokenUserInfo); } if (processTokenHandler != IntPtr.Zero) { Win32Native.CloseHandle(processTokenHandler); } } return userName; } #endregion IncludeUserName }//GetProcessCommand #endregion GetProcessCommand #region WaitProcessCommand /// /// This class implements the Wait-process command /// [Cmdlet(VerbsLifecycle.Wait, "Process", DefaultParameterSetName = "Name", HelpUri = "http://go.microsoft.com/fwlink/?LinkID=135277")] public sealed class WaitProcessCommand : ProcessBaseCommand { #region Parameters /// /// Specifies the process IDs of the processes to be waited on. /// [Parameter( ParameterSetName = "Id", Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] [Alias("PID", "ProcessId")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public int[] Id { get { return processIds; } set { myMode = MatchMode.ById; processIds = value; } } /// /// Name of the processes to wait on for termintation /// [Parameter( ParameterSetName = "Name", Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Alias("ProcessName")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] Name { get { return processNames; } set { myMode = MatchMode.ByName; processNames = value; } } /// /// If specified, wait for this number of seconds /// [Parameter(Position = 1)] [Alias("TimeoutSec")] [ValidateNotNullOrEmpty] [ValidateRange(0, 32767)] public int Timeout { get { return timeout; } set { timeout = value; timeOutSpecified = true; } } private int timeout = 0; private bool timeOutSpecified; #endregion Parameters private bool disposed = false; #region IDisposable /// /// Dispose method of IDisposable interface. /// public void Dispose() { if (disposed == false) { if (waitHandle != null) { waitHandle.Dispose(); waitHandle = null; } disposed = true; } } #endregion #region private methods // Handle Exited event and display process information. private void myProcess_Exited(object sender, System.EventArgs e) { if (0 == System.Threading.Interlocked.Decrement(ref this.numberOfProcessesToWaitFor)) { if (waitHandle != null) { waitHandle.Set(); } } } #endregion #region Overrides List processList = new List(); //Wait handle which is used by thread to sleep. ManualResetEvent waitHandle; private int numberOfProcessesToWaitFor; /// /// gets the list of process /// protected override void ProcessRecord() { //adding the processes into the list foreach (Process process in MatchingProcesses()) { // Idle process has processid zero,so handle that because we cannot wait on it. if (process.Id == 0) { WriteNonTerminatingError(process, null, ProcessResources.WaitOnIdleProcess, "WaitOnIdleProcess", ErrorCategory.ObjectNotFound); continue; } // It cannot wait on itself if (process.Id.Equals(System.Diagnostics.Process.GetCurrentProcess().Id)) { WriteNonTerminatingError(process, null, ProcessResources.WaitOnItself, "WaitOnItself", ErrorCategory.ObjectNotFound); continue; } processList.Add(process); } } // ProcessRecord /// /// Wait for the process to terminate /// protected override void EndProcessing() { waitHandle = new ManualResetEvent(false); foreach (Process process in processList) { try { if (!process.HasExited) { process.EnableRaisingEvents = true; process.Exited += new EventHandler(myProcess_Exited); if (!process.HasExited) { System.Threading.Interlocked.Increment(ref this.numberOfProcessesToWaitFor); } } } catch (Win32Exception exception) { WriteNonTerminatingError(process, exception, ProcessResources.Process_is_not_terminated, "ProcessNotTerminated", ErrorCategory.CloseError); } } if (this.numberOfProcessesToWaitFor > 0) { if (timeOutSpecified) { waitHandle.WaitOne(timeout * 1000); } else { waitHandle.WaitOne(); } } foreach (Process process in processList) { try { if (!process.HasExited) { //write the error string message = StringUtil.Format(ProcessResources.ProcessNotTerminated, new object[] { process.ProcessName, process.Id }); ErrorRecord errorRecord = new ErrorRecord(new TimeoutException(message), "ProcessNotTerminated", ErrorCategory.CloseError, process); WriteError(errorRecord); } } catch (Win32Exception exception) { WriteNonTerminatingError(process, exception, ProcessResources.Process_is_not_terminated, "ProcessNotTerminated", ErrorCategory.CloseError); } } } /// /// StopProcessing /// protected override void StopProcessing() { if (waitHandle != null) { waitHandle.Set(); } } #endregion Overrides }//WaitProcessCommand #endregion WaitProcessCommand #region StopProcessCommand /// /// This class implements the stop-process command /// /// /// Processes will be sorted before being stopped. PM confirms /// that this should be fine. /// [Cmdlet(VerbsLifecycle.Stop, "Process", DefaultParameterSetName = "Id", SupportsShouldProcess = true, HelpUri = "http://go.microsoft.com/fwlink/?LinkID=113412")] [OutputType(typeof(Process))] public sealed class StopProcessCommand : ProcessBaseCommand { #region Parameters /// /// Has the list of process names on which to this command will work /// // [ProcessNameGlobAttribute] [Parameter( ParameterSetName = "Name", Mandatory = true, ValueFromPipelineByPropertyName = true)] [Alias("ProcessName")] public string[] Name { get { return processNames; } set { processNames = value; myMode = MatchMode.ByName; } } /// /// gets/sets an array of process IDs /// [Parameter( Position = 0, ParameterSetName = "Id", Mandatory = true, ValueFromPipelineByPropertyName = true)] public int[] Id { get { return processIds; } set { myMode = MatchMode.ById; processIds = value; } } /// /// gets/sets an array of objects /// [Parameter( Position = 0, ParameterSetName = "InputObject", Mandatory = true, ValueFromPipeline = true)] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public new Process[] InputObject { get { return base.InputObject; } set { base.InputObject = value; } } private bool passThru; /// /// The updated process object should be passed down the pipeline. /// [Parameter] public SwitchParameter PassThru { get { return passThru; } set { passThru = value; } } //Addition by v-ramch Mar 18 2008 //Added force parameter /// /// Specifies whether to force a process to kill /// even if it has dependent services. /// /// [Parameter] [ValidateNotNullOrEmpty] public SwitchParameter Force { get { return force; } set { force = value; } } private SwitchParameter force; #endregion Parameters #region Overrides /// /// Kill the processes. /// It is a non-terminating error if the Process.Kill() operation fails. /// protected override void ProcessRecord() { if (myMode == MatchMode.All || (myMode == MatchMode.ByName && processNames == null)) { Diagnostics.Assert(false, "trying to kill all processes"); throw PSTraceSource.NewInvalidOperationException(); } foreach (Process process in MatchingProcesses()) { // confirm the operation first // this is always false if WhatIf is set // 2005-06-21 Moved this ahead of the hasExited check string targetString = StringUtil.Format( ProcessResources.ProcessNameForConfirmation, SafeGetProcessName(process), SafeGetProcessId(process)); if (!ShouldProcess(targetString)) { continue; } try { // Many properties including Name are not available if the process has exited. // If this is the case, we skip the process. If the process is from a remote // machine, then we generate a non-terminating error because .NET doesn't support // terminate a remote process. if (process.HasExited) { if (PassThru) WriteObject(process); continue; } } catch (NotSupportedException ex) { WriteNonTerminatingError( process, ex, ProcessResources.CouldNotStopProcess, "CouldNotStopProcess", ErrorCategory.InvalidOperation); continue; } catch (Win32Exception ex) { // This process could not be stopped, so write a non-terminating error. WriteNonTerminatingError( process, ex, ProcessResources.CouldNotStopProcess, "CouldNotStopProcess", ErrorCategory.CloseError); continue; } try { //check if the process is current process and kill it at last if (Process.GetCurrentProcess().Id == SafeGetProcessId(process)) { shouldKillCurrentProcess = true; continue; } if (!Force) { // Check if the process is owned by current user if (!IsProcessOwnedByCurrentUser(process)) { string message = StringUtil.Format( ProcessResources.ConfirmStopProcess, SafeGetProcessName(process), SafeGetProcessId(process)); // caption: null = default caption if (!ShouldContinue(message, null, ref yesToAll, ref noToAll)) continue; } } //if the process is svchost stop all the dependent services before killing process if (string.Equals(SafeGetProcessName(process), "SVCHOST", StringComparison.CurrentCultureIgnoreCase)) { StopDependentService(process); } // kill the process if (!process.HasExited) { process.Kill(); } } catch (Win32Exception exception) { if (!TryHasExited(process)) { // This process could not be stopped, // so write a non-terminating error. WriteNonTerminatingError( process, exception, ProcessResources.CouldNotStopProcess, "CouldNotStopProcess", ErrorCategory.CloseError); continue; } } catch (InvalidOperationException exception) { if (!TryHasExited(process)) { // This process could not be stopped, // so write a non-terminating error. WriteNonTerminatingError( process, exception, ProcessResources.CouldNotStopProcess, "CouldNotStopProcess", ErrorCategory.CloseError); continue; } } if (PassThru) WriteObject(process); } } // ProcessRecord /// /// Kill the current process here. /// protected override void EndProcessing() { if (shouldKillCurrentProcess) { StopProcess(Process.GetCurrentProcess()); } }//EndProcessing #endregion Overrides #region Private /// /// should the current powershell process to be killed /// private bool shouldKillCurrentProcess; /// /// Boolean variables to display the warning using shouldcontinue /// private bool yesToAll, noToAll; /// /// Current windows user name /// private string currentUserName; /// /// gets the owner of the process /// /// /// returns the owner private bool IsProcessOwnedByCurrentUser(Process process) { const uint TOKEN_QUERY = 0x0008; IntPtr ph = IntPtr.Zero; try { if (Win32Native.OpenProcessToken(ClrFacade.GetSafeProcessHandle(process), TOKEN_QUERY, out ph)) { if (currentUserName == null) { using (var currentUser = WindowsIdentity.GetCurrent()) { currentUserName = currentUser.Name; } } using (var processUser = new WindowsIdentity(ph)) { return string.Equals(processUser.Name, currentUserName, StringComparison.CurrentCultureIgnoreCase); } } } catch (IdentityNotMappedException) { //Catching IdentityMappedException //Need not throw error. } catch (ArgumentException) { //Catching ArgumentException. In Win2k3 Token is zero //Need not throw error. } finally { if (ph != IntPtr.Zero) { Win32Native.CloseHandle(ph); } } return false; } /// /// Stop the service that depends on the process and its child services /// /// private void StopDependentService(Process process) { string queryString = "Select * From Win32_Service Where ProcessId=" + SafeGetProcessId(process) + " And State !='Stopped'"; try { using (CimSession cimSession = CimSession.Create(null)) { IEnumerable serviceList = cimSession.QueryInstances("root/cimv2", "WQL", queryString); foreach (CimInstance oService in serviceList) { string serviceName = oService.CimInstanceProperties["Name"].Value.ToString(); using (var service = new System.ServiceProcess.ServiceController(serviceName)) { //try stopping the service, if cant we are not writing exception try { service.Stop(); // Wait 2 sec for the status to become 'Stopped' service.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 2)); } catch (Win32Exception) { } catch (InvalidOperationException) { } catch (System.ServiceProcess.TimeoutException) { } } } } } catch (CimException ex) { var errorRecord = new ErrorRecord(ex, "GetCimException", ErrorCategory.InvalidOperation, null); WriteError(errorRecord); } } /// /// stops the given process throws non terminating error if cant /// process to be stopped /// true if process stopped successfully else false /// private void StopProcess(Process process) { Exception exception = null; try { if (!process.HasExited) { process.Kill(); } } catch (Win32Exception e) { exception = e; } catch (InvalidOperationException e) { exception = e; } if (null != exception) { if (!TryHasExited(process)) { // This process could not be stopped, // so write a non-terminating error. WriteNonTerminatingError( process, exception, ProcessResources.CouldNotStopProcess, "CouldNotStopProcess", ErrorCategory.CloseError); } } } #endregion Private }//StopProcessCommand #endregion StopProcessCommand #region DebugProcessCommand /// /// This class implements the Debug-process command /// [Cmdlet(VerbsDiagnostic.Debug, "Process", DefaultParameterSetName = "Name", SupportsShouldProcess = true, HelpUri = "http://go.microsoft.com/fwlink/?LinkID=135206")] public sealed class DebugProcessCommand : ProcessBaseCommand { #region Parameters /// /// Specifies the process IDs of the processes to be waited on. /// [Parameter( ParameterSetName = "Id", Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] [Alias("PID", "ProcessId")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public int[] Id { get { return processIds; } set { myMode = MatchMode.ById; processIds = value; } } /// /// Name of the processes to wait on for termintation /// [Parameter( ParameterSetName = "Name", Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true)] [Alias("ProcessName")] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] Name { get { return processNames; } set { myMode = MatchMode.ByName; processNames = value; } } #endregion Parameters #region Overrides /// /// gets the list of process and attach the debugger to the processes /// protected override void ProcessRecord() { //for the processes foreach (Process process in MatchingProcesses()) { string targetMessage = StringUtil.Format( ProcessResources.ProcessNameForConfirmation, SafeGetProcessName(process), SafeGetProcessId(process)); if (!ShouldProcess(targetMessage)) { continue; } // sometimes Idle process has processid zero,so handle that because we cannot attach debugger to it. if (process.Id == 0) { WriteNonTerminatingError( process, null, ProcessResources.NoDebuggerFound, "NoDebuggerFound", ErrorCategory.ObjectNotFound); continue; } try { // If the process has exited, we skip it. If the process is from a remote // machine, then we generate a non-terminating error. if (process.HasExited) { continue; } } catch (NotSupportedException ex) { WriteNonTerminatingError( process, ex, ProcessResources.CouldNotDebugProcess, "CouldNotDebugProcess", ErrorCategory.InvalidOperation); continue; } catch (Win32Exception ex) { // This process could not be stopped, so write a non-terminating error. WriteNonTerminatingError( process, ex, ProcessResources.CouldNotDebugProcess, "CouldNotDebugProcess", ErrorCategory.CloseError); continue; } AttachDebuggerToProcess(process); } } // ProcessRecord #endregion Overrides /// /// Attach debugger to the process /// private void AttachDebuggerToProcess(Process process) { string searchQuery = "Select * From Win32_Process Where ProcessId=" + SafeGetProcessId(process); using (CimSession cimSession = CimSession.Create(null)) { IEnumerable processCollection = cimSession.QueryInstances("root/cimv2", "WQL", searchQuery); foreach (CimInstance processInstance in processCollection) { try { // Call the AttachDebugger method CimMethodResult result = cimSession.InvokeMethod(processInstance, "AttachDebugger", null); int returnCode = Convert.ToInt32(result.ReturnValue.Value, System.Globalization.CultureInfo.CurrentCulture); if (returnCode != 0) { var ex = new InvalidOperationException(MapReturnCodeToErrorMessage(returnCode)); WriteNonTerminatingError( process, ex, ProcessResources.CouldNotDebugProcess, "CouldNotDebugProcess", ErrorCategory.InvalidOperation); } } catch (CimException e) { string message = e.Message; if (!string.IsNullOrEmpty(message)) { message = message.Trim(); } var errorRecord = new ErrorRecord( new InvalidOperationException(StringUtil.Format(ProcessResources.DebuggerError, message)), "GetCimException", ErrorCategory.InvalidOperation, null); WriteError(errorRecord); } } } } /// /// Map the return code from 'AttachDebugger' to error message /// private string MapReturnCodeToErrorMessage(int returnCode) { string errorMessage = string.Empty; switch (returnCode) { case 2: errorMessage = ProcessResources.AttachDebuggerReturnCode2; break; case 3: errorMessage = ProcessResources.AttachDebuggerReturnCode3; break; case 8: errorMessage = ProcessResources.AttachDebuggerReturnCode8; break; case 9: errorMessage = ProcessResources.AttachDebuggerReturnCode9; break; case 21: errorMessage = ProcessResources.AttachDebuggerReturnCode21; break; default: Diagnostics.Assert(false, "Unreachable code."); break; } return errorMessage; } } #endregion DebugProcessCommand #region StartProcessCommand /// /// This class implements the Start-process command /// [Cmdlet(VerbsLifecycle.Start, "Process",DefaultParameterSetName="Default", HelpUri = "http://go.microsoft.com/fwlink/?LinkID=135261")] [OutputType(typeof(Process))] public sealed class StartProcessCommand : PSCmdlet, IDisposable { private ManualResetEvent waithandle = null; private bool isDefaultSetParameterSpecified = false; #region Parameters /// /// Path/FileName of the process to start /// [Parameter(Mandatory = true, Position = 0)] [ValidateNotNullOrEmpty] [Alias("PSPath")] public string FilePath { get { return _path; } set { _path = value; } } private string _path; /// /// Arguments for the process /// [Parameter(Position = 1)] [Alias("Args")] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] public string[] ArgumentList { get { return _argumentlist; } set { _argumentlist = value; } } private string[] _argumentlist; /// /// Credentials for the process /// [Parameter(ParameterSetName="Default")] [Alias("RunAs")] [ValidateNotNullOrEmpty] [Credential] public PSCredential Credential { get { return _credential; } set { _credential = value; isDefaultSetParameterSpecified = true; } } private PSCredential _credential; /// /// working directory of the process /// [Parameter] [ValidateNotNullOrEmpty] public string WorkingDirectory { get { return _workingdirectory; } set { _workingdirectory = value; } } private string _workingdirectory; /// /// load user profile from registry /// [Parameter(ParameterSetName="Default")] [Alias("Lup")] public SwitchParameter LoadUserProfile { get { return _loaduserprofile; } set { _loaduserprofile = value; isDefaultSetParameterSpecified = true; } } private SwitchParameter _loaduserprofile = SwitchParameter.Present; /// /// starts process in a new window /// [Parameter(ParameterSetName="Default")] [Alias("nnw")] public SwitchParameter NoNewWindow { get { return _nonewwindow; } set { _nonewwindow = value; isDefaultSetParameterSpecified = true; } } private SwitchParameter _nonewwindow; /// /// passthru parameter /// [Parameter] public SwitchParameter PassThru { get { return _passthru; } set { _passthru = value; } } private SwitchParameter _passthru; /// /// Redirect error /// [Parameter(ParameterSetName="Default")] [Alias("RSE")] [ValidateNotNullOrEmpty] public string RedirectStandardError { get { return _redirectstandarderror; } set { _redirectstandarderror = value; isDefaultSetParameterSpecified = true; } } private string _redirectstandarderror; /// /// Redirect input /// [Parameter(ParameterSetName = "Default")] [Alias("RSI")] [ValidateNotNullOrEmpty] public string RedirectStandardInput { get { return _redirectstandardinput; } set { _redirectstandardinput = value; isDefaultSetParameterSpecified = true; } } private string _redirectstandardinput; /// /// Redirect output /// [Parameter(ParameterSetName = "Default")] [Alias("RSO")] [ValidateNotNullOrEmpty] public string RedirectStandardOutput { get { return _redirectstandardoutput; } set { _redirectstandardoutput = value; isDefaultSetParameterSpecified = true; } } private string _redirectstandardoutput; #if !CORECLR /// /// Verb /// /// /// The 'Verb' parameter is not supported in OneCore PowerShell /// because 'UseShellExecute' is not supported in CoreCLR. /// [Parameter(ParameterSetName = "UseShellExecute")] [ValidateNotNullOrEmpty] public string Verb { get { return _verb; } set { _verb = value; } } private string _verb; /// /// Window style of the process window /// /// /// The 'WindowStyle' is not supported in CoreCLR /// [Parameter] [ValidateNotNullOrEmpty] public ProcessWindowStyle WindowStyle { get { return _windowstyle; } set { _windowstyle = value; _windowstyleSpecified = true; } } private ProcessWindowStyle _windowstyle = ProcessWindowStyle.Normal; private bool _windowstyleSpecified = false; #endif /// /// wait for th eprocess to terminate /// [Parameter] public SwitchParameter Wait { get { return _wait; } set { _wait = value; } } private SwitchParameter _wait; /// /// Default Environment /// [Parameter(ParameterSetName = "Default")] public SwitchParameter UseNewEnvironment { get { return _UseNewEnvironment; } set { _UseNewEnvironment = value; isDefaultSetParameterSpecified = true; } } private SwitchParameter _UseNewEnvironment; #endregion #region overrides /// /// /// protected override void BeginProcessing() { //create an instance of the ProcessStartInfo Class ProcessStartInfo startInfo = new ProcessStartInfo(); string message = String.Empty; //Path = Mandatory parameter -> Will not be empty. try { CommandInfo cmdinfo = CommandDiscovery.LookupCommandInfo( _path, CommandTypes.Application | CommandTypes.ExternalScript, SearchResolutionOptions.None, CommandOrigin.Internal, this.Context); startInfo.FileName = cmdinfo.Definition; } catch (CommandNotFoundException) { startInfo.FileName = _path; } //Arguments if (_argumentlist != null) { StringBuilder sb = new StringBuilder(); foreach (string str in _argumentlist) { sb.Append(str); sb.Append(' '); } startInfo.Arguments = sb.ToString(); ; } //WorkingDirectory if (_workingdirectory != null) { //WorkingDirectory -> Not Exist -> Throw Error _workingdirectory = ResolveFilePath(_workingdirectory); if (!Directory.Exists(_workingdirectory)) { message = StringUtil.Format(ProcessResources.InvalidInput, "WorkingDirectory"); ErrorRecord er = new ErrorRecord(new DirectoryNotFoundException(message), "DirectoryNotFoundException", ErrorCategory.InvalidOperation, null); WriteError(er); return; } startInfo.WorkingDirectory = _workingdirectory; } else { //Working Directory not specified -> Assign Current Path. startInfo.WorkingDirectory = ResolveFilePath(this.SessionState.Path.CurrentFileSystemLocation.Path); } if (this.ParameterSetName.Equals("Default")) { if (isDefaultSetParameterSpecified) { startInfo.UseShellExecute = false; } //UseNewEnvironment if (_UseNewEnvironment) { ClrFacade.GetProcessEnvironment(startInfo).Clear(); LoadEnvironmentVariable(startInfo, Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine)); LoadEnvironmentVariable(startInfo, Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User)); } #if !CORECLR // 'WindowStyle' not supported in CoreCLR if (_nonewwindow && _windowstyleSpecified) { message = StringUtil.Format(ProcessResources.ContradictParametersSpecified, "-NoNewWindow", "-WindowStyle"); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); WriteError(er); return; } //WindowStyle startInfo.WindowStyle = _windowstyle; #endif //NewWindow if (_nonewwindow) { startInfo.CreateNoWindow = _nonewwindow; } //LoadUserProfile. startInfo.LoadUserProfile = _loaduserprofile; if (_credential != null) { //Gets NetworkCredentials NetworkCredential nwcredential = _credential.GetNetworkCredential(); startInfo.UserName = nwcredential.UserName; if (String.IsNullOrEmpty(nwcredential.Domain)) { startInfo.Domain = "."; } else { startInfo.Domain = nwcredential.Domain; } #if CORECLR startInfo.PasswordInClearText = ClrFacade.ConvertSecureStringToString(_credential.Password); #else startInfo.Password = _credential.Password; #endif } //RedirectionInput File Check -> Not Exist -> Throw Error if (_redirectstandardinput != null) { _redirectstandardinput = ResolveFilePath(_redirectstandardinput); if (!File.Exists(_redirectstandardinput)) { message = StringUtil.Format(ProcessResources.InvalidInput, "RedirectStandardInput '" + this.RedirectStandardInput + "'"); ErrorRecord er = new ErrorRecord(new FileNotFoundException(message), "FileNotFoundException", ErrorCategory.InvalidOperation, null); WriteError(er); return; } } //RedirectionInput == RedirectionOutput -> Throw Error if (_redirectstandardinput != null && _redirectstandardoutput != null) { _redirectstandardinput = ResolveFilePath(_redirectstandardinput); _redirectstandardoutput = ResolveFilePath(_redirectstandardoutput); if (_redirectstandardinput.Equals(_redirectstandardoutput, StringComparison.CurrentCultureIgnoreCase)) { message = StringUtil.Format(ProcessResources.DuplicateEntry, "RedirectStandardInput", "RedirectStandardOutput"); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); WriteError(er); return; } } //RedirectionInput == RedirectionError -> Throw Error if (_redirectstandardinput != null && _redirectstandarderror != null) { _redirectstandardinput = ResolveFilePath(_redirectstandardinput); _redirectstandarderror = ResolveFilePath(_redirectstandarderror); if (_redirectstandardinput.Equals(_redirectstandarderror, StringComparison.CurrentCultureIgnoreCase)) { message = StringUtil.Format(ProcessResources.DuplicateEntry, "RedirectStandardInput", "RedirectStandardError"); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); WriteError(er); return; } } //RedirectionOutput == RedirectionError -> Throw Error if (_redirectstandardoutput != null && _redirectstandarderror != null) { _redirectstandarderror = ResolveFilePath(_redirectstandarderror); _redirectstandardoutput = ResolveFilePath(_redirectstandardoutput); if (_redirectstandardoutput.Equals(_redirectstandarderror, StringComparison.CurrentCultureIgnoreCase)) { message = StringUtil.Format(ProcessResources.DuplicateEntry, "RedirectStandardOutput", "RedirectStandardError"); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); WriteError(er); return; } } } #if !CORECLR // 'UseShellExecute' is not supported in CoreCLR else if (ParameterSetName.Equals("UseShellExecute")) { startInfo.UseShellExecute = true; //Verb if (_verb != null) { startInfo.Verb = _verb; } //WindowStyle startInfo.WindowStyle = _windowstyle; } #endif //Starts the Process Process process = start(startInfo); //Wait and Passthru Implementation. if (_passthru.IsPresent) { if (process != null) { WriteObject(process); } else { message = StringUtil.Format(ProcessResources.CannotStarttheProcess); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } } if (_wait.IsPresent) { if (process != null) { if (!process.HasExited) { waithandle = new ManualResetEvent(false); // Create and start the job object ProcessCollection jobObject = new ProcessCollection(); if (jobObject.AssignProcessToJobObject(process)) { // Wait for the job object to finish jobObject.WaitOne(waithandle); } else { // WinBlue: 27537 Start-Process -Wait doesn't work in a remote session on Windows 7 or lower. process.Exited += new EventHandler(myProcess_Exited); process.EnableRaisingEvents = true; process.WaitForExit(); } } } else { message = StringUtil.Format(ProcessResources.CannotStarttheProcess); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } } } /// /// Implements ^c, after creating a process. /// protected override void StopProcessing() { if (waithandle != null) { waithandle.Set(); } } /// /// When Process exits the wait handle is set. /// /// /// private void myProcess_Exited(object sender, System.EventArgs e) { if (waithandle != null) { waithandle.Set(); } } #region Private Methods private void LoadEnvironmentVariable(ProcessStartInfo startinfo, IDictionary EnvironmentVariables) { var processEnvironment = ClrFacade.GetProcessEnvironment(startinfo); foreach (DictionaryEntry entry in EnvironmentVariables) { if (processEnvironment.ContainsKey(entry.Key.ToString())) { processEnvironment.Remove(entry.Key.ToString()); } if (entry.Key.ToString().Equals("PATH")) { processEnvironment.Add(entry.Key.ToString(), Environment.GetEnvironmentVariable(entry.Key.ToString(), EnvironmentVariableTarget.Machine) + ";" + Environment.GetEnvironmentVariable(entry.Key.ToString(), EnvironmentVariableTarget.User)); } else { processEnvironment.Add(entry.Key.ToString(), entry.Value.ToString()); } } } private Process StartWithCreateProcess(ProcessStartInfo startinfo) { ProcessNativeMethods.STARTUPINFO lpStartupInfo = new ProcessNativeMethods.STARTUPINFO(); SafeNativeMethods.PROCESS_INFORMATION lpProcessInformation = new SafeNativeMethods.PROCESS_INFORMATION(); int error = 0; GCHandle pinnedEnvironmentBlock = new GCHandle(); string message = String.Empty; //building the cmdline with the file name given and it's arguments StringBuilder cmdLine = BuildCommandLine(startinfo.FileName, startinfo.Arguments); try { //RedirectionStandardInput if (_redirectstandardinput != null) { startinfo.RedirectStandardInput = true; _redirectstandardinput = ResolveFilePath(_redirectstandardinput); lpStartupInfo.hStdInput = GetSafeFileHandleForRedirection(_redirectstandardinput, ProcessNativeMethods.OPEN_EXISTING); } else { lpStartupInfo.hStdInput = new SafeFileHandle(ProcessNativeMethods.GetStdHandle(-10), false); } //RedirectionStandardOutput if (_redirectstandardoutput != null) { startinfo.RedirectStandardOutput = true; _redirectstandardoutput = ResolveFilePath(_redirectstandardoutput); lpStartupInfo.hStdOutput = GetSafeFileHandleForRedirection(_redirectstandardoutput, ProcessNativeMethods.CREATE_ALWAYS); } else { lpStartupInfo.hStdOutput = new SafeFileHandle(ProcessNativeMethods.GetStdHandle(-11), false); } //RedirectionStandardError if (_redirectstandarderror != null) { startinfo.RedirectStandardError = true; _redirectstandarderror = ResolveFilePath(_redirectstandarderror); lpStartupInfo.hStdError = GetSafeFileHandleForRedirection(_redirectstandarderror, ProcessNativeMethods.CREATE_ALWAYS); } else { lpStartupInfo.hStdError = new SafeFileHandle(ProcessNativeMethods.GetStdHandle(-12), false); } //STARTF_USESTDHANDLES lpStartupInfo.dwFlags = 0x100; int creationFlags = 0; if (startinfo.CreateNoWindow) { //No new window: Inherit the parent process's console window creationFlags = 0x00000000; } else { //CREATE_NEW_CONSOLE creationFlags |= 0x00000010; //STARTF_USESHOWWINDOW lpStartupInfo.dwFlags |= 0x00000001; #if CORECLR //SW_SHOWNORMAL lpStartupInfo.wShowWindow = 1; #else switch (startinfo.WindowStyle) { case ProcessWindowStyle.Normal: //SW_SHOWNORMAL lpStartupInfo.wShowWindow = 1; break; case ProcessWindowStyle.Minimized: //SW_SHOWMINIMIZED lpStartupInfo.wShowWindow = 2; break; case ProcessWindowStyle.Maximized: //SW_SHOWMAXIMIZED lpStartupInfo.wShowWindow = 3; break; case ProcessWindowStyle.Hidden: //SW_HIDE lpStartupInfo.wShowWindow = 0; break; } #endif } // Create the new process suspended so we have a chance to get a corresponding Process object in case it terminates quickly. creationFlags |= 0x00000004; IntPtr AddressOfEnvironmentBlock = IntPtr.Zero; var environmentVars = ClrFacade.GetProcessEnvironment(startinfo); if (environmentVars != null) { if (this.UseNewEnvironment) { bool unicode = false; if (ProcessManager.IsNt) { creationFlags |= 0x400; unicode = true; } pinnedEnvironmentBlock = GCHandle.Alloc(EnvironmentBlock.ToByteArray(environmentVars, unicode), GCHandleType.Pinned); AddressOfEnvironmentBlock = pinnedEnvironmentBlock.AddrOfPinnedObject(); } } bool flag; if (_credential != null) { ProcessNativeMethods.LogonFlags logonFlags = 0; if (startinfo.LoadUserProfile) { logonFlags = ProcessNativeMethods.LogonFlags.LOGON_WITH_PROFILE; } IntPtr password = IntPtr.Zero; try { #if CORECLR password = (startinfo.PasswordInClearText == null) ? Marshal.StringToCoTaskMemUni(string.Empty) : Marshal.StringToCoTaskMemUni(startinfo.PasswordInClearText); #else password = (startinfo.Password == null) ? Marshal.StringToCoTaskMemUni(string.Empty) : ClrFacade.SecureStringToCoTaskMemUnicode(startinfo.Password); #endif flag = ProcessNativeMethods.CreateProcessWithLogonW(startinfo.UserName, startinfo.Domain, password, logonFlags, null, cmdLine, creationFlags, AddressOfEnvironmentBlock, startinfo.WorkingDirectory, lpStartupInfo, lpProcessInformation); if (!flag) { error = Marshal.GetLastWin32Error(); ErrorRecord er = null; if (error == 0xc1) { message = StringUtil.Format(ProcessResources.InvalidApplication, _path); } else if (error == 0x424) { // The API 'CreateProcessWithLogonW' depends on the 'Secondary Logon' service, but the component 'Microsoft-Windows-SecondaryLogonService' // is not installed in OneCoreUAP. We will get error code 0x424 when the service is not available. message = StringUtil.Format(ProcessResources.ParameterNotSupported, "-Credential", "Start-Process"); er = new ErrorRecord(new NotSupportedException(message), "NotSupportedException", ErrorCategory.NotInstalled, null); } else { Win32Exception win32ex = new Win32Exception(error); message = StringUtil.Format(ProcessResources.InvalidStartProcess, win32ex.Message); } er = er ?? new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } goto Label_03AE; } finally { if (password != IntPtr.Zero) { ClrFacade.ZeroFreeCoTaskMemUnicode(password); } } }//end of if ProcessNativeMethods.SECURITY_ATTRIBUTES lpProcessAttributes = new ProcessNativeMethods.SECURITY_ATTRIBUTES(); ProcessNativeMethods.SECURITY_ATTRIBUTES lpThreadAttributes = new ProcessNativeMethods.SECURITY_ATTRIBUTES(); flag = ProcessNativeMethods.CreateProcess(null, cmdLine, lpProcessAttributes, lpThreadAttributes, true, creationFlags, AddressOfEnvironmentBlock, startinfo.WorkingDirectory, lpStartupInfo, lpProcessInformation); if (!flag) { error = Marshal.GetLastWin32Error(); Win32Exception win32ex = new Win32Exception(error); message = StringUtil.Format(ProcessResources.InvalidStartProcess, win32ex.Message); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } Label_03AE: // At this point, we should have a suspended process. Get the .Net Process object, resume the process, and return. Process result = Process.GetProcessById(lpProcessInformation.dwProcessId); ProcessNativeMethods.ResumeThread(lpProcessInformation.hThread); return result; } finally { if (pinnedEnvironmentBlock.IsAllocated) { pinnedEnvironmentBlock.Free(); } lpStartupInfo.Dispose(); lpProcessInformation.Dispose(); } } private Process StartWithShellExecute(ProcessStartInfo startInfo) { string message = String.Empty; Process result = null; try { result = Process.Start(startInfo); } catch (Win32Exception ex) { message = StringUtil.Format(ProcessResources.InvalidStartProcess, ex.Message); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } return result; } private Process start(ProcessStartInfo startInfo) { Process process = null; if (startInfo.UseShellExecute) { process = StartWithShellExecute(startInfo); } else { process = StartWithCreateProcess(startInfo); } return process; } #endregion #endregion #region IDisposable Overrides /// /// Dispose WaitHandle used to honor -Wait parameter /// public void Dispose() { Dispose(true); System.GC.SuppressFinalize(this); } private void Dispose(bool isDisposing) { if (waithandle != null) { waithandle.Dispose(); waithandle = null; } } #endregion #region Private Methods private string ResolveFilePath(string path) { string filepath = PathUtils.ResolveFilePath(path, this); return filepath; } private SafeFileHandle GetSafeFileHandleForRedirection(string RedirectionPath, uint dwCreationDisposition) { System.IntPtr hFileHandle = System.IntPtr.Zero; ProcessNativeMethods.SECURITY_ATTRIBUTES lpSecurityAttributes = new ProcessNativeMethods.SECURITY_ATTRIBUTES(); hFileHandle = ProcessNativeMethods.CreateFileW(RedirectionPath, ProcessNativeMethods.GENERIC_READ | ProcessNativeMethods.GENERIC_WRITE, ProcessNativeMethods.FILE_SHARE_WRITE | ProcessNativeMethods.FILE_SHARE_READ, lpSecurityAttributes, dwCreationDisposition, ProcessNativeMethods.FILE_ATTRIBUTE_NORMAL, System.IntPtr.Zero); if (hFileHandle == System.IntPtr.Zero) { int error = Marshal.GetLastWin32Error(); Win32Exception win32ex = new Win32Exception(error); string message = StringUtil.Format(ProcessResources.InvalidStartProcess, win32ex.Message); ErrorRecord er = new ErrorRecord(new InvalidOperationException(message), "InvalidOperationException", ErrorCategory.InvalidOperation, null); ThrowTerminatingError(er); } SafeFileHandle sf = new SafeFileHandle(hFileHandle, true); return sf; } internal static class ProcessManager { // Properties public static bool IsNt { get { #if CORECLR return true; #else return (Environment.OSVersion.Platform == PlatformID.Win32NT); #endif } } } internal static class EnvironmentBlock { #if CORECLR public static byte[] ToByteArray(IDictionary sd, bool unicode) #else public static byte[] ToByteArray(StringDictionary sd, bool unicode) #endif { string[] array = new string[sd.Count]; byte[] bytes = null; sd.Keys.CopyTo(array, 0); string[] strArray2 = new string[sd.Count]; sd.Values.CopyTo(strArray2, 0); Array.Sort(array, strArray2, StringComparer.OrdinalIgnoreCase); StringBuilder builder = new StringBuilder(); for (int i = 0; i < sd.Count; i++) { builder.Append(array[i]);// builder.Append('='); builder.Append(strArray2[i]); builder.Append('\0'); } builder.Append('\0'); if (unicode) { bytes = Encoding.Unicode.GetBytes(builder.ToString()); } else { bytes = ClrFacade.GetDefaultEncoding().GetBytes(builder.ToString()); } if (bytes.Length > 0xffff) { throw new InvalidOperationException("EnvironmentBlockTooLong"); } return bytes; } } private static StringBuilder BuildCommandLine(string executableFileName, string arguments) { StringBuilder builder = new StringBuilder(); string str = executableFileName.Trim(); bool flag = str.StartsWith("\"", StringComparison.Ordinal) && str.EndsWith("\"", StringComparison.Ordinal); if (!flag) { builder.Append("\""); } builder.Append(str); if (!flag) { builder.Append("\""); } if (!string.IsNullOrEmpty(arguments)) { builder.Append(" "); builder.Append(arguments); } return builder; } #endregion } /// /// ProcessCollection is a helper class used by Start-Process -Wait cmdlet to monitor the /// child processes created by the main process hosted by the Start-process cmdlet. /// internal class ProcessCollection { /// /// JobObjectHandle is a reference to the job object used to track /// the child processes created by the main process hosted by the Start-Process cmdlet. /// private Microsoft.PowerShell.Commands.SafeJobHandle jobObjectHandle; /// /// ProcessCollection constructor. /// internal ProcessCollection() { IntPtr jobObjectHandleIntPtr = NativeMethods.CreateJobObject(IntPtr.Zero, null); jobObjectHandle = new SafeJobHandle(jobObjectHandleIntPtr); } /// /// Start API assignes the process to the JobObject and starts monitoring /// the child processes hosted by the process created by Start-Process cmdlet. /// internal bool AssignProcessToJobObject(Process process) { // Add the process to the job object bool result = NativeMethods.AssignProcessToJobObject(jobObjectHandle, ClrFacade.GetRawProcessHandle(process)); return result; } /// /// Checks to see if the JobObject is empty (has no assigned processes). /// If job is empty the auto reset event supplied as input would be set. /// internal void CheckJobStatus(Object stateInfo) { ManualResetEvent emptyJobAutoEvent = (ManualResetEvent)stateInfo; int dwSize = 0; const int JOB_OBJECT_BASIC_PROCESS_ID_LIST = 3; JOBOBJECT_BASIC_PROCESS_ID_LIST JobList = new JOBOBJECT_BASIC_PROCESS_ID_LIST(); dwSize = Marshal.SizeOf(JobList); if (NativeMethods.QueryInformationJobObject(jobObjectHandle, JOB_OBJECT_BASIC_PROCESS_ID_LIST, ref JobList, dwSize, IntPtr.Zero)) { if (JobList.NumberOfAssignedProcess == 0) { emptyJobAutoEvent.Set(); } } } /// /// WaitOne blocks the current thread until the current instance receives a signal, using /// a System.TimeSpan to measure the time interval and specifying whether to /// exit the synchronization domain before the wait. /// /// /// WaitHandle to use for waiting on the job object. /// internal void WaitOne(ManualResetEvent waitHandleToUse) { TimerCallback jobObjectStatusCb = this.CheckJobStatus; using (Timer stateTimer = new Timer(jobObjectStatusCb, waitHandleToUse, 0, 1000)) { waitHandleToUse.WaitOne(); } } } /// /// JOBOBJECT_BASIC_PROCESS_ID_LIST Contains the process identifier list for a job object. /// If the job is nested, the process identifier list consists of all /// processes associated with the job and its child jobs. /// [StructLayout(LayoutKind.Sequential)] internal struct JOBOBJECT_BASIC_PROCESS_ID_LIST { /// /// The number of process identifiers to be stored in ProcessIdList. /// public uint NumberOfAssignedProcess; /// /// The number of process identifiers returned in the ProcessIdList buffer. /// If this number is less than NumberOfAssignedProcesses, increase /// the size of the buffer to accommodate the complete list. /// public uint NumberOfProcessIdsInList; /// /// A variable-length array of process identifiers returned by this call. /// Array elements 0 through NumberOfProcessIdsInList– 1 /// contain valid process identifiers. /// public IntPtr ProcessIdList; } internal static class ProcessNativeMethods { // Fields internal static readonly IntPtr INVALID_HANDLE_VALUE = IntPtr.Zero; internal static UInt32 GENERIC_READ = 0x80000000; internal static UInt32 GENERIC_WRITE = 0x40000000; internal static UInt32 FILE_ATTRIBUTE_NORMAL = 0x80000000; internal static UInt32 CREATE_ALWAYS = 2; internal static UInt32 FILE_SHARE_WRITE = 0x00000002; internal static UInt32 FILE_SHARE_READ = 0x00000001; internal static UInt32 OF_READWRITE = 0x00000002; internal static UInt32 OPEN_EXISTING = 3; // Methods // static NativeMethods(); [DllImport(PinvokeDllNames.GetStdHandleDllName, CharSet = CharSet.Ansi, SetLastError = true)] public static extern IntPtr GetStdHandle(int whichHandle); [DllImport(PinvokeDllNames.CreateProcessWithLogonWDllName, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] internal static extern bool CreateProcessWithLogonW(string userName, string domain, IntPtr password, LogonFlags logonFlags, [MarshalAs(UnmanagedType.LPWStr)] string appName, StringBuilder cmdLine, int creationFlags, IntPtr environmentBlock, [MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory, STARTUPINFO lpStartupInfo, SafeNativeMethods.PROCESS_INFORMATION lpProcessInformation); [DllImport(PinvokeDllNames.CreateProcessDllName, CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool CreateProcess([MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpCommandLine, SECURITY_ATTRIBUTES lpProcessAttributes, SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, [MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory, STARTUPINFO lpStartupInfo, SafeNativeMethods.PROCESS_INFORMATION lpProcessInformation); [DllImport(PinvokeDllNames.ResumeThreadDllName, CharSet = CharSet.Unicode, SetLastError = true)] public static extern uint ResumeThread(IntPtr threadHandle); [DllImport(PinvokeDllNames.CreateFileDllName, CharSet = CharSet.Unicode, SetLastError = true)] public static extern FileNakedHandle CreateFileW( [In, MarshalAs(UnmanagedType.LPWStr)] string lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, ProcessNativeMethods.SECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, System.IntPtr hTemplateFile ); [Flags] internal enum LogonFlags { LOGON_NETCREDENTIALS_ONLY = 2, LOGON_WITH_PROFILE = 1 } [StructLayout(LayoutKind.Sequential)] internal class SECURITY_ATTRIBUTES { public int nLength; public SafeLocalMemHandle lpSecurityDescriptor; public bool bInheritHandle; public SECURITY_ATTRIBUTES() { this.nLength = 12; this.bInheritHandle = true; this.lpSecurityDescriptor = new SafeLocalMemHandle(IntPtr.Zero, true); } } internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid { // Methods internal SafeLocalMemHandle() : base(true) { } [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] internal SafeLocalMemHandle(IntPtr existingHandle, bool ownsHandle) : base(ownsHandle) { base.SetHandle(existingHandle); } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport(PinvokeDllNames.LocalFreeDllName)] private static extern IntPtr LocalFree(IntPtr hMem); protected override bool ReleaseHandle() { return (LocalFree(base.handle) == IntPtr.Zero); } } [StructLayout(LayoutKind.Sequential)] internal class STARTUPINFO { public int cb; public IntPtr lpReserved; public IntPtr lpDesktop; public IntPtr lpTitle; public int dwX; public int dwY; public int dwXSize; public int dwYSize; public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public SafeFileHandle hStdInput; public SafeFileHandle hStdOutput; public SafeFileHandle hStdError; public STARTUPINFO() { this.lpReserved = IntPtr.Zero; this.lpDesktop = IntPtr.Zero; this.lpTitle = IntPtr.Zero; this.lpReserved2 = IntPtr.Zero; this.hStdInput = new SafeFileHandle(IntPtr.Zero, false); this.hStdOutput = new SafeFileHandle(IntPtr.Zero, false); this.hStdError = new SafeFileHandle(IntPtr.Zero, false); this.cb = Marshal.SizeOf(this); } public void Dispose(bool disposing) { if (disposing) { if ((this.hStdInput != null) && !this.hStdInput.IsInvalid) { this.hStdInput.Dispose(); this.hStdInput = null; } if ((this.hStdOutput != null) && !this.hStdOutput.IsInvalid) { this.hStdOutput.Dispose(); this.hStdOutput = null; } if ((this.hStdError != null) && !this.hStdError.IsInvalid) { this.hStdError.Dispose(); this.hStdError = null; } } } public void Dispose() { Dispose(true); } } } internal static class SafeNativeMethods { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport(PinvokeDllNames.CloseHandleDllName, SetLastError = true, ExactSpelling = true)] public static extern bool CloseHandle(IntPtr handle); [StructLayout(LayoutKind.Sequential)] internal class PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; public PROCESS_INFORMATION() { this.hProcess = IntPtr.Zero; this.hThread = IntPtr.Zero; } /// /// Dispose /// public void Dispose() { Dispose(true); } /// /// Dispose /// /// private void Dispose(bool disposing) { if (disposing) { if (this.hProcess != IntPtr.Zero) { CloseHandle(this.hProcess); this.hProcess = IntPtr.Zero; } if (this.hThread != IntPtr.Zero) { CloseHandle(this.hThread); this.hThread = IntPtr.Zero; } } } } } [SuppressUnmanagedCodeSecurity] internal sealed class SafeThreadHandle : SafeHandleZeroOrMinusOneIsInvalid { // Methods internal SafeThreadHandle() : base(true) { } protected override bool ReleaseHandle() { return SafeNativeMethods.CloseHandle(base.handle); } } [SuppressUnmanagedCodeSecurity, HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)] internal sealed class SafeJobHandle : SafeHandleZeroOrMinusOneIsInvalid { internal SafeJobHandle(IntPtr jobHandle) : base(true) { base.SetHandle(jobHandle); } protected override bool ReleaseHandle() { return SafeNativeMethods.CloseHandle(base.handle); } } #endregion #region ProcessCommandException /// /// Non-terminating errors occurring in the process noun commands /// [Serializable] public class ProcessCommandException : SystemException { #region ctors /// /// unimplemented standard constructor /// /// doesn't return public ProcessCommandException() : base() { throw new NotImplementedException(); } /// /// standard constructor /// /// /// constructed object public ProcessCommandException(string message) : base(message) { } /// /// standard constructor /// /// /// public ProcessCommandException(string message, Exception innerException) : base(message, innerException) { } #endregion ctors #region Serialization /// /// serialization constructor /// /// /// /// constructed object protected ProcessCommandException( SerializationInfo info, StreamingContext context) : base(info, context) { _processName = info.GetString("ProcessName"); } /// /// Serializer /// /// serialization information /// streaming context [SecurityPermissionAttribute( SecurityAction.Demand, SerializationFormatter = true)] public override void GetObjectData( SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); if(info == null) throw new ArgumentNullException("info"); info.AddValue("ProcessName", _processName); } #endregion Serialization #region Properties /// /// Name of the process which could not be found or operated upon /// /// public string ProcessName { get { return _processName; } set { _processName = value; } } private string _processName = String.Empty; #endregion Properties } // class ProcessCommandException #endregion ProcessCommandException }//Microsoft.PowerShell.Commands