Home > Uncategorized > Why you can’t enumerate invocable methods within Powershell

Why you can’t enumerate invocable methods within Powershell

I just spoke to JayKul on #powershell on freenode about enumerating methods that are accessible via an ADSI interface, and got the answer “COM isn’t built for reflection the way .net is.”

Here is the full conversation, digression about parenthesis included:

[10:43] == mbrownnyc [266b4002@gateway/web/freenode/ip.38.107.64.2] has joined #Powershell
[10:44] <mbrownnyc> hello all, I am curious if someone can describe how to enumerate ADSI methods available via a bound instance as [ADSI]$instance.psbase.Invoke() ?
[10:44] <mbrownnyc> research has turned up "refer to the docs for the ADSI interface" (http://social.technet.microsoft.com/Forums/windowsserver/en-US/513c514f-304d-43ab-992d-6cf69642dba9/question-about-psbaseinvoke-versus-direct-use-of-method) but I am not particularly happy with that answer :)
[10:44] <Sofapute> Question about psbase.invoke versus direct use of method
[10:45] <mbrownnyc> why am I opting for this?  just for clarity, the namespace is also available via $instance.invoke() sure
[10:46] <mbrownnyc> utilizing an [ADSI] object instance that's bound to an ADSI interface reveals access to the ADSI's interface methods, but I can not figure out a way to enumerate the methods
[10:47] <mbrownnyc> even utilizing GetMembers() does not return as I was hoping, it's like one layer too deep
[10:47] <mbrownnyc> so I am wondering if it is just truly "sorry dude... you've got to refer to the docs" or if it is possible to access them, maybe not with tab-completion, but enumerating them with a command and then using some fu to get a list
[10:48] <mbrownnyc> even some bending with Reflector (such as a GetTypes() method) would be acceptable for this purpose
[10:49] == aTypical_ has changed nick to aTypical
[10:49] <PowerSchill> mbrownnyc: I have to ask. Do you have to use ADSI?
[10:49] <mbrownnyc> I am learning powershell for Windows systems administration, so I am interested in dealing with [ADSI] class objects in an learning accessible manner
[10:49] <aTypical> Good morning, my comrades from the Axis of Evil countries.
[10:50] <mbrownnyc> PowerSchill: I am unsure... as I am new... but I believe so... for instance, I am currently just doing some administrative things to a /local/ group on a target machine
[10:50] <mbrownnyc> for which I located ADSI to the WinNT interface as a method
[10:51] <mbrownnyc> ADSI is very flexible, so it'd be worth solving
[10:52] <mbrownnyc> but if I need to shift my thinking (for instance, .NET framework classes are pretty flexible as well), and solve the problem another way, that's cool... I just am unaware
[10:52] <mbrownnyc> PowerSchill: what do you think?
[10:54] <mbrownnyc> to be verbose, I located this, which enumerates a group for its members on the local host:
[10:54] <mbrownnyc> [ADSI]$lhost_group="WinNT://./Administrators,group"
[10:54] <mbrownnyc> @($lhost_group.psbase.Invoke("Members")) | foreach-object {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
[10:54] <mbrownnyc> I want to enumerate the available methods within $lhost_group.psbase.Invoke() in this instance, so I can more easily bang out lines
[10:56] <mbrownnyc> I located the docs that reveal the Members() and even the Name property of the contained objects... but I want to know if there's a way to enumerate the methods, properties, etc, via powershell versus referring to docs
[10:56] <PowerSchill> I do very little with ADSI and its pretty basic
[10:59] <mbrownnyc> PowerSchill: Thanks for the info.  I wonder if there is another solution to this problem directly, and I'm thinking about solving in incorrect?
[11:02] <+Jaykul> mbrownnyc: so, uhm ...
[11:03] <+Jaykul> first: why are you trying to work directly with adsi? surely 99% of everything that anyone would ever want to do with that has been wrapped up into functions and cmdlets already?
[11:04] == jrpurdy_ has changed nick to jrpurdy
[11:05] <mbrownnyc> Jaykul: thanks... this is partially my question, but when I research the solution to my question ("how do I enumerate members of a local group?") the solution was to utilize ADSI
[11:05] <+Jaykul> second: there are lots of functions on poshcode working with adsi ... http://poshcode.org/4191
[11:05] <Sofapute> PowerShell Code Repository - Get-LocalGroupMembership
[11:06] <mbrownnyc> Jaykul: I will attempt to find an alternate solution, but it made me curious as to how to enumerate the ADSI methods
[11:06] <+Jaykul> just to pick one at random ;-)
[11:06] <+Jaykul> Well, I'm not saying not to use ADSI, I'm just saying someone's surely already written the function you need :)
[11:06] <mbrownnyc> Jaykul: sounds good, I'll just run through all possible letter combinations, that'll be efficient :D
[11:07] <+Jaykul> what? that function I just linked to does what you want, right?
[11:07] <mbrownnyc> Jaykul: I see... I guess my question was one driven by curiosity versus a direct solution
[11:07] <mbrownnyc> http://poshcode.org/4191 uses ADSI on the backend
[11:07] <Sofapute> PowerShell Code Repository - Get-LocalGroupMembership
[11:07] <+Jaykul> right
[11:08] <mbrownnyc> ..meta Sofapute is a bot?
[11:08] * Jaykul sighs
[11:08] <+Jaykul> yeah
[11:08] <mbrownnyc> heh thanks
[11:08] <+Jaykul> he's a PowerShell bot
[11:08] <mbrownnyc> well, so, thanks... I understand this will solve the problem... I suppose it isn't possible to enumerate functions within an ADSI interface within powershell
[11:09] <+Jaykul> it should be possible
[11:09] <+Jaykul> what do you get when you do, like ...
[11:09] <+Jaykul> $adsi = ([ADSI]("WinNT://" + $Computer + ",computer"))
[11:09] <+Jaykul> $adsi.psbase | gm -force
[11:10] <+Jaykul> actually, you probably don't need the -force, that's going to end up exposing get/set methods for every property
[11:10] <+Jaykul> also: I don't know why you have to do .psbase ... it makes me uncomfortable that $adsi | gm doesn't return all those members.
[11:11] <mbrownnyc> yes I agree
[11:12] <+Jaykul> Yeah, that's really weird
[11:12] <mbrownnyc> Jaykul: for reference, when binding ADSI WinNT interface to a group... like my previous example, the Invoke("Members") is from here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa706021%28v=vs.85%29.aspx
[11:12] <Sofapute> IADsGroup interface (Windows)
[11:13] <+Jaykul> $adsi = [ADSI]"WinNT://${Env:COmputerName},computer"
[11:13] <+Jaykul> $adsi.psbase
[11:13] <mbrownnyc> I just use `$adsi = [ADSI]"WinNT://.,computer"`
[11:13] <+jrich523> morning guys
[11:13] <mbrownnyc> where . is an alias for localhost or whatnot
[11:14] * Jaykul nods
[11:14] <aTypical> Good morning, jrich523.  C'here and give me a hug.
[11:14] <mbrownnyc> Jaykul: but do you see why I'm interested?  there must be a way to get these guys listed
[11:14] <+Jaykul> morning jrich523 (I tried to tab-complete morning, so it's still too early)
[11:14] <+Jaykul> mbrownnyc: yeah: .psbase | gm
[11:14] <+jrich523> lol i've done that before
[11:14] <mbrownnyc> that does not list Members
[11:14] <mbrownnyc> as an available method
[11:15] * Jaykul gets a group so he can see
[11:15] <+jrich523> mbrownnyc what are you trying to do?
[11:15] <+BartekB> I would blame WinNT:// ;)
[11:16] <+jrich523> hey Bart
[11:16] <+BartekB> Hi Justin. :>
[11:16] <+Jaykul> $group = $adsi.psbase.Children.Find("Administrators")
[11:16] <+Jaykul> BartekB: heh
[11:17] <+Jaykul> I blame COM
[11:17] <+BartekB> True
[11:17] <+Jaykul> I have hated COM since 1997
[11:17] <mbrownnyc> quick side syntax question... how do I execute a second statement on the same line conditionall?  For instance && in bash?
[11:17] <+Jaykul> mbrownnyc: ;
[11:17] <mbrownnyc> Jaykul: let me check that out
[11:17] <mbrownnyc> Jaykul: thanks!
[11:17] <+Jaykul> oh, conditionally
[11:17] <+BartekB> Conditional?
[11:17] == Guybrush________ [~Guybrush@pd95b59be.dip0.t-ipconnect.de] has quit [Ping timeout: 245 seconds]
[11:17] <+Jaykul> -and
[11:17] <+BartekB> if (first) { second }
[11:17] * Jaykul ponders that
[11:18] <mbrownnyc> very literal, I like it :D
[11:18] <+jrich523> to BartekB point, and Jaykul knows the name
[11:18] <+Jaykul> I like -and, but I think I'll go with BartekB's
[11:18] <aTypical> An agnostic dyslexic pondering the existence of Dog?
[11:18] <+jrich523> you can do something like
[11:18] <+jrich523> if($value = $obj|test-something){yeah}
[11:18] <+jrich523> assignment in an If
[11:19] <+jrich523> whats that called Jaykul?
[11:20] <+Jaykul> jrich523: why does it have to be called something?
[11:20] <+jrich523> it doesnt, but i recall you calling it something a a couple of days ago :)
[11:20] <mbrownnyc> Jaykul: the previous solution, utilizing Children.Find() did not work as expected, but I do not understand how you instantiated $adsi?
[11:23] <+Jaykul> jrich523: to quote the MVP mailing list (which I'm not supposed to do, but this is obviously not NDA):
[11:23] <+Jaykul> Person1 > hmm, i haven't been conscious is that the same as a = b = 2 .. like a = (b = 2) ? .... hmm does in the powershell spec (or in any spec) is there a specific name for this language featuer?
[11:24] <+Jaykul> Person2 > PayetteV2 covers this in section 5.3: Parentheses in PowerShell are not merely arithmetical grouping operators (as you know), but they also allow you to inject pipelines into expressions. In fact, the syntax diagram is
[11:24] <+Jaykul>                  ( <pipeline> )
[11:24] <+Jaykul> Where <pipeline> may devolve into an arithmetic expression.
[11:24] <+Jaykul> In the given case, the parentheses cause the value of the pipeline to be “returned” as the value of the expression to the pipeline.
[11:24] <+Jaykul> The language specification discusses this specifically in section 7.1.1.
[11:24] <+jrich523> hmm
[11:24] <+Jaykul> Grouping parentheses may be used in an expression to document the default precedence and associativity within that expression. They can also be used to override that default precedence and associativity. For example,
[11:24] <+Jaykul> 4 + 6 * 2               # 16
[11:24] <+Jaykul> 4 + (6 * 2)             # 16 document default precedence
[11:24] <+Jaykul> (4 + 6) * 2             # 20 override default precedence
[11:25] <+Jaykul> So anyway, my point is ... I think ... that grouping parenthesis are a built-in feature of almost every language
[11:25] <+Jaykul> it's just that PowerShell has this extra thing called pipeline output ...
[11:25] <+jrich523> well
[11:25] <+Jaykul> which makes them more, uhm, interesting.
[11:25] <+jrich523> ok but
[11:25] <+jrich523> it doesnt output assignments
[11:26] <+jrich523> which is why i thought this was different (and named)
[11:26] <+Jaykul> again from the language spec:
[11:26] <+Jaykul> To write to the pipeline the value of any expression containing top-level side effects, enclose that expression in parentheses, as follows:
[11:26] <+Jaykul> ($a = 1234 * 3.5)       # pipeline gets 4319
[11:26] <+Jaykul> As such, the grouping parentheses in this case are not redundant.
[11:26] <+jrich523> i shouldnt ask things like this the second i get in to work
[11:26] <+Jaykul> so I'm going with "grouping parentheses" ... if you must have a name ;)
[11:26] <+jrich523> lol
[11:27] <+Jaykul> As Person2 said in a later email: The behavior is NOT contradictory with respect to pipeline behavior when you first remember that parentheses are for grouping pipelines, not for grouping arithmetic expressions.
[11:27] == Semt-x [~Sander@D97A8F82.cm-3-3c.dynamic.ziggo.nl] has joined #Powershell
[11:27] * Jaykul chuckles
[11:27] <+jrich523> yeah, that makes sense i guess
[11:28] <+Jaykul> hey, I had two links for you
[11:28] <+Jaykul> did you see this http://jdhitsolutions.com/blog/2013/08/creating-styling-html-reports-with-powershell/
[11:28] <Sofapute> Creating Styling HTML Reports with PowerShell
[11:28] <+Jaykul> It reminds me of the first draft of your solution ;)
[11:28] <+jrich523> i bet mines cooler :)
[11:28] <+jrich523> oh i've seen this
[11:28] <+jrich523> yeah mine is way cooler :)
[11:30] <+jrich523> im amazed at the slow adoption rate of V3
[11:30] <mbrownnyc> Jaykul: The .Children.Find() or even .Children.GetEnumerator() does not output the methods available with Find() or even GetEnumerator() as it is not a container when instantiated with [ADSI]$lhost_group="WinNT://./Administrators,group"
[11:32] == cortez [~cortez@unaffiliated/cortez] has joined #Powershell
[11:33] <mbrownnyc> well thanks any way Jaykul ... guys... I guess I'll just refer to docs :(
[11:34] <+Jaykul> mbrownnyc: yeah, it actually looks like that might be the only way
[11:34] <+Jaykul> COM isn't built for reflection the way .net is
[11:34] <mbrownnyc> that's sort of silly to me, because if something is accessible it should be accessible...
[11:34] <+Jaykul> it was built for ... well ... reading the docs
[11:34] <mbrownnyc> ahh I think I get what you're saying
[11:34] <+Jaykul> it's accessible, but it's not introspectable
[11:35] <mbrownnyc> okay, makes sense... boo on it, but sounds good
[11:35] <mbrownnyc> thanks for a definitive answer
[11:35] <+Jaykul> that's like saying you should be able to find out all the parameters of "ls" in bash without docs ;)
[11:35] <+Jaykul> Which you should, but you can't
[11:35] <mbrownnyc> yea I understand what you mean, but I was hoping I could just do it all as I work at the shell
[11:35] <mbrownnyc> but c'est la vie
[11:36] * mbrownnyc thumbs up
[11:37] <mbrownnyc> thanks for your help, gained some more understanding of syntax, and the Children inherited method
[11:39] <+Jaykul> jrich523: http://jaykul.com/482
[11:39] <Sofapute> FreeNode #PowerShell Pastebin - flatten-xml
[11:39] <+Jaykul> mbrownnyc: the thing that bothers me the most about COM in PowerShell is when this happens:
[11:39] <+Jaykul> $group.psbase.invoke("members")
[11:39] <+Jaykul> System.__ComObject
[11:39] <+Jaykul> System.__ComObject
[11:39] <+jrich523> oh cool
[11:41] <mbrownnyc> Jaykul: yes, I came across this while digging
[11:42] <mbrownnyc> Jaykul: this is what lead me to hope... @($lhost_group.psbase.Invoke("Members")) | foreach-object {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
[11:43] <mbrownnyc> If you can execute GetType() against the COM objects, then you should be able to have visibility into the COM object's internals, or am I hopping up too far?
[11:43] <+Jaykul> but you gotta love this: http://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.invoke.aspx
[11:43] <Sofapute> DirectoryEntry.Invoke Method  (System.DirectoryServices)
[11:44] <+Jaykul> it's like, bottom line: magic
[11:44] <mbrownnyc> Yes, that's the .NET class for the $group type allocated, but it isn't clear, since the DirectoryEntry can bind to many ADSI interfaces...
[11:44] <+Jaykul> mbrownnyc: the type of a com object is just System.__ComObject
[11:45] <+Jaykul> And the whole System.DirectoryServices is just a very thin wrapper layer over the original COM implementation
[11:46] == jrpurdy has changed nick to jrpurdy_
[11:46] <+Jaykul> mbrownnyc: fwiw, when I have to work with AD, I get out the quest AD cmdlets -- unless the machine I'm on already has Microsoft's AD cmdlets.
[11:46] <mbrownnyc> okay cool...
[11:46] <+Jaykul> I wrote a whole bunch of these [ADSI] wrapper functions when I first started messing with AD
[11:47] <mbrownnyc> this is partially the challenge, this isn't AD, for what I can see the WinNT ADSI interface is the only way to interface with _local_ groups
[11:47] <+Jaykul> but eventually realized that every time I needed something new I was having to look things up and write new ones
[11:47] <+Jaykul> yeah -- unless someone's already written the functions/cmdlets
[11:47] <mbrownnyc> Jaykul: thanks very much... I suppose starting, I was hoping to trail blaze something that's totally unnecessary... nothing lost in utilizing ships built by others :)
[11:48] <mbrownnyc> because, I for sure do not know how to build ships
[11:48] <+Jaykul> ok, new topic
[11:48] <+Jaykul> :)
[11:48] <mbrownnyc> yes for sure
[11:48] <mbrownnyc> thanks
[11:48] <mbrownnyc> !
Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: