10490

Joining objects

PowerShell doesn’t have the equivalent of an SQL Union statement that lets you join objects together. What you can do is use New-Object to create the joined output.

As an example that recently came up on a forum

$outputs = @()            
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPenabled=$true" |            
foreach {            
 $nic = Get-WmiObject -Class Win32_NetworkAdapter -Filter "DeviceId='$($_.Index)'"            
            
 $output= New-Object -TypeName PSObject -Property @{            
  NICCardName = $nic.NetConnectionId            
  DHCPEnabled = $($_.DHCPEnabled)            
  IPAddress = $($_.IPAddress)            
  SubnetMask = $($_.IPSubnet)            
  Gateway = $($_.DefaultIPGateway)            
  DHCPServer = $($_.DHCPServer)            
  DNSDomain =  $($_.DNSDomain)            
  DNSDomainSuffixSearchOrder = $($_.DNSDomainSuffixSearchOrder)            
  DNSServerSearchOrder = $($_.DNSServerSearchOrder)            
 }             
$outputs += $output            
}            
$outputs


Get the NetworkAdapterConfigurations where they are IPenabled. Then for each get the associated adapter.



Create a new object and add the properties.  Add the object to the array of results.



At the end output the array.



I would not use the array and just output the object and allow the pipeline to take care of any other processing

Scripting Games Comments VIII: Creating Objects

One thing we have to do quite frequently is create an object and populate some variables.  In PowerShell v1 we would do something like this

001
002
003
004
005
006
007
008
$r = Get-WmiObject -Class Win32_OperatingSystem
$system = New-Object System.Management.Automation.PSObject

Add-Member -InputObject $system -MemberType Noteproperty -Name SystemDevice -Value $r.SystemDevice
Add-Member -InputObject $system -MemberType Noteproperty -Name SystemDrive -Value $r.SystemDrive
Add-Member -InputObject $system -MemberType Noteproperty -Name SystemDirectory -Value $r.SystemDirectory

$system

 

We get some data – in this case from WMI

We use New-Object to create an object – I’ve used the full type name deliberately

$system = New-Object PSObject

works just as well.

Add-Member is used to add three NoteProperties and then we display the object to get

SystemDevice                             SystemDrive                              SystemDirectory                       
------------                             -----------                              ---------------                       
\Device\HarddiskVolume2                  C:                                       C:\Windows\system32
                   

Its a bit of a contrived example but it works.

It is possible to make this a bit easier and less typing

001
002
003
004
005
006
007
008
$r = Get-WmiObject -Class Win32_OperatingSystem
$system = New-Object System.Management.Automation.PSObject

$system | Add-Member -MemberType Noteproperty -Name SystemDevice -Value $r.SystemDevice -PassThru |
Add-Member -MemberType Noteproperty -Name SystemDrive -Value $r.SystemDrive -PassThru |
Add-Member -MemberType Noteproperty -Name SystemDirectory -Value $r.SystemDirectory

$system

 

Add-Member has a –PassThru parameter that enables us to pipeline the property creations.

PowerShell v2 makes it even easier

001
002
003
004
005
006
007
008
$r = Get-WmiObject -Class Win32_OperatingSystem
$system = New-Object System.Management.Automation.PSObject -Property @{
        SystemDevice = $r.SystemDevice 
        SystemDrive  = $r.SystemDrive 
        SystemDirectory = $r.SystemDirectory
    }

$system

 

New-Object does all the work for us – it even creates each property as a NoteProperty.  All we do is give the property information as a hash table.  If you want this all on one line then separate each pair by a semi-colon “;”

Combining Output

A recent question of the PowerShell forum asked how the output of two scripts could be combined.  The scripts in question were using Get-ChildItem and Get-Acl to pull back two sets of information related to the file.

PowerShell produces objects. .NET objects with a PowerShell wrapper. The questioner was looking for something like the UNION operator in TSQL. Unfortunately, you can’t combine objects like that. Trying to match up the properties and methods would be a nightmare.

So we need to combine the way we produce the information to create a single object with all of the data we require

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
$data = @()
Get-ChildItem -Path "C:\scripts" -Recurse | foreach {
    $file = New-Object -TypeName System.Management.Automation.PSObject
Add-Member -InputObject $file -MemberType NoteProperty -Name "FullName" -Value $_.Fullname
Add-Member -InputObject $file -MemberType NoteProperty -Name "LastAccessTime" -Value $_.LastAccessTime
    Add-Member -InputObject $file -MemberType NoteProperty -Name "LastWriteTime" -Value $_.LastWriteTime
   
    $acl = Get-Acl -Path $_.FullName
    Add-Member -InputObject $file -MemberType NoteProperty -Name "Owner" -Value $acl.Owner
    Add-Member -InputObject $file -MemberType NoteProperty -Name "AccessToString" -Value $acl.AccessToString
    Add-Member -InputObject $file -MemberType NoteProperty -Name "Group" -Value $acl.Group
   
    $data += $file
}
$data | Export-Csv -Path c:\scripts\acl.csv -NoTypeInformation

 

Start by using Get-ChildItem to read the directory lists.  Then foreach object we create a new object and use Add-Member to create some properties on it. In this case we pick off the full name of the object and the last times it was accessed & written to.

We also need to get some ACL information. We can use Get-Acl within our loop – we only read the file directories once this way. And then we add a few more properties.  Add the object to our array and loop back for the next file.

At the end we can dump the information to a csv file for future use.

Technorati Tags: ,,