Created
January 24, 2017 15:58
-
-
Save 1RedOne/23feb9504c58e1eafe2c3a24a994c488 to your computer and use it in GitHub Desktop.
Explanation of multiple object output in PowerShell functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| PowerShell ALWAYS does its best to try to make sure it converts output into the most useful format. One of the ways it does this is by seeing the type of object that it is first displaying in a function, and ensuring that all future objects also match this format. Sometimes it's possible, and sometimes it's not. | |
| In the case of your code, PowerShell executes and then tries to emit the results of `Compare-Object`, and succeeds. 'Compare-Object' emits an object that has these properties. | |
| Name MemberType Definition | |
| ---- ---------- ---------- | |
| Equals Method bool Equals(System.Object obj) | |
| GetHashCode Method int GetHashCode() | |
| GetType Method type GetType() | |
| ToString Method string ToString() | |
| InputObject NoteProperty System.ServiceProcess.ServiceController InputObject=AdobeARMservice | |
| SideIndicator NoteProperty string SideIndicator==> | |
| These properties set the stage for what can also be emitted within this command, unless you do some fancy tricks. The reason you're **not** seeing the output of your later commands is that they don't also output the same properties. | |
| To illustrate this quirk in action, see this code: | |
| function Ham2{ | |
| [pscustomobject]@{Name='FoxDeploy';Job="Coder"} | |
| [pscustomobject]@{Name='Ham';Profession="Coder"} | |
| } | |
| When this executes, the properties of the FIRST object emitted determine what gets displayed later on in the code. For example: | |
| >ham2 | |
| Name Job | |
| ---- --- | |
| FoxDeploy Coder | |
| Ham | |
| **Working around this** | |
| There are a few ways to work around this. | |
| First and foremost, a PowerShell best practice is that your scripts should ONLY emit one type of object. This is why functions have an `.OUTPUT` declaration available in their Help and `[CmdletBinding()]`, PowerShell expects a command to issue only one type of object, plus maybe some `-Verbose`, or ErrorStream messages. | |
| If you REALLY want to emit two types of objects, you could ensure that the first object has all of the properties you might ever want to display. Going back to my earlier example, if I added a `Profession` property to the first object, now my second object's `Profession` property will now become visible. | |
| function Ham2{ | |
| [pscustomobject]@{Name='FoxDeploy';Job="Coder";Profession=''} | |
| [pscustomobject]@{Name='Ham';Profession="Coder"} | |
| } | |
| PS C:\Users\Stephen> ham2 | |
| Name Job Profession | |
| ---- --- ---------- | |
| FoxDeploy Coder | |
| Ham Coder | |
| **Probably what you want but not recommended** | |
| If you REALLY want to emit two or more different types of objects (which you surely don't, *right*?) then you can get around this quirk by using `Format-List` or `Format-Table`. Be warned: these convert the output into text formatting commands and you'll lose Object properties and people will generally think it was a hacky thing to do. But it *will work*. | |
| function iFeelIcky{ | |
| $spservices = gsv AdobeARMservice,bits | |
| $compared = Compare-Object (get-service bits,winrm) $spservices -SyncWindow 0 | |
| $compared | Format-Table | |
| foreach ($spService in $spServices) | |
| { | |
| $out = new-object psobject | |
| $out | add-member noteproperty DisplayName $spService.DisplayName | |
| $out | add-member noteproperty Status $spService.Status | |
| $out | |
| } | |
| } | |
| C:\Users\Stephen> iFeelIcky | |
| InputObject SideIndicator | |
| ----------- ------------- | |
| AdobeARMservice => | |
| bits <= | |
| bits => | |
| winrm <= | |
| DisplayName Status | |
| ----------- ------ | |
| Adobe Acrobat Update Service Running | |
| Background Intelligent Transfer Service Running | |
| } | |
| I hope that helped! Let me know if you'd like me to dive deeper or for some reason want me to stay up on this soap box :-) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment