How to import CSV column? Import-Csv not working as planned - powershell

I have a drop down list that's being populated by a CSV file. There are many columns in the CSV, but it only pulls from the Name column. Here's what I have that works just fine in most Win 7, and all Win 8+ PC's I've tried it on.
$customers = Import-CSV "$dir\Apps\customers.csv"
$List = $customers.name | Sort-Object
After that there's a ForEach loop to put each item from the list into the menu.
Lately I've been noticing an issue on a couple Win 7 PC's that I can't figure out. The import option doesn't work unless I specify all the headers with the -Header option. I get this error:
After getting it to import correctly by adding all the headers I can't get it to save $customers.name into the $List variable, with or without the sorting. However, if I provide an index number (ex $customers[2].name) it works.
To work around this I've looked at ways to measure the number of rows in the CSV by using the following options after $customers:
$csvlength = Get-Content "$dir\Apps\customers.csv" | Measure-Object - lines
or
$csvlength = Import-CSV "$dir\Apps\customers.csv" | Measure-Object
From there I can see the length by looking at $csvlength.lines or $csvlength.count.
Is there a way to use that information to save the list of names into $List? I've tried something like this with no success:
$List = $customers[0-$csvlength.count] | Sort-Object
Also, I've noticed that when importing the headers it includes Name in the list. If at all possible I'd like to not include the header. I also have a line at the end of the CSV that has other info in it, but no name. That shows up as a blank line. If possible I'd like that to be removed as well.

PowerShell v2 $array.Foo only allows access to a property Foo of the array object itself, not to a property Foo of the array elements. Allowing access to element properties via the array variable is one of the major changes that was introduced with PowerShell v3.
To work around this limitiation in v2 you need to expand the property before sorting:
$List = $customers | Select-Object -Expand name | Sort-Object

Related

Reading Multiple Entry from CSV using PowerShell

I have a CSV file that contains multiple vendors (Cisco, Redhat, vmware..etc), I need a PowerShell script to read this column (vendor) and add separate column "Multiple1 or Multiple2" (Remark) if the CSV contains multiple entries of same vendors.
I have attached screen shot of the sample file.
I tried from end to get this done, but it didn't work.
Okay, after Spikeys last comment I had a go at guessing what he might want to achieve.
I created a CSV file:
Product,Template
Microsoft Windows,
RedHat Enterprise,
Apple Safari,
Microsoft Windows,
RedHat Enterprise,
RedHat Enterprise,
and then wrote the following script. It's commented and produces the following output:
Product Template
------- --------
Microsoft Windows Multiple2
RedHat Enterprise Multiple3
Apple Safari Multiple1
Microsoft Windows Multiple2
RedHat Enterprise Multiple3
RedHat Enterprise Multiple3
Code:
$Csv = Import-Csv -Path "C:\Book1.csv"
#Hastables have key - value pairs. Example "Microsoft Windows" = 1. Here 'Microsoft Windows' is the key and '1' is the value
[hashtable]$ProductCount = #{}
#Go through each line in the CSV. This returns the product name e.g. Microsoft Windows
ForEach ($Product in $Csv.Product)
{
#If there us no key for the current product in hashtable $Productcount, then add it with value 1
If ($ProductCount.Keys -notcontains $Product)
{
$ProductCount.Add($Product, 1)
}
#If the above does not apply, then increase the value (effectively the count) by 1
Else
{
$ProductCount[$Product] = $ProductCount[$Product] + 1
}
}
#Go through each row in the CSV file. Each row is returned as it's own object with a 'Product' and 'Template' property
ForEach ($Row in $Csv)
{
#Extract the count for the current product from hastable $ProductCount
$Count = $ProductCount[$Row.Product]
#Set the 'Template' property for the current row object to multipile + the count we got earlier
$Row.Template = "Multiple$Count"
}
#Save the changes to the CSV file as a new CSV. You can also overwrite your old one if you like
$Csv | Export-Csv -Path "C:\Book2.csv"
I don't quite understand your question, but here are some techniques I find useful when working with CSV files.
Example CSV:
Name,City
Bob,BlackPool
Alice,Dover
Carl,Manchester
Presume you assign the CSV file to a variable like so
$CSV = Import-CSV -Path "C:\Stuff.csv"
1. You can access all rows in a column by typing the variable dot(.) column header, so
$CSV.Name
returns:
Bob
Alice
Carl
2. To access a row in a CSV file you need to use indexing, so
$CSV[1]
returns:
Name City
---- ----
Alice Dover
3. An easy way to replace a property of a specific row is to filter it using Where-Object. Say I want to change Carl's city to London.
$($CSV | Where-Object {$_.Name -like "Carl"}).City = "London"
Here is what happens:
What's in the parentheses is processed first, so we are selecting a row where the Name property is like "Carl" (You can use wilcard here, so "Ca*" would have worked too). Then, outside of the parentheses, we are setting the city property to "London".
Note: $_ represents the data currently in a pipeline, in this case that's the row containing Carl.
There is more stuff to know, but this might help you the most.
Don't forget to save your changes by using the Export-CSV cmdlet!
$CSV | Export-CSV -Path "C:\new.csv" -NoTypeInformation

Powershell - Querying CSV column names and writing them to a new CSV

So I'm trying to look at column names in a CSV, write them to an array and then spit the data back out into a new CSV with a new column attached. I don't really care what the current data table looks like so long as I can add a column to the headers. This seems like a fairly basic thing to be able to do but I can't seem to find any situations where anyone has done this. For example:
"Name","Location","Phone"
"John Smith","Toronto","555.555.5555"
"Jane Doe","Dallas","555.555.5554"
I just want to keep the Name, Location and Phone column names and put them into another CSV with one extra column. The catch is, in reality, there are more columns and they aren't always the same so the script needs to be able to be column name-agnostic. I should be able to feed it any CSV with any number of columns with different names and be able to get an output file with just the column names. I've tried at least a dozen different ways to do this and keep bumping into different issues.
Example:
$validatedfilepath = "validfile.csv"
$csvData = New-Object PSObject
$csvData = Import-CSV "file.csv" | Add-Member #{ID="$null"} -PassThru
$csvdata = $csvdata | get-member -Name * -MemberType NoteProperty
$csvData = #($csvData.Name)
$csvData
That will show me the exact list of column names that I want in my new validfile but I have no idea how to export it into a CSV as the column names. Each time I've tried doing export-csv, it either gives me the character length count in a new row for each or some other goofy stuff.
Thanks
The Export-CSV reads the column names from the members of the input object. So you are on the right track already, you just need to simplify a bit, like this:
$csvData = Import-CSV "file.csv" | Add-Member #{ID="$null"} -PassThru
# You can now modify/enrich/filter the data somehow, for example like $csvdata[0].ID = 56387, then just export it:
$csvData | Export-CSV -NoTypeInformation -Path "newfile.csv"
The error you made is overwriting the imported data in $csvdata with the Get-Member result. And then you overwrite it again with the #($csvData.Name) expression.

Filtering specific value from csv file using PowerShell

I am having problem with filtering a specific value from my csv file. The csv file looks as follows:
"1","19/Oct/2016","15:03:58","19/Oct/2014","15:03:58","0:00:00","---","---","nice_meme#help.com","---","sip","1232Kbps","---","Out","1140","1","---","---","---","user:---","---","---","---","---","---","---","---","Failed Attempt; ""Your call could not be completedOver.""","3","---","---","---","---","---","---","---","---","---","---","---","---","---"
As you can see there are multiple values with '---', I tried a lot of ways to remove these three dashes. I do not know how to filter them out using PowerShell. I want to get the rows that are not equal to the three dashes.
Something like this:
$a = Import-CSV -Path "C:\Transformed\test.csv" | Where-Object {$_.Header -neq "---"}

PowerShell to extract specific column from csv and store in a variable

My keys.csv file looks like this
PrjKey BldKey key
LS LOOKUPSNAP1 LS-LOOKUPSNAP1
LS LSUH3 LS-LSUH3
LSPERF LPMDS0 LSPERF-LPMDS0
LSPERF LSP0 LSPERF-LSP0
I want to extract the values column "key" and store in a variable. I tried this
Import-Csv .\keys.csv | select key | ft -hide
the output has a blank line at the top. How can I eliminate it. I only want those 4 values to be "stored in a variable" Yes I don't want to save the output as a csv again.
Can someone help please?
You had the right idea of using Select-Object to get the one property you want. The two issues you had was that Select-Object key returns and object array with a key property when it looks like you just want string array of keys. Also never use Format-cmdlets when you want to save the data or use it in another form. They destroy objects for the purpose of display data on the screen. So that all being said..
$keys = Import-Csv .\keys.csv | select -ExpandProperty key
Depending on your PowerShell version
$keys = (Import-Csv .\keys.csv).key

Reformat column names in a csv with PowerShell

Question
How do I reformat an unknown CSV column name according to a formula or subroutine (e.g. rename column " Arbitrary Column Name " to "Arbitrary Column Name" by running a trim or regex or something) while maintaining data?
Goal
I'm trying to more or less sanitize columns (the names) in a hand-produced (or at least hand-edited) csv file that needs to be processed by an existing PowerShell script. In this specific case, the columns have spaces that would be removed by a call to [String]::Trim(), or which could be ignored with an appropriate regex, but I can't figure a way to call or use those techniques when importing or processing a CSV.
Short Background
Most files and columns have historically been entered into the CSV properly, but recently a few columns were being dropped during processing; I determined it was because the files contained a space (e.g., Select-Object was being told to get "RFC", but Import-CSV retrieved "RFC ", so no matchy-matchy). Telling the customer to enter it correctly by hand (though preferred and much simpler) is not an option in this case.
Options considered
I could manually process the text of the file, but that is a messy and error prone way to re-invent the wheel. I wonder if there's a syntax with Select-Object that would allow a softer match for column names, but I can't find that info.
The closest I have come conceptually is using a calculated property in the call to Select-Object to rename the column, but I can only find ways to rename a known column to another known column. So, this would require enumerating the columns and matching them exactly (preferred) or a softer match (like comparing after trimming or matching via regex as a fallback) with expected column names, then creating a collection of name mappings to use in constructing calculated properties from that information to select into a new object.
That seems like it would work, but more it's work than I'd prefer, and I can't help but hope that there's a simpler way I haven't been able to find via Google. Maybe I should try Bing?
Sample File
Let's say you have a file.csv like this:
" RFC "
"1"
"2"
"3"
Code
Now try to run the following:
$CSV = Get-Content file.csv -First 2 | ConvertFrom-Csv
$FixedHeaders = $CSV.PSObject.Properties.Name.Trim(' ')
Import-Csv file.csv -Header $FixedHeaders |
Select-Object -Skip 1 -Property RFC
Output
You will get this output:
RFC
---
1
2
3
Explanation
First we use Get-Content with parameter -First 2 to get the first two lines. Piping to ConvertFrom-Csv will allow us to access the headers with PSObject.Properties.Name. Use Import-Csv with the -Header parameter to use the trimmed headers. Pipe to Select-Object and use -Skip 1 to skip the original headers.
I'm not sure about comparisons in terms of efficiency, but I think this is a little more hardened, and imports the CSV only once. You might be able to use #lahell's approach and Get-Content -raw, but this was done and it works, so I'm gonna leave it to the community to determine which is better...
#import the CSV
$rawCSV = Import-Csv $Path
#get actual header names and map to their reformatted versions
$CSVColumns = #{}
$rawCSV |
Get-Member |
Where-Object {$_.MemberType -eq "NoteProperty"} |
Select-Object -ExpandProperty Name |
Foreach-Object {
#add a mapping to the original from a trimmed and whitespace-reduced version of the original
$CSVColumns.Add(($_.Trim() -replace '(\s)\s+', '$1'), "$_")
}
#Create the array of names and calculated properties to pass to Select-Object
$SelectColumns = #()
$CSVColumns.GetEnumerator() |
Foreach-Object {
$SelectColumns += {
if ($CSVColumns.values -contains $_.key) {$_.key}
else { #{Name = $_.key; Expression = $CSVColumns[$_.key]} }
}
}
$FormattedCSV = $rawCSV |
Select-Object $SelectColumns
This was hand-copied to a computer where I don't have the rights to run it, so there might be an error - I tried to copy it correctly
You can use gocsv https://github.com/DataFoxCo/gocsv to see the headers of the csv, you can then rename the headers, behead the file, swap columns, join, merge, any number of transformations you want