Zachary Loeber

I eat complexity and am never without a meal.

PowerShell: Inheriting Parameters (Proxy Functions)

2017-07-30 5 min read Powershell Zachary Loeber

If you want one function to have all the parameters of another function here is one method you could use.

What?

This may seem like a bit of an odd topic. But hear me out as there are some interesting use cases to for wanting to pull in all the parameters from one function for use in another. I’d call this a ‘proxy function’ but it is more useful than that. Let me explain.

My ‘Use Case’

Consider querying Active Directory with ADSI (none of that sissy ActiveDirectory module stuff). What are the differences between searching for a user versus a computer? Mostly the difference is a bit of LDAP filter trickery. And if you think about it, you only have one type of real query for a good many things in AD, that for AD objects. The LDAP filters, search base, scope, credentials, and other aspects of the ADSI searcher may differ but the general idea is the same.

So logically, if I were to break down the functions for creating a function for searching for a user in AD it might look something like this:

If you wanted to support all of the different ways you could connect to AD along with all of the different ADSI searcher options you end up with a bunch of parameters that you would have to deal with passing through the chain of functions. My Get-DSObject function parameter block is a beast, check it out..

Blech!

That would be a ton of parameters to repeat over and over again for minor query differences and logic nuances for different functions for finding computers, users, groups, or group members (just to name a few). So how can I create one set of base parameters and inherit them by the functions that will be quasi-wrapping around the same Get-DSObject function I’ll be using?

Note: I’ll not go into classes and object inheritance here as I’m almost certain that in a more fully featured language like C# you could do this with much more elegant techniques.

Clever Dynamic Parameters

Dynamic parameters can be tricky and have some nuances that make them less than ideal for a good many things. But in this case they are exceedingly useful. To construct all the parameters of Get-DSObject as part of a parameter block of another function I use a function I found in SnippetPX.

This pulls in the already loaded function (or cmdlet) then using the metadata for that command, it generates brand new runtimedefinedparameter objects that mirror those of the passed function/cmdlet. This is exactly what we need to emit from our DynamicParam block!

Using this function in the dynamic parameter block of another function looks something like this for one of my easier examples:

If you were to look at the comment based help and parameter block code that I’m not having to include in this function by using this method I save over 200 lines of code. This adds up VERY quickly.

You can see in this code that I don’t have to include a ton of other parameters to make the whole thing work. But I do have to do a few other things if I want pipeline variables to work and for PlatyPS to recognize and populate parameter help text later on when I create a module. Firstly, we need to disable positional binding. Otherwise the Identity parameter that we would want to pipeline as position 0 will not work as intended.

Note: This doesn’t disable positional binding entirely, any parameter that has a position manually defined will still work. Our proxied function has them manually defined for this very reason.

Additionally, comment based help doesn’t help you out a lick when using dynamic parameters. But since the new-proxyfunction retains any helpmessage text in the original parameter definitions, PlatyPS will still generate the appropriate module documentation later on. This is why we include the help text in the original function  (get-dsobject).

For recreating the parameter splat for the original function you will see I reference a variable that is simply an array for all the parameters for that function.

I pre-generate this array ahead of time in my module to eek out a little bit of performance. This could have been pre-generated in the begin block though. Here is the function to grab the parameters for a function:

I also use New-DynamicParameter for one very small part of this function, to create the local variables for each parameter that gets passed that is a dynamic parameter. This function can be used for a whole lot more and is highly recommended for more advanced dynamicparam blocks.

Conclusion

I wrote this article to point out a technique I started using. I also put this out there half hoping that someone will point me out to a better, more clever, way of accomplishing this kind of task in PowerShell. If you have something in mind that invalidates this entire post I’d love to hear about it 🙂 If you are at all interested in the project I’m putting together that inspired this post you can check it out here. It isn’t fully realized yet but it does have a pretty large code base worth tinkering with.