Dictionary with multiple values per key - powershell

I need a datatype for the PowerShell to add different values to a key. which type should I choose?
The data are like:
+--------+--------+--------+--------+
| Serv1 | Serv2 | Serv3 | Serv4 |
| -------+--------+--------+------- |
| User1 | User2 | User3 | User4 |
| User3 | User1 | User2 | User4 |
| User7 | User8 | User9 | ------ |
+--------+--------+--------+--------+

This would be easier to answer with more information. But based on that, it looks like a [hashtable] where the values are arrays is what you want.
Example:
$hash = #{
Serv1 = #(
'User1',
'User3',
'User7'
)
Serv2 = #(
'User2',
'User1'
)
}
# add a new user to an existing key
$hash.Serv2 += 'User8'
# add a new key
$hash.Serv3 = #(
'User3',
'User2'
)

Related

PowerShell: Splitting an Array into two columns

I have an array with the following values:
| Firstname | Lastname | Username |
|-----------|------------------|----------|
| person1 | person1_lastname | p1 |
| person2 | person2_lastname | p2 |
| person3 | person3_lastname | p3 |
| person4 | person4_lastname | p4 |
This is the code that produces the above results:
$finalUsers = foreach($person in $excludedUsers) {
if ($person.Username -notin $ausLunchJobs.AssigneeUser -and $person.Username -notin $ausLunchJobs.AssigneeUser2) {
$person | Select-Object Firstname, Lastname, Username
}
}
I want to split that array into two columns and pair the Username data together.
Ideal output:
| Username | Username2 |
|----------|-----------|
| p1 | p2 |
| p3 | p4 |
Any guidance on how I can achieve something like this?
TIA
Create 1 new object per row you want displayed in the table:
$userPairs = for($i = 0; $i -lt $finalUsers.Count; $i += 2){
$finalUsers[$i] |Select-Object Username,#{ Name='Username2'; Expression={ $finalUsers[$i+1].username } }
}
Result:
PS ~> $userPairs |Format-Table
Username Username2
-------- ---------
p1 p2
p3 p4

How do I join tables while putting the results in a json array?

Table name: people
+----+------+-------------+-------+
| id | name | city | state |
+----+------+-------------+-------+
| 1 | Joe | Los Angeles | CA |
+----+------+-------------+-------+
| 2 | Jill | Miami | FL |
+----+------+-------------+-------+
| 3 | Asa | Portland | OR |
+----+------+-------------+-------+
Table name: pets
+----+----------+------+
| id | pet_name | type |
+----+----------+------+
| 1 | Spike | dog |
+----+----------+------+
| 1 | Fluffy | cat |
+----+----------+------+
| 2 | Oscar | dog |
+----+----------+------+
How would I join the two tables above to include a column containing JSON of results matched in the 'pets' table (PostgreSQL)?
+----+------+------------------------------------------------------------+
| id | name | pets |
+----+------+------------------------------------------------------------+
| 1 | Joe | [{name:'Spike', type:'dog'}, {name: 'Fluffy', type:'cat'}] |
+----+------+------------------------------------------------------------+
| 2 | Jill | [{name:'Oscar', type:'dog'}] |
+----+------+------------------------------------------------------------+
| 3 | Asa | [] |
+----+------+------------------------------------------------------------+
Use json_agg() to aggregate over json-objects:
SELECT people.id
, name
, json_agg(
CASE WHEN pet_name IS NOT NULL THEN
json_build_object(
'name', pet_name
, 'type', type
)
END
)
FROM people
LEFT JOIN pets ON people.id = pets.id
GROUP BY
people.id
, name
ORDER BY
people.id;

Selecting unique values per rows in pscustomobject

I have this custom object:
**Id | Name | User**
1 | A | {Joe, Joe, Chloe, Cindy}
2 | B | {Joe, Andy, Andy, Cindy, Cindy}
3 | C | {Joe, Joe, Chloe, Chloe, Andy, Andy}
I need to sort unique users for each individual object like below:
**Id | Name | User**
1 | A | {Joe, Chloe, Cindy}
2 | B | {Joe, Andy, Cindy}
3 | C | {Joe, Chloe, Andy}
I need to output the ID or Name after sorting.
The closest I could get was to run a | sort-object -unique, but it doesn't work as I was not able to pull the individual IDs/Names.
You can use "Select-Object" with a hashtable (also known as a calculated property):
$objects | Select-Object Id,Name,#{ Name = "User"; Expression = { $_.User | Select-Object -Unique } }

Powershell Hashtable Export to CSV

I am trying to create a CSV export that contains all rows in the data spreadsheet that the IDs from the search spreadsheet show up in.
I have managed to create the searching element through PowerShell now but am having trouble exporting the data into the CSV format.
Below are some example tables, the actual data has up to 8 values (including ID column), but only the first three are guaranteed to be filled.
Data Spreadsheet
+------+---------+---------+---------+---------------------+
| ID | Value 1 | Value 2 | Value 3 | Value 4 |
+------+---------+---------+---------+---------------------+
| 1234 | London | Serial1 | HP | Laptop User |
| 2345 | Moscow | Serial7 | | HR Application |
| 1234 | London | Serial9 | | Finance Application |
| 3456 | Madrid | Serial4 | HP | Laptop User |
+------+---------+---------+---------+---------------------+
Search Spreadsheet
+------+
| ID |
+------+
| 1234 |
| 2345 |
+------+
Desired Result
+------+---------+---------+---------+---------------------+
| ID | Value 1 | Value 2 | Value 3 | Value 4 |
+------+---------+---------+---------+---------------------+
| 1234 | London | Serial1 | HP | Laptop User |
| 2345 | Moscow | Serial7 | | HR Application |
| 1234 | London | Serial9 | | Finance Application |
+------+---------+---------+---------+---------------------+
Below is the current code that I have with the attempts to export to CSV removed.
$finalValues = #{}
$users = Import-Csv "SEARCH.csv"
$data = Import-Csv "DATA.csv" | Group-Object -property ID -AsHashTable
foreach ($user in $users)
{
If ($data.Contains($user.ID))
{
#write-output $data[$user.ID].ID
$finalValues.Add($data[$user.ID].ID, $data[$user.ID])
}
}
The following two commands (ran after the rest of the script has executed) have the below output.
$finalValues.Values
ID : 1234
Value 1 : London
Value 2 : Serial 1
Value 3 : HP
Value 4 :
Value 5 :
Value 6 :
Value 7 : Laptop User
ID : 2345
Value 1 : Moscow
Value 2 : Serial7
Value 3 :
Value 4 :
Value 5 :
Value 6 :
Value 7 : HR Application
ID : 1234
Value 1 : London
Value 2 : Serial9
Value 3 :
Value 4 :
Value 5 :
Value 6 :
Value 7 : Finance Application
$finalValues
{1234, 1234} {#{ID=1234; Value 1=London; Value 2=Serial1; Value 3=HP; Value 4=; Value 5=; Value 6=; Value 7=Laptop User}, #{ID=1234; Value 1=London; Value 2=Serial 9... ; Value 7 =Finance Application}}
2345 {#{ID=2345; Value 1=Moscow; Value 2=Serial7; Value 3=; Value 4=; Value 5=; Value 6=; Value 7=HR Application}}
When exporting to CSV with the following command I get the following result:
$finalValues | export-csv -Path test.csv -NoTypeInformation
+------------+-------------+----------------+--------------------------------------------+----------------------------------------------+---------------+-------+
| IsReadOnly | IsFixedSize | IsSynchronized | Keys | Values | SyncRoot | Count |
+------------+-------------+----------------+--------------------------------------------+----------------------------------------------+---------------+-------+
| FALSE | FALSE | FALSE | System.Collections.Hashtable+KeyCollection | System.Collections.Hashtable+ValueCollection | System.Object | 14 |
+------------+-------------+----------------+--------------------------------------------+----------------------------------------------+---------------+-------+
When exporting to CSV with the following command I get the following result:
$finalValues.Values | export-csv -Path test.csv -NoTypeInformation
+-------+------------+-------------+---------------+----------------+
| Count | IsReadOnly | IsFixedSize | SyncRoot | IsSynchronized |
+-------+------------+-------------+---------------+----------------+
| 1 | FALSE | FALSE | System.Object | FALSE |
| 1 | FALSE | FALSE | System.Object | FALSE |
| 3 | FALSE | FALSE | System.Object | FALSE |
| 1 | FALSE | FALSE | System.Object | FALSE |
| 1 | FALSE | FALSE | System.Object | FALSE |
| 1 | FALSE | FALSE | System.Object | FALSE |
| 1 | FALSE | FALSE | System.Object | FALSE |
| 1 | FALSE | FALSE | System.Object | FALSE |
| 2 | FALSE | FALSE | System.Object | FALSE |
| 2 | FALSE | FALSE | System.Object | FALSE |
| 1 | FALSE | FALSE | System.Object | FALSE |
| 2 | FALSE | FALSE | System.Object | FALSE |
| 1 | FALSE | FALSE | System.Object | FALSE |
| 1 | FALSE | FALSE | System.Object | FALSE |
+-------+------------+-------------+---------------+----------------+
#BenH's answer is clearly a better way to implement this, but I just wanted to explain what the issue was with your original code. The problem is that $data is a HashTable mapping a string (the user ID) to an array (actually it's a Collection<PSObject> but for our purposes it behaves the same). Even in the case of ID '2345' where there is only one matching record, $data still stores it as an array with one element:
PS> $data['2345'].GetType().Name
Collection`1
PS> $data['2345'].Count
1
PS> $data['2345'] # Returns the array of values
ID : 2345
Value 1 : Moscow
Value 2 : Serial7
Value 3 :
Value 4 : HR Application
PS> $data['2345'][0] # Returns the first element of the array of values
ID : 2345
Value 1 : Moscow
Value 2 : Serial7
Value 3 :
Value 4 : HR Application
Thus, when this line executes...
$finalValues.Add($data[$user.ID].ID, $data[$user.ID])
...you are adding a new item to $data where both the key and the value are arrays. This is why the output of piping $finalValues or $finalValues.Values to Export-Csv behaves as if the values are arrays; it's because they are.
To fix this, when accessing items in $data we'll need an inner loop to "unwrap" each value. Also, we can't use a HashTable for $finalValues because you're using ID as the key but there are duplicate IDs ('1234') in the results. Since all we need is a flat list of records to eventually pass to Export-Csv, we can just use an array instead. Here's some modified code...
$finalValues = #() # Cannot be a HashTable because there may be multiple results with the same ID
$users = Import-Csv "SEARCH.csv"
$data = Import-Csv "DATA.csv" | Group-Object -property ID -AsHashTable
foreach ($user in $users)
{
If ($data.Contains($user.ID))
{
# "Unwrap" the array stored at $data[$user.ID]
foreach ($dataRecord in $data[$user.ID])
{
$finalValues += $dataRecord
}
}
}
$finalValues | Export-Csv -Path test.csv -NoTypeInformation
...that produces this CSV...
"ID","Value 1","Value 2","Value 3","Value 4"
"1234","London","Serial1","HP","Laptop User"
"1234","London","Serial9","","Finance Application"
"2345","Moscow","Serial7","","HR Application"
This could be simplified by using a Where-Object filter and then exporting with Export-CSV.
$Search = Import-CSV "SEARCH.csv"
Import-CSV "DATA.csv" | Where-Object {$Search.ID -Contains $_.ID} | Export-CSV C:\exampleexportpath.csv -NoTypeInformation

Talend split fields from one to double

I have mysql table with text field "email", which can contain "user#example.com" and "user1#example.com;user2#example.com;user3#example.com".
| Name | Email |
| user | user#example.com |
| user1 | user1#example.com;user2#example.com;user3#example.com |
How can i do output with Talend such this:
| Name | Email |
| user | user#example.com |
| user1 | user1#example.com |
| user1 | user2#example.com |
| user1 | user3#example.com
The tNormalize component does exactly this. You can provide a character for separation, in your case ; and get rows as result afterwards.
EDIT
AxelH pointed out that it is possible as well to use a String for separation, this is not a Character.