Created
May 11, 2013 16:18
-
-
Save p0w3rsh3ll/5560438 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Requires -Version 3 | |
Function Get-PSH2013Learder { | |
<# | |
.SYNOPSIS | |
Get the Scripting Games 2013 leaderboard of a given category | |
.DESCRIPTION | |
Just for fun. | |
.PARAMETER Category | |
The full name of the category you're looking for. | |
.PARAMETER EventNumber | |
Integer that represents the event number. | |
.PARAMETER Repeat | |
Switch to go in an infinite loop. | |
.PARAMETER EveryMinutes | |
When executed in loop mode, it allows you to set how often the display is "refreshed". | |
By default, it refreshes every 10 minutes. | |
.PARAMETER UserName | |
Your full user name. It will be added to the Top users list and show your rank and how much you scored. | |
.PARAMETER TopUsers | |
Integer that allows you how many top users are included in the output. | |
.EXAMPLE | |
Get-PSH2013Learder -Category Beginner -EventNumber 1 -UserName "ScriptingWife" | |
Retrieve the top 10 users in the Beginner category for Event 1 and include ScriptingWife regardless her current position | |
.EXAMPLE | |
Get-PSH2013Learder -Category Advanced -EventNumber 1 -TopUsers 5| Select Rank,Name,Score | ft -AutoSize | |
Retrieve the top 5 users in the Advanced category | |
.EXAMPLE | |
Get-PSH2013Learder -Category Advanced -EventNumber 1 -UserName "_Emin_" -EveryMinutes 60 -Repeat | |
Retrieve the Top 10 users in the Advanced category, include my username and refresh the list every hour | |
#> | |
[CmdletBinding(DefaultParameterSetName='All')] | |
Param( | |
[Parameter(Mandatory)] | |
[Alias('Track')] | |
[ValidateSet('Advanced','Beginner')] | |
[string]$Category, | |
[Parameter(Mandatory)] | |
[ValidateRange(1,6)] | |
[int]$EventNumber, | |
[Parameter(ParameterSetName='Loop',Mandatory)] | |
[switch]$Repeat, | |
[Parameter(ParameterSetName='Loop')] | |
[ValidateRange(2,1140)] | |
[int]$EveryMinutes=10, | |
[Parameter()] | |
[string]$UserName, | |
[Parameter()] | |
[ValidateRange(1,10)] | |
[Int]$TopUsers = 10 | |
) | |
Begin{ | |
} | |
Process { | |
if ($PSCmdlet.ParameterSetName -eq 'Loop') { | |
Write-Verbose -Message ('Execution time: {0}' -f (Get-Date).ToLongTimeString()) -Verbose | |
Write-Verbose -Message ('Event {0}: {1}' -f $EventNumber,$(($SG2013Calendar | Where EventID -eq $EventNumber).Title)) -Verbose | |
Write-Verbose -Message ('Event Closed?: {0}' -f (Test-isEventClosed -ID $EventNumber)) -Verbose | |
# Call the function once, i.e., without the EveryMinutes parameters | |
$PSBoundParameters.Remove('EveryMinutes') | Out-Null | |
$PSBoundParameters.Remove('Repeat') | Out-Null | |
Get-PSH2013Learder @PSBoundParameters | |
# Wait | |
Write-Verbose -Message ('Waiting {0} minutes, next refresh at {1}' -f $EveryMinutes,(Get-Date).AddMinutes($EveryMinutes).ToLongTimeString()) -Verbose | |
Start-Sleep -Seconds ($EveryMinutes*60) | |
Clear-Host | |
# Call the function recursively | |
Get-PSH2013Learder @PSBoundParameters -Repeat:$true -EveryMinutes $EveryMinutes | |
} else { | |
if (Test-isEventClosed -ID $EventNumber) { | |
Write-Verbose -Message "Event $($EventNumber): $(($SG2013Calendar|Where EventID -eq $EventNumber).Title) closed on $(($SG2013Calendar|Where EventID -eq $EventNumber).VotingEnd)" | |
if ($UserName) { | |
$LeaderBoard = Get-SlowLeader -EventNumber $EventNumber -Category $Category | |
$LeaderBoard | Sort-Object -Descending:$false -Property Rank | Select -First $TopUsers | |
$LeaderBoard | Where-Object { $_.Name -eq "$UserName"} | |
} else { | |
Get-QuickLeader -EventNumber $EventNumber -Category $Category -TopUsers $TopUsers | |
} | |
} else { | |
Get-QuickLeader -EventNumber $EventNumber -Category $Category -TopUsers $TopUsers | |
if ($UserName) { | |
Get-QuickLeader -EventNumber $EventNumber -Category $Category | Where Name -eq $UserName | |
} | |
} | |
} | |
} | |
End {} | |
} | |
# Courtesy of Tobias Weltner | |
# http://powershell.com/cs/blogs/tobias/archive/2011/10/27/regular-expressions-are-your-friend-part-1.aspx | |
Function Get-Matches { | |
param( | |
[Parameter(Mandatory=$true)] | |
$Pattern, | |
[Parameter(ValueFromPipeline=$true)] | |
$InputObject | |
) | |
begin { | |
try { | |
$regex = New-Object Regex($pattern) | |
} | |
catch { | |
Throw "Get-Matches: Pattern not correct. '$Pattern' is no valid regular expression." | |
} | |
$groups = @($regex.GetGroupNames() | | |
Where-Object { ($_ -as [Int32]) -eq $null } | | |
ForEach-Object { $_.toString() }) | |
} | |
process { | |
foreach ($line in $InputObject) { | |
foreach ($match in ($regex.Matches($line))) { | |
if ($groups.Count -eq 0) { | |
([Object[]]$match.Groups)[-1].Value | |
} else { | |
$rv = 1 | Select-Object -Property $groups | |
$groups | ForEach-Object { | |
$rv.$_ = $match.Groups[$_].Value | |
} | |
$rv | |
} | |
} | |
} | |
} | |
} | |
# Function used to read closed entries | |
Function Get-SlowLeader { | |
[CmdletBinding()] | |
Param( | |
$EventNumber, | |
$Category | |
) | |
Begin { | |
$ok = $true | |
# Build a local path | |
$LocalPath = Join-Path -Path $env:temp -ChildPath "SG2013\$($Category)\$($EventNumber)" | |
if (-not(Test-Path -Path $LocalPath -PathType Container)) { | |
# Create the folder | |
try { | |
New-Item -Path $LocalPath -ItemType Directory -Force -ErrorAction Stop | Out-Null | |
Write-Verbose -Message "Creating folder $LocalPath" | |
} Catch { | |
Write-Warning -Message "Failed to create directory $LocalPath because $($_.Exception.Message)" | |
$ok = $false | |
} | |
} | |
# Check if download is required | |
$root= "http://scriptinggames.org/entries/2013/Summer" | |
$mainpage = Invoke-WebRequest -URI "$root/$Category/$EventNumber/" | |
if ($ok) { | |
if ((Get-ChildItem -Path $LocalPath -Filter "*.txt").Count -gt 0) { | |
Write-Verbose -Message "Items for event $($Category)\$($EventNumber) already downloaded" | |
} else { | |
$Count = 0 | |
$mainpage.Links.href | Where-Object { $_ -match "\.txt" } | | |
ForEach-Object -Process { | |
Write-Progress -Activity "Reading files for event $($EventNumber): $(($SG2013Calendar | | |
Where EventID -eq $EventNumber).Title)" -Status $Count -PercentComplete ($Count/($mainpage.Links.href).Count*100) | |
$Count++ | |
try { | |
$entry = (Invoke-WebRequest -URI "$root/$Category/$EventNumber/$_" -ErrorAction Stop) | |
$Content = $entry.Content | |
# Save the content locally | |
Set-Content -Path (Join-Path -Path $LocalPath -ChildPath $_) -Value $($entry.Content) -ErrorAction Stop | |
} catch { | |
Write-Warning -Message "Failed to download entry $count because $($_.Exception.Message)" | |
$ok = $false | |
} | |
} | |
} | |
} | |
# Initialize variables for process block | |
$allusers = @() | |
} | |
Process { | |
if ($ok) { | |
Get-ChildItem -Path $LocalPath -Filter "*.txt" | ForEach-Object { | |
$Content = Get-Content $_.FullName -ReadCount 0 | |
$extractedValues = @($Content -split ([char]10)) | | |
Get-Matches "^TOTAL\sSCORE\sWAS\s(?<Points>\d{1,4})\sFROM\s(?<Votes>\d{1,4})\sTOTAL\sVOTES" | |
$allusers += New-Object -TypeName psobject -Property @{ | |
Name = ($_ -split "\.")[0] | |
Score = '{0:N4}' -f ($extractedValues.Points/$extractedValues.Votes) | |
Votes = $extractedValues.Votes | |
} | |
} | |
# Add a rank property | |
$i=0 | |
$allusers | Sort-Object -Descending -Property Score | ForEach-Object { | |
$i++ | |
$_ | Add-Member -MemberType NoteProperty -Name Rank -Value $i | |
} | |
# Output | |
$allusers # | Sort-Object -Descending:$false -Property Rank | Select -First 11 | |
} | |
} | |
End {} | |
} | |
# This is the calendar of the Scripting Games 2013 | |
$SG2013Calendar = @( | |
@{ | |
EventID = 1 ; Title = "An Archival Atrocity" ; | |
Start = ([datetime]'2013-04-23 00:00:00').ToLocalTime() ; | |
End = ([datetime]'2013-04-30 00:00:00').ToLocalTime() ; | |
VotingEnd = ([datetime]'2013-05-07 00:00:00').ToLocalTime() | |
}, | |
@{ | |
EventID = 2 ; Title = "An Inventory Intervention" ; | |
Start = ([datetime]'2013-05-02 00:00:00').ToLocalTime() ; | |
End = ([datetime]'2013-05-07 00:00:00').ToLocalTime() ; | |
VotingEnd = ([datetime]'2013-05-14 00:00:00').ToLocalTime() | |
}, | |
@{ | |
EventID = 3 ; Title = "A Disk Decision" ; | |
Start = ([datetime]'2013-05-09 00:00:00').ToLocalTime() ; | |
End = ([datetime]'2013-05-14 00:00:00').ToLocalTime() ; | |
VotingEnd = ([datetime]'2013-05-21 00:00:00').ToLocalTime() | |
}, | |
@{ | |
EventID = 4 ; Title = "An Auditing Adventure" ; | |
Start = ([datetime]'2013-05-16 00:00:00').ToLocalTime() ; | |
End = ([datetime]'2013-05-21 00:00:00').ToLocalTime() ; | |
VotingEnd = ([datetime]'2013-05-28 00:00:00').ToLocalTime() | |
}, | |
@{ | |
EventID = 5 ; Title = "The Logfile Labyrinth" ; | |
Start = ([datetime]'2013-05-23 00:00:00').ToLocalTime() ; | |
End = ([datetime]'2013-05-28 00:00:00').ToLocalTime() ; | |
VotingEnd = ([datetime]'2013-05-04 00:00:00').ToLocalTime() | |
}, | |
@{ | |
EventID = 6 ; Title = "The Core Configurator" ; | |
Start = ([datetime]'2013-05-30 00:00:00').ToLocalTime() ; | |
End = ([datetime]'2013-06-04 00:00:00').ToLocalTime() ; | |
VotingEnd = ([datetime]'2013-06-11 00:00:00').ToLocalTime() ; | |
} | |
) | |
# Uses the above calendar | |
Function Test-isEventClosed { | |
Param($ID) | |
Process { | |
if ((Get-Date) -gt ($SG2013Calendar | Where EventID -eq $ID).VotingEnd){ | |
$true | |
} else { | |
$false | |
} | |
} | |
} | |
# Function to read the top 10 online leaderboard's page | |
Function Get-QuickLeader { | |
[CmdletBinding()] | |
Param( | |
$EventNumber, | |
$Category, | |
[int]$TopUsers=10 | |
) | |
Begin {} | |
Process { | |
# Get the top 10 users from page | |
try { | |
$URI = 'http://scriptinggames.org/serverside-leaderboard.php' | |
$page = (Invoke-WebRequest -Uri $URI -ErrorAction Stop).AllElements[0].OuterText -split "`n" | |
} catch { | |
Write-Warning "Failed to read the web page" | |
break | |
} | |
# Calculate the line number where the "caterory eventnumber" keyword is located | |
# Using select-string as there's only 1 match | |
$StartingLine = ($page | Select-String -Pattern "^$($Category)\s[$EventNumber]").LineNumber | |
Write-Verbose "Found category $Category at line $StartingLine" | |
# Was using a Select-String previously that could have 0, 1 or mores matches | |
# NEW: using a while loop to look for participant | |
# Could also have used a Select-String with -Context parameter on previous command $StartingLine = ... | |
$arusers = @() | |
$i = 0 | |
while ($true) { | |
if (@($page)[$StartingLine+$i] -notmatch "^$([char]8226)\s") { | |
# If the line isn't a participant, we exit the loop | |
break | |
} else { | |
# Store a participant object in the array | |
$arusers += @($page)[$StartingLine+$i]| ForEach-Object -Process { | |
New-Object -TypeName PSObject -Property @{ | |
Rank = $i+1 | |
Name = (($_ -split ",")[0] -replace ([char]8226),"").Trim() | |
Score = ($_ -split ", scoring")[1].Trim() | |
} | |
} | |
# Increase counter | |
$i++ | |
} | |
} | |
$arusers | Select -First $TopUsers | |
} | |
End {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment