// // Copyright (c) 2009 Microsoft Corporation. All rights reserved. // // DISCLAIMER OF WARRANTY: The software is licensed “as-is.” You // bear the risk of using it. Microsoft gives no express warranties, // guarantees or conditions. You may have additional consumer rights // under your local laws which this agreement cannot change. To the extent // permitted under your local laws, Microsoft excludes the implied warranties // of merchantability, fitness for a particular purpose and non-infringement. namespace Microsoft.Samples.PowerShell.Commands { using System; using System.Collections.Generic; using System.Diagnostics; using System.Management.Automation; // Windows PowerShell namespace. using System.Security.Permissions; using Win32Exception = System.ComponentModel.Win32Exception; #region GetProcCommand /// /// This class implements the get-proc cmdlet. /// [Cmdlet(VerbsCommon.Get, "Proc", DefaultParameterSetName = "ProcessName")] public class GetProcCommand : PSCmdlet { #region Fields /// /// The names of the processes to act on. /// private string[] processNames; /// /// The identifiers of the processes to act on. /// private int[] processIds; /// /// The process objects to act on. /// private Process[] inputObjects; #endregion Fields #region Parameters /// /// Gets or sets the list of process names on /// which the Get-Proc cmdlet will work. /// [Parameter( Position = 0, ParameterSetName = "ProcessName", ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)] [ValidateNotNullOrEmpty] public string[] Name { get { return this.processNames; } set { this.processNames = value; } } /// /// Gets or sets the list of process identifiers on /// which the Get-Proc cmdlet will work. /// [Parameter( ParameterSetName = "Id", Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The unique id of the process to get.")] public int[] Id { get { return this.processIds; } set { this.processIds = value; } } /// /// Gets or sets Process objects directly. If the input is a /// stream of [collection of] Process objects, the cmdlet bypasses the /// ProcessName and Id parameters and reads the Process objects /// directly. This allows the cmdlet to deal with processes that have /// wildcard characters in their name. /// Process objects /// [Parameter( ParameterSetName = "InputObject", Mandatory = true, ValueFromPipeline = true)] public Process[] Input { get { return this.inputObjects; } set { this.inputObjects = value; } } #endregion Parameters #region Cmdlet Overrides /// /// The ProcessRecord method calls the Process.GetProcesses /// method to retrieve the processes. Then, the WriteObject /// method writes the associated processes to the pipeline. /// protected override void ProcessRecord() { List matchingProcesses; WriteDebug("Obtaining the list of matching process objects."); switch (ParameterSetName) { case "Id": matchingProcesses = this.GetMatchingProcessesById(); break; case "ProcessName": matchingProcesses = this.GetMatchingProcessesByName(); break; case "InputObject": matchingProcesses = this.GetProcessesByInput(); break; default: ThrowTerminatingError( new ErrorRecord( new ArgumentException("Bad ParameterSetName"), "UnableToAccessProcessList", ErrorCategory.InvalidOperation, null)); return; } // switch (ParameterSetName) WriteDebug("Outputting the matching process objects."); matchingProcesses.Sort(ProcessComparison); foreach (Process process in matchingProcesses) { WriteObject(process); } } // ProcessRecord #endregion Overrides #region protected Methods and Data /// /// Retrieves the list of all processes matching the ProcessName /// parameter and generates a nonterminating error for each /// specified process name which is not found even though the name /// contains no wildcards. /// /// The matching processes. [EnvironmentPermissionAttribute( SecurityAction.LinkDemand, Unrestricted = true)] private List GetMatchingProcessesByName() { new EnvironmentPermission( PermissionState.Unrestricted).Assert(); List allProcesses = new List(Process.GetProcesses()); // The keys dictionary is used for rapid lookup of // processes that are already in the matchingProcesses list. Dictionary keys = new Dictionary(); List matchingProcesses = new List(); if (null == this.processNames) { matchingProcesses.AddRange(allProcesses); } else { foreach (string pattern in this.processNames) { WriteVerbose("Finding matches for process name \"" + pattern + "\"."); // WildCard serach on the available processes WildcardPattern wildcard = new WildcardPattern( pattern, WildcardOptions.IgnoreCase); bool found = false; foreach (Process process in allProcesses) { if (!keys.ContainsKey(process.Id)) { string processName = SafeGetProcessName(process); // Remove the process from the allProcesses list // so that it is not tested again. if (processName.Length == 0) { allProcesses.Remove(process); } // Perform a wildcard search on this particular // process name and check whether it matches the // pattern specified. if (!wildcard.IsMatch(processName)) { continue; } WriteDebug("Found matching process id " + process.Id + "."); // A match is found. found = true; // Store the process identifier so that the same process // is not added twice. keys.Add(process.Id, 0); // Add the process to the processes list. matchingProcesses.Add(process); } } // foreach (Process... if (!found && !WildcardPattern.ContainsWildcardCharacters(pattern)) { WriteError(new ErrorRecord( new ArgumentException("Cannot find process name " + "\"" + pattern + "\"."), "ProcessNameNotFound", ErrorCategory.ObjectNotFound, pattern)); } } // foreach (string... } // if (null... return matchingProcesses; } // GetMatchingProcessesByName /// /// Returns the name of a process. If an error occurs, a blank /// string is returned. /// /// The process whose name is /// returned. /// The name of the process. [EnvironmentPermissionAttribute( SecurityAction.LinkDemand, Unrestricted = true)] protected static string SafeGetProcessName(Process process) { new EnvironmentPermission(PermissionState.Unrestricted).Assert(); string name = String.Empty; if (process != null) { try { return process.ProcessName; } catch (Win32Exception) { } catch (InvalidOperationException) { } } return name; } // SafeGetProcessName #endregion Cmdlet Overrides #region Private Methods /// /// Function to sort by process name first, and then by /// the process identifier. /// /// First process object. /// Second process object. /// /// Returns less than zero if x is less than y, /// greater than 0 if x is greater than y, and 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; } else { return x.Id.CompareTo(y.Id); } } /// /// Retrieves the list of all processes matching the Id /// parameter and generates a nonterminating error for /// each specified process identofier which is not found. /// /// /// An array of processes that match the given identifier. /// [EnvironmentPermissionAttribute( SecurityAction.LinkDemand, Unrestricted = true)] private List GetMatchingProcessesById() { new EnvironmentPermission( PermissionState.Unrestricted).Assert(); List matchingProcesses = new List(); if (null != this.processIds) { // The keys dictionary is used for rapid lookup of the // processes already in the matchingProcesses list. Dictionary keys = new Dictionary(); foreach (int processId in this.processIds) { WriteVerbose("Finding match for process id " + processId + "."); if (!keys.ContainsKey(processId)) { Process process; try { process = Process.GetProcessById(processId); } catch (ArgumentException ex) { WriteError(new ErrorRecord( ex, "ProcessIdNotFound", ErrorCategory.ObjectNotFound, processId)); continue; } WriteDebug("Found matching process."); matchingProcesses.Add(process); keys.Add(processId, 0); } } } return matchingProcesses; } // GetMatchingProcessesById /// /// Retrieves the list of all processes matching the InputObject /// parameter. /// /// The matching processes. [EnvironmentPermissionAttribute( SecurityAction.LinkDemand, Unrestricted = true)] private List GetProcessesByInput() { new EnvironmentPermission( PermissionState.Unrestricted).Assert(); List matchingProcesses = new List(); if (null != this.Input) { // The keys dictionary is used for rapid lookup of the // processes already in the matchingProcesses list. Dictionary keys = new Dictionary(); foreach (Process process in this.Input) { WriteVerbose("Refreshing process object."); if (!keys.ContainsKey(process.Id)) { try { process.Refresh(); } catch (Win32Exception) { } catch (InvalidOperationException) { } matchingProcesses.Add(process); } } } return matchingProcesses; } // GetProcessesByInput #endregion Private Methods } // End GetProcCommand class. #endregion GetProcCommand }