looping through a csv - powershell

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.

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 - Trying to combine data from 2 CSV files into one based on column value

long time listener first time caller.
Normally I am pretty good at finding and digging and getting what I need and then modifying it to suit. This one seems to be a little trickier than what I have managed to pull off before. I am self taught in PowerShell mostly out of curiosity to see what I can do.
I am trying to create a report from data from 2 CSVs, and "most" of the data in the 2 CSVs are identical. There is simply 1 column of data in one of the CSVs that I want to add to the other one. I live regularly in the world of excel and I can do this with a formula in a matter of seconds [=VLOOKUP(H8,C:C,2,FALSE)] but accomplishing the same goal in PowerShell seems to be eluding me.
As I mentioned, I tend to try and find others who have done similar things and modify it. The best sounding one I found here ( Combine data from 2 CSV files into 1 new CSV using Powershell ) and I am still trying to play with the code on that site. Sometimes I find something and I try and stick with it too long where there might be another command that I am not familiar with that is better suited to what I should be looking at and might just need a pointer in that direction.
But here is a visual representation of what I am trying to do.
And every email address in File 2, is present in File 1.
Use Import-Csv to parse both CSV input files into arrays of [pscustomobject] instances for OOP processing.
For file 2, build a hashtable that maps the Email column values to their License values.
Then use a calculated property with Select-Object to append a property to the objects parsed from file 1, using the hashtable to map each Email property to the License value from file 2; if there is no hashtable entry for a given Email property value, $null is returned, which in the context of exporting to CSV (with Export-Csv) amounts to an empty field (column value).
# Import file 2 and create a hashtable that maps each Email
# column value to the License column value.
$ht = #{}
Import-Csv File2 | ForEach-Object { $ht[$_.Email] = $_.License }
# Import file 1 and append a License column that contains
# the license value from file 2 if the Email column value matches.
Import-Csv File1 |
Select-Object *, #{ Name='License'; Expression={ $ht[$_.Email] } }
# | Export-Csv ... # complete as needed

How can I prevent from forming multiple tables in a Powershell foreach?

I'm developing a script that connects to Azure AD and extracts failed login for any user so I'm probably going to get more than a row for user.
I have this code in a foreach (there is anything after part of code):
$ConvertedOutput | Select-Object #{Label="UserId"; Expression={$_.UserId}},
#{Label="CreationTime"; Expression={$_.CreationTime}},
#{Label="UserAgent"; Expression={$FinalOutput[0]."Value"}},
#{Label="Operation"; Expression={$_.Operation}},
#{Label="LogonError"; Expression={$_.LogonError}},
#{Label="ClientIP"; Expression={$_.ClientIP}} | Format-Table
How can I prevent from forming multiple tables? I only wanted the table for the first record, then additional records under the same table.
Thanks
here is the output
# Create an empty array to store your results in
[array]$results = #()
# This is your existing loop
foreach (...) {
...
$ConvertedOutput = <your existing code>
...
# Append your object to the results array
$results += $ConvertedOutput | Select-Object ... <your existing code>
}
# Now your results object contains all of the values from inside your loop
# So let's display that!
Write-Output $results
Welcome to stack overflow. I general, it is recommended to supply sample (fake) data in text format rather then pictures (of just headers), the makes life easier for us to answer your question.
Reading your code part, it doesn't add much value unless you planned to further extend it. All expressions generate the same keys and values as the original object, meaning that you can simplify this to just: Select-Object UserId, CreationTime, UserAgent, Operation, LogonError, LogonError, ClientIP or even: Select-Object * (or just omit the complete Select-Object), if you do not select a column subset.
With regards to your question,
By default PowerShell normally concatenates the output by it self, meaning that there is probably something else (that you are not sharing, e.g. a Write-Host command) that causes the data to be released preliminary from the pipeline.
Let me show this with fictive object lists created on the fly from three separate CSV lists:
$Result = &{
ConvertFrom-Csv #'
Id,FirstName,LastName
1,Nancy,Davolio
2,Andrew,Fuller
3,Janet,Leveling
'#
ConvertFrom-Csv #'
Id,FirstName,LastName
4,Margaret,Peacock
5,Steven,Buchanan
6,Michael,Suyama
'#
ConvertFrom-Csv #'
Id,FirstName,LastName
7,Robert,King
8,Laura,Callahan
9,Anne,Dodsworth
'#
}
With the above command, $Result contains the following data:
PS C:\> $Result
Id FirstName LastName
-- --------- --------
1 Nancy Davolio
2 Andrew Fuller
3 Janet Leveling
4 Margaret Peacock
5 Steven Buchanan
6 Michael Suyama
7 Robert King
8 Laura Callahan
9 Anne Dodsworth
One important thing to mention here, is that the columns of the three list should be have the same columns (or at least the first row should contain all expected columns), see: Not all properties displayed
If this doesn't help you further, I recommend you to add you more details to your question.

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

Comparing two text files and only keeping unique values

All,
I am VERY new to powershell and am attempting to write a script and have run into an issue.
I currently have two text files. For argument sake the first can be called required.txt and the second can be called exist.txt.
I have a script which queries a server and determines a list of all existing groups and writes these to a text file. At the same time the customer has a list of new groups they wish to create. I want to compare the new list (required.txt) with the existing list (exist.txt) and anything which doesn't exist be piped out to a new text file which is then picked up and imported using another process.
I've got the scripting done to gather the list from the server I just need to know how to do the comparison between the existing and required.
Any suggestions welcome.
Richard
you don't have to use as much variables :
$FinalGroups=Compare-Object (get-content .\required.txt) (get-content .\existing.txt) |
where {$_.SideIndicator -eq "<="} |
select -ExpandProperty inputObject |
sort