Earn 40,000 RR points after you spend $1,000 on purchases in the first 3 months of account opening
Author Archives: Managed WordPress Migration User
Find RetroPie Unscraped Data
This is intended to be used as the supplemental script (3_CheckXML.ps1) to be used in conjunction with the 1_Clean-NoIntroRoms.ps1 and 2_CompareFolderResults.ps1 scripts. This script allows you check missing scraped data in RetroPie by examining the gamelist.xml file for each game system on you RetroPie. This can save you HOURS of time manually checking for missing ROM scraped data.
#CheckXML.ps1 #5.3 # -Added Changelog in Comments #5.2: # -Added variables for Write-Out Colors and Updated to Write-Out v1.3 # -Missing attributes set to $true were not being detected, only worked if they had a blank value #5.1: # -No Changes #5.0 # -New Release $global:scriptName = $PSCommandPath $global:scriptVersion = "v5.3" $global:GameListRoot = "\\retropie\configs\all\emulationstation\gamelists\" $global:MultiCartExceptions = "\(([^/)]*)(DISK|Disk|disk|Reel|4B-001, 4B-009, 8B-001, Sachen|4B-007, 4B-008, 8B-004, Sachen|4B-005, 4B-006, 8B-003, Sachen|4B-002, 4B-004, 8B-002, Sachen)([^/)]*)\)" $global:IgnoreMulticartDuplicates = $true $global:ValidateVerbose = $false #Validate all Data & Override ValidateChild $global:logFile = (Split-Path -Path $PSCommandPath -Parent) + "\logs\" + (Split-Path -Path $PSCommandPath.Replace(".ps1",".log") -Leaf) $global:logOverwrite = $true $global:ValidateChild = [ordered]@{ "path" = $false "name" = $true "cover" = $false "image" = $true "marquee" = $false "video" = $false "rating" = $false "desc" = $true "releasedate" = $false "developer" = $false "publisher" = $false "genre" = $false "players" = $false "kidgame" = $false } $global:romNoIntroHashTable = [ordered]@{ #RetroPieDirName = No-IntroDirName "atari2600" = "Atari - 2600" "atari5200" = "Atari - 5200" "atari7800" = "Atari - 7800 [Headered]" "atarijaguar" = "Atari - Jaguar" "atarilynx" = "Atari - Lynx [Headered]" "atarist" = "Atari - ST" "coleco" = "Coleco - ColecoVision" "fds" = "Nintendo - Family Computer Disk System [headered]" "gamegear" = "Sega - Game Gear" "gb" = "Nintendo - Game Boy" "gba" = "Nintendo - Game Boy Advance" "gbc" = "Nintendo - Game Boy Color" "mastersystem" = "Sega - Master System - Mark III" "megadrive" = "Sega - Mega Drive - Genesis" "msx" = "Microsoft - MSX" "n64" = "Nintendo - Nintendo 64" "nes" = "Nintendo - Nintendo Entertainment System [headered]" "ngp" = "SNK - Neo Geo Pocket" "ngpc" = "SNK - Neo Geo Pocket Color" "pcengine" = "NEC - PC Engine - TurboGrafx 16" "sega32x" = "Sega - 32X" "sg-1000" = "Sega - SG-1000" "snes" = "Nintendo - Super Nintendo Entertainment System" "vectrex" = "GCE - Vectrex" "virtualboy" = "Nintendo - Virtual Boy" "wonderswan" = "Bandai - WonderSwan" "wonderswancolor" = "Bandai - WonderSwan Color" } #Output Color Variables $global:colorMain = "Green" $global:colorSub1 = "DarkGreen" $global:colorSub2 = "Cyan" $global:colorSub3 = "DarkRed" $global:colorOk = "DarkCyan" $global:colorWarn = "Yellow" $global:colorError = "Red" Function Main() { #Output Color Variables $global:colorMain = "Green" $global:colorSub1 = "DarkGreen" $global:colorSub2 = "Cyan" $global:colorOk = "DarkCyan" $global:colorWarn = "Yellow" $global:colorError = "Red" #Powershell 4 or greater is required If (!($PSVersionTable.PSVersion.Major -ge 4) -OR ($PSVersionTable.PSVersion -eq $null)) { Write-Host -ForegroundColor $global:colorError "Powershell v4 or greater is required, quitting script!" Exit } #Create Log File If ($global:logOverwrite -eq $true) { Write-Out -NoNewLine -LogFile $global:logFile -Overwrite } Else { Write-Out -NoNewLine -LogFile $global:logFile } #Array to Track Results For Each Game System $gameArray = @() #Check XML Gamelists for Missing Scraped Metadata $tStart = (Get-Date) Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -Text "INITIALIZE" -ForegroundColor $global:colorMain -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Script Name : $($global:scriptName)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Version: : $($global:scriptVersion)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Game List Root : $($global:GameListRoot)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Multicart Exceptions : $($global:MultiCartExceptions)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Ignore Multicart Exceptions : $($global:IgnoreMulticartDuplicates)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Validate Verbose : $($global:ValidateVerbose)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log File : $($global:logFile)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log Overwrite : $($global:logOverwrite)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Start Time : $($tStart)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -PostLine 1 -LogFile $global:logFile ForEach ($GameSystem in $global:romNoIntroHashTable.keys) { #Create Object to Store Info For Each Game System $gameObject = New-Object -TypeName psobject $gameObject | Add-Member -MemberType NoteProperty -Name GameSystem -Value $GameSystem $gameObject | Add-Member -MemberType NoteProperty -Name GameList -Value "$($global:GameListRoot)$($GameSystem)\gamelist.xml" $gameObject | Add-Member -MemberType NoteProperty -Name GameListExist -Value $false $gameObject | Add-Member -MemberType NoteProperty -Name Games -Value @{} $gameObject | Add-Member -MemberType NoteProperty -Name RomsUnscraped -Value 0 $gameObject | Add-Member -MemberType NoteProperty -Name MissingMetadata -Value 0 $gameObject | Add-Member -MemberType NoteProperty -Name DuplicateRoms -Value 0 Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -Text "PROCESSING: $($gameObject.GameList)" -ForegroundColor $global:colorMain -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -Text "STEP 1/3 - Confirm XML Exists" -ForegroundColor $global:colorSub1 -LogFile $global:logFile Write-Out -Text "=====================================" -ForegroundColor $global:colorSub1 -LogFile $global:logFile If (Test-Path -LiteralPath $gameObject.GameList -PathType Leaf) { $gameObject.GameListExist = $true Write-Out -Text "Exists - Continue" -ForegroundColor $global:colorSub1 -LogFile $global:logFile #Read GameList [XML]$gameXML = Get-Content $gameObject.GameList Write-Out -Text "STEP 2/3 - Validate Game Details" -ForegroundColor $global:colorSub1 -PreLine 1 -LogFile $global:logFile Write-Out -Text "=====================================" -ForegroundColor $global:colorSub1 -LogFile $global:logFile #Loop Each Game in the XML File ForEach($gameMetadata in $gameXML.gameList.game) { $RomScraped = $true #Output Validation If ($global:ValidateVerbose -eq $true) { #Validate All Attributes Write-Out -Text "$($gameMetadata.path)" -ForegroundColor $global:colorSub2 -LogFile $global:logFile Write-Out -Text "-------------------------------------" -ForegroundColor $global:colorSub2 -LogFile $global:logFile ForEach ($Child in $global:ValidateChild.keys) { If ($gameMetadata.$Child -eq "" -OR $gameMetadata.$Child -eq $null) { $gameObject.MissingMetadata++ $RomScraped = $false Write-Out -Text "$($Child): ","MISSING" -ForegroundColor $global:colorSub2,$global:colorError -LogFile $global:logFile } Else { Write-Out -Text "$($Child): ","$($gameMetadata.$Child)" -ForegroundColor $global:colorSub2,$global:colorOk -LogFile $global:logFile } } Write-Out -LogFile $global:logFile } Else { #Validate Only True Attributes $MetadataErrors = @() ForEach ($Child in $global:ValidateChild.keys) { If ($global:ValidateChild[$Child] -eq $true) { If ($gameMetadata.$Child -eq "" -OR $gameMetadata.$Child -eq $null) { $gameObject.MissingMetadata++ $RomScraped = $false $MetadataErrors += $Child } } } If ($MetadataErrors.Count -gt 0) { Write-Out -Text "$($gameMetadata.path)" -ForegroundColor $global:colorSub2 -LogFile $global:logFile Write-Out -Text "-------------------------------------" -ForegroundColor $global:colorSub2 -LogFile $global:logFile ForEach ($Error in $MetadataErrors) { Write-Out -Text "$($Error): ","MISSING" -ForegroundColor $global:colorSub2,$global:colorError -LogFile $global:logFile } Write-Out -LogFile $global:logFile } } If ($RomScraped -eq $false) { $gameObject.RomsUnscraped++ } #Add Games ROM File & Name to HashTable To Check For Duplicates $gameObject.Games.add($gameMetadata.path,$gameMetadata.name) } If ($gameObject.MissingMetadata -eq 0) { Write-Out -Text "Validation - Successful with $($gameObject.MissingMetadata) Errors" -ForegroundColor $global:colorSub1 -LogFile $global:logFile } Else { Write-Out -Text "Validation - ","Failed with Unscraped ROMs: $($gameObject.RomsUnscraped) and Missing Metadata: $($gameObject.MissingMetadata)" -ForegroundColor $global:colorSub1,$global:colorError -LogFile $global:logFile } #Check For Duplicates in XML Gamelists Write-Out -Text "STEP 3/3 - Check For Duplicates" -ForegroundColor $global:colorSub1 -PreLine 1 -LogFile $global:logFile Write-Out -Text "=====================================" -ForegroundColor $global:colorSub1 -LogFile $global:logFile #Get List of Unique ROM Base Names $colUniqueRoms = $gameObject.Games.Keys | ForEach {$gameObject.Games[$_].Split("(")[0]} $colUniqueRoms = $colUniqueRoms | Sort-Object -Unique Write-Out -Text "Unique Names: $($colUniqueRoms.Count) " -ForegroundColor $global:colorSub1 -LogFile $global:logFile Write-Out -Text "Total ROMs: $($gameObject.Games.Count) " -ForegroundColor $global:colorSub1 -LogFile $global:logFile If ($gameObject.Games.Count -gt $colUniqueRoms.Count) { Write-Out -Text "Potential Duplicates: $($gameObject.Games.Count - $colUniqueRoms.Count)" -ForegroundColor $global:colorWarn -LogFile $global:logFile } Else { Write-Out -Text "Potential Duplicates: $($gameObject.Games.Count - $colUniqueRoms.Count)" -ForegroundColor $global:colorSub1 -LogFile $global:logFile } #Find Duplicates ForEach ($uniqueRom in $colUniqueRoms) { #Get HashTable Key for Each Duplicate If ($global:IgnoreMulticartDuplicates) { $Duplicates = $gameObject.Games.Keys | ? { $gameObject.Games[$_] -match ("^"+[regex]::escape($uniqueRom)+"\(") -AND $gameObject.Games[$_] -cnotmatch $global:MultiCartExceptions } } Else { #Ensure Match to First '(' Incase of Common Name (ex: 'Megaman' vs 'Megaman 2') $Duplicates = $gameObject.Games.Keys | ? { $gameObject.Games[$_] -match ("^"+[regex]::escape($uniqueRom)+"\(") } } If ($Duplicates.Count -gt 1) { $gameObject.DuplicateRoms+= ($Duplicates.Count - 1) Write-Out -Text "Duplicate($($Duplicates.Count - 1)): $($uniqueRom)" -ForegroundColor $global:colorSub2 -PreLine 1 -LogFile $global:logFile Write-Out -Text "----------------------------------------" -ForegroundColor $global:colorSub2 -LogFile $global:logFile ForEach ($Dup in $Duplicates) { Write-Out -Text "ROM: ","$($Dup )" -ForegroundColor $global:colorSub2,$global:colorError -LogFile $global:logFile } } } If ($gameObject.DuplicateRoms -eq 0) { Write-Out -Text "Duplicates: None Found" -ForegroundColor $global:colorSub1 -PreLine 1 -PostLine 1 -LogFile $global:logFile } Else { Write-Out -Text "Duplicates: ","$($gameObject.DuplicateRoms) Found" -ForegroundColor $global:colorSub1,$global:colorError -PreLine 1 -PostLine 1 -LogFile $global:logFile } } Else { Write-Out -Text "Not Exist - Skip" -ForegroundColor $global:colorError -PostLine 1 -LogFile $global:logFile } #Add Game System to Array to Track Results $gameArray += $gameObject } #Display Final Results Write-Out -Text "*****************************************************************" -ForegroundColor $global:colorMain -PreLine 1 -LogFile $global:logFile Write-Out -Text "END RESULTS" -ForegroundColor $global:colorMain -LogFile $global:logFile Write-Out -Text "*****************************************************************" -ForegroundColor $global:colorMain -LogFile $global:logFile ForEach ($game in $gameArray) { Write-Out -Text "* $($game.GameSystem):" -ForegroundColor $global:colorMain -LogFile $global:logFile If ($game.GameListExist -eq $false) { Write-Out -Text "Error ($($game.GameList)) Does Not Exist" -ForegroundColor $global:colorError -LogFile $global:logFile } Else { Write-Out -Text "* -Total Games: $($game.Games.Count)" -ForegroundColor $global:colorMain -LogFile $global:logFile If ($game.RomsUnscraped -eq 0) { Write-Out -Text "* -ROMs Not Scraped: $($game.RomsUnscraped)" -ForegroundColor $global:colorMain -LogFile $global:logFile } Else { Write-Out -Text "* -ROMs Not Scraped: ","$($game.RomsUnscraped)" -ForegroundColor $global:colorMain,$global:colorError -LogFile $global:logFile } If ($game.MissingMetadata -eq 0) { Write-Out -Text "* -Missing Metadata: $($game.MissingMetadata)" -ForegroundColor $global:colorMain -LogFile $global:logFile } Else { Write-Out -Text "* -Missing Metadata: ","$($game.MissingMetadata)" -ForegroundColor $global:colorMain,$global:colorError -LogFile $global:logFile } If ($game.DuplicateRoms -eq 0) { Write-Out -Text "* -Duplicate ROMs: $($game.DuplicateRoms)" -ForegroundColor $global:colorMain -LogFile $global:logFile } Else { Write-Out -Text "* -Duplicate ROMs: ","$($game.DuplicateRoms)" -ForegroundColor $global:colorMain,$global:colorError -LogFile $global:logFile } } Write-Out -ForegroundColor $global:colorMain -Text "* "-LogFile $global:logFile } $tEnd = (Get-Date) Write-Out -ForegroundColor $global:colorMain -Text "* Start Time : $($tStart)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* End Time : $($tEnd)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Elapsed Time : $([math]::Round(($tEnd-$tStart).totalseconds, 2)) seconds" -LogFile $global:logFile Write-Out -Text "*****************************************************************" -ForegroundColor $global:colorMain -LogFile $global:logFile } Function Write-Out { <# .SYNOPSIS Write output to console and/or log file. Supports multiple foreground and background colors on a single line and advanced options to insert lines, spaces, or tabs before or after the text as well as timestamps. .DESCRIPTION Uses Write-Host to output color text to the console, and supports using multiple foreground and background colors on a single line. Uses Set-Content and Add-Content to output to a file. It works by accepting strings as an array and then you can assign the foreground or background colors by passing them as arrays for the matching text. It also accepts Default which allows you skip specifying a color and use the default. This function requires Powershell 4.0 to support the alias attribute in the function. .PARAMETER Text Optional. Array of strings to write to console/log. If you do not need to use multiple colors on a single line you can pass a single string instead of an array of strings. Otherwise, if you need to multiple colors on a single line pass an array of strings and associated colors using -ForegroundColor, -BackgroundColor, -ForegroundColorDefault, or -BackgroundColorDefault. .PARAMETER ForegroundColor Optional. Array of foreground Colors to write to console. Default means the ForegroundColorDefault value is used. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER ForegroundColorDefault Optional. Default foreground color to write to console. Default is set to white. Valid Colors: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackgroundColor Optional. Array of background colors to write to console. Default means the BackgroundColorDefault value is used. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackgroundColorDefault Optional. Default background color to write to console. Default is none. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER PreLine Optional. Add blank lines before your text. Default is 0. .PARAMETER PreSpace Optional. Add spaces before your text. Default is 0. .PARAMETER PreTab Optional. Add Tabs before your text. Default is 0. .PARAMETER TimeStampFormat Optional. Format used for time stamps. Default is 'yyyy-MM-dd HH:mm:ss' .PARAMETER TimeStamp Optional. Adds time stamp in square brackets before your text. .PARAMETER ClearHost Optional. Clear the console before your text. .PARAMETER PostLine Optional. Add blank lines after your text. Default is 0. .PARAMETER PostSpace Optional. Add spaces after your text. Default is 0. .PARAMETER PostTab Optional. Add tabs after your text. Default is 0. .PARAMETER NoNewLine Optional. Do not add a new line after your text and optional post text options. Default is to add a new line. .PARAMETER LogFile Optional. Absolute or relative path of the log file. .PARAMETER Overwrite Optional. Ovewrite the log file. Default is to append to the log file. .INPUTS Parameters above .OUTPUTS None .NOTES Author: Brian Steinmeyer URL: http://sigkillit.com/ Created: 4/18/2020 Version 1.3 - Added LogOnly Option for only writing text to a log file Version 1.2 - Set Text, ForegroundColor, and BackgroundColor to default value of @() to fix errors checking counts in some circumstances - Fixed an issue where ForegroundColorDefault and BackgroundColorDefault were not working properly in some circumstances - Added Requires -Version 4.0 Version 1.1 - Completely rewrote the "Main Text" section - Added "Default" as a color option, which allows you to use the default values for foreground/background - Useful when you want to specify a backgroundcolor in certain parts of a line like the middle - Ex: Write-Out -Text "How to ","highlight ","the middle text" -BackgroundColor Default,Yellow,Default Version: 1.0 - Initial Creation inspired by PSWriteColor (https://github.com/EvotecIT/PSWriteColor) - Improved upon by switching Foreground and Background Colors to default values if colors are not specifid for all strings. Will also ignore extra colors if more colors are specified than strings specified. .EXAMPLE Write-Out -Text "Start with Red Text ","Then Switch to Blue Text ","Now Magenta" -ForegroundColor Red,Blue,Magenta .EXAMPLE Write-Out -Text "White on Black ","Black on White ","Dark Cyan on Cyan ","Yellow on Green ","Default Color" -ForegroundColor White,Black,DarkCyan,Yellow -BackgroundColor Black,White,Cyan,Green .EXAMPLE Write-Out -Text "Make this"," entire line"," the same color by setting defaults" -ForegroundColorDefault Yellow -BackgroundColorDefault Magenta .EXAMPLE Write-Out -Text "Add a blank line and two tabs ","before ","my text" -ForegroundColor Green,Cyan,White -PreLine 1 -PreTab 2 .EXAMPLE Write-Out -Text "Add two blank ","lines ","after my text" -ForegroundColor White,Green,White -PostLine 2 .EXAMPLE Write-Out -Text "Add 3 spaces before my text" -ForegroundColor Gray -Prespace 3 .EXAMPLE Write-Out -Text "White text and a tab after" -ForegroundColor White -NoNewLine -PostTab 1 Write-Out -Text "Black text on Yellow ","and then back to white" -ForegroundColor Black,White -BackgroundColor Yellow .EXAMPLE Write-Out -Text "An easy way to ","highlight ","text in the middle" -BackgroundColor Default,Yellow .EXAMPLE Write-Out -Text "You can even add a ","time stamp ","before your output" -ForegroundColor White,Green,White -TimeStamp -PreLine 3 .EXAMPLE Write-Out -Text "You can change the ","time stamp format" -ForegroundColor White,Yellow -TimeStamp -TimeStampFormat "dd-MM-yyy HH:mm" -PreLine 1 -PostLine 1 .EXAMPLE Write-Out -Text "An"," Error"," occurred let's write overwrite/create a new log file" -ForegroundColor White,Red,White -TimeStamp -LogFile "script.log" -Overwrite .EXAMPLE Write-Out -Text "Now you can ","Append ","this line to your log file" -ForegroundColor Cyan,Magenta -TimeStamp -LogFile "script.log" #> [CmdletBinding()] Param ( [Parameter(Mandatory=$false)] [AllowEmptyString()] [alias ('T')] [String[]] $Text = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('FGC', 'FC')] [string[]] $ForegroundColor = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('FGCD', 'FCD')] [string] $ForegroundColorDefault = [ConsoleColor]::White, [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('BGC', 'BC')] [String[]] $BackgroundColor = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('BGCD', 'BCD')] [string] $BackgroundColorDefault = "Default", [Parameter(Mandatory=$false)] [int] $PreLine = 0, [Parameter(Mandatory=$false)] [int] $PreSpace = 0, [Parameter(Mandatory=$false)] [int] $PreTab = 0, [Parameter(Mandatory=$false)] [Alias('TSF', 'TS')] [string] $TimeStampFormat = 'yyyy-MM-dd HH:mm:ss', [Parameter(Mandatory=$false)] [switch] $TimeStamp, [Parameter(Mandatory=$false)] [switch] $ClearHost, [Parameter(Mandatory=$false)] [int] $PostLine = 0, [Parameter(Mandatory=$false)] [int] $PostSpace = 0, [Parameter(Mandatory=$false)] [int] $PostTab = 0, [Parameter(Mandatory=$false)] [switch] $NoNewLine = $false, [Parameter(Mandatory=$false)] [alias ('Log', 'L')] [string] $LogFile = '', [Parameter(Mandatory=$false)] [switch] $LogOnly = $false, [Parameter(Mandatory=$false)] [switch] $Overwrite = $false ) Begin { #Nothing to Do Here } Process { #Optional - Do Not Write to ConsoleColor If (!($LogOnly)) { #Optional - Prefix Text If ($ClearHost) { Clear-Host } If ($PreLine -gt 0) { For ($i = 0; $i -lt $PreLine; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line(s) before Main text If ($PreSpace -gt 0) { For ($i = 0; $i -lt $PreSpace; $i++) { Write-Host -Object " " -NoNewLine } } # Add Tab(s) before Main text If ($PreTab -gt 0) { For ($i = 0; $i -lt $PreTab; $i++) { Write-Host -Object "`t" -NoNewLine } } # Add Space(s) before Main text If ($TimeStamp) { Write-Host -Object "[$([datetime]::Now.ToString($TimeStampFormat))]" -NoNewline } # Add Timestamp before Main Text #MAIN TEXT If (($Text.Count -gt 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -eq 0)) { #Text Only Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColorDefault -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -gt 0) -AND ($BackgroundColor.Count -eq 0)) { #Text and ForegroundColor Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($ForegroundColor.Count -le $i) { $ForegroundColor += $ForegroundColorDefault } #ForegroundColor Not Specified Set to Default If ($ForegroundColor[$i] -eq "Default") { $ForegroundColor[$i] = $ForegroundColorDefault } If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColorDefault -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -gt 0)) { #Text and BackgroundColor Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($BackgroundColor.Count -le $i) { $BackgroundColor += $BackgroundColorDefault } #BackgroundColor Not Specified Set to Default If ($BackgroundColor[$i] -eq "Default") { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColorDefault -NoNewLine } } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColor[$i] -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -gt 0) -AND ($BackgroundColor.Count -gt 0)) { #Text, ForegroundColor, and BackgroundColor Specified (FAILS NOT WRITING DEFAULT) For ($i = 0; $i -lt $Text.Count; $i++) { If ($ForegroundColor.Count -le $i) { $ForegroundColor += $ForegroundColorDefault } #ForegroundColor Not Specified Set to Default If ($BackgroundColor.Count -le $i) { $BackgroundColor += $BackgroundColorDefault } #BackgroundColor Not Specified Set to Default If ($ForegroundColor[$i] -eq "Default") { $ForegroundColor[$i] = $ForegroundColorDefault } If ($BackgroundColor[$i] -eq "Default") { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColorDefault -NoNewLine } } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColor[$i] -NoNewLine } } } Else { #No Text, ForegroundColor, or BackgroundColor Specified ($Text.Count -eq 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -eq 0) } #Post Text If ($PostSpace -gt 0) { for ($i = 0; $i -lt $PostSpace; $i++) { Write-Host -Object " " -NoNewLine } } # Add Tab(s) after Main text If ($PostTab -gt 0) { for ($i = 0; $i -lt $PostTab; $i++) { Write-Host -Object "`t" -NoNewLine } } # Add Space(s) after Main text If ($PostLine -gt 0) { for ($i = 0; $i -lt $PostLine; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line(s) after Main text If ($NoNewLine) { Write-Host -NoNewline } else { Write-Host } # Add New Line after Main Text Unless NoNewLine is Supplied } #Log File $TextToWrite = "" #Build Text to Write to Log File If ($PreLine -gt 0) { For ($i = 0; $i -lt $PreLine; $i++) { $TextToWrite += "`n" } } # Add empty line(s) before Main text If ($PreSpace -gt 0) { For ($i = 0; $i -lt $PreSpace; $i++) { $TextToWrite += " " } } # Add Tab(s) before Main text If ($PreTab -gt 0) { For ($i = 0; $i -lt $PreTab; $i++) { $TextToWrite += "`t" } } # Add Space(s) before Main text If ($TimeStamp) { $TextToWrite += "[$([datetime]::Now.ToString($TimeStampFormat))]" } # Add Timestamp before Main Text If ($Text.Count -gt 0) { For ($i = 0; $i -lt $Text.Count; $i++) { $TextToWrite += $Text[$i] } } #Add Main Text If ($PostSpace -gt 0) { for ($i = 0; $i -lt $PostSpace; $i++) { $TextToWrite += " " } } # Add Tab(s) after Main text If ($PostTab -gt 0) { for ($i = 0; $i -lt $PostTab; $i++) { $TextToWrite += "`t" } } # Add Space(s) after Main text If ($PostLine -gt 0) { for ($i = 0; $i -lt $PostLine; $i++) { $TextToWrite += "`n" } } # Add empty line(s) after Main text If ($LogFile -eq "") { #No LogFile Specified - Skip } ElseIf(!(Test-Path -Path $LogFile)) { #Create Log File If Does Not Exist If ($NoNewLine) { $nf = New-Item -Path $LogFile -type file -force -Value $TextToWrite } Else { $nf = New-Item -Path $LogFile -type file -force -Value $TextToWrite`r`n } } Else { #Log File Exists If($Overwrite) { #Overwrite Log File If ($NoNewLine) { Set-Content -Path $LogFile -Value $TextToWrite -NoNewline } Else { Set-Content -Path $LogFile -Value $TextToWrite } } Else { #Append Log File Try { If ($NoNewLine) { Add-Content -Path $LogFile -Value $TextToWrite -ErrorAction Stop -NoNewline } Else { Add-Content -Path $LogFile -Value $TextToWrite -ErrorAction Stop } } Catch { Start-Sleep -s 3 If ($NoNewLine) { Add-Content -Path $LogFile -Value $TextToWrite -NoNewline } Else { Add-Content -Path $LogFile -Value $TextToWrite } } } } } End { #Nothing to Do Here } } Main
Compare RetroPie ROM Folders
This is intended to be used as the supplemental script (2_CompareFolderResults.ps1) to be used in conjunction with the 1_Clean-NoIntroRoms.ps1 and 3_CheckXML.ps1 scripts. This script allows you to compare the files/roms in 2 directories to show the differences in files of each folder by using the compare-object cmdlet. It is intended to compare the different results in 1_Clean-NoIntroRoms.ps1 when you change the filters for a system.
2_CompareFolderResults.ps1
See supplemental scripts:
- 1_Clean-NoIntroRoms.ps1 – Clean No-Intro 2018 ROMs by eliminating duplicates and keeping 1 x ROM per Game by using filters for preference
- 3_CheckXML.ps1 – Find missing scraped data in RetroPie by examining the gamelist.xml file for each game system on you RetroPie
Global Variable Definitions:
- $global:scriptName
- Name of the Script, defaults to full name of the script
- $global:scriptVersion
- Script Version
- $global:romsPath
- Initial root folder containing ROMs for each No-Intro Game System, equivalent to “roms” directory on RetroPie
- $global:roms1Path
- Secondary root folder containing ROMs for each No-Intro Game System to compare to initial root folder. If you want to test modifying filters on 1_Clean-NoIntroRoms.ps1, you can use this directory to compare your results
- $global:logFile
- Log file output of the entire run. Default is a “logs” directory in the same directory as the script with a log name that matches the script’s base name. Ex: .\logs\1_Clean-NoIntroRom.log
- $global:logOverwrite
- Overwrite the log file. Default is $true
- $global:romNoIntroHashTable
- Hashtable setting each game systems directory name on RetroPie and in the No-Intro 2018 complete ROM set. Default directory names are used for each. Uses the No-Intro Directory Name for comparing game systems in $global:romsPath and $global:roms1Path
#CompareFolderResults.ps1 #5.3 # -Added Changelog in Comments #5.2 # -Added variables for Write-Out Colors and Updated to Write-Out v1.3 #5.1 # -No Changes #5.0 # -New Release $global:scriptName = $PSCommandPath $global:scriptVersion = "v5.3" $global:romsPath = "C:\Games\RetroPie\roms\" $global:roms1Path = "C:\Games\RetroPie\roms1\" $global:logFile = (Split-Path -Path $PSCommandPath -Parent) + "\logs\" + (Split-Path -Path $PSCommandPath.Replace(".ps1",".log") -Leaf) $global:logOverwrite = $true $global:romNoIntroHashTable = [ordered]@{ #RetroPieDirName = No-IntroDirName "atari2600" = "Atari - 2600" "atari5200" = "Atari - 5200" "atari7800" = "Atari - 7800 [Headered]" "atarilynx" = "Atari - Lynx [Headered]" "atarijaguar" = "Atari - Jaguar" "atarist" = "Atari - ST" "coleco" = "Coleco - ColecoVision" "fds" = "Nintendo - Family Computer Disk System [headered]" "gamegear" = "Sega - Game Gear" "gb" = "Nintendo - Game Boy" "gba" = "Nintendo - Game Boy Advance" "gbc" = "Nintendo - Game Boy Color" "mastersystem" = "Sega - Master System - Mark III" "megadrive" = "Sega - Mega Drive - Genesis" "msx" = "Microsoft - MSX" "n64" = "Nintendo - Nintendo 64" "nes" = "Nintendo - Nintendo Entertainment System [headered]" "ngp" = "SNK - Neo Geo Pocket" "ngpc" = "SNK - Neo Geo Pocket Color" "pcengine" = "NEC - PC Engine - TurboGrafx 16" "sega32x" = "Sega - 32X" "sg-1000" = "Sega - SG-1000" "snes" = "Nintendo - Super Nintendo Entertainment System" "vectrex" = "GCE - Vectrex" "virtualboy" = "Nintendo - Virtual Boy" "wonderswan" = "Bandai - WonderSwan" "wonderswancolor" = "Bandai - WonderSwan Color" } #Output Color Variables $global:colorMain = "Green" $global:colorSub1 = "Green" $global:colorSub2 = "DarkGreen" $global:colorSub3 = "DarkRed" $global:colorOk = "Green" $global:colorWarn = "Yellow" $global:colorError = "Red" Function Main() { #Powershell 4 or greater is required If (!($PSVersionTable.PSVersion.Major -ge 4) -OR ($PSVersionTable.PSVersion -eq $null)) { Write-Host -ForegroundColor $global:colorError "Powershell v4 or greater is required, quitting script!" Exit } #Create Log File If ($global:logOverwrite -eq $true) { Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile -Overwrite } Else { Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile } Write-Out -ForegroundColor $global:colorMain -Text "INITIALIZE" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Script Name : $global:scriptName" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Version: : $global:scriptVersion" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Dir : $($global:romsPath)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Dir1 : $($global:roms1Path)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log File : $($global:logFile)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log Overwrite : $($global:logOverwrite)" -LogFile $global:logFile $tStart = (Get-Date) Write-Out -ForegroundColor $global:colorMain -Text "* Start Time : $($tStart)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile $diffCount = 0 ForEach ($key in $global:romNoIntroHashTable.keys) { Write-Out -PreLine 1 -Text "PROCCESSING ($($key)): $($global:romsPath | Split-Path -Leaf) :: $($global:roms1Path | Split-Path -Leaf)" -ForegroundColor $global:colorSub1 -LogFile $global:logFile Write-Out -Text "----------------------------------------------------------" -ForegroundColor $global:colorSub1 -LogFile $global:logFile If ((Test-Path -LiteralPath "$($global:romsPath)$($key)" -PathType Container) -AND (Test-Path -LiteralPath "$($global:roms1Path)$($key)" -PathType Container)) { $fso = Get-ChildItem -Recurse -File -Path "$($global:romsPath)$($key)" $fso1 = Get-ChildItem -Recurse -File -Path "$($global:roms1Path)$($key)" If ($fso.Count -gt 0 -AND $fso1.Count -gt 0) { $results = Compare-Object -ReferenceObject $fso -DifferenceObject $fso1 $diffFound = $false ForEach ($r in $results) { If ($r.SideIndicator -eq "<=") { $diffFound = $true $diffCount++ Write-Out -Text "$($r.SideIndicator) $($r.InputObject)" -ForegroundColor $global:colorSub2 -LogFile $global:logFile } ElseIf ($r.SideIndicator -eq "=>") { $diffFound = $true $diffCount++ Write-Out -Text "$($r.SideIndicator) $($r.InputObject)" -ForegroundColor $global:colorSub3 -LogFile $global:logFile } Else { #Not Different } } If ($diffFound -eq $false) { Write-Out -Text "No Differences Found" -ForegroundColor $global:colorSub2 -LogFile $global:logFile } } Else { Write-Out -Text "ROM Folder(s) Do Not Have ROMs" -ForegroundColor $global:colorError -LogFile $global:logFile } } Else { Write-Out -Text "ROM Folder(s) Do Not Exist" -ForegroundColor $global:colorError -LogFile $global:logFile } } #Results Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "END RESULTS" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile $tEnd = (Get-Date) Write-Out -ForegroundColor $global:colorMain -Text "* Differences Found : $($diffCount)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Start Time : $($tStart)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* End Time : $($tEnd)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Elapsed Time : $([math]::Round(($tEnd-$tStart).totalseconds, 2)) seconds" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile } Function Write-Out { <# .SYNOPSIS Write output to console and/or log file. Supports multiple foreground and background colors on a single line and advanced options to insert lines, spaces, or tabs before or after the text as well as timestamps. .DESCRIPTION Uses Write-Host to output color text to the console, and supports using multiple foreground and background colors on a single line. Uses Set-Content and Add-Content to output to a file. It works by accepting strings as an array and then you can assign the foreground or background colors by passing them as arrays for the matching text. It also accepts Default which allows you skip specifying a color and use the default. This function requires Powershell 4.0 to support the alias attribute in the function. .PARAMETER Text Optional. Array of strings to write to console/log. If you do not need to use multiple colors on a single line you can pass a single string instead of an array of strings. Otherwise, if you need to multiple colors on a single line pass an array of strings and associated colors using -ForegroundColor, -BackgroundColor, -ForegroundColorDefault, or -BackgroundColorDefault. .PARAMETER ForegroundColor Optional. Array of foreground Colors to write to console. Default means the ForegroundColorDefault value is used. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER ForegroundColorDefault Optional. Default foreground color to write to console. Default is set to white. Valid Colors: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackgroundColor Optional. Array of background colors to write to console. Default means the BackgroundColorDefault value is used. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackgroundColorDefault Optional. Default background color to write to console. Default is none. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER PreLine Optional. Add blank lines before your text. Default is 0. .PARAMETER PreSpace Optional. Add spaces before your text. Default is 0. .PARAMETER PreTab Optional. Add Tabs before your text. Default is 0. .PARAMETER TimeStampFormat Optional. Format used for time stamps. Default is 'yyyy-MM-dd HH:mm:ss' .PARAMETER TimeStamp Optional. Adds time stamp in square brackets before your text. .PARAMETER ClearHost Optional. Clear the console before your text. .PARAMETER PostLine Optional. Add blank lines after your text. Default is 0. .PARAMETER PostSpace Optional. Add spaces after your text. Default is 0. .PARAMETER PostTab Optional. Add tabs after your text. Default is 0. .PARAMETER NoNewLine Optional. Do not add a new line after your text and optional post text options. Default is to add a new line. .PARAMETER LogFile Optional. Absolute or relative path of the log file. .PARAMETER Overwrite Optional. Ovewrite the log file. Default is to append to the log file. .INPUTS Parameters above .OUTPUTS None .NOTES Author: Brian Steinmeyer URL: http://sigkillit.com/ Created: 4/18/2020 Version 1.3 - Added LogOnly Option for only writing text to a log file Version 1.2 - Set Text, ForegroundColor, and BackgroundColor to default value of @() to fix errors checking counts in some circumstances - Fixed an issue where ForegroundColorDefault and BackgroundColorDefault were not working properly in some circumstances - Added Requires -Version 4.0 Version 1.1 - Completely rewrote the "Main Text" section - Added "Default" as a color option, which allows you to use the default values for foreground/background - Useful when you want to specify a backgroundcolor in certain parts of a line like the middle - Ex: Write-Out -Text "How to ","highlight ","the middle text" -BackgroundColor Default,Yellow,Default Version: 1.0 - Initial Creation inspired by PSWriteColor (https://github.com/EvotecIT/PSWriteColor) - Improved upon by switching Foreground and Background Colors to default values if colors are not specifid for all strings. Will also ignore extra colors if more colors are specified than strings specified. .EXAMPLE Write-Out -Text "Start with Red Text ","Then Switch to Blue Text ","Now Magenta" -ForegroundColor Red,Blue,Magenta .EXAMPLE Write-Out -Text "White on Black ","Black on White ","Dark Cyan on Cyan ","Yellow on Green ","Default Color" -ForegroundColor White,Black,DarkCyan,Yellow -BackgroundColor Black,White,Cyan,Green .EXAMPLE Write-Out -Text "Make this"," entire line"," the same color by setting defaults" -ForegroundColorDefault Yellow -BackgroundColorDefault Magenta .EXAMPLE Write-Out -Text "Add a blank line and two tabs ","before ","my text" -ForegroundColor Green,Cyan,White -PreLine 1 -PreTab 2 .EXAMPLE Write-Out -Text "Add two blank ","lines ","after my text" -ForegroundColor White,Green,White -PostLine 2 .EXAMPLE Write-Out -Text "Add 3 spaces before my text" -ForegroundColor Gray -Prespace 3 .EXAMPLE Write-Out -Text "White text and a tab after" -ForegroundColor White -NoNewLine -PostTab 1 Write-Out -Text "Black text on Yellow ","and then back to white" -ForegroundColor Black,White -BackgroundColor Yellow .EXAMPLE Write-Out -Text "An easy way to ","highlight ","text in the middle" -BackgroundColor Default,Yellow .EXAMPLE Write-Out -Text "You can even add a ","time stamp ","before your output" -ForegroundColor White,Green,White -TimeStamp -PreLine 3 .EXAMPLE Write-Out -Text "You can change the ","time stamp format" -ForegroundColor White,Yellow -TimeStamp -TimeStampFormat "dd-MM-yyy HH:mm" -PreLine 1 -PostLine 1 .EXAMPLE Write-Out -Text "An"," Error"," occurred let's write overwrite/create a new log file" -ForegroundColor White,Red,White -TimeStamp -LogFile "script.log" -Overwrite .EXAMPLE Write-Out -Text "Now you can ","Append ","this line to your log file" -ForegroundColor Cyan,Magenta -TimeStamp -LogFile "script.log" #> [CmdletBinding()] Param ( [Parameter(Mandatory=$false)] [AllowEmptyString()] [alias ('T')] [String[]] $Text = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('FGC', 'FC')] [string[]] $ForegroundColor = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('FGCD', 'FCD')] [string] $ForegroundColorDefault = [ConsoleColor]::White, [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('BGC', 'BC')] [String[]] $BackgroundColor = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('BGCD', 'BCD')] [string] $BackgroundColorDefault = "Default", [Parameter(Mandatory=$false)] [int] $PreLine = 0, [Parameter(Mandatory=$false)] [int] $PreSpace = 0, [Parameter(Mandatory=$false)] [int] $PreTab = 0, [Parameter(Mandatory=$false)] [Alias('TSF', 'TS')] [string] $TimeStampFormat = 'yyyy-MM-dd HH:mm:ss', [Parameter(Mandatory=$false)] [switch] $TimeStamp, [Parameter(Mandatory=$false)] [switch] $ClearHost, [Parameter(Mandatory=$false)] [int] $PostLine = 0, [Parameter(Mandatory=$false)] [int] $PostSpace = 0, [Parameter(Mandatory=$false)] [int] $PostTab = 0, [Parameter(Mandatory=$false)] [switch] $NoNewLine = $false, [Parameter(Mandatory=$false)] [alias ('Log', 'L')] [string] $LogFile = '', [Parameter(Mandatory=$false)] [switch] $LogOnly = $false, [Parameter(Mandatory=$false)] [switch] $Overwrite = $false ) Begin { #Nothing to Do Here } Process { #Optional - Do Not Write to ConsoleColor If (!($LogOnly)) { #Optional - Prefix Text If ($ClearHost) { Clear-Host } If ($PreLine -gt 0) { For ($i = 0; $i -lt $PreLine; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line(s) before Main text If ($PreSpace -gt 0) { For ($i = 0; $i -lt $PreSpace; $i++) { Write-Host -Object " " -NoNewLine } } # Add Tab(s) before Main text If ($PreTab -gt 0) { For ($i = 0; $i -lt $PreTab; $i++) { Write-Host -Object "`t" -NoNewLine } } # Add Space(s) before Main text If ($TimeStamp) { Write-Host -Object "[$([datetime]::Now.ToString($TimeStampFormat))]" -NoNewline } # Add Timestamp before Main Text #MAIN TEXT If (($Text.Count -gt 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -eq 0)) { #Text Only Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColorDefault -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -gt 0) -AND ($BackgroundColor.Count -eq 0)) { #Text and ForegroundColor Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($ForegroundColor.Count -le $i) { $ForegroundColor += $ForegroundColorDefault } #ForegroundColor Not Specified Set to Default If ($ForegroundColor[$i] -eq "Default") { $ForegroundColor[$i] = $ForegroundColorDefault } If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColorDefault -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -gt 0)) { #Text and BackgroundColor Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($BackgroundColor.Count -le $i) { $BackgroundColor += $BackgroundColorDefault } #BackgroundColor Not Specified Set to Default If ($BackgroundColor[$i] -eq "Default") { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColorDefault -NoNewLine } } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColor[$i] -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -gt 0) -AND ($BackgroundColor.Count -gt 0)) { #Text, ForegroundColor, and BackgroundColor Specified (FAILS NOT WRITING DEFAULT) For ($i = 0; $i -lt $Text.Count; $i++) { If ($ForegroundColor.Count -le $i) { $ForegroundColor += $ForegroundColorDefault } #ForegroundColor Not Specified Set to Default If ($BackgroundColor.Count -le $i) { $BackgroundColor += $BackgroundColorDefault } #BackgroundColor Not Specified Set to Default If ($ForegroundColor[$i] -eq "Default") { $ForegroundColor[$i] = $ForegroundColorDefault } If ($BackgroundColor[$i] -eq "Default") { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColorDefault -NoNewLine } } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColor[$i] -NoNewLine } } } Else { #No Text, ForegroundColor, or BackgroundColor Specified ($Text.Count -eq 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -eq 0) } #Post Text If ($PostSpace -gt 0) { for ($i = 0; $i -lt $PostSpace; $i++) { Write-Host -Object " " -NoNewLine } } # Add Tab(s) after Main text If ($PostTab -gt 0) { for ($i = 0; $i -lt $PostTab; $i++) { Write-Host -Object "`t" -NoNewLine } } # Add Space(s) after Main text If ($PostLine -gt 0) { for ($i = 0; $i -lt $PostLine; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line(s) after Main text If ($NoNewLine) { Write-Host -NoNewline } else { Write-Host } # Add New Line after Main Text Unless NoNewLine is Supplied } #Log File $TextToWrite = "" #Build Text to Write to Log File If ($PreLine -gt 0) { For ($i = 0; $i -lt $PreLine; $i++) { $TextToWrite += "`n" } } # Add empty line(s) before Main text If ($PreSpace -gt 0) { For ($i = 0; $i -lt $PreSpace; $i++) { $TextToWrite += " " } } # Add Tab(s) before Main text If ($PreTab -gt 0) { For ($i = 0; $i -lt $PreTab; $i++) { $TextToWrite += "`t" } } # Add Space(s) before Main text If ($TimeStamp) { $TextToWrite += "[$([datetime]::Now.ToString($TimeStampFormat))]" } # Add Timestamp before Main Text If ($Text.Count -gt 0) { For ($i = 0; $i -lt $Text.Count; $i++) { $TextToWrite += $Text[$i] } } #Add Main Text If ($PostSpace -gt 0) { for ($i = 0; $i -lt $PostSpace; $i++) { $TextToWrite += " " } } # Add Tab(s) after Main text If ($PostTab -gt 0) { for ($i = 0; $i -lt $PostTab; $i++) { $TextToWrite += "`t" } } # Add Space(s) after Main text If ($PostLine -gt 0) { for ($i = 0; $i -lt $PostLine; $i++) { $TextToWrite += "`n" } } # Add empty line(s) after Main text If ($LogFile -eq "") { #No LogFile Specified - Skip } ElseIf(!(Test-Path -Path $LogFile)) { #Create Log File If Does Not Exist If ($NoNewLine) { $nf = New-Item -Path $LogFile -type file -force -Value $TextToWrite } Else { $nf = New-Item -Path $LogFile -type file -force -Value $TextToWrite`r`n } } Else { #Log File Exists If($Overwrite) { #Overwrite Log File If ($NoNewLine) { Set-Content -Path $LogFile -Value $TextToWrite -NoNewline } Else { Set-Content -Path $LogFile -Value $TextToWrite } } Else { #Append Log File Try { If ($NoNewLine) { Add-Content -Path $LogFile -Value $TextToWrite -ErrorAction Stop -NoNewline } Else { Add-Content -Path $LogFile -Value $TextToWrite -ErrorAction Stop } } Catch { Start-Sleep -s 3 If ($NoNewLine) { Add-Content -Path $LogFile -Value $TextToWrite -NoNewline } Else { Add-Content -Path $LogFile -Value $TextToWrite } } } } } End { #Nothing to Do Here } } Main
RetroPie Install Guide RaspberryPi 4
This is the updated article specifically for the RetroPie on the RaspberryPi 4 with the Retroflag NESPi 4 Case. This will support up to most systems up until Playstation 1 (PS1). If you’re interested in RetroPie on the RaspberryPi 3/3B+, you can refer to my original article but please note this one has some additional information that still applies.


Hardware Used
Here is the hardware and pricing on my build. You can lessen the cost by using existing hardware or replacing it with cheaper items. The important items are the Raspberry Pi 4B & RetroFlag NESPi 4 Case.
- RaspberryPi 4 Model B 4GB RAM
- $59 on Amazon
- Note: No need to get 8GB as it does not affect game performance
- SanDisk 128GB Extreme microSDXC UHS-I Memory Card
- $24.88 on Amazon
- Note: You can go much smaller if you plan to store ROMs on a SSD such as an 8GB card for about $8
- RetroFlag NESPi 4 Case
- $39.99 on Amazon
- Exact replicate of NES, functioning power & reset buttons, removable USB 3.0 SSD HDD, and all cables moved to the back now. Retroflag makes cases for other
- Optional: Western Digital 1TB WD Blue 3D NAND Internal PC SSD
- $104.99 on Amazon
- Although optional, I would recommend this to store the ROMs as USB 3.0 gives better performance for an SSD vs. the microSD card and more longevity
- Optional: 2 x 8Bitdo Sn30 Pro+ Bluetooth Gamepad
- $49.99 each on Amazon
- Note: You can use an existing PS/XBox controller or a much cheaper USB controller.
- Optional: Rii mini i8+ Keyboard
- $19.95 on Amazon
- Note: You can use an existing USB or USB Wireless keyboard
Software Used
Resources
- RetroPie Install Guide
- Update/Backup RetroPie
- Supported RetroPie Emulators
- Skyscraper
- Setup 8Bitdo Bluetooth Controller
- Check MD5 Hash on a File In Windows (Useful to verify BIOS Hashes)
- certutil -hashfile c:\folder\bios.bin MD5
- Note: Replace MD5 with the MD5 hash of the file
- Run ROMs from a USB Drive
- Clean No-Intro 2018 ROM set
Update 8Bitdo Controller Firmware
- Download the latest 8Bitdo Controller Firmware on a Windows Computer
- Run the update utility and follow the onscreen instructions
Create RetroPie SD Card
- Download RetroPie image on a Windows Computer
- Extract the image using 7zip
- Connect the Micro SD card to the computer using a MicroSD card reader
- In Windows, use balena Etcher to write the image on a MicroSD Card
- Note: It will format the card for you. If needed, you can format the card as fat so windows will recognize it prior to running etcher
Install the RaspberryPi Into the Case
- Make sure the case is powered off
- Install the RaspberryPi into the Retroflag case as per the directions
- Switch the Safe Shutdown switch to ON
- Connect the Micro HDMI cable, Ethernet Cable, keyboard USB dongle, insert the microSD card, and insert the power USB-C cable
- NOTE: Do NOT mount the SSD Into the Cartridge Case yet, we will need to format it as exFat or FAT32 on a PC using directions later in this article!
Configure US Keyboard on First Boot
- Make sure the keyboard dongle is connected and the keyboard is charged and powered on
- Turn the power to “ON” on the case
- On the Welcome Screen, hold any button on the keyboard to configure it, and configure it as follows:
- D-PAD UP: Up Arrow
- D-PAD DOWN: Down Arrow
- D-PAD LEFT: Left Arrow
- D-PAD RIGHT: Right Arrow
- START: 1
- SELECT: 2
- Button A / East: Enter (Same as OK key)
- Button B /South: Escape
- For all other keys, hold any button to skip configuring
- When OK is highlighted, press the Enter button
- When prompted about not enabling a hotkey button, highlight YES and press Enter to use the default select button
- Navigate to the RetroPie menu and press Enter on the keyboard
- Select RASPI-CONFIG and press Enter on the keyboard
- Select Localization Options and press Enter on the keyboard
- Select Change Keyboard Layout and press Enter on the keyboard
- Select Generic 105-key (Intl) PC and press Enter on the keyboard
- For the keyboard layout, select Other and press Enter on the keyboard
- Select English (US) and press Enter on the keyboard
- Select English (US) and press Enter on the keyboard
- Select Default Keyboard Layout and press Enter on the keyboard
- Select No Composer Key and press Enter on the keyboard
- Select Finish and press Enter on the keyboard
- Select RASPI-CONFIG and press Enter on the keyboard
Optional – Connect WiFi (Skip if using Wired LAN)
- Navigate to the RetroPie menu and press Enter on the keyboard
- Select RASPI-CONFIG and press Enter on the keyboard
- Select Localization Options and press Enter on the keyboard
- Select Change WI-FI Country and press Enter on the keyboard
- Select United States and press Enter on the keyboard
- Press OK on the success message
- Select Finish and press Enter on the keyboard
- *Select WIFI and press OK on the keyboard
- Select Connect to WIFI network and press Enter on the keyboard
- Select the SSID, and press Enter on the keyboard
- Enter the SSID PSIK and press Enter on the keyboard
- Select Exit and press Enter on the keyboard
Optional – Enable SSH (Useful later for scraping ROMs)
- Navigate to the RetroPie menu and press Enter on the keyboard
- Select RASPI-CONFIG and press Enter on the keyboard
- Select Interface Options and press Enter on the keyboard
- Select SSH and press Enter on the keyboard
- Select Yes to enable SSH and press Enter on the keyboard
- Press OK to confirm SSH is enabled
- Select Finish and press Enter on the keyboard
Optional – Update RetroPie
- Navigate to the RetroPie menu and press Enter on the keyboard
- Select RETROPIE SETUP and press Enter on the keyboard
- Select Update and press Enter on the keyboard
- When prompted, select Yes and press Enter on the keyboard
- Press OK/YES to all proceeding messages
- Select Exit and press Enter on the keyboard
- If Retropie Does Not Boot Emulation Station and is stuck asking for the retropie login
- Login as pi
- Navigate to the RetroPie menu and press Enter on the keyboard
- Select RASPI-CONFIG and press Enter on the keyboard
- Select Boot Options and press Enter on the keyboard
- Select Desktop/CLI and press Enter on the keyboard
- Select Console Autologin and press Enter on the keyboard
- Select Finish and press Enter on the keyboard
- Select Yes to reboot and press Enter on the keyboard
- It should not restart and autologin to emulationstation again
Add the RetoFlag Safe Shutdown Script for Power/Reset Buttons
I personally recommend using crcerror’s forked version of the retroflag script vs. the official retroflag version of the script for the power/reset buttons. Here are the differences and instructions to install either:
- crcerror Script
- Button Functions:
- Press Reset in Emulator: Exits emulator back to Emulationstation
- Press Reset in Emulationstation: Restarts Emulationstation
- Press Reset in Console: Restart the RaspberryPi
- Press Power in Console, Emulationstation, or ROM Emulator: Shutdown the RaspberryPi
- Install Directions:
- Ensure you are connected to the internet & the keyboard is connected
- Press F4 to enter the terminal
- In the terminal, type the one-line command below (Case Sensitive):
- wget -O – “https://raw.githubusercontent.com/crcerror/retroflag-picase/master/install.sh” | sudo bash
- RetroPie will restart once complete
- Button Functions:
- Retroflag Script
- Button Functions:
- Press Reset in Emulator/Emulationstation: Restart the RaspberryPi
- Press Reset in Console: Nothing
- Press Power in Emulator/Emulationstation: Shutdown the RaspberryPi
- Press Power in Console: Nothing
- Install Directions:
- Ensure you are connected to the internet & the keyboard is connected
- Press F4 to enter the terminal
- In the terminal, type the one-line command below (Case Sensitive):
- wget -O – “https://raw.githubusercontent.com/RetroFlag/retroflag-picase/master/install.sh” | sudo bash
- RetroPie will restart once complete
- Button Functions:
Setup Bluetooth Controllers
This is written for the 8Bitdo controllers, but should be the same for any Bluetooth controller
- Navigate to the RetroPie menu and press Enter on the keyboard
- Select BLUETOOTH and press Enter on the keyboard
- Make sure 8Bitdo mapping hack is set to off
- Power on the 8Bitdo controller by holding the start button until the blue light comes on. Once it is blinking, set it to pairing mode by holding the select button for 3 seconds and the blue light will start rapidly blinking
- Select Register and Connect Bluetooth Device and press Enter on the keyboard
- The controller will show up with its MAC address as 8Bitdo, select it and press Enter on the keyboard
- Select DisplayYesNo and press Enter on the keyboard
- Repeat for each additional controller
- Select Setup udev rule for joypad and press Enter on the keyboard
- Select an 8Bitdo controller and press Enter on the keyboard
- Press Enter on the keyboard to confirm the entry was added
- Select Cancel and press Enter on the keyboard to return to Emulationstation
- Press 1 on the keyboard to bring up the Main Menu
- Select Configure Input and press Enter on the keyboard
- When prompted to configure input, press Enter on the keyboard
- Hold any key on the 8Bitdo SNES30 controller and configure it as follows
- D-PAD UP: Up Arrow
- D-PAD DOWN: Down Arrow
- D-PAD LEFT: Left Arrow
- D-PAD RIGHT: Right Arrow
- START: Start
- SELECT: Select
- A: A
- B: B
- X: X
- Y: Y
- LEFT SHOULDER: L
- RIGHT SHOULDER: R
- For all others, hold any button to skip configuration (Or use the keyboard to skip down to OK)
- When OK is highlighted, press the Enter on the keyboard
- When prompted about not enabling a hotkey button, highlight YES and press Enter on the keyboard to use the default select button
- Repeat for each Controller
- Press 1 on the keyboard to bring up the Main Menu
- Select Quit and press Enter on the keyboard
- Select Restart System and press Enter on the keyboard
- Select Yes to confirm the restart and press Enter on the keyboard
Install Optional Emulators
System | OPT Emulator | Note |
Apple II | linapple | |
Atari ST | hatari | |
Commodor 64 | vice | |
Coleco Vision | lr-blueMSX | coolcv not supported on Pi4 due to video drivers at this time, using lr-blueMSX instead |
Dragon 32 / Tandy CoCo | xroar | |
Intellivision | lr-freeintv | |
MSX | lr-fmsx | Adds the following files to BIOS folder: CARTS.SHA, CYRILLIC.FNT, DISK.ROM, FMPAC.ROM, FMPAC16.ROM, ITALIC.FNT, KANJI.ROM, MSX.ROM, MSX2.ROM, MSX2EXT.ROM, MSX2P.ROM, MSX2PEXT.ROM, MSXDOS2.ROM, PAINTER.ROM, RS232.ROM |
Virtual Boy | lr-beetle-vb | |
Wonderswan / Wonderswan Color | lr-beetle-wswan | |
Zmachine | frotz | Includes Zork 1, 2, and 3 |
- Navigate to RetroPie menu and press Enter on the keyboard
- Select RETROPIE SETUP and press Enter on the keyboard
- Select Manage packages and press enter on the keyboard
- Select Manage Optional packages and press enter on the keyboard
- Select %EMULATOR_NAME% and press enter on the keyboard
- Select Install from source (latest) or Install from binary and press Enter on the keyboard and wait for the installer to finish
- Select Back and press Enter on the keyboard
- Select Back and press Enter on the keyboard
- Select Back and press Enter on the keyboard
- Select Exit and press Enter on the keyboard
- Select Yes and press Enter on the keyboard
Install Experimental Emulators
System | Exp Emulator | Note |
Nintendo DS | drastic | |
Atari Jaguar | lr-virtualjaguar | Does not run great on PI4 still, reports that lr-mess works well |
- Navigate to RetroPie menu and press Enter on the keyboard
- Select RETROPIE SETUP and press Enter on the keyboard
- Select Manage packages and press enter on the keyboard
- Select Manage Optional packages and press enter on the keyboard
- Select %EMULATOR_NAME% and press enter on the keyboard
- Select Install from source (latest) or Install from binary and press Enter on the keyboard and wait for the installer to finish
- Select Back and press Enter on the keyboard
- Select Back and press Enter on the keyboard
- Select Back and press Enter on the keyboard
- Select Exit and press Enter on the keyboard
- Select Yes and press Enter on the keyboard
Add BIOS and Config Files to the SD Card
- From a Windows computer containing the BIOS and Config Files, open the samba share for the RetroPie by entering \\retropie
- If this does not work, navigate to the RetroPie menu, press Enter on the keyboard, select Show IP, press OK on the keyboard and note the IP then press Enter on the keyboard
- Try to access the samba share for the RetroPie by using the IP address noted above: \\IPADDRESS
- Copy the BIOS files to the BIOS Share
- OPTIONAL – Copy Configs to the CONFIGS share
- You only need to do this if you have previous configurations backed up & do not want to treat this as a brand new install
Prepare the SSD and Copy ROMS
Note: See my article on cleaning ROM collections:
http://sigkillit.com/2019/06/19/clean-no-intro-2018-rom-set/
- Plug the SSD into a Linux or Windows PC and format the SSD drive as exFAT or FAT32
- Create a folder called retropie-mount on the root of the drive
- Mount the SSD drive into the RetroFlag “Cartridge” case
- Install the cartridge into the RetroFlag case and ensure the SSD firmly inserts into the connector and then power on the RetroPie
- It will proceed to automatically copy the Retropie folder and all of its content (You may need to reboot to start the copy)
- From a Windows computer containing the ROM Files, open the samba share for the RetroPie by entering \\retropie
- If this does not work, navigate to the RetroPie menu, press Enter on the keyboard, select Show IP, press OK on the keyboard and note the IP then press Enter on the keyboard
- Try to access the samba share for the RetroPie by using the IP address noted above: \\IPADDRESS
- Copy your ROMs to the ROMS share
Special Configurations for ROMs to Work Properly
Atari 800 / Atari 5200 Load BIOS
- Launch an Atari 800/5200 game
- If you launched a 5200 game, select Standard 5200 cartridge option or if you launched a 800 game you won’t see this prompt just continue. You’ll get a warning that you need a real Atari/OS.
- Press F1 on the keyboard to open the menu
- Select Emulator Configuration and press enter on the keyboard
- Select System ROM Settings and press enter on the keyboard
- Select Find ROM images in a directory, navigate to the BIOS directory (/home/pi/RetroPie/BIOS) and press the space bar on the keyboard to select that directory.
- Press Escape on the keyboard to go back a menu
- Select Save Configuration File and press enter on the keyboard
- Select Save Configuration on Exit and press enter on the keyboard
- Press Escape on the keyboard to go back a menu
- Select Exit Emulator and press enter on the keyboard
- If you have the correctly named BIOS files and it should automatically configure them
Atari 5200 Auto Load Game (Prevents Memo Pad from Loading)
If the screen loads to a blue memo pad instead of loading the game, this is because it’s set to an 800 system. You can press F1 and load the rom fine each time or you can do the following to override it
- Launch the Atari 5200 game
- Press the Select + X (Hotkey + X) to bring up the Quick Menu
- Select Options and press enter on the keyboard
- Select Atari System and press the right arrow to select 5200
- Press B to return to the previous menu
- Select Resume and press A to return to the game
- Test to see if it works now. If it works, you can permanently save it by going back to Controls and selecting Save Core Overrides
Atari 800 / Atari 5200 Configure Controller
- Launch Atari 800/5200 game
- Press the Select + X (Hotkey + X) to bring up the Quick Menu
- Select Controls and press A
- Next to user 1 Device Type, press the right arrow to select Atari Joystick
- Press B to return to the previous menu
- Select Resume and press A to return to the game
- Test to see if it works now. If it works, you can permanently save it by going back to Controls and selecting Save Core Overrides
Sinclair ZX Spectrum
Not all games will work with a joystick! However, if the input does not seem to be working
- Launch a ZX Spectrum game
- Press the Select + X (Hotkey + X) to bring up the Quick Menu
- Select Controls and press A
- Next to user 1 Device Type, press the right arrow to select Kempton Joystick or Cursor Joystick
- Press B to return to the previous menu
- Select Resume and press A to return to the game
- Test to see if it works now. If it works, you can permanently save it by going back to Controls and selecting Save Core Overrides
Install Skyscraper
- Press F4 on the keyboard to exit emulationstation and enter the terminal
- Enter the following command at the terminal:
- sudo ~/RetroPie-Setup/retropie_setup.sh
- Select Manage Packages and press Enter on the keyboard
- Select Optional Packages and press Enter on the keyboard
- Select Skyscraper and press Enter on the keyboard
- Select Install from pre-built biner or Install from source and press Enter on the keyboard
- Select Back and press Enter on the keyboard (Repeat 3x’s)
- Select Exit and press Enter on the keyboard
- Optional – Add Login for screenscraper.fr, enter the following command at the terminal:
- sudo nano /opt/retropie/config/all/skyscraper/config.ini
- Add the below lines
- [screenscraper]
- userCreds=”USER:PASSWORD”
- Replace USER with your username and PASSWORD with your password
- Press Ctrl + O then press Enter on the keyboard to save the file
- Press Ctrl + X to exit
- Type emulationstation and press Enter to go back to emulationstation
Scrape ROMs with Skyscraper
Scrape All Game Data
- Press F4 on the keyboard to exit emulationstation and enter the terminal
- Note: once you exit emulationstation, you can SSH into the PI so you can use your TV while you wait for the ROM scrapes to occur which take hours to days. The default username is pi and password is raspberry
- Enter the following command at the terminal:
- sudo ~/RetroPie-Setup/retropie_setup.sh
- Select Manage Packages and press Enter on the keyboard
- Select Optional Packages and press Enter on the keyboard
- Select Skyscraper and press Enter on the keyboard
- Select Configuration/Options and press Enter on the keyboard
- Select Gather Source and press Enter on the keyboard
- Choose the source, I recommend using ScreenScraper and TheGamesDB. SkyScraper will use both sources to give you the most complete data
- Select Gather Resources and press Enter on the keyboard
- Select the game system you want to scrape (suggest 1 at a time as it takes a few hours & the sources will limit the # of scrapes in a time limit) and press Enter on the keyboard
- Note: This caches the game info & images in \\retropie\configs\all\skyscraper\ and only needs run once unless you add new games. It then uses this cache to build the game info, which greatly increases the speed since it all local. However, you will need to monitor the size of the cache to make sure it does not fill the SD card.
- Select Generate Games Lists and press Enter on the keyboard
- Select the game system(s) you want to scrape and press Enter on the keyboard
- Note: This builds the game images, description, etc
- Select Run on all systems and press Enter on the keyboard then WAIT!
Fix Incorrect or Missing Scrape Data From ScreenScraper
I found what I consider to be errors or missing game data for some Games on the ScreenScraper DB or GameFAQs (Use it as a parent DB to add new Games) and submitted proposals to correct them or add data. However, some of my requests were denied. I’ve created custom fixes you can download here and the rest of the info will be pulled from TheGamesDB or Screenscraper as an additional source.
- Download the zip file here
- Unzip to file to \\retropie\configs\all\skyscraper\import\
- You will need to Gather Resources and select Import as the Source
Here’s a complete list of the corrections I made:
- coleco
- Super Action Soccer (USA, Europe) – Named the game “Super Action Football (soccer)” which causes potential duplicates with “Super Action Football” since the root names match and the brackets should be reserved for info such as region. My suggestion was denied to rename the game to something without brackets such as “Super Action Football aka Soccer” or “Super Action Football ‘Soccer'”. My fix overrides the Title and forces it to use TheGamesDB as the data source for the rest of the game instead of Screenscraper.
- gb
- 4 in 1 (Europe) (4B-001, Sachen-Commin) (Unl).txt
- 4 in 1 (Europe) (4B-002, Sachen) (Unl).txt
- 4 in 1 (Europe) (4B-004, Sachen-Commin) (Unl).txt
- 4 in 1 (Europe) (4B-005, Sachen-Commin) (Unl).txt
- 4 in 1 (Europe) (4B-006, Sachen) (Unl).txt
- 4 in 1 (Europe) (4B-007, Sachen) (Unl).txt
- 4 in 1 (Europe) (4B-008, Sachen) (Unl).txt
- 4 in 1 (Europe) (4B-009, Sachen) (Unl).txt
- 4 in 1 (Taiwan) (En,Zh) (4B-003, Sachen-Commin) (Unl).txt
- All of the above games scrape as “4-in-1 Fun Pak” instead of the proper “4 in 1” Sachen games. I tried submitting them as new games but was denied because Wikipedia was not a good enough source (https://en.wikipedia.org/wiki/Thin_Chen_Enterprise). My fix includes generic images and game info.
- gba
- 2 Games in 1 – Scooby-Doo + Scooby-Doo 2 – Monsters Unleashed (USA)
- 2 in 1 – Asterix & Obelix – Bash Them All! + Asterix & Obelix XXL (Europe) (En,Fr,De,Es,It,Nl)
- 2-in-1 Fun Pack – Shrek 2 + Madagascar (USA)
- Donkey Kong (USA) (Advance Play Edition)
- Double Game! – Golden Nugget Casino & Texas Hold ’em Poker (Europe)
- Golf (USA) (Advance Play Edition)
- Harry Potter Collection (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)
- Hugo 2 in 1 (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl)
- Kaisertal – Fight the Necronis War (Europe) (Demo)
- Pinball (USA) (Advance Play Edition)
- Soccer (USA) (Advance Play Edition)
- Tennis (USA) (Advance Play Edition)
- Winnie the Pooh’s Rumbly Tumbly Adventure & Rayman 3 (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)
- Yoshi’s Cookie (USA) (Advance Play Edition)
- My requests to add descriptions on the above were denied because any source with info was not good enough. My fix includes a description for these games.
- gbc
- Jurassic Boy II + Thunder Blast Man (World) (1B-002, 1B-003, Sachen) (Unl)
- Space Invasion & Karate Joe (Europe) (Unl)
- Space Invasion & Painter (Europe) (Unl)
- Space Invasion (Europe) (Unl)
- My requests to add descriptions on the above were denied because any source with info was not good enough. My fix includes a description for these games.
- snes
- PowerFest 94 – Ken Griffey Jr. Presents Major League Baseball (USA)
- PowerFest 94 – Super Mario Bros. – The Lost Levels (USA)
- PowerFest 94 – Super Mario Kart (USA)
- There is no separate game for the PowerFest 94 versions and it scrapes under the original game. My recommendation was denied because they consider it the same game with a timer. My fix overrides the Title and forces it to use TheGamesDB as the data source for the rest of the game instead of Screenscraper.
Remove Spam/Phishing Email From All Mailboxes
In 365, you can use Compliance Searches to search and/or remove emails across all of your user’s mailboxes. Compliance searches have replaced the Search-Mailbox cmdlet, which has been deprecated as of April 2020.
Pre-Requisites
You must be a member of the Discovery Management role group or be assigned the Compliance Search management role. Here’s how you can add a user to the Discovery Management group and confirm membership
#Connect to Security and Compliance Center $UserCredential = Get-Credential $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.compliance.protection.outlook.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection Import-PSSession $Session -DisableNameChecking #Add User to Discovery Management Group (Replace John Doe with your user) Add-RoleGroupMember -Identity "Discovery Management" -Member "John Doe" #Confirm Membership Get-RoleGroupMember -Identity "Discovery Management" #Disconnect Session Remove-PSSession $Session
Function to Search & Remove Spam/Phishing Emails From All Mailboxes
Modify the Search Variables below to suite your needs
Function RemoveMaliciousEmails() { #MODIFY THE BELOW VARIABLES - YOU MUST USE THEM ALL AND OPTIONALLY LEAVE SUBJECT BLANK!!! $compSearchName = "MaliciousEmail_$(Get-Date -Format "MMddyyyy_HHmm")" $compStartDate = "2020-02-24" #YYYY-MM-DD $compEndDate = "2020-02-25" #Must be different than Start Date, if searching "today" make this date tomorrow $compFrom = "hacker@phishing.com" #You can use just the domain for a wildcard sender BUT USE WITH CAUTION $compSubject = "Phishing Test" #Use backtick ` to escape special characters in the subject such as a quote ex: Dave shared `"New File`" with you # #DO NOT MODIFY ANYTHING BELOW HERE $UserCredential = Get-Credential $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.compliance.protection.outlook.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection Import-PSSession $Session -DisableNameChecking Write-Host "NAME: $($compSearchName)" Write-Host "START: $($compStartDate)" Write-Host "END: $($compEndDate)" Write-Host "FROM: $($compFrom)" Write-Host "SUBJECT: $($compSubject)" If ($compSubject.Trim() -eq "") { $ncs = New-ComplianceSearch -Name $compSearchName -ExchangeLocation all -ContentMatchQuery "(c:c)(received=$compStartDate..$compEndDate)(from=$compFrom)" } Else { $ncs = New-ComplianceSearch -Name $compSearchName -ExchangeLocation all -ContentMatchQuery "(c:c)(received=$compStartDate..$compEndDate)(from=$compFrom)(subject=`"$compSubject`")" } Write-Host "[$(Get-Date -Format G)] Start Compliance Search: $($compSearchName)" Write-Host -NoNewLine "[$(Get-Date -Format G)] Searching" Start-ComplianceSearch -Identity $compSearchName $resultSearch = Get-ComplianceSearch -Identity $compSearchName While ($resultSearch.Status -ne "Completed") { $resultSearch = Get-ComplianceSearch -Identity $compSearchName Write-Host -NoNewLine "." Start-Sleep -s 5 } If (($resultSearch.Items -le 0) -OR ([string]::IsNullOrWhiteSpace($resultSearch.SuccessResults))) { Write-Host "`n[$(Get-Date -Format G)] Search completed with 0 successful results, Invalid Search Quitting!" -ForegroundColor Red Remove-PSSession $Session Return } Elseif ($resultSearch.Items -ge 500) { Write-Host "`n[$(Get-Date -Format G)] Search Completed with $($resultSearch.Items) successful results, you will need to run mulitple times!" -ForegroundColor Yellow } Else { Write-Host "`n[$(Get-Date -Format G)] Search Completed with $($resultSearch.Items) successful results" } Write-Host "[$(Get-Date -Format G)] Create Preview and Export of Results" Write-Host -NoNewLine "[$(Get-Date -Format G)] Processing" $ncsa = New-ComplianceSearchAction -SearchName $compSearchName -Preview $resultPreview = Get-ComplianceSearchAction -Identity "$($compSearchName)_Preview" $ncsa = New-ComplianceSearchAction -SearchName $compSearchName -Export -ExchangeArchiveFormat SinglePst -Format FxStream $resultExport = Get-ComplianceSearchAction -Identity "$($compSearchName)_Export" While ($resultPreview.Status -ne "Completed" -AND $resultExport.Status -ne "Completed") { $resultPreview = Get-ComplianceSearchAction -Identity "$($compSearchName)_Preview" $resultExport = Get-ComplianceSearchAction -Identity "$($compSearchName)_Export" #Write-Host "[$(Get-Date -Format G)] Processing..." Write-Host -NoNewLine "." Start-Sleep -s 5 } Write-Host "`n[$(Get-Date -Format G)] Preview and Export successfully created" Write-Host "[$(Get-Date -Format G)] View Results at https://protection.office.com/" Write-Host "[$(Get-Date -Format G)] Preview: Search -> Content Search -> Searches tab -> $($compSearchName)" Write-Host "[$(Get-Date -Format G)] Export: Search -> Content Search -> Exports tab -> $($compSearchName)_Export" Write-Host "[$(Get-Date -Format G)] Start Purging emails" Write-Host -NoNewLine "[$(Get-Date -Format G)] Purging" $ncsa = New-ComplianceSearchAction -SearchName $compSearchName -Purge -PurgeType HardDelete -Confirm:$False $resultPurge = Get-ComplianceSearchAction -Identity "$($compSearchName)_Purge" While ($resultPurge.Status -ne "Completed") { $resultPurge = Get-ComplianceSearchAction -Identity "$($compSearchName)_Purge" Write-Host -NoNewLine "." Start-Sleep -s 5 } Write-Host "`n[$(Get-Date -Format G)] Purge complete" $confirmDelete = Read-Host "Delete Compliance Search, Preview, Export, and Purge? [Y/N]" If ($confirmDelete -eq 'Y') { Write-Host "[$(Get-Date -Format G)] Deleting Compliance Search, Preview, Export, and Purge..." Remove-ComplianceSearchAction -Identity "$($compSearchName)_Preview" -Confirm:$False Remove-ComplianceSearchAction -Identity "$($compSearchName)_Export" -Confirm:$False Remove-ComplianceSearchAction -Identity "$($compSearchName)_Purge" -Confirm:$False Remove-ComplianceSearch -Identity $compSearchName -Confirm:$False } Write-Host "[$(Get-Date -Format G)] Removing Powershell Session..." Remove-PSSession $Session } RemoveMaliciousEmails
Output Multiple Colors on a Single Line
#Requires -Version 4.0 Function Write-Out { <# .SYNOPSIS Write output to console and/or log file. Supports multiple foreground and background colors on a single line and advanced options to insert lines, spaces, or tabs before or after the text as well as timestamps. .DESCRIPTION Uses Write-Host to output color text to the console, and supports using multiple foreground and background colors on a single line. Uses Set-Content and Add-Content to output to a file. It works by accepting strings as an array and then you can assign the foreground or background colors by passing them as arrays for the matching text. It also accepts Default which allows you skip specifying a color and use the default. This function requires Powershell 4.0 to support the alias attribute in the function. .PARAMETER Text Optional. Array of strings to write to console/log. If you do not need to use multiple colors on a single line you can pass a single string instead of an array of strings. Otherwise, if you need to multiple colors on a single line pass an array of strings and associated colors using -ForegroundColor, -BackgroundColor, -ForegroundColorDefault, or -BackgroundColorDefault. .PARAMETER ForegroundColor Optional. Array of foreground Colors to write to console. Default means the ForegroundColorDefault value is used. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER ForegroundColorDefault Optional. Default foreground color to write to console. Default is set to white. Valid Colors: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackgroundColor Optional. Array of background colors to write to console. Default means the BackgroundColorDefault value is used. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackgroundColorDefault Optional. Default background color to write to console. Default is none. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER PreLine Optional. Add blank lines before your text. Default is 0. .PARAMETER PreSpace Optional. Add spaces before your text. Default is 0. .PARAMETER PreTab Optional. Add Tabs before your text. Default is 0. .PARAMETER TimeStampFormat Optional. Format used for time stamps. Default is 'yyyy-MM-dd HH:mm:ss' .PARAMETER TimeStamp Optional. Adds time stamp in square brackets before your text. .PARAMETER ClearHost Optional. Clear the console before your text. .PARAMETER PostLine Optional. Add blank lines after your text. Default is 0. .PARAMETER PostSpace Optional. Add spaces after your text. Default is 0. .PARAMETER PostTab Optional. Add tabs after your text. Default is 0. .PARAMETER NoNewLine Optional. Do not add a new line after your text and optional post text options. Default is to add a new line. .PARAMETER LogFile Optional. Absolute or relative path of the log file. .PARAMETER Overwrite Optional. Ovewrite the log file. Default is to append to the log file. .INPUTS Parameters above .OUTPUTS None .NOTES Author: Brian Steinmeyer URL: http://sigkillit.com/ Created: 4/18/2020 Version 1.3 - Added LogOnly Option for only writing text to a log file Version 1.2 - Set Text, ForegroundColor, and BackgroundColor to default value of @() to fix errors checking counts in some circumstances - Fixed an issue where ForegroundColorDefault and BackgroundColorDefault were not working properly in some circumstances - Added Requires -Version 4.0 Version 1.1 - Completely rewrote the "Main Text" section - Added "Default" as a color option, which allows you to use the default values for foreground/background - Useful when you want to specify a backgroundcolor in certain parts of a line like the middle - Ex: Write-Out -Text "How to ","highlight ","the middle text" -BackgroundColor Default,Yellow,Default Version: 1.0 - Initial Creation inspired by PSWriteColor (https://github.com/EvotecIT/PSWriteColor) - Improved upon by switching Foreground and Background Colors to default values if colors are not specifid for all strings. Will also ignore extra colors if more colors are specified than strings specified. .EXAMPLE Write-Out -Text "Start with Red Text ","Then Switch to Blue Text ","Now Magenta" -ForegroundColor Red,Blue,Magenta .EXAMPLE Write-Out -Text "White on Black ","Black on White ","Dark Cyan on Cyan ","Yellow on Green ","Default Color" -ForegroundColor White,Black,DarkCyan,Yellow -BackgroundColor Black,White,Cyan,Green .EXAMPLE Write-Out -Text "Make this"," entire line"," the same color by setting defaults" -ForegroundColorDefault Yellow -BackgroundColorDefault Magenta .EXAMPLE Write-Out -Text "Add a blank line and two tabs ","before ","my text" -ForegroundColor Green,Cyan,White -PreLine 1 -PreTab 2 .EXAMPLE Write-Out -Text "Add two blank ","lines ","after my text" -ForegroundColor White,Green,White -PostLine 2 .EXAMPLE Write-Out -Text "Add 3 spaces before my text" -ForegroundColor Gray -Prespace 3 .EXAMPLE Write-Out -Text "White text and a tab after" -ForegroundColor White -NoNewLine -PostTab 1 Write-Out -Text "Black text on Yellow ","and then back to white" -ForegroundColor Black,White -BackgroundColor Yellow .EXAMPLE Write-Out -Text "An easy way to ","highlight ","text in the middle" -BackgroundColor Default,Yellow .EXAMPLE Write-Out -Text "You can even add a ","time stamp ","before your output" -ForegroundColor White,Green,White -TimeStamp -PreLine 3 .EXAMPLE Write-Out -Text "You can change the ","time stamp format" -ForegroundColor White,Yellow -TimeStamp -TimeStampFormat "dd-MM-yyy HH:mm" -PreLine 1 -PostLine 1 .EXAMPLE Write-Out -Text "An"," Error"," occurred let's write overwrite/create a new log file" -ForegroundColor White,Red,White -TimeStamp -LogFile "script.log" -Overwrite .EXAMPLE Write-Out -Text "Now you can ","Append ","this line to your log file" -ForegroundColor Cyan,Magenta -TimeStamp -LogFile "script.log" #> [CmdletBinding()] Param ( [Parameter(Mandatory=$false)] [AllowEmptyString()] [alias ('T')] [String[]] $Text = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('FGC', 'FC')] [string[]] $ForegroundColor = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('FGCD', 'FCD')] [string] $ForegroundColorDefault = [ConsoleColor]::White, [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('BGC', 'BC')] [String[]] $BackgroundColor = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('BGCD', 'BCD')] [string] $BackgroundColorDefault = "Default", [Parameter(Mandatory=$false)] [int] $PreLine = 0, [Parameter(Mandatory=$false)] [int] $PreSpace = 0, [Parameter(Mandatory=$false)] [int] $PreTab = 0, [Parameter(Mandatory=$false)] [Alias('TSF', 'TS')] [string] $TimeStampFormat = 'yyyy-MM-dd HH:mm:ss', [Parameter(Mandatory=$false)] [switch] $TimeStamp, [Parameter(Mandatory=$false)] [switch] $ClearHost, [Parameter(Mandatory=$false)] [int] $PostLine = 0, [Parameter(Mandatory=$false)] [int] $PostSpace = 0, [Parameter(Mandatory=$false)] [int] $PostTab = 0, [Parameter(Mandatory=$false)] [switch] $NoNewLine = $false, [Parameter(Mandatory=$false)] [alias ('Log', 'L')] [string] $LogFile = '', [Parameter(Mandatory=$false)] [switch] $LogOnly = $false, [Parameter(Mandatory=$false)] [switch] $Overwrite = $false ) Begin { #Nothing to Do Here } Process { #Optional - Do Not Write to ConsoleColor If (!($LogOnly)) { #Optional - Prefix Text If ($ClearHost) { Clear-Host } If ($PreLine -gt 0) { For ($i = 0; $i -lt $PreLine; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line(s) before Main text If ($PreSpace -gt 0) { For ($i = 0; $i -lt $PreSpace; $i++) { Write-Host -Object " " -NoNewLine } } # Add Tab(s) before Main text If ($PreTab -gt 0) { For ($i = 0; $i -lt $PreTab; $i++) { Write-Host -Object "`t" -NoNewLine } } # Add Space(s) before Main text If ($TimeStamp) { Write-Host -Object "[$([datetime]::Now.ToString($TimeStampFormat))]" -NoNewline } # Add Timestamp before Main Text #MAIN TEXT If (($Text.Count -gt 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -eq 0)) { #Text Only Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColorDefault -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -gt 0) -AND ($BackgroundColor.Count -eq 0)) { #Text and ForegroundColor Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($ForegroundColor.Count -le $i) { $ForegroundColor += $ForegroundColorDefault } #ForegroundColor Not Specified Set to Default If ($ForegroundColor[$i] -eq "Default") { $ForegroundColor[$i] = $ForegroundColorDefault } If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColorDefault -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -gt 0)) { #Text and BackgroundColor Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($BackgroundColor.Count -le $i) { $BackgroundColor += $BackgroundColorDefault } #BackgroundColor Not Specified Set to Default If ($BackgroundColor[$i] -eq "Default") { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColorDefault -NoNewLine } } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColor[$i] -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -gt 0) -AND ($BackgroundColor.Count -gt 0)) { #Text, ForegroundColor, and BackgroundColor Specified (FAILS NOT WRITING DEFAULT) For ($i = 0; $i -lt $Text.Count; $i++) { If ($ForegroundColor.Count -le $i) { $ForegroundColor += $ForegroundColorDefault } #ForegroundColor Not Specified Set to Default If ($BackgroundColor.Count -le $i) { $BackgroundColor += $BackgroundColorDefault } #BackgroundColor Not Specified Set to Default If ($ForegroundColor[$i] -eq "Default") { $ForegroundColor[$i] = $ForegroundColorDefault } If ($BackgroundColor[$i] -eq "Default") { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColorDefault -NoNewLine } } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColor[$i] -NoNewLine } } } Else { #No Text, ForegroundColor, or BackgroundColor Specified ($Text.Count -eq 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -eq 0) } #Post Text If ($PostSpace -gt 0) { for ($i = 0; $i -lt $PostSpace; $i++) { Write-Host -Object " " -NoNewLine } } # Add Tab(s) after Main text If ($PostTab -gt 0) { for ($i = 0; $i -lt $PostTab; $i++) { Write-Host -Object "`t" -NoNewLine } } # Add Space(s) after Main text If ($PostLine -gt 0) { for ($i = 0; $i -lt $PostLine; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line(s) after Main text If ($NoNewLine) { Write-Host -NoNewline } else { Write-Host } # Add New Line after Main Text Unless NoNewLine is Supplied } #Log File $TextToWrite = "" #Build Text to Write to Log File If ($PreLine -gt 0) { For ($i = 0; $i -lt $PreLine; $i++) { $TextToWrite += "`n" } } # Add empty line(s) before Main text If ($PreSpace -gt 0) { For ($i = 0; $i -lt $PreSpace; $i++) { $TextToWrite += " " } } # Add Tab(s) before Main text If ($PreTab -gt 0) { For ($i = 0; $i -lt $PreTab; $i++) { $TextToWrite += "`t" } } # Add Space(s) before Main text If ($TimeStamp) { $TextToWrite += "[$([datetime]::Now.ToString($TimeStampFormat))]" } # Add Timestamp before Main Text If ($Text.Count -gt 0) { For ($i = 0; $i -lt $Text.Count; $i++) { $TextToWrite += $Text[$i] } } #Add Main Text If ($PostSpace -gt 0) { for ($i = 0; $i -lt $PostSpace; $i++) { $TextToWrite += " " } } # Add Tab(s) after Main text If ($PostTab -gt 0) { for ($i = 0; $i -lt $PostTab; $i++) { $TextToWrite += "`t" } } # Add Space(s) after Main text If ($PostLine -gt 0) { for ($i = 0; $i -lt $PostLine; $i++) { $TextToWrite += "`n" } } # Add empty line(s) after Main text If ($LogFile -eq "") { #No LogFile Specified - Skip } ElseIf(!(Test-Path -Path $LogFile)) { #Create Log File If Does Not Exist If ($NoNewLine) { $nf = New-Item -Path $LogFile -type file -force -Value $TextToWrite } Else { $nf = New-Item -Path $LogFile -type file -force -Value $TextToWrite`r`n } } Else { #Log File Exists If($Overwrite) { #Overwrite Log File If ($NoNewLine) { Set-Content -Path $LogFile -Value $TextToWrite -NoNewline } Else { Set-Content -Path $LogFile -Value $TextToWrite } } Else { #Append Log File Try { If ($NoNewLine) { Add-Content -Path $LogFile -Value $TextToWrite -ErrorAction Stop -NoNewline } Else { Add-Content -Path $LogFile -Value $TextToWrite -ErrorAction Stop } } Catch { Start-Sleep -s 3 If ($NoNewLine) { Add-Content -Path $LogFile -Value $TextToWrite -NoNewline } Else { Add-Content -Path $LogFile -Value $TextToWrite } } } } } End { #Nothing to Do Here } }
Friday COVID-19 Meme

RetroPie Install Guide
*UPDATE – Click the below link to see the updated version for the RaspberryPi 4B! This original guide is meant for the Raspberry PI 2/3
http://sigkillit.com/2020/09/09/retropie-install-guide-raspberrypi-4/


Hardware Used (Total Cost $178)
You can easily go cheaper on the hardware by getting USB controllers, getting a smaller MicroSD card, using an existing USB keyboard, not using the optional fan, etc. However, at minimum I would recommend the RaspberryPi v3 Model B+ (Latest as of this writing) and the Retroflag case!
- CanaKit RaspberryPi Version 3 Model B+, heatsink kit, and 2.5A Power Supply
- SanDisk Ultra 128GB microSDXC UHS-I Card with Adapter, Black, Standard Packaging (SDSQUNC-128G-GN6MA)
- Retroflag NESPI Case Plus
- $24 on Amazon
- This is an exact mini replica of the original NES with function power & reset buttons. They also make other replica game system cases, visit http://www.retroflag.com for the full list
- Optional: Pi-Fan
- 2 x 8Bitdo Sn30 Bluetooth Gamepad
- $30 each on Amazon, Total $60
- 8Bitdo makes LOTs of designs, see the full list at http://www.8bitdo.com/
- Rii mini i8+ Keyboard
Software Used
Resources
- RetroPie Install Guide
- Update/Backup RetroPie
- Supported Emulators
- Retroflag Shutdown/Restart Script (LED & Buttons Will NOT work Until Installed)
- Advanced Fork (Preferred)
- https://github.com/crcerror/retroflag-picase
- Reset in Emulator: Exits emulator back into Emulationstation mainscreen
- Reset in Emulationstation: Restarts Emulationstation
- Power off: Shutdown the RaspberryPi
- Original (Resets or Power Off the System, only works if Emulationstation is Running)
- Advanced Fork (Preferred)
- Skyscraper
- Setup 8Bitdo Bluetooth Controller
- Check MD5 Hash on a File In Windows (Useful to verify BIOS Hashes)
- certutil -hashfile c:\folder\bios.bin MD5
Update 8Bitdo Controller Firmware
- Download the latest 8Bitdo Controller Firmware on a Windows Computer
- Run the update utility and follow the onscreen instructions
Create RetroPie SD Card
- Download RetroPie image on a Windows Computer
- Extract the image using 7zip
- Connect the Micro SD card to the computer using a MicroSD card reader
- In Windows, use balena Etcher to write the image on a MicroSD Card
- Note: It will format the card for you. If needed, you can format the card as fat so windows will recognize it prior to running etcher
Install the RaspberryPi Into the Case
- Make sure the case is powered off
- Attach the heatsinks onto the RaspberryPi
- Install the RaspberryPi into the Retroflag case as per the directions
- Switch the Safe Shutdown switch to ON
- Connect the HDMI cable, Ethernet Cable, keyboard USB dongle, insert the microSD card, and insert the power cable
Configure Keyboard on First Boot
- Make sure the keyboard dongle is connected and the keyboard is charged and powered on
- Turn the power to “ON” on the case
- On the Welcome Screen, hold any button on the keyboard to configure it, and configure it as follows:
- D-PAD UP: Up Arrow
- D-PAD DOWN: Down Arrow
- D-PAD LEFT: Left Arrow
- D-PAD RIGHT: Right Arrow
- START: 1
- SELECT: 2
- A: Enter (Same as OK key)
- B: Escape
- For all other keys, hold any button to skip configuring
- When OK is highlighted, press the OK button
- When prompted about not enabling a hotkey button, highlight YES and press OK to use the default select button
- Navigate to the RetroPie menu and press OK on the keyboard
- Select RASPI-CONFIG and press OK on the keyboard
- Select Localization Options and press Enter on the keyboard
- Select Change Keyboard Layout and press Enter on the keyboard
- Select Generic 105-key (Intl) PC and press Enter on the keyboard
- For the keyboard layout, select Other and press Enter on the keyboard
- Select English (US) and press Enter on the keyboard
- Select English (US) and press Enter on the keyboard
- Select Default Keyboard Layout and press Enter on the keyboard
- Select No Composer Key and press Enter on the keyboard
- Select Finish and press Enter on the keyboard
- Select RASPI-CONFIG and press OK on the keyboard
Optional – Connect to WiFi (Skip if using wired LAN)
- Navigate to the RetroPie menu and press OK on the keyboard
- Select RASPI-CONFIG and press OK on the keyboard
- Select Localization Options and press OK on the keyboard
- Select Change WI-FI Country and press OK on the keyboard
- Select United States and press OK on the keyboard
- Press OK on the success message
- Select Finish and press OK on the keyboard
- *Select WIFI and press OK on the keyboard
- Select Connect to WIFI network and press OK on the keyboard
- Select the SSID, and press OK on the keyboard
- Enter the SSID PSIK and press Enter on the keyboard
- Select Exit and press Enter on the keyboard
Optional – Update RetroPie
- Navigate to the RetroPie menu and press OK on the keyboard
- Select RETROPIE SETUP and press OK on the keyboard
- Select Update and press Enter on the keyboard
- When prompted, select Yes and press Enter on the keyboard
- Press OK/YES to all proceeding messages
- Select Exit and press Enter on the keyboard
- If Retropie Does Not Boot Emulation Station and is stuck asking for the retropie login
- Login as pi
- Navigate to the RetroPie menu and press OK on the keyboard
- Select RASPI-CONFIG and press OK on the keyboard
- Select Boot Options and press OK on the keyboard
- Select Desktop/CLI and press OK on the keyboard
- Select Console Autologin and press OK on the keyboard
- Select Finish and press OK on the keyboard
- Select Yes to reboot and press OK on the keyboard
- It should not restart and autologin to emulationstation again
Add the Retroflag Safe Shutdown Script
Retroflag Case Power LED & Buttons Will NOT Work Until This is Installed
- Make sure internet connected.
- Make sure keyboard connected.
- Press F4 enter terminal.
- In the terminal, type the one-line command below (Case sensitive):
- Advanced Fork (Preferred)
- wget -O – “https://raw.githubusercontent.com/crcerror/retroflag-picase/master/install.sh” | sudo bash
- Press Reset in Emulator: Exits emulator back to Emulationstation
- Press Reset in Emulationstation: Restarts Emulationstation
- Press Reset in Console: Restart the RaspberryPi
- Press Power in Console/Emulationstation/Emulator: Shutdown the RaspberryPi
- Original
- wget -O – “https://raw.githubusercontent.com/RetroFlag/retroflag-picase/master/install.sh” | sudo bash
- Press Reset in Emulator/Emulationstation: Restart the RaspberryPi
- Press Reset in Console: Nothing
- Press Power in Emulator/Emulationstation: Shutdown the RaspberryPi
- Press Power in Console: Nothing
- It will reboot after this and the reset & power buttons will now function
Setup Bluetooth Controllers
- Navigate to the RetroPie menu and press OK on the keyboard
- Select BLUETOOTH and press OK on the keyboard
- Make sure 8Bitdo mapping hack is set to off
- Power on the SNES30 controller by holding the start button until the blue light comes on. Once it is blinking, set it to pairing mode by holding the select button for 3 seconds and the blue light will start rapidly blinking
- Select Register and Connect Bluetooth Device and press Enter on the keyboard
- The controller will show up with its MAC address as 8Bitdo, select it and press Enter on the keyboard
- Select DisplayYesNo and press Enter on the keyboard
- Repeat for each additional controller
- Select Setup udev rule for joypad and press Enter on the keyboard
- Select an 8Bitdo controller and press Enter on the keyboard
- Press Enter on the keyboard to confirm the entry was added
- Select Cancel and press Enter on the keyboard to return to Emulationstation
- Press 1 on the keyboard to bring up the Main Menu
- Select Configure Input and press OK on the keyboard
- When prompted to configure input, press OK on the keyboard
- Hold any key on the 8Bitdo SNES30 controller and configure it as follows
- D-PAD UP: Up Arrow
- D-PAD DOWN: Down Arrow
- D-PAD LEFT: Left Arrow
- D-PAD RIGHT: Right Arrow
- START: Start
- SELECT: Select
- A: A
- B: B
- X: X
- Y: Y
- LEFT SHOULDER: L
- RIGHT SHOULDER: R
- For all others, hold any button to skip configuration (Or use the keyboard to skip down to OK)
- When OK is highlighted, press the OK on the keyboard
- When prompted about not enabling a hotkey button, highlight YES and press OK on the keyboard to use the default select button
- Repeat for each Controller
- Press 1 on the keyboard to bring up the Main Menu
- Select Quit and press OK on the keyboard
- Select Restart System and press OK on the keyboard
- Select Yes to confirm the restart and press OK on the keyboard
Add Optional & Experimental Emulators
Optional Emulators
SYSTEM | OPTIONAL EMULATOR | NOTE |
Apple II | linapple | |
Atari ST | hatari | |
Commodor 64 | vice | |
Coleco Vision | coolcv | |
Dragon 32 / Tandy CoCo | xroar | |
Intellivision | lr-freeintv | |
MSX | lr-fmsx | Adds the following files to BIOS folder: CARTS.SHA, CYRILLIC.FNT, DISK.ROM, FMPAC.ROM, FMPAC16.ROM, ITALIC.FNT, KANJI.ROM, MSX.ROM, MSX2.ROM, MSX2EXT.ROM, MSX2P.ROM, MSX2PEXT.ROM, MSXDOS2.ROM, PAINTER.ROM, RS232.ROM |
Virtual Boy | lr-beetle-vb | |
Wonderswan / Wonderswan Color | lr-beetle-wswan | |
Zmachine | frotz | Includes Zork 1, 2, and 3 |
- Navigate to the RetroPie menu and press OK on the keyboard
- Select RETROPIE SETUP and press OK on the keyboard
- Select Manage packages and press enter on the keyboard
- Select Manage Optional packages and press enter on the keyboard
- Select %EMULATOR_NAME% and press enter on the keyboard
- Select Install from source (latest) or Install from binary and press enter on the keyboard and wait for the installer to finish
- Select Back and press enter on the keyboard
- Select Back and press enter on the keyboard
- Select Back and press enter on the keyboard
- Select Exit and press enter on the keyboard
- Select Yes and press enter on the keyboard
Experimental Emulators
SYSTEM | EXPERIMENTAL EMULATOR |
Nintendo DS | drastic |
- Navigate to the RetroPie
menu and press OK on the keyboard
- Select RETROPIE SETUP and press OK on the keyboard
- Select Manage packages and press enter on the keyboard
- Select Manage Experimental packages and press enter on the keyboard
- Select %EMULATOR_NAME% and press enter on the keyboard
- Select Install from source
(latest) or Install from binary and press enter on the keyboard and wait for
the installer to finish
- Select Back and press enter on the keyboard
- Select Back and press enter on the keyboard
- Select Back and press enter on the keyboard
- Select Exit and press enter on the keyboard
- Select Yes and press enter on the keyboard
Add BIOS, Config, and ROM Files to the SD Card
NOTE: See my post on cleaning up NoIntro 2018 ROMs:
http://sigkillit.com/2019/06/19/clean-no-intro-2018-rom-set/
- Navigate to the RetroPie menu and press OK on the keyboard
- Select SHOW IP and press OK on the keyboard
- Note the IP and press Enter on the keyboard
- From a Windows computer containing the ROMS, open the samba share for the RetroPie by entering \\IPADDRESS
- Copy the BIOS files to the BIOS Share
- Copy the ROMs to the ROMs share
- OPTIONAL – Copy Configs to the CONFIGS share
- You only need to do this if you have previous configurations backed up & do not want to treat this as a brand new install
- Press 1, select Quit
Special Configurations for ROMs to Work Properly
Atari 800 / Atari 5200 Load BIOS
You need to configure the emulator to point it to the correct BIOS files for these to work
- Launch an Atari 800/5200 game
- If you launched a 5200 game, select Standard 5200 cartridge option or if you launched a 800 game you won’t see this prompt just continue. You’ll get a warning that you need a real Atari/OS.
- Press F1 on the keyboard to open the menu
- Select Emulator Configuration and press enter on the keyboard
- Select System ROM Settings and press enter on the keyboard
- Select Find ROM images in a directory, navigate to the BIOS directory (/home/pi/RetroPie/BIOS) and press the space bar on the keyboard to select that directory.
- Press Escape on the keyboard to go back a menu
- Select Save Configuration File and press enter on the keyboard
- Select Save Configuration on Exit and press enter on the keyboard
- Press Escape on the keyboard to go back a menu
- Select Exit Emulator and press enter on the keyboard
- If you have the correctly named BIOS files and it should automatically configure them
Atari 5200 Auto Load Game (Prevents Memo Pad From Loading)
If the screen loads to a blue memo pad instead of loading the game, this is because it’s set to an 800 system. You can press F1 and load the rom fine each time or you can do the following to override it
- Launch the Atari 5200 game
- Press the Select + X (Hotkey + X) to bring up the Quick Menu
- Select Options and press enter on the keyboard
- Select Atari System and press the right arrow to select 5200
- Press B to return to the previous menu
- Select Resume and press A to return to the game
- Test to see if it works now. If it works, you can permanently save it by going back to Controls and selecting Save Core Overrides
Atari 800 / Atari 5200 Configure Controller
- Launch Atari 800/5200 game
- Press the Select + X (Hotkey + X) to bring up the Quick Menu
- Select Controls and press A
- Next to user 1 Device Type, press the right arrow to select Atari Joystick
- Press B to return to the previous menu
- Select Resume and press A to return to the game
- Test to see if it works now. If it works, you can permanently save it by going back to Controls and selecting Save Core Overrides
Sinclair ZX Spectrum
Not all games will work with a joystick! However, if the input does not seem to be working
- Launch a ZX Spectrum game
- Press the Select + X (Hotkey + X) to bring up the Quick Menu
- Select Controls and press A
- Next to user 1 Device Type, press the right arrow to select Kempton Joystick or Cursor Joystick
- Press B to return to the previous menu
- Select Resume and press A to return to the game
- Test to see if it works now. If it works, you can permanently save it by going back to Controls and selecting Save Core Overrides
Scrape ROMS with Skyscraper
- Press 1 on the keyboard to enter the Main Menu
- Select Quit and press OK on the keyboard
- Select Quit Emulationstation and press OK
- Enter the following command at the bash prompt
- sudo /home/pi/RetroPie-Setup/retropie_setup.sh
- Select Manage Packages and press Enter on the keyboard
- Select Experimental Packages and press Enter on the keyboard
- Select Skyscraper and press Enter on the keyboard
- Select Install from source and press Enter on the keyboard
- Select Configuration/Options and press Enter on the keyboard
- Select Gather Resources and press Enter on the keyboard
- Select the game system you want to scrape (suggest 1 at a time as it takes a few hours) and press Enter on the keyboard
- Note: This caches the game info & images in \\retropie\configs\all\skyscraper\ and only needs run once unless you add new games. It then uses this cache to build the game info, which greatly increases the speed since it all local. However, you will need to monitor the size of the cache to make sure it does not fill the SD card.
- Select Generate Games Lists and press Enter on the keyboard
- Select the game system(s) you want to scrape and press Enter on the keyboard
- Note: This builds the game images, description, etc
- Select Run on all systems and press Enter on the keyboard then WAIT!
Clean No-Intro 2018 ROM Set
IMPORTANT UPDATE 12/06/2020 – This is updated for v5.3!!!
Overview
I did not want my RetroPie to be cluttered with ROMs I did not want. I only wanted the original games, I did not want duplicates or revisions, and I only wanted games in English so I could read the on screen text. For example, the NES has about 716 officially licensed games and the No-Intro 2018 ROM set has about 2,748 games in it. I wanted to reduce that number closer to the officially licensed games count to save space and reduce the amount of ROMs I would have to scroll through each time. I decided to create the below powershell scripts based on the No-Intro 2018 ROM set to accomplish my goal, which I’ll explain each step in detail.
http://sigkillit.com/wp-content/uploads/2020/12/Clean-NoIntro2018_v53.zip
You can also download the older archived scripts, but I HIGHLY RECOMMEND sticking with latest scripts!
The No-Intro 2018 ROM set includes the following game systems that are compatible with RetroPie/Emulationstation:
- Atari: 2600
- Atari: 5200
- Atari: 7800
- Atari: Jaguar
- Atari: Lynx
- Bandai: WonderSwan
- Bandai: WonderSwan Color
- Coleco: ColecoVision
- GCE: Vectrex
- Microsoft: MSX
- NEC: PC Engine / TurboGrafx 16
- Nintendo: Family Computer Disk System
- Nintendo: Game Boy
- Nintendo: Game Boy Advance
- Nintendo: Game Boy Color
- Nintendo: Nintendo 64
- Nintendo: Nintendo Entertainment System
- Nintendo: Super Nintendo Entertainment System
- Nintendo: Virtual Boy
- SNK: Neo Geo Pocket
- SNK: Neo Geo Pocket Color
- Sega: 32X
- Sega: Game Gear
- Sega: Master System / Mark III
- Sega: Mega Drive / Genesis
- Sega: SG-1000
The No-Intro ROMs follow a pretty standardized naming scheme such as:
- Battletoads (Europe).zip
- Battletoads (Japan).zip
- Battletoads (USA).zip
- Captain Skyhawk (Europe).zip
- Captain Skyhawk (USA) (Rev A).zip
- Captain Skyhawk (USA).zip
As you can see, the base name of the ROM is followed by detailed descriptions such as the region released, revision, language, etc which is contained in parentheses. The script is based on using this naming scheme to get unique ROM base names by grabbing everything to the left of the first parentheses. It then further analyzes the results based on filters for each game system, which decide the ROM to keep. The default filters are set to prefer the USA version and the earliest revision (On older gaming systems, later revisions usually just made changes like the sprite used for a charactor or the color and not necessarily “bug” fixes like more modern game systems). Using the examples above, the script would keep “Battletoads (USA).zip) and “Captain Skyhawk (USA).zip”. See below for further details on using the scripts.
1_Clean-NoIntroRoms.ps1
See supplemental scripts:
- 2_CompareFolderResults.ps1 to compare ROM results by modifying filters
- 3_CheckXML.ps1 to check for missing scraped data in RetroPie
Global Variable Definitions:
- $global:scriptName
- Name of the Script, defaults to full name of the script
- $global:scriptVersion
- Script Version
- $global:romNoIntroDirectory
- Source No-Intro 2018 Game System ROM Directory, each game system should have a folder in here that matches in $global:romNoIntroHashTable. Default is “C:\Games\No-Intro 2018\”
- $global:romCleanDirectory
- Destination directory to copy No-Intro 2018 ROMs to, each game system will have a folder in here that matches in $global:romNoIntroHashTable (Default is the RetroPie game system directory names). This way it never modifies the ROMs in the source directory. Default is “C:\Games\RetroPie\roms\”
- $global:romCleanDirectoryPurge
- Remove each game system directory in $global:romCleanDirectory so it does not exist before copying the ROMs. Default is $true
- $global:romOverWrite
- Overwrite existing ROMs in each game system directory in $global:romCleanDirectory if the game system directory exists. When $false, it will not copy any ROMs into the game system directory if it exists. When $true, it will copy and overwrite ROMs into the game system directory if it exists, but will not remove any additional ROMs or files that exist. Default is $false
- $global:romFilterDirectory
- Directory that stores the “filters” for each game system. The filters are .ps1 files named using the RetroPie directory name defined in $global:romNoIntroHashTable. I have customized the filters for each system and included them by default. You can modify them to your liking or if they do not exist, the script will generate a generic filter for each system. Default is a “filters” folder in the same directory as the script
- $global:romRetropieDirectory
- Location of the ROM directory on the RetroPie, which is used if you want the script to auto copy the ROMs to your RetroPie. Default is “\\retropie\roms\”
- $global:romRetropieDirectoryPurge
- Purge each game system’s ROM directory before copying ROMs to the RetroPie. Default is $true
- $global:romRetropieUpload
- Auto copy the ROMs from $global:romCleanDirectory to $global:romRetropieDirectory. Default is $true
- $global:logFile
- Log file output of the entire run and additional log files are placed in the same directory. Default is a “logs” directory in the same directory as the script with a log name that matches the script’s base name. Ex: .\logs\1_Clean-NoIntroRom.log
- $global:logOverwrite
- Overwrite the log files. Default is $true
- $global:logVerbose
- Show the full details of how it decides which ROMs to keep. This should only be used for debugging purposes and will increase the run time of the script. Default is $false
- $global:romNoIntroHashTable
- Hashtable setting each game systems directory name on RetroPie and in the No-Intro 2018 complete ROM set. Default directory names are used for each
Filter File Variable Definitions:
I have customized and included these since v5.0 and they are located in .\filters\<gamesystem>.ps1. If you want customize which ROMs are kept for each system, this is what you want to change.
- $romUnzip
- Unzip ROMs for emulators that don’t support .zip. $false will NOT unzip them and $true will unzip them
- $romsDoNotDelete
- Any exact ROM name (including extension) in this list will NOT be deleted. ROMs listed here will not be deleted even in they match a value in $romsExceptions or they are NOT the Primary ROM via $romSortOrder
- Ex: “Castlevania (USA) (Rev A).zip”
- $romsExceptions
- Any ROMs containing these strings or exact ROM name will be removed unless the exact ROM name is in $romsDoNotDelete
- $romsSortOrder
- Preferred sorting order to pick 1 Primary ROM to keep when evaluating duplicates. Uses regular expressions to define the preferred sorting order based on language, and if there are no matches it will determine the primary ROM by alphabetical sort. ROMs in $romsExceptions will not be deleted even if it is not determined to be the Primary ROM
#Clean-NoIntroRoms.ps1 #5.3 # -Re-Added Function Get-NoIntroDefaultFilters which was accidently removed from version 5.2 # -Renamed "config" to "filter" Main Function Section 1 Log # -Added Changelog in Comments #5.2 # -Added variables for Write-Out Colors and Updated to Write-Out v1.3 # -Updated Filters for scraping #5.1 # -Fixed minor bugs and updating filters for scraping #5.0 # -Rewrote the code to be modular by importing filters for each game system instead of using separate scripts # -Added variables to define where to store game system filters and logs # -Replaced $MyInvocation.MyCommand.Name with $PSCommandPath which requires Powershell 3 or greater # -Replaced Log-Write with Write-Out function which requires Powershell 4 or greater # -Added Atari Jaguar because it can run on PI4 with proper customization # -Fixed bug with romsDoNotDelete # -Fixed bug where exceptions were not removed from uniqueRom causing it to still evaluate them for duplicates $global:scriptName = $PSCommandPath $global:scriptVersion = "v5.3" $global:romNoIntroDirectory = "C:\Games\Complete ROM Sets\No-Intro 2018\" $global:romCleanDirectory = "C:\Games\RetroPie\roms\" $global:romCleanDirectoryPurge = $true $global:romOverWrite = $false $global:romFilterDirectory = (Split-Path -Path $PSCommandPath -Parent) + "\filters\" $global:romRetropieDirectory = "\\retropie\roms\" $global:romRetropieDirectoryPurge = $true $global:romRetropieUpload = $true $global:logFile = (Split-Path -Path $PSCommandPath -Parent) + "\logs\" + (Split-Path -Path $PSCommandPath.Replace(".ps1",".log") -Leaf) $global:logOverwrite = $true $global:logVerbose = $false $global:romNoIntroHashTable = [ordered]@{ #RetroPieDirName = No-IntroDirName "atari2600" = "Atari - 2600" "atari5200" = "Atari - 5200" "atari7800" = "Atari - 7800 [Headered]" "atarijaguar" = "Atari - Jaguar" "atarilynx" = "Atari - Lynx [Headered]" "atarist" = "Atari - ST" "coleco" = "Coleco - ColecoVision" "fds" = "Nintendo - Family Computer Disk System [headered]" "gamegear" = "Sega - Game Gear" "gb" = "Nintendo - Game Boy" "gba" = "Nintendo - Game Boy Advance" "gbc" = "Nintendo - Game Boy Color" "mastersystem" = "Sega - Master System - Mark III" "megadrive" = "Sega - Mega Drive - Genesis" "msx" = "Microsoft - MSX" "n64" = "Nintendo - Nintendo 64" "nes" = "Nintendo - Nintendo Entertainment System [headered]" "ngp" = "SNK - Neo Geo Pocket" "ngpc" = "SNK - Neo Geo Pocket Color" "pcengine" = "NEC - PC Engine - TurboGrafx 16" "sega32x" = "Sega - 32X" "sg-1000" = "Sega - SG-1000" "snes" = "Nintendo - Super Nintendo Entertainment System" "vectrex" = "GCE - Vectrex" "virtualboy" = "Nintendo - Virtual Boy" "wonderswan" = "Bandai - WonderSwan" "wonderswancolor" = "Bandai - WonderSwan Color" } #Output Color Variables $global:colorMain = "Green" $global:colorSub1 = "DarkGreen" $global:colorSub2 = "Green" $global:colorSub3 = "DarkRed" $global:colorOk = "Green" $global:colorWarn = "Yellow" $global:colorError = "Red" Function Main() { #Powershell 4 or greater is required If (!($PSVersionTable.PSVersion.Major -ge 4) -OR ($PSVersionTable.PSVersion -eq $null)) { Write-Host -ForegroundColor $global:colorError "Powershell v4 or greater is required, quitting script!" Exit } #Create Log File If ($global:logOverwrite -eq $true) { Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile -Overwrite } Else { Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile } Write-Out -ForegroundColor $global:colorMain -Text "SECTION 1: INITIALIZE" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Script Name : $($global:scriptName)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Version: : $($global:scriptVersion)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM No-Intro Dir : $($global:romNoIntroDirectory)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Clean Dir : $($global:romCleanDirectory)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Clean Dir Purge : $($global:romCleanDirectoryPurge)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Overwrite : $($global:romOverWrite)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Filter Dir : $($global:romFilterDirectory)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Retropie Dir : $($global:romRetropieDirectory)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Retropie Dir Purge : $($global:romRetropieDirectoryPurge)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Upload to Retropie : $($global:romRetropieUpload)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log File : $($global:logFile)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log Overwrite : $($global:logOverwrite)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log Verbose : $($global:logVerbose)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Description : Cleanup 2018 No-Intro ROMs" -LogFile $global:logFile $tStart = (Get-Date) Write-Out -ForegroundColor $global:colorMain -Text "* Start Time : $($tStart)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile $tLog = $global:logFile.Replace(".log","_Exceptions.log") Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "SECTION 2: BUILD LIST OF UNIQUE EXCEPTIONS FILTERS FOR NO-INTRO ROMS" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log File : $($tLog)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log Overwrite : $($global:logOverwrite)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Description : Use No-Intro Naming Scheme to Build a List of Unique Exception Filters Used to Remove" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Unwanted ROMs For Each System Ex: (Beta), (Proto),(Japan)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile $ArgumentHash = @{ Source = $global:romNoIntroDirectory HashTable = $global:romNoIntroHashTable Log = $tLog LogOverwrite = $global:logOverwrite } Get-NoIntroRomsExceptions @ArgumentHash Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "SECTION 3: CLEANUP NO-INTRO ROMS" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log File : Per Game System" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Log Overwrite : $($global:logOverwrite)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Description : Use filters to copy No-Intro 2018 ROMs from Source to clean directory" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile ForEach ($key in $global:romNoIntroHashTable.keys) { $tLog = "$((Split-Path -Path $global:logFile -Parent))\$($key).log" $tFilters = "$($global:romFilterDirectory)$($key).ps1" $tSource = "$($global:romNoIntroDirectory)$($global:romNoIntroHashTable[$key])" $tDestination = "$($global:romCleanDirectory)$($key)" Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "PROCESS: $key" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Description : $($global:romNoIntroHashTable[$key])" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Filters : $($tFilters)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Source Dir : $($tSource)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Clean Dir : $($tDestination)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Clean Dir Purge : $($global:romCleanDirectoryPurge)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Overwrite : $($global:romOverWrite)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorSub1 -Text "Log File : $($tLog)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorSub1 -Text "Log Overwrite : $($global:logOverwrite)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorSub1 -Text "Log Verbose : $($global:logVerbose)" -LogFile $global:logFile If ($global:romCleanDirectoryPurge) { If(Test-Path -LiteralPath "$($tDestination)") { Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Clean Dir Exists, Purge Before Processing" -LogFile $global:logFile Write-Out -ForegroundColor DarkRed -Text "Purge: $($tDestination)" -LogFile $global:logFile Remove-Item "$($tDestination)" -Recurse -Force -Confirm:$false } Else { Write-Out -ForegroundColor $global:colorWarn -Text "ROM Clean Dir Does Not Exist, Skip Purge Before Processing" -LogFile $global:logFile } } $ArgumentHash = @{ System = $key Description = $global:romNoIntroHashTable[$key] Source = $tSource Destination = $tDestination Overwrite = $global:romOverWrite Filters = $tFilters Log = $tLog LogOverwrite = $global:logOverwrite LogVerbose = $global:logVerbose } Clean-NoIntroRoms @ArgumentHash Write-Out -ForegroundColor $global:colorSub1 -Text "Processing $($key) Complete" -LogFile $global:logFile } Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "SECTION 4: END RESULTS" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Retropie Dir : $($global:romRetropieDirectory)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Retropie Dir Purge : $($global:romRetropieDirectoryPurge)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* ROM Upload to Retropie : $($global:romRetropieUpload)" -LogFile $global:logFile If ($global:romRetropieUpload) { #Loop Each ROM Directory and Copy to RetroPie ForEach ($key in $global:romNoIntroHashTable.keys) { $tSource = "$($global:romCleanDirectory)$($key)" $tDestination = "$($global:romRetropieDirectory)$($key)" Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "* $($key)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* =======================================================" -LogFile $global:logFile If (Test-Path -LiteralPath "$($tSource)") { Write-Out -ForegroundColor $global:colorMain -Text "* Source Exist: $($tSource)" -LogFile $global:logFile If (Test-Path -LiteralPath "$($tDestination)") { Write-Out -ForegroundColor $global:colorMain -Text "* Dest Exist: $($tDestination)" -LogFile $global:logFile If ($global:romRetropieDirectoryPurge) { Write-Out -ForegroundColor $global:colorError -Text "* Purge: $($tDestination)" -LogFile $global:logFile Get-ChildItem "$($tDestination)" -Recurse | Remove-Item -Force -Confirm:$false } Write-Out -ForegroundColor $global:colorMain -Text "* Copy ROMs from '$($tSource)' to '$($tDestination)'" -LogFile $global:logFile Copy-Item -Path "$($tSource)\*" -Destination "$($tDestination)" -Recurse -Force } Else { Write-Out -ForegroundColor $global:colorWarn -Text "* Dest NOT Exist: $($tDestination)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Create Folder: $($tDestination)" -LogFile $global:logFile If (New-Item -ItemType Directory -Path $tDestination -Force) { Write-Out -ForegroundColor $global:colorMain -Text "* Copy ROMs from '$($tSource)' to '$($tDestination)'" -LogFile $global:logFile Copy-Item -Path "$($tSource)\*" -Destination "$($tDestination)" -Recurse -Force } Else { Write-Out -ForegroundColor $global:colorError -Text "* ERROR Creating Destination No ROMs Copied!" -LogFile $global:logFile } } } Else { Write-Out -ForegroundColor $global:colorError -Text "* Source NOT Exist: $($tSource)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorError -Text "* ERROR CANNOT COPY!!!" -LogFile $global:logFile } } } $tEnd = (Get-Date) Write-Out -ForegroundColor $global:colorMain -Text "* End Time : $($tEnd)" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "* Elapsed Time : $([math]::Round(($tEnd-$tStart).totalseconds, 2)) seconds" -LogFile $global:logFile Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile } Function Get-NoIntroRomsExceptions() { Param ( [Parameter(Mandatory=$true)] [Alias("Source")] [string]$RomDir, [Parameter(Mandatory=$true)] [Alias("HashTable")] [hashtable]$RomHashTable, [Parameter(Mandatory=$true)] [Alias("Log")] [string]$LogFile, [Parameter(Mandatory=$false)] [string]$LogOverwrite = $false ) If ($LogOverwrite -eq $true) { Write-Out -ForegroundColor $global:colorMain -Text " " -LogFile $LogFile -Overwrite } Else { Write-Out -ForegroundColor $global:colorMain -Text " " -LogFile $LogFile } $colUniqueRomsAll = @() ForEach ($key in $RomHashTable.keys) { #Process Current ROM Directory Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "PROCESS: $($RomDir)$($RomHashTable[$key])" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "=======================================================" -LogFile $LogFile #Confirm No-Intro ROM Directory Exists If(!(Test-Path -LiteralPath "$($RomDir)$($RomHashTable[$key])")) { #Directory Does Not Exist Write-Out -ForegroundColor $global:colorError -Text "ERROR: ROM Directory Does Not Exist!!!" -LogFile $LogFile } Else { #Directory Exists Write-Out -ForegroundColor $global:colorSub1 -Text "Directory Exists: Continue Processing" -LogFile $LogFile $colRoms = @() $colUniqueRoms = @() $colRoms = Get-ChildItem -LiteralPath "$($RomDir)$($RomHashTable[$key])" $colRoms | ForEach-Object ` { $colUniqueRoms += '(' + $_.basename.split("(",2)[1] } $colUniqueRoms = $colUniqueRoms | Sort-Object -Unique $colUniqueRomsAll += $colUniqueRoms Write-Out -ForegroundColor $global:colorMain -Text "Found $($colUniqueRoms.Count) Potential Exceptions to Filter:" -LogFile $LogFile ForEach ($name in $colUniqueRoms) { Write-Out -ForegroundColor $global:colorSub1 -Text "$($name)" -LogFile $LogFile } } } Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "PROCESS: Combined Unique Exceptions" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "=======================================================" -LogFile $LogFile $colUniqueRomsAll = $colUniqueRomsAll | Sort-Object -Unique Write-Out -ForegroundColor $global:colorMain -Text "Found $($colUniqueRomsAll.Count) Combined Potential Exceptions to Filter:" -LogFile $LogFile ForEach ($name in $colUniqueRomsAll) { Write-Out -ForegroundColor $global:colorSub1 -Text "$($name)" -LogFile $LogFile } } Function Clean-NoIntroRoms() { Param ( [Parameter(Mandatory=$true)] [Alias("System")] [string]$GameSystem, [Parameter(Mandatory=$true)] [Alias("Description")] [string]$GameDescription, [Parameter(Mandatory=$true)] [Alias("Source")] [string]$RomSource, [Parameter(Mandatory=$true)] [Alias("Destination")] [string]$RomDestination, [Parameter(Mandatory=$true)] [Alias("Overwrite")] [bool]$RomOverwrite, [Parameter(Mandatory=$true)] [Alias("Filters")] [string]$RomFilters, [Parameter(Mandatory=$true)] [Alias("Log")] [string]$LogFile, [Parameter(Mandatory=$false)] [bool]$LogOverwrite = $true, [Parameter(Mandatory=$false)] [bool]$LogVerbose = $false ) $countTotal = 0 $countUnique = 0 $countExceptionsDeleted = 0 $countDuplicatesDeleted = 0 $countNonDuplicatesDeleted = 0 #Create Log File If ($LogOverwrite -eq $true) { Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 1/6): Processing Information" -LogFile $LogFile -Overwrite } Else { Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 1/6): Processing Information" -LogFile $LogFile } Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Game System : $($GameDescription)" -LogFile $LogFile $timeStart = (Get-Date) Write-Out -ForegroundColor $global:colorSub1 -Text "Start Time : $($timeStart)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Source Dir : $($RomSource)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Clean Dir : $($RomDestination)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs Overwrite : $($RomOverwrite)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Filters : $($RomFilters)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Log File : $($LogFile)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Log Overwrite : $($LogOverwrite)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Log Verbose : $($LogVerbose)" -LogFile $LogFile If(!(Test-Path -LiteralPath $RomSource)) { Write-Out -ForegroundColor $global:colorError -Text "ERROR: ROM Source Directory Does Not Exist - Stop Processing!" -LogFile $LogFile Return } If(!(Test-Path -LiteralPath $RomFilters)) { #Set Defaults For: $romUnzip, $romsDoNotDelete, $romsExceptions, $romsSortOrder Write-Out -ForegroundColor $global:colorWarn -Text "WARNING: ROM Filters File Does Not Exist, Set Default Values - Continue Processing!" -LogFile $LogFile Write-Out -ForegroundColor $global:colorWarn -Text "$($RomFilters): Write `$romUnzip Default" -LogFile $LogFile Write-Out -ForegroundColor $global:colorWarn -Text "$($RomFilters): Write `$romsDoNotDelete Default" -LogFile $LogFile Write-Out -ForegroundColor $global:colorWarn -Text "$($RomFilters): Write `$romsExceptions Default" -LogFile $LogFile Write-Out -ForegroundColor $global:colorWarn -Text "$($RomFilters): Write `$romsSortOrder Default" -LogFile $LogFile $DefaultFilters = Get-NoIntroDefaultFilters (Split-Path -Path $RomFilters -Leaf) Write-Out -ForegroundColor $global:colorWarn -Text "Write to File: $($RomFilters)" -LogFile $LogFile $nf = New-Item -Path $RomFilters -type file -force -Value $DefaultFilters } #Set Custom Variables to Cleanup ROMs for Each System by Dot Sourcing($romUnzip, $romsDoNotDelete, $romsExceptions, $romsSortOrder) Write-Out -ForegroundColor $global:colorSub1 -Text "Import Variables from $($RomFilters)" -LogFile $LogFile . "$($RomFilters)" Write-Out -ForegroundColor $global:colorMain -Text "ROM Exceptions to Keep" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "-------------------------------------------------------" -LogFile $LogFile If (($romsDoNotDelete.Count -le 0) -OR $romsDoNotDelete -eq $null) { Write-Out -ForegroundColor $global:colorWarn -Text "None" -LogFile $LogFile } Else { ForEach ($rom in $romsDoNotDelete) { Write-Out -ForegroundColor $global:colorSub1 -Text "$($rom)" -LogFile $LogFile } } Write-Out -ForegroundColor $global:colorMain -Text "Delete ROMs Containing" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "-------------------------------------------------------" -LogFile $LogFile If (($romsExceptions.Count -le 0) -OR $romsExceptions -eq $null) { Write-Out -ForegroundColor $global:colorWarn -Text "None" -LogFile $LogFile } Else { ForEach ($rom in $romsExceptions) { Write-Out -ForegroundColor $global:colorSub1 -Text "$($rom)" -LogFile $LogFile } } Write-Out -ForegroundColor $global:colorMain -Text "ROM Sort Order" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "-------------------------------------------------------" -LogFile $LogFile ForEach ($rom in $romsSortOrder) { Write-Out -ForegroundColor $global:colorSub1 -Text "$($rom)" -LogFile $LogFile } #Get List of ROMs and Unique ROMs in the original No-Intro 2018 ROM set Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 2/6): Get All No-Intro ROMs and Unique ROMs to Process" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile [System.Collections.ArrayList]$colRoms = @() (Get-ChildItem -LiteralPath $RomSource).ForEach({$obj = [PSCustomObject]@{ FullName = $_.FullName; Name = $_.Name};$colRoms.add($obj)|out-null}) $colUniqueRoms = @() $colUniqueRoms = $colRoms | ForEach-Object { $_.Name.split("(")[0] } | Sort-Object -Unique #Count Total Original Source ROMs and Original Source Unique ROMs $countTotal = $colRoms.count $countUnique = $colUniqueRoms.count Write-Out -ForegroundColor $global:colorSub1 -Text "Total ROMs: $($countTotal)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Total Unique ROMs: $($countUnique)" -LogFile $LogFile #Remove Exceptions - Further Speeds Things Up By Not Having to Process As Much Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 3/6): Remove Exceptions" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile If (($romsExceptions.Count -le 0) -OR $romsExceptions -eq $null) { Write-Out -ForegroundColor $global:colorWarn -Text "None" -LogFile $LogFile } Else { #Remove Exception from colRoms Array For ($i=0; $i -lt $colRoms.Count; $i++) { ForEach ($romException in $romsExceptions) { #Check If Current ROM Matches Exception If ($colRoms[$i].Name -match [regex]::escape($romException)) { #Exception Found (Flag Delete) #Special Case Do Not Delete ROMs Check $romDND = $false If ($romsDoNotDelete.Count -gt 0) { ForEach ($doNotDelete in $romsDoNotDelete) { If ($doNotDelete -eq $colRoms[$i].Name) { #Found Special Case (Flag NOT Delete) $romDND = $true break } } } #Check to Delete or Not If ($romDND -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "DO NOT DELETE EXCEPTON (Special Case): $($colRoms[$i].Name)" -LogFile $LogFile } Else { #Delete ROM Write-Out -ForegroundColor DarkRed -Text "DELETE EXCEPTION '$($romException)': $($colRoms[$i].Name)" -LogFile $LogFile $colRoms.RemoveAt($i) $i-- $countExceptionsDeleted++ } break } } } } #Update Unique ROMs to Remove Exceptions $colUniqueRoms = $colRoms | ForEach-Object { $_.Name.split("(")[0] } | Sort-Object -Unique #Identify Primary ROM to Keep and Remove Duplicates Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 4/6): Identify Primary ROM and Remove Duplicates" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile ForEach ($uniqueRom in $colUniqueRoms) { #Determine Duplicates For Each Unique ROM Name $colDuplicateRoms = @() $colDuplicateRoms = $colRoms.Name -match ("^"+[regex]::escape($uniqueRom)+"\(") Write-Out -ForegroundColor $global:colorMain -Text "PROCESS: '$($uniqueRom)'" -LogFile $LogFile If ($colDuplicateRoms.count -gt 1) { #Determine Primary ROM In Each Duplicate ROM Set By Matching Sorting Preference :regloop ForEach ($sortRegex in $romsSortOrder ) { #Process ROMS That Match A Sorting Order $primaryRom = "" $colRomsToSort = @() [array]$colRomsToSort = $colDuplicateRoms -match $sortRegex $colRomsToSort = $colRomsToSort | Sort-Object If ($colRomsToSort.count -ge 1) { #Find Primary ROM To Keep If ($LogVerbose -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "TEST REGEX ($($colRomsToSort.count) Matches): $($sortRegex)" -LogFile $LogFile } For($i = $colRomsToSort.GetLowerBound(0); $i -le $colRomsToSort.GetUpperBound(0); $i++) { $matchRomException = $false If ($LogVerbose -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "Primary ROM Found (Match $($i + 1) of $($colRomsToSort.GetUpperBound(0) + 1)): $($colRomsToSort[$i])" -LogFile $LogFile } #Check Primary ROM For Exceptions ForEach ($romException in $romsExceptions) { If ($colRomsToSort[$i] -match [regex]::escape($romException)) { $matchRomException = $true If ($LogVerbose -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "Primary ROM Exception Found (Match $($i+1) of $($colRomsToSort.count): $($romException)" -LogFile $LogFile } break } } #Set Primary ROM If ($matchRomException -eq $false) { $primaryRom = $colRomsToSort[$i] break regloop } } } Else { If ($LogVerbose -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "SKIP REGEX (No Matches): $($sortRegex)" -LogFile $LogFile } } } #Display Primary ROM Result If ($primaryRom -eq "") { If ($LogVerbose -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "Primary ROM Set: No Primary Found!" -LogFile $LogFile } } Else { If ($LogVerbose -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "Primary ROM Set: $($primaryRom)" -LogFile $LogFile } } #Remove All Duplicate ROMS Except Primary ROM ForEach ($duplicateRom in $colDuplicateRoms) { #Primary ROM Found If ($duplicateRom -eq $primaryRom) { #Keep Primary ROM Write-Out -ForegroundColor $global:colorSub1 -Text "KEEP(Primary): $($duplicateRom)" -LogFile $LogFile } Else { #Special Case Do Not Delete ROMs Check $romDND = $false If ($romsDoNotDelete.Count -gt 0) { ForEach ($doNotDelete in $romsDoNotDelete) { If ($doNotDelete -eq $duplicateRom) { $romDND = $true break } } } If ($romDND -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "DO NOT DELETE (Special Case): $($duplicateRom)" -LogFile $LogFile } Else { If ($primaryRom -eq "") { #No Primary Found Delete Duplicate Write-Out -ForegroundColor DarkRed -Text "DELETE(No Primary Found): $($duplicateRom)" -LogFile $LogFile } Else { #Not The Primary ROM Delete Duplicate Or Exception Write-Out -ForegroundColor DarkRed -Text "DELETE(Duplicate/Exception): $($duplicateRom)" -LogFile $LogFile } #Delete ROM For ($i=0; $i -lt $colRoms.Count; $i++) { If ($colRoms[$i].Name -eq $duplicateRom) { $colRoms.RemoveAt($i) $i-- } } $countDuplicatesDeleted++ } } } } Else { #NOTE - $colDuplicateRoms acts as a variable (type=object) because there's a single item in the array! #Non-Duplicate ROM Primary By Default If ($LogVerbose -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "SKIP REGEX (No Duplicates): $($sortRegex)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Primary ROM Set (Non-Duplicate): $($colDuplicateRoms)" -LogFile $LogFile } #Check Primary ROM For Exceptions $matchRomException = $false ForEach ($romException in $romsExceptions) { #Check If Current ROM Matches Exception If ($colDuplicateRoms -match [regex]::escape($romException)) { #Exception Found (Flag Delete) $matchRomException = $true #Special Case Do Not Delete ROMs Check $romDND = $false If ($romsDoNotDelete.Count -gt 0) { ForEach ($doNotDelete in $romsDoNotDelete) { If ($doNotDelete -eq $colDuplicateRoms) { #Found Special Case (Flag NOT Delete) $romDND = $true break } } } break } } #Check to Delete or Not If ($matchRomException -eq $false) { Write-Out -ForegroundColor $global:colorSub1 -Text "KEEP(Primary Non-Duplicate): $($colDuplicateRoms)" -LogFile $LogFile } Else { #Delete If ($romDND -eq $true) { #Special Case Keep Write-Out -ForegroundColor $global:colorSub1 -Text "DO NOT DELETE (Special Case Non-Duplicate): $($colDuplicateRoms)" -LogFile $LogFile } Else { #Delete ROM Write-Out -ForegroundColor DarkRed -Text "DELETE (Exception Non-Duplicate) '$($romException)': $($colDuplicateRoms)" -LogFile $LogFile For ($i=0; $i -lt $colRoms.Count; $i++) { If ($colRoms[$i].Name -eq $duplicateRom) { $colRoms.RemoveAt($i) $i-- } } } } } } #Copy NoIntro ROMs Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 5/6): Copy No-Intro ROMs" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile #Confirm Source ROM Directory Exists If (Test-Path -LiteralPath $RomSource) { Write-Out -ForegroundColor $global:colorSub1 -Text "Source Exist: '$($RomSource)'" -LogFile $LogFile #Confirm Destination Directory Exists If (Test-Path -LiteralPath $RomDestination) { #Destination Directory Exists - Overwrite? If ($RomOverwrite -eq $true) { Write-Out -ForegroundColor $global:colorWarn -Text "Destination EXIST (Overwrite): '$($RomDestination)'" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Copy $($colRoms.count) ROMs from '$($RomSource)*' to '$($RomDestination)'" -LogFile $LogFile ForEach ($rom in $colRoms) { Copy-Item -LiteralPath $rom.FullName -Destination $RomDestination -Recurse -Force } } Else { Write-Out -ForegroundColor $global:colorWarn -Text "Destination EXIST (Do Not Overwrite): '$($RomDestination)'" -LogFile $LogFile Write-Out -ForegroundColor $global:colorWarn -Text "No Files Copied!'" -LogFile $LogFile } } Else { Write-Out -ForegroundColor $global:colorSub1 -Text "Destination Not Exist: '$($RomDestination)'" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Create Folder: '$($RomDestination)'" -LogFile $LogFile If (New-Item -ItemType Directory -Path $RomDestination -Force) { Write-Out -ForegroundColor $global:colorSub1 -Text "Copy $($colRoms.count) ROMs from '$($RomSource)' to '$($RomDestination)'" -LogFile $LogFile ForEach ($rom in $colRoms) { Copy-Item -LiteralPath $rom.FullName -Destination $RomDestination -Recurse -Force } } Else { Write-Out -ForegroundColor $global:colorError -Text "ERROR Creating Destination No ROMs Copied!" -LogFile $LogFile } } } Else { Write-Out -ForegroundColor $global:colorError -Text "Source NOT Exist: '$($RomSource)'" -LogFile $LogFile Write-Out -ForegroundColor $global:colorError -Text "ERROR CANNOT COPY!!!" -LogFile $LogFile } #Optionally Unzip ROMs Incase .zip Not Supported By Emulator If ($romUnzip -eq $true) { Write-Out -ForegroundColor $global:colorSub1 -Text "Unzip ROMs In: '$($RomDestination)'" -LogFile $LogFile $colRoms = Get-ChildItem -LiteralPath $RomDestination -Filter "*.zip" ForEach ($rom in $colRoms) { Expand-Archive $rom.FullName -DestinationPath $RomDestination -Force Remove-Item -LiteralPath $rom.FullName -Force } } #Results Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 6/6): Processing Results" -LogFile $LogFile Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs TOTAL : $($countTotal)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs UNIQUE : $($countUnique)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs Exceptions Deleted : $($countExceptionsDeleted)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs Dups Deleted : $($countDuplicatesDeleted)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs Non-Dup Deleted : $($countNonDuplicatesDeleted)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs Total Deleted : $($countExceptionsDeleted + $countDuplicatesDeleted + $countNonDuplicatesDeleted)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs Total After Clean : $($countTotal - ($countExceptionsDeleted + $countDuplicatesDeleted + $countNonDuplicatesDeleted))" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Start Time : $($timeStart)" -LogFile $LogFile $timeEnd = (Get-Date) Write-Out -ForegroundColor $global:colorSub1 -Text "End Time : $($timeEnd)" -LogFile $LogFile Write-Out -ForegroundColor $global:colorSub1 -Text "Elapsed Time : $([math]::Round(($timeEnd-$timeStart).totalseconds, 2)) seconds" -LogFile $LogFile } Function Get-NoIntroDefaultFilters { Param ( [Parameter(Mandatory=$false)] [string] $Name = "", [Parameter(Mandatory=$false)] [string] $Unzip = '$false' ) Begin { #Nothing to Do Here } Process { $DefaultFilters = @" #$Name v5.3 #Unzip ROMs That Do Not Support .ZIP Files On RetroPie `$romUnzip = $Unzip `n "@ $DefaultFilters += @' #Any Exact ROM Name (Including Extension) In This List Will Not Be Deleted #-ROMs listed here will NOT be deleted even if they match a value in romsExceptions #-ROMs listed here will NOT be deleted if it's NOT the Primary ROM via romsSortOrder #-Ex: "Castlevania (USA) (Rev A).zip" $romsDoNotDelete = @( ) #Any ROMs Containing These Strings Or Exact ROM Name Will Be Removed Unless the Exact ROM Name Is In romsDoNotDelete $romsExceptions = @( "[BIOS]" ,"[b]" ,"(Alpha)" ,"(Beta)" ,"(Beta 1)" ,"(Beta 2)" ,"(Beta 3)" ,"(Proto)" ,"(Proto 1)" ,"(Proto 2)" ,"(Promo)" ,"(Sample)" ,"(Debug Version)" ,"(Enhancement Chip)" ,"(GameCube Edition)" ,"(Promo, Virtual Console)" ,"(Virtual Console)" ,"(Wii Virtual Console)" ,"(Wii U Virtual Console)" ,"(Asia)" ,"(Australia)" ,"(Brazil)" ,"(Canada)" ,"(China)" ,"(France)" ,"(Germany)" ,"(Hong Kong)" ,"(Italy)" ,"(Japan)" ,"(Korea)" ,"(Netherlands)" ,"(Russia)" ,"(Spain)" ,"(Sweden)" ,"(Taiwan)" ) #Preferred Sorting Order to Pick 1 Primary ROM to Keep When Evaluating Duplicates #-Order Selects Specific Names followed by more generalized names based around language #-ROMs in romsExceptions will not be deleted even if it is not determined as the primary #-Ex: "Joust (USA).zip" would be primary over "Joust (Japan).zip" $romsSortOrder = @( #--------------------------------------- #---USA PREFERRED ORDER--- #--------------------------------------- #(USA).zip "\(USA\)\.zip" #(USA) (Unl).zip ,"\(USA\)\s*\(Unl\)\.zip" #(USA) (En,*).zip ,"\(USA\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(USA) (En,*) (Unl).zip ,"\(USA\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(USA) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(USA\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(USA, Europe).zip ,"\(USA,\s*Europe\)\.zip" #(USA, Europe) (Unl).zip ,"\(USA,\s*Europe\)\s*\(Unl\)\.zip" #(USA, Europe) (En,*).zip ,"\(USA,\s*Europe\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(USA, Europe) (En,*) (Unl).zip ,"\(USA,\s*Europe\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(USA, Europe) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(USA,\s*Europe\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(Japan, USA).zip ,"\(Japan,\s*USA\)\.zip" #(Japan, USA) (Unl).zip ,"\(Japan,\s*USA\)\s*\(Unl\)\.zip" #(Japan, USA) (En,*).zip ,"\(Japan,\s*USA\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(Japan, USA) (En,*) (Unl).zip ,"\(Japan,\s*USA\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(Japan, USA) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(Japan,\s*USA\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(USA, Asia).zip ,"\(USA,\s*Asia\)\.zip" #(USA, Asia) (Unl).zip ,"\(USA,\s*Asia\)\s*\(Unl\)\.zip" #(USA, Asia) (En,*).zip ,"\(USA,\s*Asia\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(USA, Asia) (En,*) (Unl).zip ,"\(USA,\s*Asia\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(USA, Asia) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(USA,\s*Asia\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(USA, Australia).zip ,"\(USA,\s*Australia\)\.zip" #(USA, Australia) (Unl).zip ,"\(USA,\s*Australia\)\s*\(Unl\)\.zip" #(USA, Australia) (En,*).zip ,"\(USA,\s*Australia\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(USA, Australia) (En,*) (Unl).zip ,"\(USA,\s*Australia\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(USA, Australia) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(USA,\s*Australia\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(USA, Korea).zip ,"\(USA,\s*Korea\)\.zip" #(USA, Korea) (Unl).zip ,"\(USA,\s*Korea\)\s*\(Unl\)\.zip" #(USA, Korea) (En,*).zip ,"\(USA,\s*Korea\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(USA, Korea) (En,*) (Unl).zip ,"\(USA,\s*Korea\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(USA, Korea) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(USA,\s*Korea\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(USA) (Rev #) ,"^(?=.*?\(USA\))(?=.*?\(Rev\s*[0-9\.]{0,4}\)).*$" #(USA) (Rev A) ,"^(?=.*?\(USA\))(?=.*?\(Rev\s*[A-Z]{0,4}\)).*$" #(USA) (Rev #A) ,"^(?=.*?\(USA\))(?=.*?\(Rev\s*[A-Z0-9\.]{0,4}\)).*$" #(USA) (Alt) OR (Alternate) ,"^(?=.*?\(USA\))(?=.*?(\(Alt\)|\(Alternate\))).*$" #(USA) (Alt #) ,"^(?=.*?\(USA\))(?=.*?\(Alt\s*[A-Z0-9]{1,2}\)).*$" #(USA) ,"\(USA\)" #(USA, Europe) ,"\(USA,\s*Europe\)" #(Japan, USA) ,"\(Japan,\s*USA\)" #(USA, Asia) ,"\(USA,\s*Asia\)" #(USA, Australia) ,"\(USA,\s*Australia\)" #(USA, Korea) ,"\(USA,\s*Korea\)" #(*USA*) ,"\((.*?)USA(.*?)\)" #--------------------------------------- #---WORLD PREFERRED ORDER--- #--------------------------------------- #(World).zip "\(World\)\.zip" #(World) (Unl).zip ,"\(World\)\s*\(Unl\)\.zip" #(World) (En,*).zip ,"\(World\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(World) (En,*) (Unl).zip ,"\(World\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(World) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(World\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(World) (Rev #) ,"^(?=.*?\(World\))(?=.*?\(Rev\s*[0-9\.]{0,4}\)).*$" #(World) (Rev A) ,"^(?=.*?\(World\))(?=.*?\(Rev\s*[A-Z]{0,4}\)).*$" #(World) (Rev #A) ,"^(?=.*?\(World\))(?=.*?\(Rev\s*[A-Z0-9\.]{0,4}\)).*$" #(World) (Alt) OR (Alternate) ,"^(?=.*?\(World\))(?=.*?(\(Alt\)|\(Alternate\))).*$" #(World) (Alt #) ,"^(?=.*?\(World\))(?=.*?\(Alt\s*[A-Z0-9]{1,2}\)).*$" #(World) ,"\(World\)" #(*World*) ,"\((.*?)World(.*?)\)" #--------------------------------------- #---EUROPE PREFERRED ORDER--- #--------------------------------------- #(Europe).zip "\(Europe\)\.zip" #(Europe) (Unl).zip ,"\(Europe\)\s*\(Unl\)\.zip" #(Europe) (En,*).zip ,"\(Europe\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(Europe) (En,*) (Unl).zip ,"\(Europe\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(Europe) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(Europe\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(Japan, Europe).zip ,"\(Japan,\s*Europe\)\.zip" #(Japan, Europe) (Unl).zip ,"\(Japan,\s*Europe\)\s*\(Unl\)\.zip" #(Japan, Europe) (En,*).zip ,"\(Japan,\s*Europe\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(Japan, Europe) (En,*) (Unl).zip ,"\(Japan,\s*Europe\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(Japan, Europe) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(Japan,\s*Europe\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(Europe) (Rev #) ,"^(?=.*?\(Europe\))(?=.*?\(Rev\s*[0-9\.]{0,4}\)).*$" #(Europe) (Rev A) ,"^(?=.*?\(Europe\))(?=.*?\(Rev\s*[A-Z]{0,4}\)).*$" #(Europe) (Rev #A) ,"^(?=.*?\(Europe\))(?=.*?\(Rev\s*[A-Z0-9\.]{0,4}\)).*$" #(Europe) (Alt) OR (Alternate) ,"^(?=.*?\(Europe\))(?=.*?(\(Alt\)|\(Alternate\))).*$" #(Europe) (Alt #) ,"^(?=.*?\(Europe\))(?=.*?\(Alt\s*[A-Z0-9]{1,2}\)).*$" #(Europe) ,"\(Europe\)" #(*Europe*) ,"\((.*?)Europe(.*?)\)" #--------------------------------------- #---JAPAN PREFERRED ORDER--- #--------------------------------------- #(Japan).zip "\(Japan\)\.zip" #(Japan) (Unl).zip ,"\(Japan\)\s*\(Unl\)\.zip" #(Japan) (En,*).zip ,"\(Japan\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(Japan) (En,*) (Unl).zip ,"\(Japan\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(Japan) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(Japan\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(Japan, Korea).zip ,"\(Japan,\s*Korea\)\.zip" #(Japan, Korea) (Unl).zip ,"\(Japan,\s*Korea\)\s*\(Unl\)\.zip" #(Japan, Korea) (En,*).zip ,"\(Japan,\s*Korea\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\.zip" #(Japan, Korea) (En,*) (Unl).zip ,"\(Japan,\s*Korea\)\s*\(En(,|\+|Ca|Da|De|En|Es|Fi|Fr|It|Ja|Nl|No|Pl|Pt|Sv|Zh)*?\)\s*\(Unl\)\.zip" #(Japan, Korea) <Anything Except (Alt ) or (Rev ) or (Demo)>.zip ,"^(?=.*?\(Japan,\s*Korea\))((?!\(Alt\s*[A-Z0-9]{0,2}\)|\(Rev\s*[A-Z0-9\.]{0,4}\)|\(Demo\)).)*$" #(Japan) (Rev #) ,"^(?=.*?\(Japan\))(?=.*?\(Rev\s*[0-9\.]{0,4}\)).*$" #(Japan) (Rev A) ,"^(?=.*?\(Japan\))(?=.*?\(Rev\s*[A-Z]{0,4}\)).*$" #(Japan) (Rev #A) ,"^(?=.*?\(Japan\))(?=.*?\(Rev\s*[A-Z0-9\.]{0,4}\)).*$" #(Japan) (Alt) OR (Alternate) ,"^(?=.*?\(Japan\))(?=.*?(\(Alt\)|\(Alternate\))).*$" #(Japan) (Alt #) ,"^(?=.*?\(Japan\))(?=.*?\(Alt\s*[A-Z0-9]{1,2}\)).*$" #(Japan) ,"\(Japan\)" #(*Japan*) ,"\((.*?)Japan(.*?)\)" #--------------------------------------- #---ALL ELSE FAILED PREFERRED ORDER--- #--------------------------------------- #(Unknown) ,"\(Unknown\)" ) '@ Return $DefaultFilters } End { #Nothing to Do Here } } Function Write-Out { <# .SYNOPSIS Write output to console and/or log file. Supports multiple foreground and background colors on a single line and advanced options to insert lines, spaces, or tabs before or after the text as well as timestamps. .DESCRIPTION Uses Write-Host to output color text to the console, and supports using multiple foreground and background colors on a single line. Uses Set-Content and Add-Content to output to a file. It works by accepting strings as an array and then you can assign the foreground or background colors by passing them as arrays for the matching text. It also accepts Default which allows you skip specifying a color and use the default. This function requires Powershell 4.0 to support the alias attribute in the function. .PARAMETER Text Optional. Array of strings to write to console/log. If you do not need to use multiple colors on a single line you can pass a single string instead of an array of strings. Otherwise, if you need to multiple colors on a single line pass an array of strings and associated colors using -ForegroundColor, -BackgroundColor, -ForegroundColorDefault, or -BackgroundColorDefault. .PARAMETER ForegroundColor Optional. Array of foreground Colors to write to console. Default means the ForegroundColorDefault value is used. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER ForegroundColorDefault Optional. Default foreground color to write to console. Default is set to white. Valid Colors: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackgroundColor Optional. Array of background colors to write to console. Default means the BackgroundColorDefault value is used. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackgroundColorDefault Optional. Default background color to write to console. Default is none. Valid Colors: Default, Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER PreLine Optional. Add blank lines before your text. Default is 0. .PARAMETER PreSpace Optional. Add spaces before your text. Default is 0. .PARAMETER PreTab Optional. Add Tabs before your text. Default is 0. .PARAMETER TimeStampFormat Optional. Format used for time stamps. Default is 'yyyy-MM-dd HH:mm:ss' .PARAMETER TimeStamp Optional. Adds time stamp in square brackets before your text. .PARAMETER ClearHost Optional. Clear the console before your text. .PARAMETER PostLine Optional. Add blank lines after your text. Default is 0. .PARAMETER PostSpace Optional. Add spaces after your text. Default is 0. .PARAMETER PostTab Optional. Add tabs after your text. Default is 0. .PARAMETER NoNewLine Optional. Do not add a new line after your text and optional post text options. Default is to add a new line. .PARAMETER LogFile Optional. Absolute or relative path of the log file. .PARAMETER Overwrite Optional. Ovewrite the log file. Default is to append to the log file. .INPUTS Parameters above .OUTPUTS None .NOTES Author: Brian Steinmeyer URL: http://sigkillit.com/ Created: 4/18/2020 Version 1.3 - Added LogOnly Option for only writing text to a log file Version 1.2 - Set Text, ForegroundColor, and BackgroundColor to default value of @() to fix errors checking counts in some circumstances - Fixed an issue where ForegroundColorDefault and BackgroundColorDefault were not working properly in some circumstances - Added Requires -Version 4.0 Version 1.1 - Completely rewrote the "Main Text" section - Added "Default" as a color option, which allows you to use the default values for foreground/background - Useful when you want to specify a backgroundcolor in certain parts of a line like the middle - Ex: Write-Out -Text "How to ","highlight ","the middle text" -BackgroundColor Default,Yellow,Default Version: 1.0 - Initial Creation inspired by PSWriteColor (https://github.com/EvotecIT/PSWriteColor) - Improved upon by switching Foreground and Background Colors to default values if colors are not specifid for all strings. Will also ignore extra colors if more colors are specified than strings specified. .EXAMPLE Write-Out -Text "Start with Red Text ","Then Switch to Blue Text ","Now Magenta" -ForegroundColor Red,Blue,Magenta .EXAMPLE Write-Out -Text "White on Black ","Black on White ","Dark Cyan on Cyan ","Yellow on Green ","Default Color" -ForegroundColor White,Black,DarkCyan,Yellow -BackgroundColor Black,White,Cyan,Green .EXAMPLE Write-Out -Text "Make this"," entire line"," the same color by setting defaults" -ForegroundColorDefault Yellow -BackgroundColorDefault Magenta .EXAMPLE Write-Out -Text "Add a blank line and two tabs ","before ","my text" -ForegroundColor Green,Cyan,White -PreLine 1 -PreTab 2 .EXAMPLE Write-Out -Text "Add two blank ","lines ","after my text" -ForegroundColor White,Green,White -PostLine 2 .EXAMPLE Write-Out -Text "Add 3 spaces before my text" -ForegroundColor Gray -Prespace 3 .EXAMPLE Write-Out -Text "White text and a tab after" -ForegroundColor White -NoNewLine -PostTab 1 Write-Out -Text "Black text on Yellow ","and then back to white" -ForegroundColor Black,White -BackgroundColor Yellow .EXAMPLE Write-Out -Text "An easy way to ","highlight ","text in the middle" -BackgroundColor Default,Yellow .EXAMPLE Write-Out -Text "You can even add a ","time stamp ","before your output" -ForegroundColor White,Green,White -TimeStamp -PreLine 3 .EXAMPLE Write-Out -Text "You can change the ","time stamp format" -ForegroundColor White,Yellow -TimeStamp -TimeStampFormat "dd-MM-yyy HH:mm" -PreLine 1 -PostLine 1 .EXAMPLE Write-Out -Text "An"," Error"," occurred let's write overwrite/create a new log file" -ForegroundColor White,Red,White -TimeStamp -LogFile "script.log" -Overwrite .EXAMPLE Write-Out -Text "Now you can ","Append ","this line to your log file" -ForegroundColor Cyan,Magenta -TimeStamp -LogFile "script.log" #> [CmdletBinding()] Param ( [Parameter(Mandatory=$false)] [AllowEmptyString()] [alias ('T')] [String[]] $Text = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('FGC', 'FC')] [string[]] $ForegroundColor = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('FGCD', 'FCD')] [string] $ForegroundColorDefault = [ConsoleColor]::White, [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('BGC', 'BC')] [String[]] $BackgroundColor = @(), [Parameter(Mandatory=$false)] [ValidateSet("Default","Black","DarkBlue","DarkGreen","DarkCyan","DarkRed","DarkMagenta","DarkYellow","Gray","DarkGray","Blue","Green","Cyan","Red","Magenta","Yellow","White")] [alias ('BGCD', 'BCD')] [string] $BackgroundColorDefault = "Default", [Parameter(Mandatory=$false)] [int] $PreLine = 0, [Parameter(Mandatory=$false)] [int] $PreSpace = 0, [Parameter(Mandatory=$false)] [int] $PreTab = 0, [Parameter(Mandatory=$false)] [Alias('TSF', 'TS')] [string] $TimeStampFormat = 'yyyy-MM-dd HH:mm:ss', [Parameter(Mandatory=$false)] [switch] $TimeStamp, [Parameter(Mandatory=$false)] [switch] $ClearHost, [Parameter(Mandatory=$false)] [int] $PostLine = 0, [Parameter(Mandatory=$false)] [int] $PostSpace = 0, [Parameter(Mandatory=$false)] [int] $PostTab = 0, [Parameter(Mandatory=$false)] [switch] $NoNewLine = $false, [Parameter(Mandatory=$false)] [alias ('Log', 'L')] [string] $LogFile = '', [Parameter(Mandatory=$false)] [switch] $LogOnly = $false, [Parameter(Mandatory=$false)] [switch] $Overwrite = $false ) Begin { #Nothing to Do Here } Process { #Optional - Do Not Write to ConsoleColor If (!($LogOnly)) { #Optional - Prefix Text If ($ClearHost) { Clear-Host } If ($PreLine -gt 0) { For ($i = 0; $i -lt $PreLine; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line(s) before Main text If ($PreSpace -gt 0) { For ($i = 0; $i -lt $PreSpace; $i++) { Write-Host -Object " " -NoNewLine } } # Add Tab(s) before Main text If ($PreTab -gt 0) { For ($i = 0; $i -lt $PreTab; $i++) { Write-Host -Object "`t" -NoNewLine } } # Add Space(s) before Main text If ($TimeStamp) { Write-Host -Object "[$([datetime]::Now.ToString($TimeStampFormat))]" -NoNewline } # Add Timestamp before Main Text #MAIN TEXT If (($Text.Count -gt 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -eq 0)) { #Text Only Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColorDefault -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -gt 0) -AND ($BackgroundColor.Count -eq 0)) { #Text and ForegroundColor Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($ForegroundColor.Count -le $i) { $ForegroundColor += $ForegroundColorDefault } #ForegroundColor Not Specified Set to Default If ($ForegroundColor[$i] -eq "Default") { $ForegroundColor[$i] = $ForegroundColorDefault } If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColorDefault -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -gt 0)) { #Text and BackgroundColor Specified For ($i = 0; $i -lt $Text.Count; $i++) { If ($BackgroundColor.Count -le $i) { $BackgroundColor += $BackgroundColorDefault } #BackgroundColor Not Specified Set to Default If ($BackgroundColor[$i] -eq "Default") { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColorDefault -NoNewLine } } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColorDefault -BackgroundColor $BackgroundColor[$i] -NoNewLine } } } ElseIf (($Text.Count -gt 0) -AND ($ForegroundColor.Count -gt 0) -AND ($BackgroundColor.Count -gt 0)) { #Text, ForegroundColor, and BackgroundColor Specified (FAILS NOT WRITING DEFAULT) For ($i = 0; $i -lt $Text.Count; $i++) { If ($ForegroundColor.Count -le $i) { $ForegroundColor += $ForegroundColorDefault } #ForegroundColor Not Specified Set to Default If ($BackgroundColor.Count -le $i) { $BackgroundColor += $BackgroundColorDefault } #BackgroundColor Not Specified Set to Default If ($ForegroundColor[$i] -eq "Default") { $ForegroundColor[$i] = $ForegroundColorDefault } If ($BackgroundColor[$i] -eq "Default") { If ($BackgroundColorDefault -eq "Default") { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -NoNewLine } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColorDefault -NoNewLine } } Else { Write-Host $Text[$i] -ForegroundColor $ForegroundColor[$i] -BackgroundColor $BackgroundColor[$i] -NoNewLine } } } Else { #No Text, ForegroundColor, or BackgroundColor Specified ($Text.Count -eq 0) -AND ($ForegroundColor.Count -eq 0) -AND ($BackgroundColor.Count -eq 0) } #Post Text If ($PostSpace -gt 0) { for ($i = 0; $i -lt $PostSpace; $i++) { Write-Host -Object " " -NoNewLine } } # Add Tab(s) after Main text If ($PostTab -gt 0) { for ($i = 0; $i -lt $PostTab; $i++) { Write-Host -Object "`t" -NoNewLine } } # Add Space(s) after Main text If ($PostLine -gt 0) { for ($i = 0; $i -lt $PostLine; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line(s) after Main text If ($NoNewLine) { Write-Host -NoNewline } else { Write-Host } # Add New Line after Main Text Unless NoNewLine is Supplied } #Log File $TextToWrite = "" #Build Text to Write to Log File If ($PreLine -gt 0) { For ($i = 0; $i -lt $PreLine; $i++) { $TextToWrite += "`n" } } # Add empty line(s) before Main text If ($PreSpace -gt 0) { For ($i = 0; $i -lt $PreSpace; $i++) { $TextToWrite += " " } } # Add Tab(s) before Main text If ($PreTab -gt 0) { For ($i = 0; $i -lt $PreTab; $i++) { $TextToWrite += "`t" } } # Add Space(s) before Main text If ($TimeStamp) { $TextToWrite += "[$([datetime]::Now.ToString($TimeStampFormat))]" } # Add Timestamp before Main Text If ($Text.Count -gt 0) { For ($i = 0; $i -lt $Text.Count; $i++) { $TextToWrite += $Text[$i] } } #Add Main Text If ($PostSpace -gt 0) { for ($i = 0; $i -lt $PostSpace; $i++) { $TextToWrite += " " } } # Add Tab(s) after Main text If ($PostTab -gt 0) { for ($i = 0; $i -lt $PostTab; $i++) { $TextToWrite += "`t" } } # Add Space(s) after Main text If ($PostLine -gt 0) { for ($i = 0; $i -lt $PostLine; $i++) { $TextToWrite += "`n" } } # Add empty line(s) after Main text If ($LogFile -eq "") { #No LogFile Specified - Skip } ElseIf(!(Test-Path -Path $LogFile)) { #Create Log File If Does Not Exist If ($NoNewLine) { $nf = New-Item -Path $LogFile -type file -force -Value $TextToWrite } Else { $nf = New-Item -Path $LogFile -type file -force -Value $TextToWrite`r`n } } Else { #Log File Exists If($Overwrite) { #Overwrite Log File If ($NoNewLine) { Set-Content -Path $LogFile -Value $TextToWrite -NoNewline } Else { Set-Content -Path $LogFile -Value $TextToWrite } } Else { #Append Log File Try { If ($NoNewLine) { Add-Content -Path $LogFile -Value $TextToWrite -ErrorAction Stop -NoNewline } Else { Add-Content -Path $LogFile -Value $TextToWrite -ErrorAction Stop } } Catch { Start-Sleep -s 3 If ($NoNewLine) { Add-Content -Path $LogFile -Value $TextToWrite -NoNewline } Else { Add-Content -Path $LogFile -Value $TextToWrite } } } } } End { #Nothing to Do Here } } Main
Lyft Referral Code
Lyft $10 Referral Code:
BRIAN054066