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

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

Related

Create Record using Headers from a .csv

<EDIT: I kind of have it working, but in order to get it to work, my template csv has to have a blank line for every line I am going to be adding to it. So, if I could figure out how to add lines to the imported empty (just a header row) csv file, I could then use export-csv at the end. (It would be somewhat slower, but it would at least work.)>
I am creating a .csv file in PowerShell. The output file has 140 columns. Many of them are null.
I started out just doing
$out = 'S-'+$Snum+',,,,,TRUE,,,,,'+'S-'+$Snum+',"'
$out = $out + '{0:d9}' -f $item.SupplierCode2
until I had filled all the columns with the correct value. But, the system that is reading the output keeps changing the column locations. So, I wanted to take the header row from the template for the system and use that to name the columns. Then, if the columns change location, it won't matter because I will be referring to it by name.
Because there are so many columns, I'm trying to avoid a solution that has me enter all the column names. By using a blank .csv with just the headers, I can just paste that into the csv whenever it changes and I won't have to change my code.
So, I started by reading my csv file in so I can use the headers.
$TempA = Import-Csv -Path $Pathta -Encoding Default
Then I was hoping I could do something like this:
$TempA.'Supplier Key' = "S-$Snum"
$TempA.'Auto Complete' = "TRUE"
$TempA.'Supplier ID' = "S-$Snum"
$tempA.'Supplier Data - Supplier Reference ID' = '{0:d9}' -f $item.SupplierCode2
I would only need to fill in the fields that have values, everything else would be null.
Then I was thinking I could write out this record to a file. My old write looked like this
$writer2.WriteLine($out)
I wanted to write the line from the new csv line instead
$writer2.WriteLine($TempA)
I'd rather use streams if I can because the files are large and using add-Content really slows things down.
I know I need to do something to add a line to $TempA and I would like each loop to start with a new line (with all nulls) because there are times when certain lines only have a small subset of the values populated.
Clearly, I'm not taking the correct approach here. I'd really appreciate any advice anyone can give me.
Thank you.
If you only want to fill in certain fields, and don't mind using Export-Csv you can use the -append and -force switches, and it will put the properties in the right places. For example, if you had the template CSV file with only the column names in it you could do:
$Output = ForEach($item in $allItems){
[PSCustomObject]#{
'Supplier Key' = "S-$Snum"
'Auto Complete' = "TRUE"
'Supplier ID' = "S-$Snum"
'Supplier Data - Supplier Reference ID' = '{0:d9}' -f $item.SupplierCode2
}
}
$Output | Export-Csv -Path $Pathta -Append -Force
That would create objects with only the four properties that you are interested in, and then output them to the CSV in the correct columns, adding commas as needed to create blank values for all other columns.

PowerShell (Get-ChildItem).Length bug

I'm learning to use Windows PowerShell and I noticed that (Get-ChildItem).Length returns file size when there is only one file in the directory. Do I have to write my own function to get the length or is there a simpler method?
That's not a bug. When there is more than one file, the command will return an array. With the property Length you will get in this case the size of the array.
Some example how to get the size:
Get-ChildItem | select -ExpandProperty Length
or
If you want to manipulate the values further, try maybe something like that
Get-ChildItem | foreach {$_.Length}

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

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

why export-csv returns a file that contains wierd data?

I have a binary cmdlet Get-CustomPSObject. When I do something like:
Get-CustomPSObject > a.txt
the result is stored as a plain text, meaning that the Get-CustomPSObject is working fine.
However when I try:
Get-CustomPSObject | Export-csv a.csv
The a.csv file becomes:
"Capacity","Count","IsReadOnly","IsFixedSize","SyncRoot","IsSynchronized"
"4","1","False","False","System.Object","False"
none of these fields are in my PSObject. I've no idea what they stands for. Any thoughts?
Export-CSV takes the first object it recieves to create the headers. Most likely, your Get-CustomPSOjbect runs a method/cmdlet/script that returns an object you didn't save. E.g. you use something like
get-childitem
and not
$files = get-childitem
inside your Get-CustomPSObject function.
EDIT
Okay, so you're cmdlet is a binary cmdlet. Important information. I'm no expert in this, so please correct me if I'm wrong.
When you make a binary cmdlet that can output multiple objects, you need to write them one by one. One of the ideas behind PowerShell is the use of a pipeline that can use objects as they come without waiting for the complete array.
Because of your current "design flaw" in your binary cmdlet, Export-CSV tries to export the array(as one item) to a csv-file and not the elements inside.
You now use this:
WriteObject(list/array of objects)
This is bad. It outputs all objects at the same time.
To fix it, run this at the end of your "object-creation-loop":
WriteObject(mycurrentobject)
This is good. You enable the use of pipeline and every object is sent out one by one when they're created. Export-CSV can then recieve each object and convert them to csv-format.
In your first example using > the output is run through Powershell formatting system while in the second using export-csv it is not.
If you look at get-custompsobject | gm you should see those extra properties that aren't shown in console or sent to your text file.
For export-csv you can control which properties are sent to the csv file using select-object
get-custompsobjct | select-object column1, column2 | export-csv a.csv

looping through a csv

just wondering if i could do this in powershell, or even a c#/vb.net command line program.
I have data that looks like this:
(source: kalleload.net)
I have a Teams Table. It looks like this:
| id | teamname | teamcity |
so for example, C2 has the value "Atlanta Braves". I need to split this up into "Atlanta" and "Braves". Data is consistent. for example "New York Mets" is actually "NewYork Mets".
So i need to go through column C and D and insert all the teams (no duplicates into the db).
One line of PowerShell will read in the CSV file and create a custom object for each home and away team listing (with a property for the city name and for the team name). The last command in the pipeline will eliminate the duplicates.
$TeamsAndCities = import-csv -path c:\mycsvfile.csv | foreach-object { $_.away, $_.home | select-object #{Name='City';Expression={$_.split(' ')[0]}}, #{Name='Team';Expression={$_.split(' ')[1]}} } | select-object -unique
You can do database access from PowerShell as well, but that might be suited to a new question with some more details about the database you are connecting to.
I rarely code in VBA/VB but...
Something like
Dim rngAwayTeam As Range, rngHomeTeam As Range
set rngAwayTeam = Worksheets("YourWorksheet").Range("C2")
set rngHomeTeam = Worksheets("YourWorksheet").Range("D2")
Dim rowOffset As Integer
rowOffset = 1
Do While (rngAwayTeam.Offset(rowOffset,1).Text <> "")
'Do something with rngAwayTeam.Offset(rowOffset,1).Text
'and rngHomeTeam.Offset(rowOffset,1).Text
rowOffset = rowOffset + 1
Loop
There are other ways I'm sure, but, here is what I would do.
Yes that is an excel macro. Again, I rarely use VBA or .Net, just trying to help you out the best I can. You could just use a C# COM object for the database side of things. (Still new, can't comment.)
You can do it in C# console application quite easily.
All you have to do is loop through each line in the file, adding it to an array using split on the comma (,).
Then you can use your array to display the values or retrieve a specific value on a row.