{"id":12761,"date":"2011-09-08T00:01:00","date_gmt":"2011-09-08T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2011\/09\/08\/use-powershell-to-pick-random-winning-users-from-text\/"},"modified":"2011-09-08T00:01:00","modified_gmt":"2011-09-08T00:01:00","slug":"use-powershell-to-pick-random-winning-users-from-text","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-pick-random-winning-users-from-text\/","title":{"rendered":"Use PowerShell to Pick Random Winning Users from Text"},"content":{"rendered":"<p><strong>Summary<\/strong>: Learn how to use Windows PowerShell to select random winners from a text file.<\/p>\n<p class=\"CodeBlock\">&nbsp;<\/p>\n<p><img decoding=\"async\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\" \/>Hey, Scripting Guy! I have a question. It is neither a vital server performance issue nor is it a dramatic process optimization revelation, but it is something that will make my life a lot easier. First the background: I have been going to our local IT user group for a while, and one of the members wrote a command-line application that would accept a text file that contained our attendees for the night. Well, that member recently moved to another city, and now we are in desperate need of something that will do a random drawing for us for our prize giveaways that we have at each meeting. I guess I could send email to the departing member and ask for the command-line application, but I have been preaching Windows PowerShell for so long that I sort of feel like I should create the solution in Windows PowerShell. But I need a bit of help doing that. Do you have any ideas for doing a random sort on a text file?<\/p>\n<p>&mdash;CS<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\" \/>Hello CS,<\/p>\n<p>Microsoft Scripting Guy Ed Wilson here. Good afternoon, CS. During the 2011 Scripting Games, I wrote a script to perform a random sort of people who had submitted scripts during the event. I was doing daily drawings, and I also needed to exclude people who had previously won a prize, so my script is a bit overkill for what you need to do.<\/p>\n<p>I was talking to someone the other day about this very thing. What my friend had done was rather clever. He said that he created a hash table with the key as the data to sort, and the value as a random number produced via the <b>Get-Random<\/b> cmdlet. He then used the <b>getenumerator<\/b><i> <\/i>method from the hash table and piped it to the <b>Sort-Object<\/b> cmdlet to sort the hash table based on the random numbers. This has the effect of randomizing the list of user group names. I thought it was a clever approach to the problem, so I wrote the RandomSortUsersViaHashTable.ps1 script. The complete text of the script is shown here:<\/p>\n<p style=\"padding-left: 30px\">$users = Get-Content C:\\fso\\UserGroupNames.txt<\/p>\n<p style=\"padding-left: 30px\">$hash = @{}<\/p>\n<p style=\"padding-left: 30px\">foreach ($u in $users)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;{<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $hash.add($u,(Get-Random -Maximum $users.count))<\/p>\n<p style=\"padding-left: 30px\">&nbsp;} #end foreach<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">$hash.GetEnumerator() | Sort-Object -Property value |<\/p>\n<p style=\"padding-left: 30px\">Select-Object -First 5<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p>The first thing I do is use the <b>Get-Content<\/b> cmdlet to read the contents of the user group list into an array of user names. Next, I create an empty hash table, and store it in the <b>$hash<\/b> variable. I then use the <b>foreach<\/b><i> <\/i>statement to walk the array of user names. This portion of the script is shown here:<\/p>\n<p style=\"padding-left: 30px\">$users = Get-Content C:\\fso\\UserGroupNames.txt<\/p>\n<p style=\"padding-left: 30px\">$hash = @{}<\/p>\n<p style=\"padding-left: 30px\">foreach ($u in $users)<\/p>\n<p>Inside the <b>ScriptBlock<\/b> for the <b>foreach<\/b> statement, I use the <b>add<\/b><i> <\/i>method to add the user name and a random number to the hash table. One thing to note: I limit the random number to the maximum number of users that are listed in the UsergroupNames.txt file. There is no real need to do this because I am later going to use the <b>Select-Object<\/b> cmdlet to choose the first five users anyway. Here is the line of code that adds the user names and the random number to the hash table:<\/p>\n<p style=\"padding-left: 30px\">$hash.add($u,(Get-Random -Maximum $users.count))<\/p>\n<p>I then use the <b>getenumerator<\/b><i> <\/i>method from the <b>hashtable<\/b> object, and pipe the <b>hashtable<\/b> to the <b>Sort-Object<\/b> cmdlet where I sort the <b>hashtable<\/b> based on the value of the random number. Finally, I choose five people from the <b>hashtable<\/b>. This portion of the script is shown here:<\/p>\n<p style=\"padding-left: 30px\">$hash.GetEnumerator() | Sort-Object -Property value |<\/p>\n<p style=\"padding-left: 30px\">Select-Object -First 5<\/p>\n<p>When the script runs, the output shown in the following figure is displayed.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3240.hsg-9-8-11-1.jpg\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of output displayed when script is run\" alt=\"Image of output displayed when script is run\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3240.hsg-9-8-11-1.jpg\" \/><\/a><\/p>\n<p>While the approach is valid and makes for a relatively cool script, there is a simpler way to accomplish the task of grabbing user names in a random fashion from a text file. In fact, the nine-line script boils down to a single line. In the following command, I use the <b>Get-Content<\/b> cmdlet (<b>gc<\/b> is an alias) to read the contents of the UserGroupNames.txt file. I pipe the results to the <b>Sort-Object<\/b> cmdlet and use a script block to choose a random name from the text file stream. I then select the first five users.<\/p>\n<p style=\"padding-left: 30px\">gc C:\\fso\\UserGroupNames.txt | sort{get-random} | select -First 5<\/p>\n<p>The command when run three times and the associated output are shown here.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7242.hsg-9-8-11-2.jpg\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of command run three times and associated output\" alt=\"Image of command run three times and associated output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7242.hsg-9-8-11-2.jpg\" \/><\/a><\/p>\n<p>Perhaps, the easiest way to do this is to use the <b>Get-Content<\/b> cmdlet to read the contents of the text file, and bypass the <b>Sort-Object<\/b> cmdet completely. I can tell the <b>Get-Random<\/b> cmdlet to return only five user names from the text file, so I do not really need to sort the list first. This command is shown here (<b>gc<\/b> is an alias for the <b>Get-Content<\/b> cmdlet):<\/p>\n<p style=\"padding-left: 30px\">gc C:\\fso\\UserGroupNames.txt | Get-Random -Count 5<\/p>\n<p>I run the command a few times to check to see if it is returning different names. As shown in the following figure, it works.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0410.hsg-9-8-11-3.jpg\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image showing command works\" alt=\"Image showing command works\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0410.hsg-9-8-11-3.jpg\" \/><\/a><\/p>\n<p>If I do not need to select only a certain number of users, I can use the <b>Get-Random<\/b> cmdlet to randomize the entire list by using the <b>count<\/b><i> <\/i>property of the array to read the contents of the text file into a variable. Here is one way to accomplish this task:<\/p>\n<p style=\"padding-left: 30px\">$users = gc C:\\fso\\UserGroupNames.txt<\/p>\n<p style=\"padding-left: 30px\">Get-Random -InputObject $users -Count $users.Count<\/p>\n<p>In the following figure, I read the contents of the text file into the <b>$users<\/b> variable, and then I supply it as an <b>inputobject<\/b> to the <b>Get-Random<\/b> cmdlet. I then use the <b>Measure-Object<\/b> cmdlet to count how many items are returned by the command. The figure is shown here.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4263.hsg-9-8-11-4.jpg\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of reading text file contents into $users variable\" alt=\"Image of reading text file contents into $users variable\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4263.hsg-9-8-11-4.jpg\" \/><\/a><\/p>\n<p>As seen in the following figure, the contents of the text file consist of 12 users. In addition, a comparison between the text file and the random output shows that the user names are in fact displayed in a random order.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8463.hsg-9-8-11-5.jpg\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of contents of text file with 12 users\" alt=\"Image of contents of text file with 12 users\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8463.hsg-9-8-11-5.jpg\" width=\"250\" \/><\/a><\/p>\n<p>If memory consumption is an issue, the command can be revised to take advantage of the pipeline. The revised command is shown here:<\/p>\n<p style=\"padding-left: 30px\">$users = gc C:\\fso\\UserGroupNames.txt<\/p>\n<p style=\"padding-left: 30px\">$users | Get-Random -Count $users.Count<\/p>\n<p>&nbsp;<\/p>\n<p>CS, that is it for generating random user names from a text file. I invite you to join me tomorrow for another exciting episode of BATCHman.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p>&nbsp;<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n<p><b><\/b>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Learn how to use Windows PowerShell to select random winners from a text file. &nbsp; Hey, Scripting Guy! I have a question. It is neither a vital server performance issue nor is it a dramatic process optimization revelation, but it is something that will make my life a lot easier. First the background: I [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[18,3,4,45],"class_list":["post-12761","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-arrays-hash-tables-and-dictionary-objects","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Learn how to use Windows PowerShell to select random winners from a text file. &nbsp; Hey, Scripting Guy! I have a question. It is neither a vital server performance issue nor is it a dramatic process optimization revelation, but it is something that will make my life a lot easier. First the background: I [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/12761","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=12761"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/12761\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=12761"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=12761"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=12761"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}