Extending Get-Process to show the Process Chain using PowerShell Proxy Functions

Comments 0

Share to social media

A proxy function or wrapper function allows you to deploy a custom version of a function or cmdlet while the internal functionality remains implemented. That means you can get a core cmdlet or function, add parameters (or remove), and write the code for these parameters, customizing a new version of this core cmdlet or function. Also, we get the begin, process and end block exposed from the PowerShell advanced functions, allowing control over the command steppable pipeline.

The SteppablePipeline allows you to implement a cmdlet (advanced function) by delegating most of the implementation to another cmdlet in a memory-efficient, streaming manner.

From this stackoverflow post by mklement0: “Specifically, a steppable pipeline allows you to delegate the implementation of your proxy function to a script block whose life cycle is kept in sync with the proxy function itself, in terms of initialization (begin block), per-object pipeline input processing (process block), and termination (end block), which means that the single instantiation of the wrapped cmdlet is in effect directly connected to the same pipeline as the proxy function itself.”

Let´s create a scenario with SQL Server. If you use xp_cmdshell to call the notepad executable, your session will be hanging until you kill the process in the OS, which can be done with Task Manager. Execute the following if you want to try it:

You will see something similar to:

SQL Query 2

The app will not open a window on your machine, but if you go to task manager you will see it, and you can kill it.

Or, if you want to see the complete chain using Process Explorer:

But using PowerShell, Get-Process:

It´s not listed:

It would be fantastic if we could get the process chain in the Get-Process return values, so we will add a new parameter called ShowChain to Get-Process to extend its functionality.

Note: the final code is very long, and the snippets are available in the article for browsing and understanding the process. You can download the final working code (in a .txt file) from the Simple Talk site here.

FIRST STEP – GET THE METADATA FROM GET-PROCESS

The first step is to get the metadata from Get-Process and saved to a file called Get-Process.txt in the temp folder to check how it works:

The output file will be the following:

Using the words of my good friend Shay Levy :

“Don’t get intimidated by the result. This is what a proxy function looks like. As you can see, the generated code starts by including all the cmdlet parameters and then defines the script blocks of the command. At the end, there are instructions for the Get-Help cmdlet.

In the Begin block, the Get-Process command ($wrappedCmd) is retrieved, and the parameters are passed to it (@PSBoundParameters). A steppable pipeline is initialized ($steppablePipeline), which invokes the cmdlet ($scriptCmd), and finally, the Begin starts. At the end of the code sample, you can find a multiline comment that is used to instruct the Help that Get-Help should display when you type Get-Help <ProxyFunction>.”

In this script, add the following:

Our new cmdlet will have the same name of the core cmdlet Get-Process . It´s not a problem as we will see later in this article. Now it’s time to create the Function that will retrieve the Process Chain :

SECOND STEP – CREATE THE PARAMETER

The next step is create the switch parameter ShowChain:

It is inserted the code thusly:

THIRD STEP – CREATE THE FUNCTION WITH THE PROCESS CHAIN.

The function gets the ProcesseId column from Get-Process and query the WMI win32_process to get the child process because Get-Process does not return the ParentID column. Then it creates a loop to find the complete chain showing in the yellow color and with ‘-‘to hierarchical show.

Using the same names

The Proxy Function using the same name of the core cmdlet is not a problem because the function takes precedence in the running, also having the same name, we have the capability of the command discovery process. Here´s the list of precedence :

  • · Alias: All Windows PowerShell aliases in the current session
  • · Filter/Function: All Windows PowerShell functions
  • · Cmdlet: The cmdlets in the current session (“Cmdlet” is the default)
  • · ExternalScript: All .ps1 files in the paths that are listed in the Path environment variable ($env:PATH)
  • · Application: All non-Windows-PowerShell files in paths that are listed in the Path environment variable
  • · Script: Script blocks in the current session

The magic happens in the begin block of the function where I check if the ShowChain parameter was passed, remove it from the $psboundparameters because this parameter does not exist in the core Get-Process cmdlet. If I don’t remove it will have an error when piping the function Get-ProcessChain:

It is finished, and the final code  follows:

Reminder: this code is available (in a .txt file), from the Simple Talk site here.

Then, our Proxy Function is ready to use. To load it into memory we can dot-sourcing

Or load it into your profile. I have in my profile a module called Functions where I store all the functions that I use in my day-to-day

And calling the function:

You will now see the subordinate processes:

And calling only the SQL Server process the process chain will be visible

Which will cause the following to be shown (if you have not killed the notepad instance from the start of the article):

And killing the process 10284, which in my connection, corresponds to Notepad the SQL Server session:

Causes the xp_cmdshell to return with a NULL output:

Proxy functions are very useful if you want to customize the core cmdlets instead of creating a new hoke function for that.

Note: Do not use PowerShell ISE. It messes with the colors, instead of dot-source (as we saw before), the function and calls in the PowerShell console

References

Proxy Functions: Spice Up Your PowerShell Core Cmdlets (Shay Levy)

 

About the author

Laerte Junior

See Profile

Laerte Junior is a Cloud and Datacenter Management MVP, focused on PowerShell and automation and, through through his technology blog and simple-talk articles, an an active member of the SQL Server and PowerShell community around the World. He is a skilled Principal Database Architect, Developer, and Administrator, specializing in SQL Server and PowerShell Programming and Automation. He also is PASS Virtual Chapter Mentor , Co-Lead of the PASS PowerShell Virtual Chapter and former PASS Regional Mentor for Brasil. In addition He is also a HUGE Star Wars Fan, his main skill. "May The Force be with us" You should follow him on Twitter as @LaerteSQLDBA

Laerte Junior's contributions