I would like to compare values in two columns in file1.csv with file2.csv, then assigned the matching value to a new column in file1.csv.
ATM, this is the working so far. Simpler format would be ideal.
$report = Import-CSV -Path "C:\report.csv" -Encoding UTF8
$reference = Import-CSV -Path "C:\team.csv" -Encoding UTF8
foreach ($team1 in $report){
$matched = $false
foreach ($team2 in $reference){
$obj = "" | select "Type","Setup","Responsible","Team","Main"
if($team1.'Setup' -like "*$($team2.'Main')*"){
$matchCounter++
$matched = $true
$obj.'Type' = $team1.'Type'
$obj.'Setup' = $team1.'Setup'
$obj.'Responsible' = $team1.'Responsible'
$obj.'Team' = $team2.'Team'
$obj | Export-Csv -Path "C:\Output.csv" -Append -NoTypeInformation -Encoding
UTF8
}
}
}
This is what the files like;
file1
type setup responsible
---- ------- -----------
y master fin susan
y sensei kuno peter
y sensei jon peter
y junior jumo
file2
main team
---- -----
master sa1
sensei sr2
jumo st6
desired file3
type setup responsible team
---- ------- ----------- -----
y master fin susan sa1
y sensei kuno peter sr2
y sensei jon peter sr2
y junior jumo st6
What I would like to achieve is column setup and responsible (file1) to be compared to main column (file2) and get its adjacent team. Atm, im not sure how to go about skipping cells in column1 with no reference in file2, but existed in column2. Also, to compare only the first character of setup in file1 with file2.
I guess you you just want to do this:
# $report = Import-CSV -Path "C:\report.csv" -Encoding UTF8
$report = ConvertFrom-Csv #'
type, setup, responsible
y, master fin, susan
y, sensei kuno, peter
y, sensei jon, peter
y, junior, jumo
'#
# $reference = Import-CSV -Path "C:\team.csv" -Encoding UTF8
$reference = ConvertFrom-Csv #'
main, team
master, sa1
sensei, sr2
jumo, st6
'#
foreach ($team1 in $report){
foreach ($team2 in $reference){
if($team1.Setup[0] -eq $team2.Main[0]){
[pscustomobject]#{
Type = $team1.Type
Setup = $team1.Setup
Responsible = $team1.Responsible
Team = $team2.Team
}
}
}
} # |Export-Csv -Path .\Output.csv -NoTypeInformation -Encoding UTF8
Results:
Type Setup Responsible Team
---- ----- ----------- ----
y master fin susan sa1
y sensei kuno peter sr2
y sensei jon peter sr2
y junior jumo st6
Note that the for correctly using the PowerShell Pipeline (and performance reasons), the final (Export-Csv) cmdlet shouldn't reside in your process but actually at the end of the pipeline.
Related
I have a csv file that contains data in the below format:
Name Codes
------- ---------
John AJFKC,EFUY
Ben EFOID, EIUF
Alex OIPORE, OUOIJE
I would like to get the above in the below format and output it into a new csv file as below:
Name Codes
------- ---------
John AJFKC
John EFUY
Ben EFOID
Ben EIUF
Alex OIPORE
Alex OUOIJE
You can do the following if there will always be 2 codes per name:
Import-Csv file.csv | Foreach-Object {
$codes = ($_.Codes -split ',').Trim()
[pscustomobject]#{Name = $_.Name; Codes = $codes[0]}
[pscustomobject]#{Name = $_.Name; Codes = $codes[1]}
}
If the number of codes per name is unknown, you can do the following:
Import-Csv file.csv | Foreach-Object {
$codes = ($_.Codes -split ',').Trim()
foreach ($code in $codes) {
[pscustomobject]#{Name = $_.Name; Codes = $code}
}
}
If this is how this file really looks, it's not a Csv file. It's just a text file based copying and using what you posted. It's left-justified, vs columns, here the staggered look of it. The file has 5 spaces for that name column between it and that left justified Codes column with a code array.
So, though it looks like a table/tabular format, it's not really that. As in an import that name column would include the first of the code strings, thus cause some issues with your desired output. So, that text file would need to be manipulated a bit more, or who or whatever provides you the file, should make is a legitimate CSV.
So, here's my take on the assumptions in the aforementioned.
(Get-Content -Path 'D:\Temp\UserRecord.csv') -replace ', ',',' |
Select -Skip 2 |
ForEach {
$Name = (($PSItem) -split '\s+')[0]
($PSItem -split '\s+')[1] -split ',' |
ForEach {
[PSCustomObject]#{
Name = $Name
Codes = $PSItem
}
}
}
# Results
<#
Name Codes
---- -----
John AJFKC
John EFUY
Ben EFOID
Ben EIUF
Alex OIPORE
Alex OUOIJE
#>
try this:
Import-Csv "c:\temp\test.csv" -Delimiter "`t" | %{
$Name=$_.Name
$_.Codes -split "," | %{ [pscustomobject]#{Name=$Name;Code=$_.Trim()}}
}
I have CSV1 (as below) where I have to populate the last column from CSV 2 given below..
CSV1
Computer Product Code Country Department LaptopDesktop
-------- ------- ---- ------- ---------- -------------
Com1 EliteDesk 705 HP2190 AU FN
Com2 EliteBook 830 HP1023 AU IT
Com3 EliteBook 830 HP1023 FR FN
Com4 Zbook 15U HP2020 IN FN
Com5 OptiPlex 3010 DL1721 FR FN
CSV2
Product Type Code
------- ---- ----
EliteBook 1030 L HP1020
EliteBook 1040 L HP1021
EliteBook 830 L HP1023
Zbook 15U L HP2020
EliteDesk 800 D HP3035
EliteDesk 705 D HP2190
Thinkpad L480 L LE990
OptiPlex 3010 D DL1721
with below code, I'm unable to update 'LaptopDesktop' column in CSV1 whereas output gets appended with -Append parameter or without that, it just overwrite the whole CSV.....How do I fix this?
{
$SystemData =#()
$Productinfo = Import-Csv "C:\CSV2.csv"
$Mastercsv = Import-Csv "C:\CSV1.csv"
foreach($record in $Mastercsv)
{
$mcode = $($record.code)
$mDLtype = $($record.LaptopDesktop)
$SysType = ($Productinfo | where {$_.code -eq $mcode}).type
if ($SysType -eq $null)
{
$sysType = 'Unknown, due to non-matching code'
}
$AddsysType=New-Object PSCustomObject
Add-Member -InputObject $AddsysType -membertype noteproperty -name "LaptopDesktop" -value $sysType
$SystemData +=$AddsysType
}Return, $SystemData
}
$DeviceType= Update-SystemType
$DeviceType| Export-Csv 'C:\CSV1.csv' -Force -NoTypeInformation
I think the fact you've just opened the file to import then try to export to it again is confusing PowerShell. In any case, it's probably not a good idea to over-write the file in this way as it could lead to corruption. Probably better to write to a separate CSV like this:
function Update-SystemType {
Import-Csv ".\CSV2.csv" | ForEach-Object {$codeHash = #{}}{
$codeHash[$_.Code] = $_
}{}
Import-Csv ".\CSV1.csv" |
ForEach-Object {
$_.LaptopDesktop = $(if($codeHash.ContainsKey($_.Code)){$codeHash[$_.Code].Type}else{"Unknown"})
$_
}
}
Update-SystemType |
Export-Csv '.\CSV3.csv' -Force -NoTypeInformation
If you really want to replace the original afterwards, then you can over-write it like this:
Move-Item -Path .\CSV3.csv -Destination .\CSV1.csv -Force
When posting csv sample data, either use the real comma delimited format -or-
the columnar representation after Import-Csv.
## Q:\TEst\2019\01\17\SO_54236818.ps1
$Mastercsv = Import-Csv ".\CSV1.csv"
$Productinfo = Import-Csv ".\CSV2.csv"
foreach($record in $Mastercsv){
$record.LaptopDesktop = ($Productinfo|Where-Object Code -eq $record.code).Type
}
$Mastercsv | Format-Table -Auto
Sample output
Computer Product Code Country Department LaptopDesktop
-------- ------- ---- ------- ---------- -------------
Com1 EliteDesk 705 HP2190 AU FN D
Com2 EliteBook 830 HP1023 AU IT L
Com3 EliteBook 830 HP1023 FR FN L
Com4 Zbook 15U HP2020 IN FN L
Com5 OptiPlex 3010 DL1721 FR FN D
Com6 unknown na DE IT
I have seen powershell script which also I have in mind. What I would like to add though is another column which would show the side indicator comparators ("==", "<=", "=>") and be named them as MATCH(if "==") and MISMATCH(if "<=" and "=>").
Any advise on how I would do this?
Here is the link of the script (Credits to Florent Courtay)
How can i reorganise powershell's compare-object output?
$a = Compare-Object (Import-Csv 'C:\temp\f1.csv') (Import-Csv 'C:\temp\f2.csv') -property Header,Value
$a | Group-Object -Property Header | % { New-Object -TypeName psobject -Property #{Header=$_.name;newValue=$_.group[0].Value;oldValue=$_.group[1].Value}}
========================================================================
The output I have in mind:
Header1 Old Value New Value STATUS
------ --------- --------- -----------
String1 Value 1 Value 2 MATCH
String2 Value 3 Value 4 MATCH
String3 NA Value 5 MISMATCH
String4 Value 6 NA MISMATCH
Here's a self-contained solution; simply replace the ConvertFrom-Csv calls with your Import-Csv calls:
# Sample CSV input.
$csv1 = #'
Header,Value
a,1
b,2
c,3
'#
$csv2 = #'
Header,Value
a,1a
b,2
d,4
'#
Compare-Object (ConvertFrom-Csv $csv1) (ConvertFrom-Csv $csv2) -Property Header, Value |
Group-Object Header | Sort-Object Name | ForEach-Object {
$newValIndex, $oldValIndex = ((1, 0), (0, 1))[$_.Group[0].SideIndicator -eq '=>']
[pscustomobject] #{
Header = $_.Name
OldValue = ('NA', $_.Group[$oldValIndex].Value)[$null -ne $_.Group[$oldValIndex].Value]
NewValue = ('NA', $_.Group[$newValIndex].Value)[$null -ne $_.Group[$newValIndex].Value]
Status = ('MISMATCH', 'MATCH')[$_.Group.Count -gt 1]
}
}
The above yields:
Header OldValue NewValue Status
------ -------- -------- ------
a 1 1a MATCH
c 3 NA MISMATCH
d NA 4 MISMATCH
Note:
The assumption is that a given Header column value appears at most once in each input file.
The Sort-Object Name call is needed to sort the output by Header valuesThanks, LotPings.
, because, due to how Compare-Object orders its output (right-side-only items first), the order of groups created by Group-Object would not automatically reflect the 1st CSV's order of header values (d would appear before c).
I am using Import-CSV to get the data from a csv file that looks like:
P1,1,3,4
P2,4,5,6
P3,1,2,3
P4,8.7,6,3
I would like to keep the white-space in front of the text as it indicates the hierarchy. Import-CSV returns:
P1,1,3,4
P2,4,5,6
P3,1,2,3
P4,8.7,6,3
Is there a way to keep the white space?
Your CSV isn't correctly formatted, the items in each row should all be quoted to meet the file specification:
"P1,"1","3","4"
" P2,"4","5","6"
" P3,"1","2","3"
" P4,"8.7","6","3"
You can take a shortcut and only wrap the entries with leading spaces in quotes:
P1,1,3,4
" P2",4,5,6
" P3",1,2,3
" P4",8.7,6,3
Then Import-CSV will function as you're expecting, headers added for demonstration:
Import-CSV leading_spaces.csv -Header "Field1","Field2","Field3","Field4"
Gives you your desired output:
Field1 Field2 Field3 Field4
------ ------ ------ ------
P1 1 3 4
P2 4 5 6
P3 1 2 3
P4 8.7 6 3
As per James C's comment, you can do this with Get-Content:
$myData = Get-Content .\test2.txt
foreach($line in ($myData | Select-Object -Skip 1)){
[array]$results += [pscustomobject]#{
$myData[0].Split(",")[0] = $line.Split(",")[0]
$myData[0].Split(",")[1] = $line.Split(",")[1]
$myData[0].Split(",")[2] = $line.Split(",")[2]
$myData[0].Split(",")[3] = $line.Split(",")[3]
}
}
Maybe this will help, it will create a new object for each row:
get-content test.csv | % {
$row = New-Object PSObject
$i = 0
$_ -split "," | %{
$row | add-member Noteproperty "column$i" $_
$i++
}
$row
}
Output will look like this:
column0 column1 column2 column3
------- ------- ------- -------
P1 1 3 4
P2 4 5 6
P3 1 2 3
P4 8.7 6 3
So I have a CSV file which I need to manipulate a bit, select the data I need and export to another CSV file.
The code I have is:
$rawCSV = "C:\Files\raw.csv"
$outputCSV = "C:\Files\output.csv"
Import-Csv -Header #("a","b","c","d") -Path $rawCSV |
select -Skip 7 |
Where-Object { $_.b.length -gt 1 } |
ft b,a,c,d |
Out-File $outputCSV
So this code uses the Import-Csv command to allow me to select just the columns I need, add some headers in the order I want and then I am simply putting the output in to a CSV file called $outputCSV. The contents of this output file look something like this:
b a c d
- - - -
john smith 29 England
mary poopins 79 Walton
I am not sure what the delimiter is in this output and rather than these columns being treated as individuals, they are treated as just one column. I have gone on further to replace all the spaces with a comma using the code:
$b = foreach ($line in $a)
{
$fields = $line -split '`n'
foreach ($field in $fields)
{
$field -replace " +",","
}
}
Which produces a file that looks like this:
b,a,c,d
john,smith,29,England
mary,poppins,79,Walton
But these are all still treated as one column instead of four separate columns as I need.
* UPDATE *
Using the answer given by #, I now get a file looking like this:
Don't use ft to reorder your columns - it's intended to format output for the screen, not really suitable for CSV.
"Manual" solution:
$rawCSV = "C:\Files\raw.csv"
$outputCSV = "C:\Files\output.csv"
# Import and filter your raw data
$RawData = Import-Csv -Header #("a","b","c","d") -Path $rawCSV
$Data = $RawData | Select -Skip 7 | Where-Object { $_.b.length -gt 1 }
# Write your headers to the output file
"b","a","c","d" -join ',' | Out-File $outputCSV -Force
$ReorderedData = foreach($Row in $Data){
# Reorder the columns in each row
'{0},{1},{2},{3}' -f $Row.b , $Row.a , $Row.c, $Row.d
}
# Write the reordered rows to the output file
$ReorderedData | Out-File $outputCSV -Append
Using Export-Csv:
As of PowerShell 3.0, you could also push the rows into a [pscustomobject] and pipe that to Export-Csv (pscustomobject preserves the order in which you supply the properties):
$rawCSV = "C:\Files\raw.csv"
$outputCSV = "C:\Files\output.csv"
# Import and filter your raw data
$RawData = Import-Csv -Header #("a","b","c","d") -Path $rawCSV
$Data = $RawData | Select -Skip 7 | Where-Object { $_.b.length -gt 1 }
# Take the columns you're interested in, put them into new custom objects and export to CSV
$Data | ForEach-Object {
[pscustomobject]#{ "b" = $_.b; "a" = $_.a; "c" = $_.c; "d" = $_.d }
} | Export-Csv -NoTypeInformation $outputCSV
Export-Csv will take care of enclosing strings in quotes to escape ',' properly (one thing less for you to worry about)
First of all, what your raw CSV file looks like? If it's already like this
john,smith,29,England
mary,poppins,79,Walton
then import-csv will give you an array of objects which you can easily manipulate (and objects are the main reason to use PowerShell ;). For example, to check what you have after import:
$r = Import-Csv -Path $rawCSV -Header #("b","a","c","d")
$r.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
$r[0] | get-member
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
a NoteProperty System.String a=smith
b NoteProperty System.String b=john
c NoteProperty System.String c=29
d NoteProperty System.String d=England
For now you have array of objects with properties named "a","b","c","d". To manipulate objects you have select-object cmdlet:
$r | Select-Object a,b,c,d
a b c d
- - - -
smith john 29 England
poppins mary 79 Walton
And after all use export-csv to set the output file:
$r | where { $_.b.length -gt 1 } |
select a,b,c,d |
Export-Csv -NoTypeInformation -Encoding utf8 -path $outputCSV
I could think of two possible reasons why your data teated as one column:
consuming application expect different encoding and can't find
delimiters
delimiters are not commas but something else