#requires -version 2.0 # Jeffery Hicks # http://jdhitsolutions.com/blog # follow on Twitter: http://twitter.com/JeffHicks # # Learn more Windows PowerShell with a copy of Windows PowerShell 2.0: TFM (SAPIEN Press 2010) # # "Those who forget to script are doomed to repeat their work." # **************************************************************** # * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED * # * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF * # * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, * # * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. * # **************************************************************** Function Join-Object { <# .Synopsis Join multiple objects together into a single object. .Description This function is designed to join, or merge two or more objects together. You can either pipe objects via cmdlets to Join-Object or specify a comma separated list of objects. A new object will be created with all unique properties and values from the original objects. If a property is duplicated among objects but with a different value, then it will be renamed. For example, if two objects both have a Name property but with different values, the custom object will have properties of Name and Name_1. Join-Object works best with input objects that themselves are not arrays or collections of other objects, but it can be done. The intent was to be able to merge related information into a single object that you could then export or convert. If you are joining WMI objects, you might prefer to use the Select-WMI function to strip out system properties like __CLASS. You can download this function from http://jdhitsolutions.com/blog/2010/05/select-wmi/. By default the new object will contain a property called _TypeInformation which will store an array of type information from the original objects. Use -NoTypeInformation to skip this. You can also include the original source objects in their "raw" state as part of the new object. Specify -IncludeOriginal to store the input objects as an array in the _SourceObject property. .Parameter InputObject Any valid PowerShell object. .Parameter IncludeOriginal If specified, the original input object will be stored in an array and be defined in the _SourceObject property on the new, custom object. .Parameter NoTypeInformation By default, each input object's type is stored in an array and defined in the _TypeInformation property on the new, custom object. If you do not want this information, then specify this switch. .Example PS C:\> (gwmi win32_computersystem),(gwmi win32_bios) | join-object Combine two WMI objects into a single object. .Example PS C:\> (gwmi win32_computersystem),(gwmi win32_bios) | select-wmi | join-object -NoTypeInformation Combine two WMI objects into a single object, but without the class properties. Select-WMI is a third-party developed function you can download from http://jdhitsolutions.com/blog/2010/05/select-wmi/ .Example PS C:\> $computers | foreach { (gwmi win32_operatingsystem -ComputerName $_),(gwmi win32_computersystem -ComputerName$_) | select-wmi | join-object} | export-csv c:\temp\sysreport.csv -NoTypeInformation Where $computers is a collection of computernames, get WMI information from two classes (win32_operatingsystem and win32_computersystem). Join these two objects, stripping out system properties and export the results to a csv file. Each computer will have it's own custom object comprised of both WMI classes. .Example PS C:\> $data=$fso.GetFile("c:\pagefile.sys"),$fso.GetDrive("c:") | join-object -IncludeOriginal $fso is a COM FileSystemObject. The results of the two methods are joined and safved to $data. You can view the original objects by looking at $data._SourceObjects .Inputs Any valid object .Outputs A custom object .Link New-Object .Notes NAME: Join-Object VERSION: 1.0 AUTHOR: Jeffery Hicks LASTEDIT: May 12, 2010 #> [CmdletBinding()] Param( [Parameter(Position=0, ValueFromPipeline=$True, Mandatory=$True, HelpMessage="Enter a valid PowerShell object")] [object[]]$Inputobject, [switch]$IncludeOriginal, [switch]$NoTypeInformation ) Begin { write-verbose "Starting $($myinvocation.mycommand)" #initialize a hash table for new properties $newProp=@{} #initialize a hash table to handle duplicate property names $duplicate=@{} #initialize an array to hold raw objects $raw=@() #initialize an array to hold object metadata $metatypes=@() } Process { foreach ($parentobject in $InputObject) { #handle inputobjects that are arrays themselves foreach ($object in $parentobject) { $raw+=$object write-verbose "Adding type $($object.GetType().Fullname)" $metaTypes+=$object.GetType().Fullname $object | get-member -MemberType Properties | foreach { if ($newProp.Contains($_.name) ) { write-Verbose "Property $($_.name) already defined $($newProp.item($_.name))" #skip properties that have duplicate values #only include the property if it has a different value #and then rename the property like myProperty_1 if ($newProp.item($_.name) -ne $object.($_.Name)) { $duplicate.item($_.name)+=1 $newName=$_.name+"_"+$duplicate.item($_.name) write-Verbose "Adding $newName = $($object.($_.Name))." $newProp.Add($newName,$object.($_.name)) } } else { Write-Verbose "Adding property $($_.name)" $newProp.Add($_.name,$object.($_.name)) } } #foreach } #foreach object } #foreach parentobject } #Process End { if ($IncludeOriginal) { #add raw objects as a property Write-Verbose "Adding original raw objects" $newProp.Add("_SourceObjects",$raw) } if ($NoTypeInformation) { write-verbose "Skipping meta type information" } else { #add unique object metadata as a property $newProp.Add("_TypeInformation",($metaTypes | Select-object -unique)) } #write the new object to the pipeline New-Object PSObject -Property $NewProp write-verbose "Ending $($myinvocation.mycommand)" } } #end Function #this script also defines an alias for this function. Set-Alias -Name jo -Value Join-Object