Friday Fun: capture pokemon using PowerShell

A few years ago, I wrote a quick function to download all the pokemon pictures from www.pokemon.com/us/pokedex for my kids to create the equivalent of the pokedex:

Pokedex-01

Beyond that, I don’t know anything about Pokemon, so don’t ask me anything about them 😛

Due to the recent success of Pokémon Go, I thought that I should extend the function, make it more friendly, accessible,… and share it, of course 😀

If you like Pokemon and PowerShell, this page is for you. You’ll discover, get to know Pokemon and have them all at your finger tips in your favorite console:

The first thing to do is to capture all the pictures from the main site:
Capturing-pokemon-ISE-03

The function aims to download all the files. You can launch it, interrupt it, relaunch it. It’ll restart where it left till the end. You’ve got to have at least 720 (the current total of pokemon) jpeg files in the Pokedex folder so that the other functions work.
The Build-Pokedex function will always end by displaying how many Pokemon exist.

Capturing-pokemon-ISE-04

Now, to use the Find-Pokemon and Show-Pokemon, it’s pretty straightforward

www.GIFCreator.me_S6xeyX

If you just pipe the two cmdlets together, the picture will be shown:

Find-Pokemon -Name Kyurem | Show-Pokemon 

Show-pokemon-01

If you use the -Online switch, the default browser should open the web page corresponding to the pokemon you looked for

Find-Pokemon -Name Kyurem | Show-Pokemon -Online

Show-pokemon-02

To discover a new Pokemon more randomly, you can do

0..720 | Get-Random | Find-Pokemon | Show-Pokemon -Online

Enjoy and have fun 😎

#Requires -Version 3.0
Function Build-Pokedex {
<#
.SYNOPSIS
Downloads all pokemon pictures
.DESCRIPTION
Downloads all pokemon pictures into your Pictures\Pokedex folder
#>
[CmdletBinding()]
Param()
Begin {
# Create a folder named Pokedex under Pictures
if (-not(Test-Path -Path "$($HOME)/Pictures/Pokedex" -PathType Container)) {
$null = mkdir -Path "$($HOME)/Pictures/Pokedex"
Write-Verbose -Message "Successfully created $($HOME)/Pictures/Pokedex folder"
} else {
Write-Verbose -Message "$($HOME)/Pictures/Pokedex folder already present"
}
# Defining a standard user agent
$UA = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko'
}
Process {
# Read main pokedex page
try {
# Using .Net as Invoke-WebRequest may hang
$client = New-Object System.Net.WebClient
$client.Headers.Add('user-agent', "$($UA)")
$Pokedex = ($client.DownloadString('http://www.pokemon.com/us/pokedex')) -split '\n'|
Where { $_ -match '\<a\shref="/us/pokedex/' } |
Select -skip 1
Write-Verbose -Message 'Successfully reached main pokedex page online'
} catch {
Write-Warning -Message "Failed to read http://www.pokemon.com/us/pokedex because $($_.Exception.Message)"
}
if ($Pokedex) {
$Pokedex | ForEach-Object {
# Reset
$ID = $Name = $File = $null
# Get the name and id of each pokemon
$ID, $Name = ([regex]'\<a\shref="/us/pokedex/.+"\>(?<ID>\d{1,3})\s-\s(?<Name>.+)\</a\>').Matches($_) |
Select -Expand Groups | Select -Last 2 -Expand Value
$Name = $Name -replace '&#39;',"'"
$Name = $Name -replace 'é','é'
$Name = $Name -replace '♀',''
$Name = $Name -replace "♂",''
# $Name = $Name -replace '♀','female'
# $Name = $Name -replace '♂','male'
# Define the local path for each pokemon
$File = '{2}/Pictures/Pokedex/{0:000}-{1}.png' -f [int]$ID,$Name,"$($HOME)/"
# Turn on progress default preference
$ProgressPreference = 'Continue'
$progressHT = @{
Activity = 'Capturing pokemon' ;
Status = "$($ID)/$($Pokedex.Count): $Name" ;
PercentComplete = (([int]$ID/($Pokedex.Count))*100) ;
}
Write-Progress @progressHT
if (-not(Test-Path -Path $File)) {
try {
# Turn off progress because of invoke-webrequest
$ProgressPreference = 'SilentlyContinue'
# Define a hashtable to download each pokemon
$HT = @{
URI = 'http://assets.pokemon.com/assets/cms2/img/pokedex/full/{0:000}.png' -f [int]$ID ;
OutFile = $File ;
UseBasicParsing = $true ;
UserAgent = $UA ;
}
$null = Microsoft.PowerShell.Utility\Invoke-WebRequest @HT -ErrorAction Stop
Write-Verbose -Message "Get pokemon id $($ID) named $($Name)"
} catch {
Write-Warning -Message "Failed to get pokemon for $($ID):$($Name) because $($_.Exception.Message)"
}
} else {
Write-Verbose -Message "Already have file for $($ID):$($Name)"
}
}
Write-Progress -Activity 'Capturing pokemon' -Status 'completed' -Completed
}
}
End {
$GCIHT = @{
Path = "$($HOME)/Pictures/Pokedex" ;
Include = '*.png' ;
Recurse = $true ;
Force = $true ;
ErrorAction = 'SilentlyContinue' ;
}
if ((Get-ChildItem @GCIHT | Measure).Count -eq $Pokedex.Count) {
Write-Verbose -Message "Successfully downloaded all $($Pokedex.Count) pokemon pictures" -Verbose
} else {
Write-Warning -Message "Could not download $($Pokedex.Count) pokemon pictures"
}
}
}
Function Get-Pokedex {
<#
.SYSNOPSIS
Read the content of previously downloaded pokemon pictures
.DESCRIPTION
Helper function to get all pokemon properties (name, id and filepath) into an array of objects
#>
[CmdletBinding()]
Param()
Begin {}
Process {
}
End{
$GCIHT = @{
Path = "$($HOME)/Pictures/Pokedex" ;
Include = '*.png' ;
Recurse = $true ;
Force = $true ;
ErrorAction = 'SilentlyContinue' ;
}
$PokemonFiles = Get-ChildItem @GCIHT
if (($PokemonFiles | Measure).Count -ge 720) {
$PokemonFiles | ForEach-Object {
$ID = $Name = $null
$ID,$Name = ([regex]'(?<ID>\d{1,3})-(?<Name>.+)').Matches($_.BaseName)|
Select -Expand Groups | Select -Last 2 -Expand Value
[PSCustomObject]@{
ID = [int]$ID ;
Name = $Name ;
FilePath = $_.FullName ;
}
}
}
}
}
Function Find-Pokemon {
<#
.SYNNOPSIS
Find a pokemon by name or id
.DESCRIPTION
Read the local pokedex pictures and find a pokemon by name or id
.PARAMETER ID
Pokemon id number
.PARAMTER Name
Pokemon name
.EXAMPLE
Find-Pokemon -Name Vaporeon
.EXAMPLE
Find-Pokemon -ID 251
#>
[CmdletBinding(DefaultParameterSetName='ByName')]
Param()
DynamicParam {
$Dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$ParameterName = 'Name'
$AttribColl1 = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$Param1Att = New-Object System.Management.Automation.ParameterAttribute
$Param1Att.Mandatory = $true
$Param1Att.ValueFromPipeline = $true
$Param1Att.ParameterSetName = 'ByName'
$AttribColl1.Add($Param1Att)
$AttribColl1.Add((New-Object System.Management.Automation.ValidateSetAttribute(Get-Pokedex | Select-Object -ExpandProperty Name)))
$Dictionary.Add($ParameterName,(New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttribColl1)))
$ParameterID = 'ID'
$AttribColl2 = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$Param2Att = New-Object System.Management.Automation.ParameterAttribute
$Param2Att.Mandatory = $true
$Param2Att.ValueFromPipeline = $true
$Param2Att.ParameterSetName = 'ByID'
$AttribColl2.Add($Param2Att)
$AttribColl2.Add((New-Object System.Management.Automation.ValidateSetAttribute(Get-Pokedex | Select-Object -ExpandProperty ID)))
$Dictionary.Add($ParameterID,(New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterID, [int], $AttribColl2)))
$Dictionary
}
Begin {}
Process {
$Pokedex = Get-Pokedex
Switch ($PsCmdlet.ParameterSetName) {
'ById' {
$Pokedex.Where({$_.ID -eq $PsBoundParameters[$ParameterID]})
break
}
'ByName' {
$Pokedex.Where({$_.Name -eq $PsBoundParameters[$ParameterName]})
break
}
default {}
}
}
End {}
}
Function Show-Pokemon {
<#
.SYNOPSIS
Either show the local picture or open its webpage
.DESCRIPTION
Either show the local picture of the pokemon or browse online its webpage
.PARAMETER FilePath
Location of the pokemon picture
.PARAMETER ID
Id of the pokemon
.PARAMETER Online
Switch to online mode
.EXAMPLE
Find-Pokemon -Name Vaporeon | Show-Pokemon
.EXAMPLE
646 | Find-Pokemon | Show-Pokemon -Online
.EXAMPLE
Show-Pokemon -Id 646
#>
[CmdletBinding(DefaultParameterSetName='ByFileName')]
Param(
[Parameter(ParameterSetName='ByFileName',Mandatory,ValueFromPipelineByPropertyName)]
[string]$FilePath,
[Parameter(ParameterSetName='ById',Mandatory,ValueFromPipelineByPropertyName)]
[string]$ID,
[Parameter(ParameterSetName='ById')]
[Switch]$Online
)
Begin {
$BaseURI = 'http://www.pokemon.com/us/pokedex/'
}
Process {
Switch ($PsCmdlet.ParameterSetName) {
'ByFileName' {
# %SystemRoot%\System32\rundll32.exe "%ProgramFiles%\Windows Photo Viewer\PhotoViewer.dll", ImageView_Fullscreen %1
Start-Process -FilePath "$($env:SystemRoot)\System32\rundll32.exe" -ArgumentList @(
('"{0}\Windows Photo Viewer\PhotoViewer.dll", ' -f $($env:ProgramFiles)),
'ImageView_Fullscreen',
"$($FilePath)"
)
break
}
'ById' {
Start-Process ('http://www.pokemon.com/us/pokedex/{0}' -f $ID)
}
default {}
}
}
End {}
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.