how to merge header and sub header in csv in powershell? - powershell

Assume I have a sample.csv file with 2 rows with multiple columns as
Account, Id, Date
Jan, Dec, Feb
now, I want to convert this file which consists single row, and change it in column order as output.csv in PowerShell scripting
Account,Id,Date,Jan,Feb,Dec
I tried many ways..
Import-Csv 'sample.csv' | Group-Object ID | ForEach-Object { [PsCustomObject]#{ Header = $_.Group.Dept -join ',' } } | Export-Csv 'output.csv' -NoTypeInformation

Without going into detail on the issues you may encounter, here is what you can try:
#"
Account, Id, Date
Jan, Dec, Feb
one, two, three
"# | ConvertFrom-Csv -PipelineVariable "Header" | Select-Object -First 1 |
ForEach-Object -Process {
($_.PSObject.Properties.Value, $Header[0].PSObject.Properties.Name | Write-Output) -join ","
}
Tapping into the PSObject wrapper exposes additional properties not shown when piped to Get-Member. The main one we are after is the Column Names (.Name), and the first rows values (.Value). Select-Object -First 1, is to ensure only the first row is selected and not any other rows you may have. So, we join both property values and all that's left to do is export to a new csv.

Related

Sort CSV powershell script delete duplicate, keep the one with a special value in 3rd column

How do I delete double entriys in a csv by one column and leave the one with one special value in one of the columns?
Example: I got a csv with
Name;Employeenumber;Accessrights
Max;123456;ReadOnly
Berta;133556;Write
Jhonny;161771;ReadOnly
Max;123456;Write
I want to end up with:
Name;Employeenumber;Accessrights
Max;123456;Write
Berta;133556;Write
Jhonny;161771;ReadOnly
I tried by Get-Content Select-Object -unique, but that does not solve the problem that it should only keep the ones with the value "write" at the property Accessrights.
So I have no clue at all
You can use a combination of sorting and grouping ....
#'
Name;Employeenumber;Accessrights
Max;123456;ReadOnly
Berta;133556;Write
Jhonny;161771;ReadOnly
Max;123456;Write
'# |
ConvertFrom-Csv -Delimiter ';' |
Sort-Object -Property Name, Accessrights -Descending |
Group-Object -Property Name |
ForEach-Object {
$_.Group[0]
}

Selecting columns from flat file in power shell with no column name

I am new to power shell ,and I have the below format (pipe delimiter) with no column name:
01|1|06/28/2017 00:00:00|06/28/2017 00:00:00
I want to choose the third or any column from this format,I have tried the below code :
$columns=(Get-Content $filepath | Out-String | select -Skip 2 -First 1).Split("|")
but it is not working can any one help please.
Use Import-CSV with -Header and -Delimiter specified; that way, you get a structure (PSCustomObject[]) with attributes that you can reference directly and meaningfully. For example,
$EntryList = Import-CSV -Path $FilePath -Header ID,Type,StartTime,EndTime -Delimiter '|'
gets you an array of PSCustomObjects, where each object has the indicated fields. You can then (for example) refer to $EntryList[$n].ID, $EntryList[$n].StartTime, and so on.

Change value in column using powershell

I have a csv file with five columns. The last column being the students grade level. What I want to do is change the value of that column based on the gradelevel. For example if the gradelevel is 12 I want to change that to 2016, 11 to 2017, so on and so forth.
update: I did get it to semi work using the below:
Get-Content users.csv | ForEach-Object -Process {$_ -replace '12','2016'} | Set-Content users1.csv
What happens is if the student id has a 12 in it that gets changed as well to 2016. Example would be 120045 gets change to 20160045
You can import the csv, loop it in a foreach and use the $_ (this) operator and then export ist to csv
Somesthing like:
# import CSV
$list = import-csv P:\ath\to\file.csv -Delimiter ";" -Encoding Standard
# % means foreach
$list | % {
# The grades is the key for each line
# the first line of your csv represent the keys you can use
# e.g. first colum: Name | Grade | Class
# $_.Name | $_.Grade | $_.Class are your keys for every entry (2nd line and above)
# here you can work with your grades an do what you want
if($_.Grade -eq 11){
# set a new value to the grade in the actual line
$_.Grade = 2016
}
}
# now export the new list into csv
export-csv P:\ath\to\new.csv -Delimiter ";" -NoTypeInformation
That should be a basic to work with.
Greetz Eldo.O
Eldo you code worked great. I did have to change the last line from:
export-csv P:\ath\to\new.csv -Delimiter ";" -NoTypeInformation
to
$list | Export-Csv P:\ath\to\new.csv -Delimiter "," -NoTypeInformation
I was also able to add more if statements to accomplish exactly what I needed.

How to detect and remove CSV columns based on common text in header names?

I am working on a CSV File which I recently created. The CSV file contains columns with headers and corresponding rows.
I need to remove entire columns (including its data) that have specific text common to their headers. For e.g column 1 has header named intID, column 2 has header named boolID, column 3 has header named charID and so on ('ID' being the common text). There are some columns that don't have 'ID' as text in their headers, so we need to retain those.
The csv file is getting generated dynamically, so there may be more/less columns based on what data we select for the csv. But we need these columns with their headers having some common text to be removed.
How can we achieve this?
Would something like that do the trick?
$yourfile = "<path to your csv>"
# Import the CSV
$csv = Import-Csv -Path $yourfile
# Find all columns that do not end with "ID"
$colsToKeep = $csv | Get-Member -MemberType NoteProperty |?{$_.name -notmatch "^.+ID$"} | Select-Object -ExpandProperty name
# Filter out all unwanted columns
$newCsv = $csv | Select-Object -Property $colsToKeep
# Export CSV to new file
$newCsv | Export-Csv -Path "<path to new csv>"
Assuming the following:
the ID part is not a plain text "ID" but a dynamic arbitrary text
headers of interest start with int, char, bool
Let's count occurrences of ID part and build a list of headers used just once, then export the CSV.
$csv = Import-Csv 1.csv
$prefix = '^(int|char|bool)' # or '^([a-z])' for any lowercase text
$headers = $csv[0].PSObject.Properties.Name
$uniqueIDs = $headers -creplace $prefix, '' | group | ? Count -eq 1 | select -expand Name
$uniqueHeaders = $headers | ?{ $_ -creplace $prefix, '' -in $uniqueIDs }
$csv | select $uniqueHeaders | Export-Csv 2.csv -NoTypeInformation
Note: in the old PowerShell 2.0 instead of ? Count -eq 1 use ?{ $_.Count -eq 1 }

Use Import-Csv to read changable column Titles by location

I'm trying to see if there is a way to read the column values in a csv file based on the column location. The reason for this is the file I'm being handed always has it's titles being changed...
For example, lets say csv file column A (via excel) looks like the following:
ColumnOne
ValueOne
ValueTwo
ValueThree
Now the user changes the title:
Column 1
ValueOne
ValueTwo
ValueThree
Now I want to create an array of the first column. Normally what I do is the following:
$arrayFirstColumn = Import-Csv 'C:\test\test1.csv' | where-object {$_.ColumnOne} | select-object -expand 'ColumnOne'
However, as we can see if ColumnOne is changed to Column 1, it breaks this code. How can I create this array to allow an interchangeable column title, but the column location will always be the same?
You can specify headers of your own on import:
Import-Csv 'C:\path\to\your.csv' -Header 'MyHeaderA','MyHeaderB',...
As long as you don't export the data back to a CSV (or don't require the original headers to be in the output CSV as well) you can use whatever names you like. You can also specify as many header names as you like. If their number is less than the number of the columns in the CSV the additional columns will be omitted, if it's greater then the columns for the additional headers will be empty.
If you need to preserve the original headers you could get the header name(s) you need to work with in variable(s) like this:
$csv = Import-Csv 'C:\test\test1.csv'
$firstCol = $csv | Select-Object -First 1 | ForEach-Object {
$_.PSObject.Properties | Select-Object -First 1 -Expand Name
}
$arrayFirstColumn = $csv | Where-Object {$_.$firstCol} |
Select-Object -Expand $firstCol
Or you could simply read the first line from the CSV and split it to get an array with the headers:
$headers = (Get-Content 'C:\test\test1.csv' -TotalCount 1) -split ','
$firstCol = $headers[0]
One option:
$ImportFile = 'C:\test\test1.csv'
$FirstColumn = ((Get-Content $ImportFile -TotalCount 2 | ConvertFrom-Csv).psobject.properties.name)[0]
$FirstColumn
$arrayFirstColumn = Import-Csv $ImportFile | where-object {$_.$FirstColumn} | select-object -expand $FirstColumn
If you are using PowerShell v2.0 then the expression for $FirstColumn in $mjolinor's answer would be:
$FirstColumn = ((Get-Content $ImportFile -TotalCount 2 | ConvertFrom-Csv).psobject.properties | ForEach-Object {$_.name})[0]
(Apologies for starting a new answer; I do not yet have enough reputation to add a comment to mjolinor's post)