Merge two csv columns in powershell, order of columns - powershell

I am currently using the code below that I found on here to concat 2 columns into a new column. The problem is that when I export the csv, the columns are not in the order that I list below. How can I sort the columns into the order I want?
Thanks
$objs =#();
$output = Import-csv -Path C:\Users\Dan\Desktop\External_ID_Test.csv | ForEach {
$Object = New-Object PSObject -Property #{
Employee_ID = $_.Employye_ID
Base_Cost_Center = $_.Base_Cost_Center
Entity = $_.Entity
ExternalID = [String]::Concat($_.Entity,$_.Base_Cost_Center)
}
$objs += $Object;
}
$objs
$objs | Export-CSv C:\Users\Dan\Desktop\Export_External_ID_Test.csv -NoTypeInformation

Your are assigning the output of the ForEach-Object to the variable $Output but aren't outputting anything.
Simplify your script by using an ordered [PSCustomObject] and avoiding the += which will rebuild the array $objs on every iteration.
$output = Import-csv -Path C:\Users\Dan\Desktop\External_ID_Test.csv | ForEach-Object {
[PSCustomObject]{
Employee_ID = $_.Employye_ID
Base_Cost_Center = $_.Base_Cost_Center
Entity = $_.Entity
ExternalID = [String]::Concat($_.Entity,$_.Base_Cost_Center)
}
}
$output
$output | Export-CSv C:\Users\Dan\Desktop\Export_External_ID_Test.csv -NoTypeInformation

Related

Powershell: Compare 2 CSV files for equalities, then output equalities and another row

I'm trying to sort trough a recent report of PCs users don't seem to be using, for that ive got a CSV file called report, and a CVS file of all our PC's called data.
Report and Data only share 1 column which is the users full name, how can i get a result which provides both the users full name and the PC which is only from report?
So far i have the following code which works for getting the users full name, but I'm unsure how to get the device
$report = Import-Csv "C:\Temp\\report.CSV" -Delimiter ";"
$data = Import-Csv "C:\Temp\\data.CSV" -Delimiter ";"
$UserOutput = #()
ForEach ($name in $report)
{
$userMatch = $data | where {$_.FullName -like $name.FullName}
If($userMatch)
{
$UserOutput += New-Object PsObject -Property #{UserName =$name.FullName;Device=$userMatch.Device}
}
else
{
$UserOutput += New-Object PsObject -Property #{UserName =$name.FullName;Device ="NA"}
}
}
$UserOutput | ft
This gives a nice list, but i cant find the devices so it ends up looking like this
Device UserName
------ --------
NA Anders Aadal Jensen
NA Andr�s Kov�cs
NA Anette Dahnke
You can use a Group-Object -AsHashtable to correlate the FullName property on both arrays of objects. This assumes that the property values are an exact match when correlated.
$data = Import-Csv "C:\Temp\data.CSV" -Delimiter ";" |
Group-Object Device -AsHashTable -AsString
Import-Csv "C:\Temp\report.CSV" -Delimiter ";" | ForEach-Object {
$device = 'NA'
if($data.ContainsKey($_.FullName)) {
$device = $data[$_.FullName]
}
[pscustomobject]#{
UserName = $_.FullName
Device = $device
}
} | Format-Table
Assuming that the details provided by you available in both the csv file, here is a sample for you.
$CSV1 = Import-Csv "C:\Temp\\report.CSV" -Delimiter ";"
$CSV2 = Import-Csv "C:\Temp\\data.CSV" -Delimiter ";"
$Count = $CSV2.Count
$Results = For ($i = 0; $i -lt $Count; $i++) {
If ($CSV2[$i].FullName -eq $CSV1[$i].FullName) {
$Match = "Match"
}
Else {
$Match = "No Match found"
}
[PSCustomObject]#{
UserName = $CSV2[$i].FullName
Device = $CSV2[$i].Device
Results = $Match
}
}
$Results | Export-Csv -Path "C:\Temp\results.csv" -NoTypeInformation
The accepted answer looks to assume entry count on the CSVs are a one for one match. Since it has one loop comparing the same CSV array element numbers.
From your description, you mention Report.csv is a list of infrequently used PCs and the Data.csv is an "All PC" list. If your entry counts are not one-for-one, may need two loops like below.
$Results = 0..$($REPORT.Count - 1) | ForEach-Object {
$i = $_
$($DATA | ForEach-Object { if($_.Fullname -eq $REPORT[$i].Fullname) { <# DATA PSCUSOMOBJECT#> }})
}

Copy selected columns and insert to another csv using powershell

I have a two csv files. Both have same number of columns but not in row. I would like to copy 3 columns from csv1 and merge into csv2 using powershell.
I am not good at scripting. Could someone help me?
Here is code I am using.
$csv1 = Import-Csv -LiteralPath C:\BackUp\PScripts\SDO\Report.csv
$csv2 = Import-Csv -LiteralPath C:\BackUp\PScripts\SDO\7Saturday9PM.csv
$Results = #()
foreach ($record in $csv2) {
Add-Member -InputObject $record -MemberType NoteProperty -Name FoundInAD -Value $($csv1 | ? { $_.InstalledOrNA -eq $record.InstalledOrNA } | select -Property FoundInAD)
$Results += $record
}
$Results | Select-Object -Property ComputerName,PatchingStyle,LastSyncTime,LastSyncResult,LastReportedStatusTime,PendingReboot,NeededCount,InstalledOrNA,FoundInAD

Replace string in an imported CSV file

I need to import a CSV file and then replace full usernames domain\username with username.
The following lines work but I only receive the amended usernames as the output and not the full file.
Could you please advise?
$TestFile = Import-Csv .\file.csv
$NewFile = $TestFile | ForEach-Object {$_."Username" -replace 'domain\\',''}
When processing CSV input with a ForEach-Object loop you need to output the data back to the pipeline. Also, the -replace operator doesn't modify variables or properties in-place. It takes the value, does the work, and outputs the modified string to the success output stream. If you want to update a property you need to assign the modified value back to that property.
Change this:
$TestFile = Import-Csv .\file.csv
$NewFile = $TestFile | ForEach-Object {$_."Username" -replace 'domain\\',''}
into this:
$NewFile = Import-Csv .\file.csv | ForEach-Object {
$_.Username = $_.Username -replace 'domain\\', '' # update username
$_ # feed data back into the pipeline
}
and the code will do what you want.
You can perform the replace on the string data, then convert it into an object using ConvertFrom-Csv.
$TestFile = (Get-Content .\file.csv) -replace 'domain\\',''
$NewFile = ConvertFrom-Csv $TestFile
Here's one way - get the column names from the input table, iterate each row in the table, and output new custom objects with needed changes.
$table = Import-Csv "Test.csv"
# Get column names
$columnNames = ($table | Select-Object -First 1).PSObject.Properties |
Select-Object -ExpandProperty Name
# Iterate each row in the table
foreach ( $row in $table ) {
$outputObject = New-Object PSObject
foreach ( $columnName in $columnNames ) {
if ( $columnName -eq "Username" ) {
$outputObject | Add-Member NoteProperty "Username" ($row.Username.Split('\')[1])
}
else {
$outputObject | Add-Member NoteProperty $columnName $row.$columnName
}
}
$outputObject
}
To create a new CSV file as output, put the above code in a script and pipe to Export-Csv.

try to determine the max number of character in each column

I have written a script that tries to determine the max no. of character for each column. This is what I wrote:
$path = 'folder path'
$file = Get-ChildItem $path\*
$FileContent = foreach ($files in $file) {
$FileHeader = #( (Get-Content $files -First 1).Split($delimiter) )
$importcsv = #( Import-Csv $files -Delimiter "$delimiter" )
for ($i=0; $i -lt $FileHeader.Length; $i++) {
#select each column
$Column = #( $importcsv | select $FileHeader[$i] )
#find the max no. of character
$MaxChar = #(($Column[$i] |
Select -ExpandProperty $FileHeader[$i] |
Measure-Object -Maximum -Property Length).Maximum)
$output = New-Object PSObject
$output | Add-Member NoteProperty FullName ($files.FullName)
$output | Add-Member NoteProperty FileName ($files.Name)
$output | Add-Member NoteProperty Time (Get-Date -Format s)
$output | Add-Member NoteProperty FileHeader ($($FileHeader[$i]))
$output | Add-Member NoteProperty MaxCharacter ($($MaxChar[$i]))
Write-Output $output
}
}
The script above is just part of it, so $delimiter is already defined. And finally I will export the result as CSV.
The script runs without any error, but when I open the file it only gives me the first column/header the max no. of character, and the rest of column/header are missing.
The perfect result will be showing each column/header the max no. of character.
Is something wrong with my loop?
my boss is trying to create an automate process to finding all the information from the raw data and use those information to upload to the database, so part of the script that is missing is about determine the delimiter of the raw file, the $CleanHeader is clean version of $FileHeader (remove all special characters, turn capital letters to small letters), those cleanheaders will be use for headers in the table in the database. and he also want to know the maximum character in each column, so that info can use them in creating the size of the column in the table in the database (he knows this part can be done in sql), but he ask me whether it can be done in PowerShell or not.
This should work:
$ht = #{}
# import a CSV and iterate over its rows
Import-Csv $f.FullName -Delimiter "$delimiter" | ForEach-Object {
# iterate over the columns of each row
$_.PSObject.Properties | ForEach-Object {
# update the hashtable if the length of the current column value is greater
# than the value in the hashtable
if ($_.Value.Length -gt $ht[$_.Name]) {
$ht[$_.Name] = $_.Value.Length
}
}
}
# create an object for each key in the hashtable
$date = Get-Date -Format s
$ht.Keys | ForEach-Object {
New-Object -Type PSObject -Property #{
FullName = $f.FullName
Name = $f.Name
Time = $date
FileHeader = $_
MaxCharacter = $ht[$_]
}
}
FileHeader[$i] was returning the column name with quotes : "ColumnName" instead of ColumnName
To fix, just add a trim to the line where you pull the header :
$FileHeader = #( (Get-Content $files -First 1).Split($delimiter).trim('"') )

Merge 2 CSV by Value "Name" and merge Count (Powershell)

So at the momemt I'm searching for a way to merge 2 CSV files.
Here is an example for what I mean:
CSV1
"Name","Count"
"Klaus","3"
"Hans","2"
"Gerhard","1"
"Nina","6"
"Julia","10"
"Caro","19"
CSV2
"Name","Count"
"Klaus","2"
"Hans","1"
"Gerhard","1"
"Nina","1"
Now if I merge both, the output/result should be:
"Name","Count"
"Klaus","5"
"Hans","3"
"Gerhard","2"
"Nina","7"
"Julia","10"
"Caro","19"
I tried a lot, but I´ve never had suscess; I always had wrong results. Does anyone have an idea how to do this?
You can use Group-Object (alias group) to group everything by the Name property. Then you just need to sum up the Count property of each guy in the group. Measure-Object (alias measure) will do sums for you.
$grouped = Import-Csv .\csv1.csv, .\csv2.csv | group Name
$combined = $grouped |%{
New-Object PsObject -Prop #{ Name = $_.Name; Count = ($_.Group | measure -sum -prop Count).Sum }
}
$combined | Export-Csv .\combined.csv -NoType
Import the CSV files and convert each to a hash table, then find the common names:
$csv1 = Import-Csv -Path csv1.csv
$csv2 = Import-Csv -Path csv2.csv
$HashCSV1 = #{}
$HashCSV2 = #{}
$HashMerge = #{}
foreach($r in $csv1)
{
$HashCSV1[$r.Name] = $r.Count
}
foreach($r in $csv2)
{
$HashCSV2[$r.Name] = $r.Count
}
foreach ($key in $HashCSV1.Keys) {
if ($HashCSV2.ContainsKey($key)) {
$HashMerge[$key] = [int]$HashCSV1[$key] + [int]$HashCSV2[$key]
} else {
$HashMerge[$key] = $HashCSV1[$key]
}
}
foreach ($key in $HashCSV2.Keys) {
if (-not $HashCSV1.ContainsKey($key)) {
$HashMerge[$key] = $HashCSV2[$key]
}
}
&{$HashMerge.getenumerator() |
foreach {new-object psobject -Property #{Name = $_.name;Count=$_.value}}
} | export-csv merge.csv -notype