I have to admit, I’m kind of excited to be doing another Twitter Reply post. This one is the result of a post by Michael Bender. I’ve never met him, but I’ve follow his career a bit in the last few years, when I was introduced to his name via TechEd. He made a recent Tweet where he asked for a PowerShell genius to help build him a script. The goal was to randomly select a name from a CSV file, with an option to choose how many names it should randomly select.
Here’s the Tweet: https://twitter.com/MichaelBender/status/593168496571322370
I wouldn’t consider myself a genius, but if you consider what he’s after — a name from a CSV file (not a line from a text file) — then there’s a better option then the one he accepted: “get-content file.csv | get-random.” This will work, but there’s some reasons why this isn’t such a great idea. We can use the Get-Content cmdlet with CSV files, but we generally don’t. CSV files are created and formatted in such a way, that using Get-Content, instead of Import-Csv, isn’t the best way to do things.
Let’s consider that we’re using the CSV file in the image below. It has three headers, or column names: Name, Age, and HairColor.
First of all, if we use Get-Content, it’s going to consider the first line — the header line, or the column headings — a selectable line within the file. Here’s that example:
PS C:\> Get-Content .\file.csv | Get-Random Name,Age,HairColor
Uh, not helpful. While this isn’t the end of the world, as we can simply rerun the command (and probably get something different), we’d be better off to write this so that this error is not a possibility — something we’ll see in a moment, when we use Import-Csv.
Second of all, unless the only column in the CSV file is Name, then we’re not returning just a name, but instead, everything in a row of the file. This means that if I randomly choose a line in the file, that it will include information that Michael didn’t request — the age and hair color.
PS C:\> Get-Content .\file.csv | Get-Random Jeff,19,Brown
I suppose we could start parsing our returned value to just return the name ((Get-Content .\file.csv | Get-Random).Split(‘,’)), but seriously, let’s skip that and use one of the cmdlets that was built to work with CSVs directly. We’ll assume we’re still using the same CSV file in the image above.
PS C:\> Import-Csv .\file.csv | Get-Random | Select-Object Name Name ---- Lance
Um, that was easy. If we wanted to increase the number of names returned from our CSV file, then we would use Get-Random’s -Count parameter and an integer value, such as in this example:
PS C:\> Import-Csv .\file.csv | Get-Random -Count 3 | Select-Object Name Name ---- Bob Stephen Sue
I think we’re best off when we use the *-Csv cmdlets with CSV files, and the Get-Content cmdlet with most other file types we can read in PowerShell. There is at least one exception of doing this in reverse: Using Import-Csv with a text file, that has a delimiter, might help you better parse the information in your file. Consider this text file:
The next few examples will progressively show you how to use Import-Csv with a delimited text file until all of the “columns” are broken apart. When we’re finished, we can even export our data into a properly formatted CSV file, and then import it, piping those results to other cmdlets — take a look.
PS C:\> Import-Csv .\file.txt 001|Sunday|Car7 --------------- 002|Monday|Car2 003|Tuesday|Car3 004|Wednesday|Car3 005|Thursday|Car7 006|Friday|Car2 007|Saturday|Car3 PS C:\> Import-Csv .\file.txt -Header Id,Day,Car Id Day Car -- --- --- 001|Sunday|Car7 002|Monday|Car2 003|Tuesday|Car3 004|Wednesday|Car3 005|Thursday|Car7 006|Friday|Car2 007|Saturday|Car3 PS C:\> Import-Csv .\file.txt -Header Id,Day,Car -Delimiter '|' Id Day Car -- --- --- 001 Sunday Car7 002 Monday Car2 003 Tuesday Car3 004 Wednesday Car3 005 Thursday Car7 006 Friday Car2 007 Saturday Car3 PS C:\> Import-Csv .\file.txt -Header Id,Day,Car -Delimiter '|' | Export-Csv -Path C:\file-cars.csv -NoTypeInformation PS C:\> Import-Csv .\file-cars.csv Id Day Car -- --- --- 001 Sunday Car7 002 Monday Car2 003 Tuesday Car3 004 Wednesday Car3 005 Thursday Car7 006 Friday Car2 007 Saturday Car3 PS C:\> Import-Csv .\file-cars.csv | Where-Object Car -eq 'Car3' Id Day Car -- --- --- 003 Tuesday Car3 004 Wednesday Car3 007 Saturday Car3 PS C:\> Import-Csv .\file-cars.csv | Where-Object Car -eq 'Car3' | Select-Object Day Day --- Tuesday Wednesday Saturday
So, if I had seen the Tweet first, I would have to recommend Import-Csv, piped to Get-Random, and then piped to Select-Object Name. Thanks for reading the post.