' ' Copyright (c) 2006 Microsoft Corporation. All rights reserved. ' ' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO ' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A ' PARTICULAR PURPOSE. ' Imports System Imports System.Collections.Generic Imports Win32Exception = System.ComponentModel.Win32Exception Imports System.Diagnostics Imports System.Security.Permissions 'Windows PowerShell namespace Imports System.Management.Automation Imports System.ComponentModel Namespace Microsoft.Samples.PowerShell.Commands ' This sample is a complete implementation of the get-proc Cmdlet. #Region "GetProcCommand" ''' ''' This class implements the get-proc cmdlet ''' _ Public Class GetProcCommand Inherits PSCmdlet #Region "Parameters" ''' ''' The list of process names on which this cmdlet will work ''' _ Public Property Name() As String() Get Return processNames End Get Set(ByVal value As String()) processNames = value End Set End Property ''' ''' gets/sets an array of process IDs ''' _ Public Property Id() As Integer() Get Return processIds End Get Set(ByVal value As Integer()) processIds = value End Set End Property ''' ''' If the input is a stream of [collections of] Process ''' objects, we bypass the ProcessName 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 ''' _ Public Property Input() As Process() Get Return inputObjects End Get Set(ByVal value As Process()) inputObjects = value End Set End Property #End Region #Region "Cmdlet Overrides" ''' ''' For each of the requested processnames, retrieve and write ''' the associated processes. ''' Protected Overrides Sub ProcessRecord() Dim matchingProcesses As List(Of Process) WriteDebug("Obtaining list of matching process objects.") Select Case ParameterSetName Case "Id" matchingProcesses = GetMatchingProcessesById() Case "ProcessName" matchingProcesses = GetMatchingProcessesByName() Case "InputObject" matchingProcesses = GetProcessesByInput() Case Else ThrowTerminatingError(New ErrorRecord( _ New ArgumentException("Bad ParameterSetName"), _ "UnableToAccessProcessList", _ ErrorCategory.InvalidOperation, Nothing)) Return End Select WriteDebug("Outputting matching process objects.") matchingProcesses.Sort(AddressOf ProcessComparison) Dim process As Process For Each process In matchingProcesses WriteObject(process) Next process End Sub 'ProcessRecord #End Region #Region "protected Methods and Data" ''' ''' Retrieves the list of all processes matching the ProcessName ''' parameter. ''' Generates a non-terminating error for each specified ''' process name which is not found even though it contains ''' no wildcards. ''' ''' Private Function GetMatchingProcessesByName() As List(Of Process) Dim allProcesses As List(Of Process) = _ New List(Of Process)(Process.GetProcesses()) ' The keys dictionary will be used for rapid lookup of ' processes already in the matchingProcesses list. Dim keys As Dictionary(Of Integer, Byte) = _ New Dictionary(Of Integer, Byte)() Dim matchingProcesses As List(Of Process) = New List(Of Process)() If Nothing Is processNames Then matchingProcesses.AddRange(allProcesses) Else Dim pattern As String For Each pattern In processNames WriteVerbose(("Finding matches for process name """ & _ pattern & """.")) ' WildCard serach on the available processes Dim wildcard As New WildcardPattern(pattern, _ WildcardOptions.IgnoreCase) Dim found As Boolean = False Dim process As Process For Each process In allProcesses If Not keys.ContainsKey(process.Id) Then Dim processName As String = _ SafeGetProcessName(process) ' Remove the process from the allProcesses list ' so that it's not tested again. If processName.Length = 0 Then allProcesses.Remove(process) End If ' Perform a wildcard search on this particular ' process and check whehter this matches the ' pattern specified. If Not wildcard.IsMatch(processName) Then GoTo ContinueForEach2 End If WriteDebug(String.Format( _ "Found matching process id ""{0}"".", process.Id)) ' We have found a match. found = True ' Store the process ID so that we don't add the ' same one twice. keys.Add(process.Id, 0) ' Add the process to the processes list. matchingProcesses.Add(process) End If ContinueForEach2: Next process ' foreach (Process... If Not found AndAlso Not _ WildcardPattern.ContainsWildcardCharacters(pattern) _ Then WriteError(New ErrorRecord( _ New ArgumentException("Cannot find process name " & _ " " & pattern & "."), "ProcessNameNotFound", _ ErrorCategory.ObjectNotFound, pattern)) End If Next pattern End If Return matchingProcesses End Function 'GetMatchingProcessesByName ''' ''' Returns the name of a process. If an error occurs, a blank ''' string will be returned. ''' ''' The process whose name will be ''' returned. ''' The name of the process. Protected Shared Function SafeGetProcessName(ByVal process As Process) _ As String Dim name As String = "" If Not (process Is Nothing) Then Try Return process.ProcessName Catch e1 As Win32Exception Catch e2 As InvalidOperationException End Try End If Return name End Function 'SafeGetProcessName #End Region #Region "Private Methods" ''' ''' Function to sort by ProcessName first, then by Id ''' ''' first Process object ''' second Process object ''' ''' returns less than zero if x less than y, ''' greater than 0 if x greater than y, 0 if x == y ''' Private Shared Function ProcessComparison(ByVal x As Process, _ ByVal y As Process) As Integer Dim diff As Integer = String.Compare(SafeGetProcessName(x), _ SafeGetProcessName(y), StringComparison.CurrentCultureIgnoreCase) If 0 <> diff Then Return diff End If Return x.Id - y.Id End Function 'ProcessComparison ''' ''' Retrieves the list of all processes matching the Id ''' parameter. ''' Generates a non-terminating error for each specified ''' process ID which is not found. ''' ''' An array of processes that match the given id. ''' Protected Function GetMatchingProcessesById() As List(Of Process) Dim matchingProcesses As List(Of Process) = New List(Of Process) If Not (processIds Is Nothing) Then ' The keys dictionary will be used for rapid lookup of ' processes already in the matchingProcesses list. Dim keys As Dictionary(Of Integer, Byte) = _ New Dictionary(Of Integer, Byte)() Dim processId As Integer For Each processId In processIds WriteVerbose("Finding match for process id " & _ processId & ".") If Not keys.ContainsKey(processId) Then Dim process As Process Try process = _ System.Diagnostics.Process.GetProcessById( _ processId) Catch ex As ArgumentException WriteError(New ErrorRecord(ex, _ "ProcessIdNotFound", _ ErrorCategory.ObjectNotFound, processId)) GoTo ContinueForEach1 End Try WriteDebug("Found matching process.") matchingProcesses.Add(process) keys.Add(processId, 0) End If ContinueForEach1: Next processId End If Return matchingProcesses End Function 'GetMatchingProcessesById ''' ''' Retrieves the list of all processes matching the Input ''' parameter. ''' Private Function GetProcessesByInput() As List(Of Process) Dim matchingProcesses As List(Of Process) = New List(Of Process)() If Not (Nothing Is Input) Then ' The keys dictionary will be used for rapid lookup of ' processes already in the matchingProcesses list. Dim keys As Dictionary(Of Integer, Byte) = _ New Dictionary(Of Integer, Byte)() Dim process As Process For Each process In Input WriteVerbose("Refreshing process object.") If Not keys.ContainsKey(process.Id) Then Try process.Refresh() Catch e1 As Win32Exception Catch e2 As InvalidOperationException End Try matchingProcesses.Add(process) End If Next process End If Return matchingProcesses End Function 'GetProcessesByInput #End Region #Region "Private Data" Private processNames() As String Private processIds() As Integer Private inputObjects() As Process #End Region End Class 'GetProcCommand #End Region #Region "PowerShell snap-in" ' ''' ''' Create this sample as an PowerShell snap-in ''' _ Public Class GetProcPSSnapIn05 Inherits PSSnapIn ''' ''' Create an instance of the GetProcPSSnapIn05 ''' Public Sub New() End Sub 'New ''' ''' Get a name for this PowerShell snap-in. This name will ''' be used in registering ''' this PowerShell snap-in. ''' Public Overrides ReadOnly Property Name() As String Get Return "GetProcPSSnapIn05" End Get End Property ''' ''' Vendor information for this PowerShell snap-in. ''' Public Overrides ReadOnly Property Vendor() As String Get Return "Microsoft" End Get End Property ''' ''' Gets resource information for vendor. This is a string of format: ''' resourceBaseName,resourceName. ''' Public Overrides ReadOnly Property VendorResource() As String Get Return "GetProcPSSnapIn05,Microsoft" End Get End Property ''' ''' Description of this PowerShell snap-in. ''' Public Overrides ReadOnly Property Description() As String Get Return "This is a PowerShell snap-in that includes " & _ "the get-proc sample." End Get End Property End Class 'GetProcPSSnapIn05 #End Region End Namespace