GetProcessSample05 Sample

This sample shows a complete version of the Get-Proc cmdlet.

How to build the sample using Visual Studio.

  1. Open Windows Explorer and navigate to the GetProcessSample05 directory under the Samples directory.

  2. Double-click the icon for the solution (.sln) file. This opens the sample project in Visual Studio.

  3. In the Build menu, select Build Solution.

The library for the sample will be built in the default \bin or \bin\debug directories.

How to run the sample

  1. Create the following module folder:

    [user]/documents/windowspowershell/modules/GetProcessSample05

  2. Copy the sample assembly to the module folder.

  3. Start Windows PowerShell.

  4. Run the following command to load the assembly into Windows PowerShell:

    Import-module getprossessample05

  5. Run the following command to run the cmdlet:

    get-proc

Requirements

This sample requires Windows PowerShell 2.0.

Demonstrates

This sample demonstrates the following.

  • Declaring a cmdlet class using the Cmdlet attribute.

  • Declaring a cmdlet parameter using the Parameter attribute.

  • Specifying positions for parameters.

  • Specifying that parameters can take input from the pipeline. The input can be taken from an object or a value from a property of an object whose property name is the same as the parameter name.

  • Declaring a validation attribute for the parameter input.

  • Handling errors and exceptions.

  • Writing debug messages.

Example

The following code shows an implementation of the complete Get-Proc cmdlet.

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
  
  /// <summary>
  /// This class implements the get-proc cmdlet.
  /// </summary>
  [Cmdlet(VerbsCommon.Get, "Proc", 
          DefaultParameterSetName = "ProcessName")]
  public class GetProcCommand : PSCmdlet
  {
    #region Private Data
    /// <summary>
    /// Names of processes to be acted on.
    /// </summary>
    private string[] processNames;
      
    /// <summary>
    /// Identifier of the processes to be acted on.
    /// </summary>
    private int[] processIds;
    
    /// <summary>
    /// Process objects to be acted on.
    /// </summary>
    private Process[] inputObjects;
    #endregion Private Data
    
    #region Parameters
    /// <summary>
    /// Gets or sets the process names that the cmdlet will
    /// act on.
    /// </summary>
    [Parameter(
               Position = 0,
               ParameterSetName = "ProcessName",
               ValueFromPipeline = true,
               ValueFromPipelineByPropertyName = true)]
    [ValidateNotNullOrEmpty]
    public string[] Name
    {
       get { return this.processNames; }
       set { this.processNames = value; }
    }
    
    /// <summary>
    /// Gets or sets the process identifiers that the 
    /// cmdlet will act on.
    /// </summary>
    [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; }
    }
    
    /// <summary>
    /// Gets or sets the Process objects sent directly to the cmdlet. 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.
    /// <value>Process objects.</value>
    /// </summary>
    [Parameter(
               ParameterSetName = "InputObject",
               Mandatory = true,
               ValueFromPipeline = true)]
    public Process[] Input
    {
      get { return this.inputObjects; }
      set { this.inputObjects = value; }
    }
    #endregion Parameters

    #region Cmdlet Overrides
    /// <summary>
    /// The ProcessRecord method calls the Process.GetProcesses 
    /// method to retrieve the processes. Then, the WriteObject 
    /// method writes the associated processes to the pipeline.
    /// </summary>
    protected override void ProcessRecord()
    {
      List<Process> matchingProcesses;
   
      WriteDebug("Obtaining the list of matching process objects.");
      
      // Determine which helper method to use based on 
      // parameter name.
      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;
      } // End switch (ParameterSetName).
        
      WriteDebug("Outputting the matching process objects.");
        
      matchingProcesses.Sort(ProcessComparison);
      
      foreach (Process process in matchingProcesses)
      {
        WriteObject(process);
      }
    } // End ProcessRecord.
    #endregion Overrides
            
    #region protected Methods and Data
    
    /// <summary>
    /// Retrieves the list of all processes that match the ProcessName
    /// parameter, and then generates a nonterminating error for each 
    /// process name that is not found even though the name contains 
    /// no wildcards.
    /// </summary>
    /// <returns>Matching processes.</returns>
    [EnvironmentPermissionAttribute(
                                    SecurityAction.LinkDemand, 
                                    Unrestricted = true)]
    private List<Process> GetMatchingProcessesByName()
    {
      new EnvironmentPermission(
        PermissionState.Unrestricted).Assert();
       
      List<Process> allProcesses = 
        new List<Process>(Process.GetProcesses());
      
      // The keys dictionary is used for rapid lookup of 
      // processes that are already in the matchingProcesses list.
      Dictionary<int, byte> keys = new Dictionary<int, byte>();
      
      List<Process> matchingProcesses = new List<Process>();

      if (null == this.processNames)
      {
          matchingProcesses.AddRange(allProcesses);
      }
      else
      {
          foreach (string pattern in this.processNames)
          {
              WriteVerbose("Finding matches for process name \""
                      + pattern + "\".");

              // WildCard search 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);
                  }
              } // End foreach (Process...).
              if (!found &&
                 !WildcardPattern.ContainsWildcardCharacters(pattern))
              {
                  WriteError(new ErrorRecord(
                      new ArgumentException("Cannot find process name "
                      + "\"" + pattern + "\"."),
                      "ProcessNameNotFound",
                      ErrorCategory.ObjectNotFound,
                      pattern));
              }
          } // End foreach (string...).
      } // End if (null...).
         
      return matchingProcesses;
    } // End GetMatchingProcessesByName.
     
    /// <summary>
    /// Returns the name of a process.  If an error occurs, a blank
    /// string is returned.
    /// </summary>
    /// <param name="process">The process whose name is 
    /// returned.</param>
    /// <returns>The name of the process.</returns>
    [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;
    } // End SafeGetProcessName.
   
    #endregion Cmdlet Overrides
    
    #region Private Methods
    
    /// <summary>
    /// Function to sort by process name first, and then by 
    /// the process identifier.
    /// </summary>
    /// <param name="x">First process object.</param>
    /// <param name="y">Second process object.</param>
    /// <returns>
    /// Returns less than zero if x is less than y,
    /// greater than 0 if x is greater than y, and 0 if x == y.
    /// </returns>
    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);
      }
    }
    
    /// <summary>
    /// Retrieves the list of all processes matching the Id
    /// parameter and generates a nonterminating error for 
    /// each specified process identofier which is not found.
    /// </summary>
    /// <returns>
    /// An array of processes that match the given identifier.
    /// </returns>
    [EnvironmentPermissionAttribute(
       SecurityAction.LinkDemand,
       Unrestricted = true)]
    private List<Process> GetMatchingProcessesById()
    {
      new EnvironmentPermission(
          PermissionState.Unrestricted).Assert();
      
      List<Process> matchingProcesses = new List<Process>();
      
      if (null != this.processIds)
      {
        // The keys dictionary is used for rapid lookup of the 
        // processes already in the matchingProcesses list.
        Dictionary<int, byte> keys = new Dictionary<int, byte>();
        
        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);
          } // End if(...).
        } // End foreach(...).
      } // End if(...).
         
      return matchingProcesses;
    } // End GetMatchingProcessesById.
    
    /// <summary>
    /// Retrieves the list of all processes matching the InputObject
    /// parameter.
    /// </summary>
    [EnvironmentPermissionAttribute(
       SecurityAction.LinkDemand,
       Unrestricted = true)]
    private List<Process> GetProcessesByInput()
    {
      new EnvironmentPermission(
          PermissionState.Unrestricted).Assert();
      
      List<Process> matchingProcesses = new List<Process>();
      
      if (null != this.Input)
      {
        // The keys dictionary is used for rapid lookup of the
        // processes already in the matchingProcesses list.
        Dictionary<int, byte> keys = new Dictionary<int, byte>();
        
        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);
          } // End if(...).
        } // End foreach(...).
      } // End if(...).
      return matchingProcesses;
    } // End GetProcessesByInput.
    
    #endregion Private Methods
  } // GetProcCommand
  #endregion GetProcCommand
}

See Also



Show:
© 2014 Microsoft