How to check with for in list of hashes? - powershell

I have file with multiple sets of data, as it:
metadata :
mxRecords :
name : dev-dev
arecords : {#{ipv4Address=127.0.0.1}, #{ipv4Address=127.0.0.2}, #{ipv4Address=127.0.0.3}, #{ipv4Address=127.0.0.4}}
I need find sets of data, where in arecords contains ipv4Address what I need.
How can I get access to values of ipv4Address?

You have nested custom objects rather than hash tables. You can use the member access operator . to reference nested properties.
Example 1: From one object, find the arecords object that contains the target IP address
# Record example matching your post
$obj = [pscustomobject]#{
metadata = ''
mxRecords = ''
name = 'dev-dev'
arecords = [pscustomobject]#{ipv4Address='127.0.0.1'},
[pscustomobject]#{ipv4Address='127.0.0.2'},
[pscustomobject]#{ipv4Address='127.0.0.3'},
[pscustomobject]#{ipv4Address='127.0.0.4'}
}
$targetIP = '127.0.0.3'
$obj.arecords | Where ipv4Address -eq $targetIP
# Output
ipv4Address
-----------
127.0.0.3
Example 2: From multiple objects, find the object that contains an arecords array with the target IP
$obj = [pscustomobject]#{
metadata = ''
mxRecords = ''
name = 'dev-dev'
arecords = [pscustomobject]#{ipv4Address='127.0.0.1'},
[pscustomobject]#{ipv4Address='127.0.0.2'},
[pscustomobject]#{ipv4Address='127.0.0.3'},
[pscustomobject]#{ipv4Address='127.0.0.4'}
},
[pscustomobject]#{
metadata = ''
mxRecords = ''
name = 'prod-prod'
arecords = [pscustomobject]#{ipv4Address='127.0.0.10'},
[pscustomobject]#{ipv4Address='127.0.0.20'},
[pscustomobject]#{ipv4Address='127.0.0.30'},
[pscustomobject]#{ipv4Address='127.0.0.40'}
}
$targetIP = '127.0.0.10'
$obj | Where {$_.arecords.ipv4Address -contains $targetIP}
# Output
metadata mxRecords name arecords
-------- --------- ---- --------
prod-prod {#{ipv4Address=127.0.0.10}, #{ipv4Address=127.0.0.20}, #{ipv4Address=127.0.0.30}, #{ipv4Address=127.0.0.40}}

Related

Combine API results into single object in Powershell

I have two API endpoints to hit and retrieve user info and write the data into a SQL table. The endpoint uses employee ID in the URL so I am looping through each user to grab their data. Endpoint #2 contains "custom fields" for the user. I am trying to combine the returns of both endpoints and write them as a single row for each user in the SQL table.
They return PSCustomObject as a hash table.
Endpoint # 1: cat6 NoteProperty string cat6=NONE
Endpoint #2: CustomText94 NoteProperty System.Management.Automation.PSCustomObject CustomText94=#{description=; value=}
function Export-Feed {
Begin {
$serverInstance = ""
$database = ""
$tableName = ""
$employees = Get-Directory | Where-Object eestatus -eq A
}
Process {
$result = $employees | ForEach-Object -Parallel {
$params = #(
'firstname',
'middlename',
'lastname',
#{n='ADID';e={(Connect-Api -apiEndpoint "/api/v1/employee/$($_.eecode)/customfield").CustomText04.value}},
'hire_date',
'rehire_date',
'position_title',
'termination_date',
'work_email',
'employee_code',
'clocksequencenumber',
'department_code',
'department_description',
'employee_status',
'supervisor_primary',
'supervisor_primary_code',
'supervisor_secondary',
'supervisor_secondary_code',
'supervisor_tertiary',
'supervisor_tertiary_code',
'supervisor_quaternary',
'cat1',
'cat1desc',
'cat2',
'cat2desc',
'cat3',
'cat3desc',
'cat4',
'cat4desc',
'cat5',
'cat5desc',
'cat6',
'cat6desc',
'cat7',
'cat7desc',
'cat8',
'cat8desc',
'cat9',
'cat9desc'
)
Connect-Api -apiEndpoint "/api/v1/employee/$($_.eecode)" | Select-Object $params
}
}
End {
$result | Out-File c:\temp\test.txt
#Write-SqlTableData -DatabaseName $database -TableName $tableName -ServerInstance $serverInstance -SchemaName dbo -InputData $result -force
}
}
To merge two custom objects ([pscustomobject] instances, which are not the same as hashtables), use the following technique:
# Two sample input objects.
$o1 = [pscustomobject] #{ one = 1; two = 2; three = 3 }
$o2 = [pscustomobject] #{ four = 4; five = 5; six = 6 }
# Merge the two, by appending the properties of the 2nd to the 1st.
# Note: This assumes that there is no overlap between the property names.
foreach ($prop in $o2.psobject.Properties) {
$o1.psobject.Properties.Add($prop, $true)
}
# $o1 now contains the union of both property sets;
# Output it.
$o1 | Format-Table
The above yields:
one two three four five six
--- --- ----- ---- ---- ---
1 2 3 4 5 6
The above relies on every object in PowerShell having a hidden .psobject property that provides reflection information about the object, notably the collection of all properties returned by the .Properties property.
PowerShell allows properties to be dynamically added to any property, which is feature of its ETS (Extended Type System).
[pscustomobject] instances contain only such dynamic properties.
The .Add() method allows adding a copy of another object's property to an object; the $true indicates that no validation need be performed, which speeds up the operation.

Powershell convert Array of Objects into PSCustomObject

I would like to convert this array of objects
Name CIDR
---- ----
sdc-MO 10.92.18.136/20
sdc-RM 10.77.6.34/20
into a single [PSCustomObject]
sdc-MO sdc-RM
------- -------
{10.92.18.136/20} {10.77.6.34/20}
Please suggest any easy way.. Thanks
Add each object to a hashtable or other dictionary dictionary type, then use the dictionary to create the object (each entry will become a separate property):
$array = #(
[pscustomobject]#{ Name = 'sdc-MO'; CIDR = '10.92.18.136/20' }
[pscustomobject]#{ Name = 'sdc-RM'; CIDR = '10.77.6.34/20' }
)
# Prepare a new dictionary to hold the properties
$newProperties = [ordered]#{}
foreach($inputObject in $array){
# If we don't already have a property with the given name,
# create a new entry in the dictionary
if(-not $newProperties.Contains($inputObject.Name)){
$newProperties.Add($inputObject.Name, #())
}
# Add the `CIDR` value to the corresponding property name
$newProperties[$inputObject.Name] += $inputObject.CIDR
}
$newObject = [pscustomobject]$newProperties
$newObject will be like what you described in the question:
PS C:\> $newObject
sdc-MO sdc-RM
------ ------
{10.92.18.136/20} {10.77.6.34/20}

Don't quite understand powershells "-Join" and "ConvertTo-Csv"

I have this code to create a csv and display it as a table:
$Keys = ("OrderDate","Region","Rep","Product","Units","Unit Cost","Total")
$Csv = #()
$Keys | ForEach-Object {
$Csv += $_ -Join ","
}
$Csv | ConvertFrom-Csv
My output is:
OrderDate
OrderDate,Region
OrderDate,Region,Rep
OrderDate,Region,Rep,Product
OrderDate,Region,Rep,Product,Units
OrderDate,Region,Rep,Product,Units,Unit Cost
OrderDate,Region,Rep,Product,Units,Unit Cost,Total
OrderDate
---------
Region
Rep
Product
Units
Unit Cost
Total
I would like these lines to be formatted as headers of a table, like this:
OrderDate Region Rep ProductUnits Unit Cost Total
----------- -------- ---- --------------- ----------- ------
What you're attempting can be done like this:
$Keys = "OrderDate","Region","Rep","Product","Units","Unit Cost","Total"
$Object = Select-Object -InputObject 0 -Property $Keys
That's typically most useful when you don't know what the properties are when writing the script. The input object doesn't matter as long as it's a scalar value (i.e., not a collection).
To get the exact output you've specified, you'd have to do $Object | Format-Table because PowerShell defaults to list output for custom objects, but that changes the object into a string so it's just for display.
A more generally useful pattern to create an object when you do know the properties is to do this:
$Object = [PSCustomObject]#{
"OrderDate" = # Some Value
"Region" = # Some Value
"Rep" = # Some Value
"Product" = # Some Value
"Units" = # Some Value
"Unit Cost" = # Some Value
"Total" = # Some Value
}
Here you instance the object and assign the values you want immediately.

Merge 2 PowerShell variables

I have 2 PowerShell variables that include data in the following format. For the first table:
UserName Department
-------- ----------
X#Y.com IT
and data in the following format in the second table:
Country MobileNumber
------- ------------
Singapore +65 8xxxxxxx
and the other variable is the same with different column names and different content. I want to merge the 2 variables to have them in one single variable in that would be in the following format:
UserName Department Country MobileNumber
-------- ---------- ------- ------------
Update:
The result of Ansgar commnet, generate it in the following format:
UserName Department Country MobileNumber
-------- ---------- ------- ------------
{x#y.com, z#y.com} {IT, Sales} {Singapore, Singapore} the same here
Assuming that you have individual objects in your two variables you could construct new objects from them like this:
$obj = New-Object -Type PSObject -Property #{
'UserName' = $obj1.UserName
'Department' = $obj1.Department
'Country' = $obj2.Country
'MobileNumber' = $obj2.MobileNumber
}
If you have arrays of objects (which, judging from your updated question, is the case) you need to build the objects in a loop. Note that this assumes an equal number of objects in both variables. Note also that you MUST ensure that both arrays are in the correct order, unless you have some criteria by which you can match objects from one array to the corresponding object from the other array.
$obj = for ($i=0; $i -lt $obj1.Count; $i++) {
New-Object -Type PSObject -Property #{
'UserName' = $obj1[$i].UserName
'Department' = $obj1[$i].Department
'Country' = $obj2[$i].Country
'MobileNumber' = $obj2[$i].MobileNumber
}
}
I would create a new object and map the properties in a hashtable like this:
First, you have your variables with the data, in this example it is
$Variable1
$Variable2
Then we want to make a Hashtable, this will map the data in each of these two variables to a property in our new object, so we map the two properties Username and Department from the first variable and the Country and the MobileNumber from the second variable.
$properties = #{
'Username'=$Variable1.UserName;
'Department'=$Variable1.Department;
'Country'=$Variable2.Country;
'MobileNumber'=$Variable2.MobileNumber;}
Lastly we create a new object, in this example I call the object $User. We tell this object to contain the properties for our Hashtable:
$User = New-Object -TypeName psobject -Property $properties

Find matches in two different Powershell objects based on one property

I am trying to find the matching names in two different types of Powershell objects
$Object1 has two properties - Name (string), ResourceID (uint32)
$object2 has one noteproperty - Name (system.string)
This gives me a list of the matching names but I also want the corresponding resourceID property from $object1.
$computers = Compare-Object $Object1.name $WSD_CM12 | where {$_.sideindicator -eq "=>"} | foreach {$_.inputobject}
These are big objects with over 10,000 items so I'm looking for the most efficient way to accomplish this.
If I'm understanding what you're after, I'd start by creating a hash table from your Object1 collection:
$object1_hash = #{}
Foreach ($object1 in $object1_coll)
{ $object1_hash[$object1.Name] = $object1.ResourceID }
Then you can find the ResourceID for any given Object2.name with:
$object1_hash[$Object2.Name]
Test bed for creating hash table:
$object1_coll = $(
New-Object PSObject -Property #{Name = 'Name1';ResourceID = 001}
New-Object PSObject -Property #{Name = 'Name2';ResourceID = 002}
)
$object1_hash = #{}
Foreach ($object1 in $object1_coll)
{ $object1_hash[$object1.Name] = $object1.ResourceID }
$object1_hash
Name Value
---- -----
Name2 2
Name1 1
Alternative method:
# Create sample list of objects with both Name and Serial
$obj1 = New-Object -Type PSCustomObject -Property:#{ Name = "Foo"; Serial = "1234" }
$obj2 = New-Object -Type PSCustomObject -Property:#{ Name = "Cow"; Serial = "4242" }
$collection1 = #($obj1, $obj2)
# Create subset of items with only Name
$objA = New-Object -Type PSCustomObject -Property:#{ Name = "Foo"; }
$collection2 = #($objA)
#Everything above this line is just to make sample data
# replace $collection1 and $collection2 with $Object1, $WSD_CM12
# Combine into one list
($collection1 + $collection2) |
# Group by name property
Group-Object -Property Name |
# I only want items that exist in both
Where { $_.Count -gt 1 } |
# Now give me the object
Select -Expand Group |
# And get the properties
Where { $_.Serial -ne $null }