Tag Archives: Get-Random

Randomly Selecting a Name from a CSV File

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.

Randomly Selecting Name from a CSV File01

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(‘,’)[0]), 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:

Randomly Selecting Name from a CSV File02

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.

Implicit Remoting and the Exchange Cmdlets

I work in an environment where we administer Microsoft Exchange 2010 and I’m proud to say that I don’t have the Exchange Management Tools installed on my laptop. Now, that doesn’t mean I don’t sometimes RDP into an Exchange box, but it does force me to forgo that and use Windows PowerShell when I want to do something quicker than to RDP, log on, and open the EMC. One of the first things I added to my $PROFILE, after writing it for use in a script, was a function that would establish a PSSession to one of the Exchange servers. This allows me to run Exchange-specific cmdlets without leaving my laptop and without having the Exchange Management Tools installed.

The first thing I started with was an empty function that I called New-ExchangeSession.

Function New-ExchangeSession {

}

I had a few requirements for this project. One, I didn’t want to rely on connecting to the same Exchange server each time I created a PSSession. If for some reason it wasn’t available, I would have a problem connecting… in addition to a non-responsive Exchange server. Two, I didn’t want to hard code my Exchange server list in either my script (bad!) or in an external file (not as bad, but not great). What I did was make use of the Get-ADGroupMember and the Get-Random cmdlets to return the names of the Exchange Servers from an Active Directory group in which they were all members, and then randomly select one.

I did this as part of Do-Until loop. In line 3, the first thing it does is acquire the members of the group, ExchangeServers, using the Get-ADGroupMember cmdlet included in the Active Directory module. If you’re running PowerShell 3.0 or greater it will load this module automatically. If you’re not, then you’ll have to add it yourself using the Import-Module cmdlet before beginning the Do-Until loop.

Using dotted notation (.Name) we return only the Name property of the group members. Once collected, the Get-Random cmdlet is used to randomly select one of the names and then assign it to the $ExchServ variable.

Function New-ExchangeSession {
    Do {
        $ExchServ = Get-Random (Get-ADGroupMember -Identity 'ExchangeServers').Name
    }
    Until (Test-Connection -ComputerName $ExchServ -Count 1 -Quiet)
}

If you’re using something older than 3.0, and you really shouldn’t be, you’ll find the dotted notation version just doesn’t work as expected. In that case, you will have to handle this in a more procedural way as seen in the example below. Regardless of which way you get a server name and assign it to the $ExchServ variable, it must reply to a ping, by use of the Test-Connection cmdlet in line 5 above, and line 7 below. This is the conditional check of Do-Until loop. If Test-Connection returns True, it will break out of the Do-Until. If it returns False, it will randomly select another server and try again.

Function New-ExchangeSession {
    Do {
        $ExchServ = Get-ADGroupMember -Identity 'ExchangeServers'
        $ExchServ = Get-Random $ExchServ
        $ExchServ = $ExchServ.Name
    }
    Until (Test-Connection -ComputerName $ExchServ -Count 1 -Quiet)
}

We start to create the PSSession once we have an Exchange server name chosen and verified it is reachable across the network. This is done by creating a variable, $Session on line 7 below, that will store the session information. We then use that session information as part of our Import-PSSession cmdlet that brings the Exchange cmdlets down to our local computer. The final, informational message on line 9 simply indicates the Exchange server in which we’ve connected.

Function New-ExchangeSession {
    Do {
        $ExchServ = Get-Random (Get-ADGroupMember -Identity 'ExchangeServers').Name
    }
    Until (Test-Connection -ComputerName $ExchServ -Count 1 -Quiet)

    $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$ExchServ.mydomain.com/powershell" -Authentication Kerberos
    Import-PSSession -Session $Session -CommandName * -FormatTypeName * | Out-Null
    Write-Output "Connected to $ExchServ"
}

You will often, if not always, receive a warning about some of the imported commands may have unapproved verbs. To view your active session, use the Get-PSSession cmdlet, and to close the session, use the Remove-PSSession -Id  #, where # equals the Id number returned from the Get-PSSession cmdlet.