Clean No-Intro 2018 ROM Set

IMPORTANT UPDATE 6/07/2023 – Major Rewrite for v6.0!!!

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.

https://sigkillit.com/wp-content/uploads/2024/02/Clean-NoIntro2018_v60.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
  • Atari: ST
  • 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. [ Note: As of v5.5 you can use the $romSplitchar variable in each systems Filter to customize what character to split on, and by default I set it to a left Parenthesis ‘(‘ ]. 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 character 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:

Global Variable & Filter File Variable Definitions:

  • All documentation is now centrally contained in the readme.txt included in the download. Please refer to that document for definitions on the variables as well as their default values.
#1_Clean-NoIntroRoms.ps1
$global:scriptName = $PSCommandPath
$global:scriptVersion = "v6.0"
$global:romNoIntroDirectory = "C:\Games\Complete ROM Sets\No-Intro 2018\"
$global:romCustomDirectory = "C:\Games\Complete ROM Sets\Custom\"
$global:romCleanDirectory = "C:\Games\RetroPie\roms\"
$global:romCleanDirectoryPurge = $true
$global:romOverwrite = $false
$global:romFilterDirectory = (Split-Path -Path $PSCommandPath -Parent) + "\filters\"
$global:runNoIntroRomsExceptions = $true
$global:runNoIntroRoms = $true
$global:runCustomRomsExceptions = $false
$global:runCustomRoms = $false
$global:romRetropieUpload = $true
$global:romRetropieDirectory = "\\retropie\roms\"
$global:romRetropieDirectoryPurge = $true
$global:romRetropieOverwrite = $false
$global:logFile = (Split-Path -Path $PSCommandPath -Parent) + "\logs\" + (Split-Path -Path $PSCommandPath.Replace(".ps1",".log") -Leaf)
$global:logOverwrite = $true
$global:logVerbose = $false
$global:logRemoveExceptions = $true
$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"
}
$global:romCustomHashTable = [ordered]@{
	#RetroPieDirName = CustomDirName
	"amstradcpc" = "Amstrad - CPC"
	"apple2" = "Apple_2_TOSEC_2012_04_23"
	"atari800" = "Atari_8_bit_TOSEC_2012_04_23"
	"c64" = "c64"
	"coco" = "coco"
	"dragon32" = "Dragon_Data_Dragon_TOSEC_2012_04_23"
	"intellivision" = "Mattel_Intellivision _TOSEC-v2014-01-18_CM"
	"neogeo" = "neo-geo-mvs-romset"
	"trs-80" = "Tandy Radio Shack TRS-80 Color Computer - Games"
	"zmachine" = "Infocom_Z-Machine_TOSEC_2012_04_23"
	"zxspectrum" = "zx-spectrum-tosec-set-v-2020-02-18-lady-eklipse"
}
#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
	$StartScript = (Get-Date)
	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 Custom Dir          : $($global:romCustomDirectory)" -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 Run GetExceptions   : $($global:runNoIntroRomsExceptions)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* ROM Run NoIntroRoms     : $($global:runNoIntroRoms)" -LogFile $global:logFile	
	Write-Out -ForegroundColor $global:colorMain -Text "* ROM Run GetExceptions   : $($global:runCustomRomsExceptions)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* ROM Run Custom          : $($global:runCustomRoms)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* ROM Upload to Retropie  : $($global:romRetropieUpload)" -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 Retropie Overwrite  : $($global:romRetropieOverwrite)" -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 & Custom ROMs" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Script Start Time       : $($StartScript)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorSub1 -Text "Validating Global Variables" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorSub1 -Text "================================================================" -LogFile $global:logFile
	If (!(Validate-Container -Name '$global:romFilterDirectory' -Path ([ref]$global:romFilterDirectory) -Log $global:logFile -EndsWithBackslash)) { Write-Out -ForegroundColor $global:colorError -Text "EXIT SCRIPT!!!" -LogFile $global:logFile; EXIT }
	If ($global:runCustomRomsExceptions)
	{
		Write-Out -ForegroundColor $global:colorSub1 -Text "RUNCUSTOMROMSEXCEPTIONS:" -LogFile $global:logFile
		If (!(Validate-Container -Name '$global:romCustomDirectory' -Path ([ref]$global:romCustomDirectory) -Log $global:logFile -EndsWithBackslash)) { Write-Out -ForegroundColor $global:colorError -Text "EXIT SCRIPT!!!" -LogFile $global:logFile; EXIT }
	}
	If ($global:runCustomRoms)
	{
		Write-Out -ForegroundColor $global:colorSub1 -Text "RUNCUSTOMROMS:" -LogFile $global:logFile
		If (!(Validate-Container -Name '$global:romCustomDirectory' -Path ([ref]$global:romCustomDirectory) -Log $global:logFile -EndsWithBackslash)) { Write-Out -ForegroundColor $global:colorError -Text "EXIT SCRIPT!!!" -LogFile $global:logFile; EXIT }
		If (!(Validate-Container -Name '$global:romCleanDirectory' -Path ([ref]$global:romCleanDirectory) -Log $global:logFile -EndsWithBackslash)) { Write-Out -ForegroundColor $global:colorError -Text "EXIT SCRIPT!!!" -LogFile $global:logFile; EXIT }
	}
	If ($global:runNoIntroRomsExceptions)
	{
		Write-Out -ForegroundColor $global:colorSub1 -Text "RUNNOINTROROMSEXCEPTIONS:" -LogFile $global:logFile
		If (!(Validate-Container -Name '$global:romNoIntroDirectory'  -Path ([ref]$global:romNoIntroDirectory) -Log $global:logFile -EndsWithBackslash)) { Write-Out -ForegroundColor $global:colorError -Text "EXIT SCRIPT!!!" -LogFile $global:logFile; EXIT }
	}
	If ($global:runNoIntroRoms)
	{
		Write-Out -ForegroundColor $global:colorSub1 -Text "RUNNOINTROROMS:" -LogFile $global:logFile
		If (!(Validate-Container -Name '$global:romNoIntroDirectory'  -Path ([ref]$global:romNoIntroDirectory) -Log $global:logFile -EndsWithBackslash)) { Write-Out -ForegroundColor $global:colorError -Text "EXIT SCRIPT!!!" -LogFile $global:logFile; EXIT }
		If (!(Validate-Container -Name '$global:romCleanDirectory' -Path ([ref]$global:romCleanDirectory) -Log $global:logFile -EndsWithBackslash)) { Write-Out -ForegroundColor $global:colorError -Text "EXIT SCRIPT!!!" -LogFile $global:logFile; EXIT }
	}
	If($global:romRetropieUpload)
	{
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROMRETROPIEUPLOAD:" -LogFile $global:logFile
		If (!(Validate-Container -Name '$global:romRetropieDirectory' -Path ([ref]$global:romRetropieDirectory) -Log $global:logFile -EndsWithBackslash)) { Write-Out -ForegroundColor $global:colorError -Text "EXIT SCRIPT!!!" -LogFile $global:logFile; EXIT }
	}

	$StartExceptionsNoIntro = (Get-Date)
	$ExceptionsLog = $global:logFile.Replace(".log","_Exceptions_NoIntro.log")
	Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "SECTION 2A: BUILD LIST OF POTENTIAL EXCEPTIONS TO CREATE FILTERS - NO-INTRO ROMS" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Log Files               : $($ExceptionsLog)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "*                         : $($global:logFile)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Log Overwrite           : $($global:logOverwrite)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Description             : Use ROM naming scheme to build a list of potential exceptions" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "*                           to create filters used to remove unwanted ROMs for each system" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "*                           ex: (Beta), (Proto), (Japan)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	$ArgumentHash = @{
		Source = $global:romNoIntroDirectory
		Filters = $global:romFilterDirectory
		HashTable = $global:romNoIntroHashTable
		Log = $ExceptionsLog,$global:logFile
		LogOverwrite = $global:logOverwrite
	}
	If ($global:runNoIntroRomsExceptions)
	{
		If ($global:romNoIntroHashTable.Count -eq 0)
		{
			Write-Out -ForegroundColor $global:colorWarn -Text "Warning: Nothing is in romNoIntroHashTable (All sytems are probably commented out in global hashtable)" -LogFile $global:logFile
		}
		Else
		{
			Get-RomsExceptions @ArgumentHash
		}
	}
	Else
	{
		Write-Out -ForegroundColor $global:colorWarn -Text "Skip - Global Variable runNoIntroRomsExceptions set to False" -LogFile $global:logFile
	}
	$EndExceptionsNoIntro = (Get-Date)

	$StartCleanupNoIntro = (Get-Date)
	Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "SECTION 2B: 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
	$ArgumentHash = @{
		Source = $global:romNoIntroDirectory
		Destination = $global:romCleanDirectory
		Overwrite = $global:romOverwrite
		Purge = $global:romCleanDirectoryPurge	
		Filters = $global:romFilterDirectory
		HashTable = $global:romNoIntroHashTable
		Custom = $false
		Log = $global:logFile
		LogOverwrite = $global:logOverwrite 
		LogVerbose = $global:logVerbose
		LogRemoveExceptions = $global:logRemoveExceptions
	}
	If ($global:runNoIntroRoms)
	{
		If ($global:romNoIntroHashTable.Count -eq 0) 
		{
			Write-Out -ForegroundColor $global:colorWarn -Text "Warning: Nothing is in romNoIntroHashTable (All sytems are probably commented out in global hashtable)" -LogFile $global:logFile
		}
		Else
		{
			Clean-Roms @ArgumentHash
		}
	}
	Else
	{
		Write-Out -ForegroundColor $global:colorWarn -Text "Skip - Global Variable runNoIntroRoms set to False" -LogFile $global:logFile
	}
	$EndCleanupNoIntro = (Get-Date)
	
	$StartExceptionsCustom = (Get-Date)
	$ExceptionsLog = $global:logFile.Replace(".log","_Exceptions_Custom.log")
	Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "SECTION 3A: BUILD LIST OF POTENTIAL EXCEPTIONS TO CREATE FILTERS - CUSTOM ROMS" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Log Files               : $($ExceptionsLog)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "*                         : $($global:logFile)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Log Overwrite           : $($global:logOverwrite)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Description             : Use ROM naming scheme to build a list of potential exceptions" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "*                           to create filters used to remove unwanted ROMs for each system" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "*                           ex: (Beta), (Proto), (Japan)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	$ArgumentHash = @{
		Source = $global:romCustomDirectory
		Filters = $global:romFilterDirectory
		HashTable = $global:romCustomHashTable
		Log = $ExceptionsLog,$global:logFile
		LogOverwrite = $global:logOverwrite
	}
	If ($global:runCustomRomsExceptions)
	{
		If ($global:romCustomHashTable.Count -eq 0)
		{
			Write-Out -ForegroundColor $global:colorWarn -Text "Warning: Nothing is in romCustomHashTable (All sytems are probably commented out in global hashtable)" -LogFile $global:logFile
		}
		Else
		{
			Get-RomsExceptions @ArgumentHash
		}
	}
	Else
	{
		Write-Out -ForegroundColor $global:colorWarn -Text "Skip - Global Variable runCustomRomsExceptions set to False" -LogFile $global:logFile
	}
	$EndExceptionsCustom = (Get-Date)

	$StartCleanupCustom = (Get-Date)
	Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "SECTION 3B: CLEANUP CUSTOM 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 Custom ROMs from Source to clean directory" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	$ArgumentHash = @{
		Source = $global:romCustomDirectory
		Destination = $global:romCleanDirectory
		Overwrite = $global:romOverwrite
		Purge = $global:romCleanDirectoryPurge		
		Filters = $global:romFilterDirectory
		HashTable = $global:romCustomHashTable
		Custom = $true
		Log = $global:logFile
		LogOverwrite = $global:logOverwrite 
		LogVerbose = $global:logVerbose
		LogRemoveExceptions = $global:logRemoveExceptions
	}
	If ($global:runCustomRoms)
	{
		If ($global:romCustomHashTable.Count -eq 0) 
		{
			Write-Out -ForegroundColor $global:colorWarn -Text "Warning: Nothing is in romCustomHashTable (All sytems are probably commented out in global hashtable)" -LogFile $global:logFile
		}
		Else
		{
			Clean-Roms @ArgumentHash
		}
	}
	Else
	{
		Write-Out -ForegroundColor $global:colorWarn -Text "Skip - Global Variable runCustomRoms set to False" -LogFile $global:logFile
	}
	$EndCleanupCustom = (Get-Date)
	
	$StartUploadNoIntro = (Get-Date)
	Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "SECTION 4A: UPLOAD CLEANED NO-INTRO ROMS TO RETROPIE" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Log Files               : $($global:logFile)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Log Overwrite           : False" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Description             : Upload Cleaned No-Intro ROMs to Retropie" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	If ($global:romRetropieUpload)
	{
		$ArgumentHash = @{
			Source = $global:romCleanDirectory
			Destination = $global:romRetropieDirectory
			Purge = $global:romRetropieDirectoryPurge
			Overwrite = $global:romRetropieOverwrite
			HashTable = $global:romNoIntroHashTable
			Log = $global:logFile
		}
		
		If ($global:runNoIntroRoms)
		{
			If ($global:romNoIntroHashTable.Count -eq 0) 
			{
				Write-Out -ForegroundColor $global:colorWarn -Text "Warning: Nothing is in romNoIntroHashTable (All sytems are probably commented out in global hashtable)" -LogFile $global:logFile
			}
			Else
			{
				Upload-Roms @ArgumentHash
			}
		}
		Else
		{
			Write-Out -ForegroundColor $global:colorWarn -Text "Skip - Global Variable runNoIntroRoms set to False" -LogFile $global:logFile
		}
	}
	Else
	{
		Write-Out -ForegroundColor $global:colorWarn -Text "Skip - Global Variable romRetropieUpload set to False" -LogFile $global:logFile
	}
	$EndUploadNoIntro = (Get-Date)
	
	$StartUploadCustom = (Get-Date)
	Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "SECTION 4B: UPLOAD CLEANED CUSTOM ROMS TO RETROPIE" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Log Files               : $($global:logFile)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Log Overwrite           : False" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Description             : Upload Cleaned Custom ROMs to Retropie" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	If ($global:romRetropieUpload)
	{
		$ArgumentHash = @{
			Source = $global:romCleanDirectory
			Destination = $global:romRetropieDirectory
			Purge = $global:romRetropieDirectoryPurge
			Overwrite = $global:romRetropieOverwrite
			HashTable = $global:romCustomHashTable
			Log = $global:logFile
		}
		If ($global:runCustomRoms)
		{
			If ($global:romCustomHashTable.Count -eq 0) 
			{
				Write-Out -ForegroundColor $global:colorWarn -Text "Warning: Nothing is in romCustomHashTable (All sytems are probably commented out in global hashtable)" -LogFile $global:logFile
			}
			Else
			{
				Upload-Roms @ArgumentHash
			}
		}
		Else
		{
			Write-Out -ForegroundColor $global:colorWarn -Text "Skip - Global Variable runNoIntroRoms set to False" -LogFile $global:logFile
		}
	}
	Else
	{
		Write-Out -ForegroundColor $global:colorWarn -Text "Skip - Global Variable romRetropieUpload set to False" -LogFile $global:logFile
	}
	$EndUploadCustom = (Get-Date)
	
	$EndScript = (Get-Date)
	Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "SECTION 5: END RESULTS" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Exceptions ROMs (No-Intro) Elapsed Time : $([math]::Round(($EndExceptionsNoIntro - $StartExceptionsNoIntro).totalseconds, 2)) seconds" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Cleanup    ROMs (No-Intro) Elapsed Time : $([math]::Round(($EndCleanupNoIntro - $StartCleanupNoIntro).totalseconds, 2)) seconds" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Exceptions ROMs (Custom)   Elapsed Time : $([math]::Round(($EndExceptionsCustom - $StartExceptionsCustom).totalseconds, 2)) seconds" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Cleanup    ROMs (Custom)   Elapsed Time : $([math]::Round(($EndCleanupCustom - $StartCleanupCustom).totalseconds, 2)) seconds" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Upload     ROMs (No-Intro) Elapsed Time : $([math]::Round(($EndUploadNoIntro - $StartUploadNoIntro).totalseconds, 2)) seconds" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Upload     ROMs (Custom)   Elapsed Time : $([math]::Round(($EndUploadCustom - $StartUploadCustom).totalseconds, 2)) seconds" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Script Start Time                       : $($StartScript)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Script End Time                         : $($EndScript)" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "* Script Elapsed Time                     : $([math]::Round(($EndScript - $StartScript).totalseconds, 2)) seconds" -LogFile $global:logFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $global:logFile
}



Function Get-RomsExceptions()
{
	Param
	(	
		[Parameter(Mandatory=$true)]
		[Alias("Source")] 
		[string]$RomSourceDir,
		
		[Parameter(Mandatory=$true)]
		[Alias("Filters")] 
		[string]$RomFiltersDir = "",
		
		[Parameter(Mandatory=$true)]
		[Alias("HashTable")] 
		[System.Collections.Specialized.OrderedDictionary]$RomHashTable,
		
		[Parameter(Mandatory=$true)]
		[Alias("Log")]
		[string[]]$LogFiles,
		
		[Parameter(Mandatory=$false)]
		[string]$LogOverwrite = $false
	)
	
	#Create Log Files But Don't Overwrite Global Log File
	If ($LogOverwrite -eq $true)
	{
		ForEach ($LF in $LogFiles)
		{
			If ($LF -eq $global:logFile)
			{
				Write-Out -Text "" -LogFile $LF -NoNewLine -LogOnly
			}
			Else
			{
				Write-Out -Text "" -LogFile $LF -NoNewLine -Overwrite
			}
		}
	}
	Else 
	{
		Write-Out -Text "" -LogFile $LogFile -NoNewLine
	}
	
	[array]$colRomsAll = @()
	[array]$colUniqueRomsAll = @()
	ForEach ($GameSystem in $RomHashTable.keys)
	{
		#Set Per Game System Variables
		$RomSource = "$($RomSourceDir)$($RomHashTable[$GameSystem])"
		$RomFilters = "$($RomFiltersDir)$($GameSystem).ps1"
		$LogFile = $LogFiles
		$timeStart = (Get-Date)
		
		#Process Current ROM Source Dir
		Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorMain -Text "PROCESS: $GameSystem" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Description         : $($RomHashTable[$GameSystem])" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Source Dir          : $($RomSource)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Filters             : $($RomFilters)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "Start Time              : $($timeStart)" -LogFile $LogFile
		
		#Confirm Current ROM Source Dir Exists
		If(!(Test-Path -LiteralPath $RomSource))
		{
			Write-Out -ForegroundColor $global:colorError -Text "ERROR: ROM Source Directory Does Not Exist - Stop Processing!" -LogFile $LogFile
		}
		Else 
		{
			#Check If Filter Exists Then Set $romSplitstr
			If (Test-Path -LiteralPath $RomFilters)
			{
				Write-Out -ForegroundColor $global:colorSub1 -Text "Import Variables from $($RomFilters)" -LogFile $LogFile
				. $RomFilters
				Write-Out -ForegroundColor $global:colorSub1,$global:colorSub1 -Text "`$romSplitstr            : ","'$($romSplitstr)'" -LogFile $LogFile
				Write-Out -ForegroundColor $global:colorSub1,$global:colorSub1 -Text "`$romSortAscending       : ","$romSortAscending" -LogFile $LogFile
				Write-Out -ForegroundColor $global:colorSub1,$global:colorSub1 -Text "`$romUnzip               : ","$romUnzip" -LogFile $LogFile
				If ([string]::IsNullOrEmpty($romSplitstr))
				{
					Write-Out -ForegroundColor $global:colorWarn -Text "Skip - No Split String Defined in `$romSplitstr to Determine Unique ROM Name" -LogFile $LogFile
				}
				Else
				{
					[array]$colRoms = @()
					[array]$colUniqueRoms = @()
					Write-Out -ForegroundColor $global:colorSub1 -Text "...Collecting ROMs..."
					$colRoms = Get-ChildItem -LiteralPath $RomSource
					$colRomsAll += $colRoms
					Write-Out -ForegroundColor $global:colorSub1 -Text "...Sorting ROMs..."
					$colUniqueRoms = $colRoms | ForEach-Object { ($_.Name -split "(?=$($romSplitstr))",2)[1] } | Sort-Object -Unique
					$colUniqueRoms = Sort-Naturally -Array $colUniqueRoms
					$colUniqueRomsAll += $colUniqueRoms
					Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()): $($colUniqueRoms.Count) Potential Exceptions to Create Filters" -LogFile $LogFile
					Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile
					#Speedup Output on Large Rom Sets slightly vs Write-Out
					$colUniqueRoms | ForEach-Object {
						Add-Content -Path $LogFile -Value "$($_)"
						Write-Host -Object ($_ -join "`n") -ForegroundColor $global:colorSub1
					}
					Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()): Processing Results" -LogFile $LogFile
					Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile
					Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs Total              : $($colRoms.Count)" -LogFile $LogFile
					Write-Out -ForegroundColor $global:colorSub1 -Text "Potential Exceptions    : $($colUniqueRoms.Count)" -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
				}
			}
			Else
			{
				Write-Out -ForegroundColor $global:colorWarn -Text "Filters Not Exist: Do Not Process" -LogFile $LogFile
			}
		}
	}
	$timeStart = (Get-Date)
	Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $LogFile
	Write-Out -ForegroundColor $global:colorMain -Text "PROCESS: Combined Potential Exceptions from All Game Systems" -LogFile $LogFile
	Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $LogFile
	Write-Out -ForegroundColor $global:colorSub1 -Text "...Sorting ROMs..."
	$colUniqueRomsAll = $colUniqueRomsAll | Sort-Object -Unique
	$colUniqueRomsAll = Sort-Naturally -Array $colUniqueRomsAll
	Write-Out -ForegroundColor $global:colorMain -Text "Found $($colUniqueRomsAll.Count) Combined Potential Exceptions to Create Filters" -LogFile $LogFile
	#Speedup Output on Large Rom Sets slightly vs Write-Out
	$colUniqueRomsAll | ForEach-Object {
		Add-Content -Path $LogFile -Value "$($_)"
		Write-Host -Object ($_ -join "`n") -ForegroundColor $global:colorSub1
	}
	Write-Out -ForegroundColor $global:colorMain -Text "COMBINED POTENTIAL EXCEPTIONS: Processing Results" -LogFile $LogFile
	Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile
	Write-Out -ForegroundColor $global:colorSub1 -Text "Combined ROMs Total           : $($colRomsAll.Count)" -LogFile $LogFile
	Write-Out -ForegroundColor $global:colorSub1 -Text "Combined Potential Exceptions : $($colUniqueRomsAll.Count)" -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
	
	#Clean Variables
	If (Test-Path variable:colRoms) {Remove-Variable colRoms}
	If (Test-Path variable:colUniqueRoms) {Remove-Variable colUniqueRoms}
	If (Test-Path variable:colRomsAll) {Remove-Variable colRomsAll}
	If (Test-Path variable:colUniqueRomsAll) {Remove-Variable colUniqueRomsAll}
}



Function Clean-Roms()
{
	Param
	(
		[Parameter(Mandatory=$true)]
		[Alias("Source")]
		[string]$RomSourceDir,
		
		[Parameter(Mandatory=$true)]
		[Alias("Destination")]
		[string]$RomDestinationDir,
		
		[Parameter(Mandatory=$true)]
		[Alias("Overwrite")]
		[bool]$RomOverwrite,
		
		[Parameter(Mandatory=$true)]
		[Alias("Purge")]
		[bool]$RomDirPurge,
		
		[Parameter(Mandatory=$true)]
		[Alias("Filters")]
		[string]$RomFiltersDir,
		
		[Parameter(Mandatory=$true)]
		[Alias("HashTable")] 
		[System.Collections.Specialized.OrderedDictionary]$RomHashTable,
		
		[Parameter(Mandatory=$false)]
		[Alias("Custom")]
		[bool]$RomCustom = $false,
		
		[Parameter(Mandatory=$true)]
		[Alias("Log")]
		[string[]]$LogFiles,
		
		[Parameter(Mandatory=$false)]
		[bool]$LogOverwrite = $true,
		
		[Parameter(Mandatory=$false)]
		[bool]$LogVerbose = $false,
		
		[Parameter(Mandatory=$false)]
		[bool]$LogRemoveExceptions = $false
	)
		
	ForEach ($GameSystem in $RomHashTable.keys)
	{
		#Set Per Game System Variables
		$RomSource = "$($RomSourceDir)$($RomHashTable[$GameSystem])"
		$RomDestination = "$($RomDestinationDir)$($GameSystem)"
		$RomFilters = "$($RomFiltersDir)$($GameSystem).ps1"
		$LogFile = $LogFiles + "$((Split-Path -Path $LogFiles -Parent))\$($GameSystem).log"
		$timeStart = (Get-Date)
		$countTotal = 0
		$countUnique = 0
		$countExceptionsDeleted = 0
		$countDuplicatesDeleted = 0
		$countNonDuplicatesDeleted = 0
		$countMulticartGames = 0
		$countMulticartsKept = 0
		
		#Create Log Files But Don't Overwrite Global Log File
		If ($LogOverwrite -eq $true)
		{
			ForEach ($LF in $LogFile)
			{
				If ($LF -eq $global:logFile)
				{
					Write-Out -Text "" -LogFile $LF -NoNewLine -LogOnly
				}
				Else
				{
					Write-Out -Text "" -LogFile $LF -NoNewLine -Overwrite
				}
			}
		}
		Else 
		{
			Write-Out -Text "" -LogFile $LogFile -NoNewLine
		}
		
		Write-Out -PreLine 1 -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorMain -Text "PROCESS: $GameSystem" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorMain -Text "****************************************************************" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Description         : $($RomHashTable[$GameSystem])" -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 "ROM Overwrite           : $($LogOverwrite)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Clean Dir Purge     : $($RomDirPurge)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Filters             : $($RomFilters)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Custom              : $($RomCustom)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "Log Files               : $($LogFile -join "`n                        : ")" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "Log Overwrite           : $($LogOverwrite)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "Log Verbose             : $($LogVerbose)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "Log Remove Exceptions   : $($LogRemoveExceptions)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "Start Time              : $($timeStart)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 1/7): Processing Information [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile
		If(!(Test-Path -LiteralPath $RomSource))
		{
			Write-Out -ForegroundColor $global:colorError -Text "ERROR: ROM Source Directory Does Not Exist - Stop Processing!" -LogFile $LogFile
			Continue
		}
		
		If ($RomDirPurge)
		{
			If(Test-Path -LiteralPath "$($RomDestination)")
			{
				Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Clean Dir Exists, Purge Before Processing" -LogFile $LogFile
				Write-Out -ForegroundColor DarkRed -Text "Purge: $($RomDestination)" -LogFile $LogFile
				Remove-Item "$($RomDestination)" -Recurse -Force -Confirm:$false
			}
			Else
			{
				Write-Out -ForegroundColor $global:colorWarn -Text "ROM Clean Dir Does Not Exist, Skip Purge Before Processing" -LogFile $LogFile
			}
		}

		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 `$romSplitstr Default" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorWarn -Text "$($RomFilters): Write `$romSortAscending Default" -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
			Write-Out -ForegroundColor $global:colorWarn -Text "$($RomFilters): Write `$romsMultiCart Default" -LogFile $LogFile
			If ($RomCustom)
			{
				$DefaultFilters = Get-CustomDefaultFilters (Split-Path -Path $RomFilters -Leaf)
			}
			Else
			{
				$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($romSplitstr, $romSortAscending, $romUnzip, $romsDoNotDelete, $romsExceptions, $romsSortOrder, $romsMultiCart)
		Write-Out -ForegroundColor $global:colorSub1 -Text "Import Variables from $($RomFilters)" -LogFile $LogFile
		. "$($RomFilters)"
		Write-Out -ForegroundColor $global:colorSub1,$global:colorSub1 -Text "`$romSplitstr            : ","'$($romSplitstr)'" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1,$global:colorSub1 -Text "`$romSortAscending       : ","$romSortAscending" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1,$global:colorSub1 -Text "`$romUnzip               : ","$romUnzip" -LogFile $LogFile

		Write-Out -ForegroundColor $global:colorMain -Text "`$romsDoNotDelete: ROM Exceptions to Keep [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -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 "`$romsExceptions: Delete ROMs Containing [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -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 "`$romsSortOrder: ROM Sort Order [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorMain -Text "-------------------------------------------------------" -LogFile $LogFile
		If (($romsSortOrder.Count -le 0) -OR ($romsSortOrder -eq $null))
		{
				Write-Out -ForegroundColor $global:colorWarn -Text "None" -LogFile $LogFile
		}
		Else 
		{
			ForEach ($rom in $romsSortOrder)
			{
				Write-Out -ForegroundColor $global:colorSub1 -Text "$($rom)" -LogFile $LogFile
			}
		}
		
		Write-Out -ForegroundColor $global:colorMain -Text "`$romsMultiCart: ROM Multicart Exceptions to Keep [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorMain -Text "-------------------------------------------------------" -LogFile $LogFile
		If (($romsMultiCart.Count -le 0) -OR ($romsMultiCart -eq $null))
		{
				Write-Out -ForegroundColor $global:colorWarn -Text "None" -LogFile $LogFile
		}
		Else 
		{
			ForEach ($rom in $romsMultiCart)
			{
				Write-Out -ForegroundColor $global:colorSub1 -Text "$($rom)" -LogFile $LogFile
			}
		}
		
		#Get List of ROMs and Unique ROMs in the original ROM set
		Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 2/7): Get All ROMs and Unique ROMs to Process [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -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; Length = $_.length};$colRoms.add($obj)|out-null})
		If ([string]::IsNullOrEmpty($romSplitstr))
		{
			#No Split string to Determine Unique ROM Name
			Write-Out -ForegroundColor $global:colorWarn -Text "Skip - No Split String Defined in `$romSplitstr to Determine Unique ROM Name" -LogFile $LogFile
			
			Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 3/7): Remove Exceptions [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorWarn -Text "Skip" -LogFile $LogFile

			Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 4/7): Naturally Sort ROMs and Update Unique ROMs [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile	
			Write-Out -ForegroundColor $global:colorWarn -Text "Skip" -LogFile $LogFile
			
			Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 5/7): Identify Primary ROM and Remove Duplicates [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorWarn -Text "Skip" -LogFile $LogFile
			
			Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 6/7): Copy No-Intro ROMs [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorWarn -Text "Skip" -LogFile $LogFile
			
			#Remove All ROMs
			$colRoms.Clear()
		}
		Else
		{
			#Count Total Original Source ROMs and Original Source Unique ROMs
			[array]$colUniqueRoms = @()
			$colUniqueRoms = $colRoms | ForEach-Object { ($_.Name -split $romSplitstr)[0] } | Sort-Object -Unique
			$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/7): Remove Exceptions [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -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
				$ExceptionsFound = [ordered]@{}
				ForEach ($romException in $romsExceptions) 
				{			
					
					#Find Exceptions
					[array]$colExceptionRoms = ($colRoms.Name -match [regex]::escape($romException))
					[array]$colDnd = $colExceptionRoms.Where({$romsDoNotDelete -contains $_})
					[array]$colDelete = $colExceptionRoms.Where({$romsDoNotDelete -notcontains $_})

					#Do Not Delete These ROMs
					If ($colDnd.Count -gt 0)
					{
						If ($LogRemoveExceptions) 
						{ 
							#Speedup Output on Large Rom Sets vs Looping with Write-Out
							$colDnd | ForEach-Object {
								Add-Content -Path $LogFile -Value "DO NOT DELETE EXCEPTION (Special Case): $($_)"
								Write-Host -Object "DO NOT DELETE EXCEPTION (Special Case): $($_)" -ForegroundColor $global:colorSub1
							}
						}
					}
					
					#Delete ROMs
					If ($colDelete.Count -gt 0)
					{
						#Update Counters
						$countExceptionsDeleted += $colDelete.Count
						If ($ExceptionsFound.Contains($romException))
						{
							$ExceptionsFound[$romException] += $colDelete.Count
						}
						Else
						{
							$ExceptionsFound[$romException] = $colDelete.Count
						}
						
						#Delete ROMs
						If ($LogRemoveExceptions) 
						{
							#Speedup Output on Large Rom Sets slightly vs Write-Out
							$colDelete | ForEach-Object {
								$colRoms.RemoveAt([array]::IndexOf($colRoms.Name,$_))
								Add-Content -Path $LF -Value "DELETE EXCEPTION '$($romException)': $($_)"
								Write-Host -Object "DELETE EXCEPTION '$($romException)': $($_)" -ForegroundColor $global:colorSub3
								
							}
						}
						Else
						{
							$colDelete | ForEach-Object {$colRoms.RemoveAt([array]::IndexOf($colRoms.Name,$_))}
						}
					}
				}

				Write-Out -ForegroundColor $global:colorMain -Text "UNIQUE EXCEPTIONS FOUND [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]:" -LogFile $LogFile
				Write-Out -ForegroundColor $global:colorMain -Text "-------------------------------------------------------" -LogFile $LogFile
				If ($ExceptionsFound.Count -gt 0)
				{
					ForEach ($EF in $ExceptionsFound.GetEnumerator())
					{
						Write-Out -ForegroundColor $global:colorSub1 -Text "$($EF.Name) : Count=$($EF.Value)" -LogFile $LogFile
					}
				}
				Else
				{
					Write-Out -ForegroundColor $global:colorSub1 -Text "None" -LogFile $LogFile
				}
			}

			#Naturally Sort ROMs and Update Unique ROMs After Removing Exceptions (Speeds up the sort on large ROM sets)
			Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 4/7): Update Unique ROMs and Naturally Sort [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile	
			$colUniqueRoms = $colRoms | ForEach-Object { ($_.Name -split $romSplitstr)[0] } | Sort-Object -Unique
			Write-Out -ForegroundColor $global:colorMain -Text "Updated Total ROMs: $($colRoms.count)" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorMain -Text "Updated Unique ROMs: $($colUniqueRoms.count)" -LogFile $LogFile
			If ($romSortAscending)
			{
				Write-Out -ForegroundColor $global:colorMain -Text "Sort ROMs: Ascending" -LogFile $LogFile
				If ($colRoms.count -gt 1) {$colRoms = Sort-Naturally -Array $colRoms}
				If ($colUniqueRoms.count -gt 1) {$colUniqueRoms = Sort-Naturally -Array $colUniqueRoms}
			}
			Else
			{
				Write-Out -ForegroundColor $global:colorMain -Text "Sort ROMs: Descending" -LogFile $LogFile
				If ($colRoms.count -gt 1) {$colRoms = Sort-Naturally -Array $colRoms -Descending}
				If ($colUniqueRoms.count -gt 1) {$colUniqueRoms = Sort-Naturally -Array $colUniqueRoms -Descending}
			}

			#Identify Primary ROM to Keep and Remove Duplicates
			Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 5/7): Identify Primary ROM and Remove Duplicates [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile
			ForEach ($uniqueRom in $colUniqueRoms)
			{
				#Determine Duplicates For Each Unique ROM Name
				[array]$colDuplicateRoms = $colRoms.Name -match ("^"+[regex]::escape($uniqueRom)+$romSplitstr)
				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 = ""
						[array]$colRomsToSort = $colDuplicateRoms -match $sortRegex   #$sortRegex is already escaped in the filters
						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++) 
							{
								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
								$matchRomException = $false
								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
						}
					}
					
					#Determine Multicart
					$multicartFound = $false
					If ($romsMultiCart.Count -gt 0)
					{
						ForEach ($Multicart in $romsMultiCart)
						{
							$multicartMatch = [Regex]::Match($primaryRom, $Multicart).Value
							If (!([string]::IsNullOrEmpty($multicartMatch)))
							{
								$multicartFound = $true
								$multicartSearch = [Regex]::Escape($primaryRom).Replace([Regex]::Escape($multicartMatch), $Multicart)
								If ($LogVerbose -eq $true)
								{
									Write-Out -ForegroundColor $global:colorSub1 -Text "Primary ROM Multicart Detected: $($multicartMatch)" -LogFile $LogFile
									Write-Out -ForegroundColor $global:colorSub1 -Text "Primary ROM Multicart Search: $($multicartSearch)" -LogFile $LogFile
								}
								$countMulticartGames++
								break
							}
						}
					}
					
					#Remove All Duplicate ROMS Except Primary ROM, DND, or Multicarts
					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)
							{
								If ($romsDoNotDelete -contains $duplicateRom) 
								{
									#Found Special Case (Flag NOT Delete)
									$romDND = $true
								}
							}
							
							#Multicart Do Not Delete ROMs Check
							$romMC = $false
							If ($multicartFound)
							{
								If (!([string]::IsNullOrEmpty([Regex]::Match($duplicateRom, $multicartSearch).Value)))
								{
									$romMC = $true
								}
							}
							
							#Check to Delete or Not
							If ($romDND -eq $true)
							{
								Write-Out -ForegroundColor $global:colorSub1 -Text "DO NOT DELETE(Special Case): $($duplicateRom)" -LogFile $LogFile
							}
							ElseIf ($romMC -eq $true)
							{
								$countMulticartsKept++
								Write-Out -ForegroundColor $global:colorSub1 -Text "KEEP(Multicart): $($duplicateRom)" -LogFile $LogFile
							}
							Else 
							{
								If ($primaryRom -eq "")
								{
									Write-Out -ForegroundColor DarkRed -Text "DELETE(No Primary Found): $($duplicateRom)" -LogFile $LogFile
								}
								Else
								{
									Write-Out -ForegroundColor DarkRed -Text "DELETE(Duplicate/Exception): $($duplicateRom)" -LogFile $LogFile
								}					
								#Delete ROM
								$colRoms.RemoveAt([array]::IndexOf($colRoms.Name,$duplicateRom))
								# For ($i=0; $i -lt $colRoms.Count; $i++)
								# {
									# If ($colRoms[$i].Name -eq $duplicateRom)
									# {
										# $colRoms.RemoveAt($i)
										# $i--
										# break
									# }
								# }
								$countDuplicatesDeleted++
							}
						}			
					}
				}
				Else 
				{
					#v6.0 Fixed $colDuplicateRoms acting as (type=object) when there's 1 item in array by declaring $colDuplicateRoms & $colUniqueRoms as [array]
					#If No Matches Found Manually Set $colDuplicateRoms (Means ROM did not have $romSplitstr and returned file name + extension)
					If ($colDuplicateRoms.count -eq 0)
					{
						$colDuplicateRoms = $uniqueRom
						If ($LogVerbose -eq $true)
						{
							Write-Out -ForegroundColor $global:colorSub1 -Text "Primary ROM Set (Missing '$($romSplitstr)'): $($colDuplicateRoms[0])"
						}
					}
					
					#Non-Duplicate ROM Primary By Default
					If ($LogVerbose -eq $true)
					{
						Write-Out -ForegroundColor $global:colorSub1 -Text "SKIP REGEX (No Duplicates):" -LogFile $LogFile
						Write-Out -ForegroundColor $global:colorSub1 -Text "Primary ROM Set (Non-Duplicate): $($colDuplicateRoms[0])" -LogFile $LogFile
					}

					#Check Primary ROM For Exceptions
					$matchRomException = $false
					ForEach ($romException in $romsExceptions) 
					{
						If ($colDuplicateRoms[0] -match [regex]::escape($romException))
						{
							#Exception Found (Flag Delete)
							$matchRomException = $true
							break
						}
					}
					
					#Special Case Do Not Delete ROMs Check
					$romDND = $false
					If ($romsDoNotDelete.Count -gt 0)
					{
						If ($romsDoNotDelete -contains $colDuplicateRoms[0]) 
						{
							#Found Special Case (Flag NOT Delete)
							$romDND = $true
						}
					}
					
					#Check to Delete or Not
					If ($romDND -eq $true)
					{
						Write-Out -ForegroundColor $global:colorSub1 -Text "DO NOT DELETE (Special Case Non-Duplicate): $($colDuplicateRoms[0])" -LogFile $LogFile
					}
					ElseIf ($matchRomException -eq $false)
					{
						Write-Out -ForegroundColor $global:colorSub1 -Text "KEEP(Primary Non-Duplicate): $($colDuplicateRoms[0])" -LogFile $LogFile
					}
					Else 
					{
						#Delete ROM
						Write-Out -ForegroundColor DarkRed -Text "DELETE (Exception Non-Duplicate) '$($romException)': $($colDuplicateRoms[0])" -LogFile $LogFile
						$colRoms.RemoveAt([array]::IndexOf($colRoms.Name,$colDuplicateRoms[0]))
						# For ($i=0; $i -lt $colRoms.Count; $i++)
						# {
							# If ($colRoms[$i].Name -eq $colDuplicateRoms[0]) #BUG SHOULD BE $colDuplicateRoms[0] WAS COPY PASTE ERROR FROM SECTION WHERE MULTIPLE ROMS MATCH
							# {
								# $colRoms.RemoveAt($i)
								# $i--
								# break
							# }
						# }
						$countNonDuplicatesDeleted++
					}
				}
			}
			
			#Copy ROMs
			Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 6/7): Copy No-Intro ROMs [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -LogFile $LogFile
			Write-Out -ForegroundColor $global:colorMain -Text "================================================================" -LogFile $LogFile
			#Calculate Total ROM Size (MB) to Copy
			$RomsSizeMB = [math]::Round(($colRoms | Measure -Property Length -sum).Sum/1024/1024,2,[System.MidpointRounding]::AwayFromZero)
			
			#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 ($($RomsSizeMB)MB) 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 ($($RomsSizeMB)MB) 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 -LiteralPath $rom.FullName -DestinationPath $RomDestination -Force
					Remove-Item -LiteralPath $rom.FullName -Force
				}
			}
		}
		
		

		#Results
		Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem.ToUpper()) (STEP 7/7): Processing Results [$(Get-Date -Format 'MM/dd/yyyy HH:mm:ss')]" -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 Multicart Games    : $($countMulticartGames)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs Multicarts Kept    : $($countMulticartsKept)" -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 Cleaned      : $($countTotal - ($countExceptionsDeleted + $countDuplicatesDeleted + $countNonDuplicatesDeleted))" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROMs Total Cleaned Size : $($RomsSizeMB)MB" -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
		
		#Clean Variables	
		If (Test-Path variable:colRoms) {Remove-Variable colRoms}
		If (Test-Path variable:colUniqueRoms) {Remove-Variable colUniqueRoms}
		If (Test-Path variable:ExceptionsFound) {Remove-Variable ExceptionsFound}
		If (Test-Path variable:colExceptionRoms) {Remove-Variable colExceptionRoms}
		If (Test-Path variable:colDnd) {Remove-Variable colDnd}
		If (Test-Path variable:colDelete) {Remove-Variable colDelete}
		If (Test-Path variable:colDuplicateRoms) {Remove-Variable colDuplicateRoms}
	}
}



Function Upload-Roms()
{
	Param
	(
		[Parameter(Mandatory=$true)]
		[Alias("Source")]
		[string]$RomSourceDir,
		
		[Parameter(Mandatory=$true)]
		[Alias("Destination")]
		[string]$RomDestinationDir,
		
		[Parameter(Mandatory=$false)]
		[Alias("Purge")]
		[bool]$RomDirPurge = $false,
		
		[Parameter(Mandatory=$false)]
		[Alias("Overwrite")]
		[bool]$RomOverwrite = $false,
		
		[Parameter(Mandatory=$true)]
		[Alias("HashTable")] 
		[System.Collections.Specialized.OrderedDictionary]$RomHashTable,
		
		[Parameter(Mandatory=$true)]
		[Alias("Log")]
		[string[]]$LogFiles
	)
	
	ForEach ($GameSystem in $RomHashTable.keys)
	{
		#Set Per Game System Variables
		$RomSource = "$($RomSourceDir)$($GameSystem)"
		$RomDestination = "$($RomDestinationDir)$($GameSystem)"
		$LogFile = $LogFiles
		$timeStart = (Get-Date)
		
		Write-Out -ForegroundColor $global:colorMain -Text "$($GameSystem)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorMain -Text "=======================================================" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Source Dir          : $($RomSource)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Retropie Dir        : $($RomDestination)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Retropie Dir Purge  : $($RomDirPurge)" -LogFile $LogFile
		Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Retropie Overwrite  : $($RomOverwrite)" -LogFile $LogFile
		#Calculate Total ROMs and Total ROM Size (MB) to Copy to Retropie
		$RomFiles = Get-ChildItem $RomSource | Measure -Property Length -sum
		$FileCount = $RomFiles.Count
		$RomsSizeMB = [math]::Round($RomFiles.Sum/1024/1024,2,[System.MidpointRounding]::AwayFromZero)
			
		If ($RomDirPurge)
		{
			If(Test-Path -LiteralPath "$($RomDestination)")
			{
				Write-Out -ForegroundColor $global:colorSub1 -Text "ROM Retropie Dir Exists, Purge Before Processing" -LogFile $LogFile
				Write-Out -ForegroundColor DarkRed -Text "Purge: '$($RomDestination)'" -LogFile $LogFile
				Remove-Item -LiteralPath "$($RomDestination)" -Recurse -Force -Confirm:$false
			}
			Else
			{
				Write-Out -ForegroundColor $global:colorWarn -Text "ROM Retropie Dir Does Not Exist, Skip Purge Before Processing" -LogFile $LogFile
			}
		}
		
		If (Test-Path -LiteralPath "$($RomSource)")
		{
			Write-Out -ForegroundColor $global:colorSub1 -Text "Source Exist: '$($RomSource)'" -LogFile $LogFile
			If (Test-Path -LiteralPath "$($RomDestination)")
			{
				#Destination Directory Exists - Overwrite?
				If ($RomOverwrite)
				{
					Write-Out -ForegroundColor $global:colorWarn -Text "Destination EXIST (Overwrite): '$($RomDestination)'" -LogFile $LogFile
					Write-Out -ForegroundColor $global:colorSub1 -Text "Copy $($FileCount) ROMs ($($RomsSizeMB)MB) from '$($RomSource)' to '$($RomDestination)'" -LogFile $LogFile
					Copy-Item -Path "$($RomSource)\*" -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:colorWarn -Text "Destination NOT Exist: '$($RomDestination)'" -LogFile $LogFile
				If (Test-Path -LiteralPath $('\\' +([URI]$RomDestination).Host + '\roms\'))
				{
					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 $($FileCount) ROMs ($($RomsSizeMB)MB) from '$($RomSource)' to '$($RomDestination)'" -LogFile $LogFile
						Copy-Item -Path "$($RomSource)\*" -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 "ERROR $('\\' +([URI]$RomDestination).Host + '\roms\') Not Exist, Make sure Retropie is Powered on and connected to network!" -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
		}
		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
		
		#Clean Variables	
		If (Test-Path variable:RomFiles) {Remove-Variable RomFiles}
	}
}



Function Get-NoIntroDefaultFilters
{
    Param (
        [Parameter(Mandatory=$false)]
        [string]
        $Name = "",
		[Parameter(Mandatory=$false)]
        [string]
        $Splitstr = "(",
		[Parameter(Mandatory=$false)]
		[bool]
		$SortAscending = '$true',
        [Parameter(Mandatory=$false)]
        [string]
        $Unzip = '$false'
    )
    
    Begin
    {
        #Nothing to Do Here
    }
    
    Process
    {

        $DefaultFilters = @"
#$Name $global:scriptVersion
#No-Intro 2018 ROM Set

#Default String to Determine Unique ROM Name (Blank = Skip & Must Escape Reserve Characters []().\^$|?*+{})
`$romSplitstr = "$Splitstr"

#Determine Sort ROMs Ascending or Descending when selecting Primary ROM
`$romSortAscending = "$SortAscending"

#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 = @(
    #Type
	"[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)"
	#Region
    ,"(Asia)"
    ,"(Australia)"
    ,"(Brazil)"
    ,"(Canada)"
    ,"(China)"
    ,"(France)"
    ,"(Germany)"
    ,"(Hong Kong)"
    ,"(Italy)"
    ,"(Japan)"
    ,"(Korea)"
    ,"(Netherlands)"
    ,"(Russia)"
    ,"(Spain)"
    ,"(Sweden)"
    ,"(Taiwan)"
	#Demo/Test/Misc Cartridge
	#RAM Modification Cheat Cartridge
	#Duplicate ROMSs with Alternate Names
)

#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\)"
	
#Detect Games with Multicarts such as (Disk 1 of 2) 
#-Once a primary ROM is set, it is considered a Multicart Game if it matches a regex in $romsMulticart
#-Multicarts are the determined if they match the exact name of the primary ROM and match the same regex in $romsMultiCart
#-If $romsMultiCart is blank, it will not check for Multicarts
#-Ex: "\(Disk\s?[1-4].*\)"
# Primary rom "Dungeon Master (Disk 1).zip" would consider any ROM named "Dungeon Master (Disk #).zip" where # is 1 to 4 a Multicart to keep
$romsMultiCart = @(
)
'@

        Return $DefaultFilters
    }
    
    End
    {
        #Nothing to Do Here
    }
}



Function Get-CustomDefaultFilters
{
    Param (
        [Parameter(Mandatory=$false)]
        [string]
        $Name = "",
		[Parameter(Mandatory=$false)]
        [string]
        $Splitstr = "",
		[Parameter(Mandatory=$false)]
		[string]
		$SortAscending = '$true',
		[Parameter(Mandatory=$false)]
        [string]
        $Unzip = '$false'
    )
    
    Begin
    {
        #Nothing to Do Here
    }
    
    Process
    {

        $DefaultFilters = @"
#$Name $global:scriptVersion
#Custom ROM Set

#Default String to Determine Unique ROM Name (Blank = Skip & Must Escape Reserve Characters []().\^$|?*+{})
`$romSplitstr = "$Splitstr"

#Determine Sort ROMs Ascending or Descending when selecting Primary ROM
`$romSortAscending = $SortAscending

#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 = @(
)

#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 = @(
)

#Detect Games with Multicarts such as (Disk 1 of 2) 
#-Once a primary ROM is set, it is considered a Multicart Game if it matches a regex in $romsMulticart
#-Multicarts are the determined if they match the exact name of the primary ROM and match the same regex in $romsMultiCart
#-If $romsMultiCart is blank, it will not check for Multicarts
#-Ex: "\(Disk\s?[1-4].*\)"
# Primary rom "Dungeon Master (Disk 1).zip" would consider any ROM named "Dungeon Master (Disk #).zip" where # is 1 to 4 a Multicart to keep
$romsMultiCart = @(
)
'@

        Return $DefaultFilters
    }
    
    End
    {
        #Nothing to Do Here
    }
}



Function Sort-Naturally
{
	#https://github.com/LarrysGIT/Powershell-Natural-sort/blob/master/NaturalSort.ps1
    PARAM(
        [Parameter(ValueFromPipeline=$true)]
        [System.Collections.ArrayList]$Array,
        [String]$Property,
        [switch]$Descending
    )

    Add-Type -TypeDefinition @'
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace NaturalSort {
    public static class NaturalSort
    {
        [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
        public static extern int StrCmpLogicalW(string psz1, string psz2);
        public static System.Collections.ArrayList Sort(System.Collections.ArrayList foo)
        {
            foo.Sort(new NaturalStringComparer());
            return foo;
        }
    }
    public class NaturalStringComparer : IComparer
    {
        public int Compare(object x, object y)
        {
            return NaturalSort.StrCmpLogicalW(x.ToString(), y.ToString());
        }
    }
}
'@
    If ($Array)
	{
		If($Property)
		{
			$ArrayTmp = @{}
			foreach($obj in $Array)
			{
				$ArrayTmp.Add(("{0}_{1}" -f $obj.$Property, $obj.GetHashCode()), $obj)
			}
			$Keys = New-Object System.Collections.ArrayList
			$Keys.AddRange(@($ArrayTmp.Keys))
			$Keys.Sort((New-Object NaturalSort.NaturalStringComparer))
			$Array.Clear()
			ForEach($k in $Keys)
			{
				$Array.Add($ArrayTmp[$k]) | Out-Null
			}
		}
		Else
		{
			$Array.Sort((New-Object NaturalSort.NaturalStringComparer))
		}
		If($Descending)
		{
			$Array.Reverse()
		}
	}
    Return $Array
}



Function Validate-Container
{
    Param (
        [Parameter(Mandatory=$true)]
        [string]$Name,
		
		[Parameter(Mandatory=$true)]
        [ref]$Path,
		
		[Parameter(Mandatory=$false)]
		[switch]$IsValid,
		
		[Parameter(Mandatory=$false)]
		[switch]$EndsWithBackslash,
		
		[Parameter(Mandatory=$true)]
		[Alias("Log")]
		[string[]]$LogFiles
    )
	
	Write-Out -ForegroundColor $global:colorSub1 -Text "$($Name) " -NoNewLine -LogFile $LogFiles
	
	If (([URI]$Path.Value).IsUnc)
	{
		#Path is UNC
		If ($IsValid)
		{
			#Confirm It is Valid (Must have folder in path not just server name)
			If (Test-Path -LiteralPath $Path.Value -IsValid)
			{
				Write-Out -ForegroundColor $global:colorSub1 -Text "Path (UNC) Valid: '$($Path.Value)'" -LogFile $LogFiles
			}
			Else
			{
				Write-Out -ForegroundColor $global:colorError -Text "Path (UNC) NOT Valid: '$($Path.Value)'" -LogFile $LogFiles
				Return $false
			}
		}
		Else
		{
			#Confirm It Exists (Must have folder in path not just server name)
			If (Test-Path -LiteralPath $Path.Value)
			{
				Write-Out -ForegroundColor $global:colorSub1 -Text "Path (UNC) Exist: '$($Path.Value)'" -LogFile $LogFiles
			}
			Else
			{
				Write-Out -ForegroundColor $global:colorError -Text "Path (UNC) NOT Exist: '$($Path.Value)'" -LogFile $LogFiles
				Return $false
			}
		}
	}
	Else
	{
		#Path is Local
		If ($IsValid)
		{
			#Confirm It is Valid
			If (Test-Path -LiteralPath $Path.Value -IsValid)
			{
				Write-Out -ForegroundColor $global:colorSub1 -Text "Path (Local) Valid: '$($Path.Value)'" -LogFile $LogFiles
			}
			Else
			{
				Write-Out -ForegroundColor $global:colorError -Text "Path (Local) NOT Valid: '$($Path.Value)'" -LogFile $LogFiles
				Return $false
			}
		}
		Else
		{
			#Confirm It is a Container
			If (Test-Path -LiteralPath $Path.Value -PathType Container)
			{
				Write-Out -ForegroundColor $global:colorSub1 -Text "Path (Local) Exist: '$($Path.Value)'" -LogFile $LogFiles
			}
			Else
			{
				Write-Out -ForegroundColor $global:colorError -Text "Path (Local) NOT Exist: '$($Path.Value)'" -LogFile $LogFiles
				Return $false
			}
		}
	}
    
	If ($EndsWithBackslash)
	{
		If (!$Path.Value.EndsWith('\'))
		{
			$Path.Value = $Path.Value + "\"
			Write-Out -ForegroundColor $global:colorWarn -Text "Path Not End with '\', append it: $($Path.Value)" -LogFile $LogFiles
		}
	}
	
	Return $true
}



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. Array of Absolute or relative path of the log file(s). You can still provide a single log file or multiple separate by commas.
	.PARAMETER LogOnly
	Optional. Write to LogFile only, do Not output to console.
	.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: https://sigkillit.com/
	Created: 5/23/2023
	Version 1.5
	- Removed Unnecessary loop in 1.4 for log files since Test-Path, New-Item, Set-Content, and Add-Content all support -Path as string array
	Version 1.4
	- Changed LogFile from a String to String Array so you can log the same line to multiple files or provide a single value so it' backwards compatible.
	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"
	.EXAMPLE
	Write-Out -Text "You can write this line to two log files now" -LogFile "script.log","second.txt"
	#>
	[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.Count -eq 0)
		{
			#No LogFile Specified - Skip
		}
		ElseIf ($LogFile.Count -gt 0)
		{
			#LogFile Specified - Loop Array
			If(!(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

14 comments

4 pings

Skip to comment form

    • Timoteo on August 25, 2019 at 2:31 am

    Thank you, you beautiful human!
    This worked perfectly and I just had to add a few more systems like Atari Jaguar, ST, etc.

    The only small problem is it doesn’t pick duplicates when the US and Europe versions differ slightly with the naming scheme, though the only game I noticed this was for Lilo & Stitch 2 where the US version adds a subtitle. But that’s a small thing.

    1. Good catch! I just checked my Gameboy Advance romset, which has the following ROMs for Lilo & Stitch 2:

      Lilo & Stitch 2 – Haemsterviel Havoc (USA).zip
      Lilo & Stitch 2 (Europe) (En,Fr,De,Es).zip

      The script compares everything to the left of the first left parenthesis. Since the USA title has a subtitle, it’s detecting them as separate titles. In this case, I would add the European title to the exceptions to remove it. I have updated the scripts to included this exception.

    2. Just did a complete rewrite on v5.0 to make the code modular and have customized the filter files for each system to address such issues.

    • Anon on February 16, 2020 at 11:14 am

    Just a small fix – you use the alias “Sort” in some of the scripts. It’d be better to switch this to the non-alias Sort-Object, since the aliases are removed on the linux implementation of powershell. Took me a minute to find that one, but once fixed, I’m running the first script with no issue. There might be others as well to tweak.

    1. Just did a complete rewrite on v5.0 to make the code modular and replaced “Sort” with “Sort-Object” among the changes

        • Jim on April 8, 2021 at 3:16 pm

        I’m currently combing through the results of the script. I’m compiling the Parent/Clone games that were missed. If submitted, will you update your script with my findings? I should be done in less than a week.

        1. Please feel free to share your results! I will definitely add any improvements/mistakes you find.

            • Jim on April 9, 2021 at 4:34 pm

            #Excellent!! I’ve already completed…Atari – 2600, Atari 5200 (No change), Atari 7800, Atari – Jaguar, Atari – Lynx, Atari – ST, Bandai – WonderSwan, & Bandai – WonderSwan Color!

            ##The lists are organized into 3 categories. Parent/Clone List, Add Roms, & Remove Roms.

            ###Parent/Clone List – Indicates which parent rom to keep [+] and which corresponding clones to remove [-] (The Parent/Clone Lists are only applicable to roms that actually need added or removed after running the script.
            ###Add Roms – Indicates which roms to keep that are not currently kept after running the script.
            ###Remove Roms – Indicates which roms to remove that are not currently removed after running the script.

            ?????How would you like me to submit the lists? Currently they are separate .txt files per system.

          1. You can email me your suggestions at sigkill [at] sigkillit.com

            • Jim on April 9, 2021 at 4:41 pm

            Here’s Atari – 7800 as an example (Since it merely had one entry per category)
            Programs, Applications, Prototypes, Demos fall into “remove” criteria. That is uniform with your algorithm, correct?

            PARENT/CLONE LIST

            + Pete Rose Baseball (USA)
            – Baseball (Europe)

            ADD ROMS

            + 32 in 1 (Australia)

            REMOVE ROMS

            – 7800 Monitor Cart (USA) (Program) (Unl)

          2. Generally, yes it does follow that rule to remove ROMs with the default settings. However, you can manually edit the atari7800.ps1 filter if you want to customize it. I do agree that “Baseball (Europe)” is a clone of “Pete Rose Baseball (USA)” and will update that on my filters on the next update. Basically, in atari7800.ps1 in the $romsExceptions array I’ll add:

            ,”Baseball (Europe).zip” #Alternate Name of ‘Pete Rose Baseball (USA).zip’

            On your “ADD ROMS” note for “32 in 1 (Australia)” I do not have that ROM in my original list of ROMs, which is the No-Intro 2018 list. If that ROM is being removed from your ROMs and you want to keep it, on the atari7800.ps1 filter in the $romsDoNotDelete array add that exact ROM name.

            On your “REMOVE ROMS” note for “7800 Monitor Cart (USA) (Program) (Unl)” I do not have that ROM in my original list of ROMs, which is the No-Intro 2018 list. If you have that ROM in your original ROMs, you can remove it by modifying the atari7800.ps1 filter and modifying the $romsExceptions array. You can either add the exact ROM name or a portion of the name. For example, you probably would want to add one of the below where the first is an exact match and the later is a more general match:

            ,”7800 Monitor Cart (USA) (Program) (Unl).zip”

            OR

            ,”(Program)”

    • Natalie Sult-Friesen on July 9, 2021 at 2:43 pm

    I must say, you did a great deal of work for which I say Thank You very Much. I am curious how exactly you removed the Japan games without deleting 1 by 1 or doing a ctrl and select? Please enlighten me as to your method because I would like the knowledge for the future. Thanks so much for all of your hard work, Great Job

    • Brian on November 1, 2021 at 12:31 pm

    Thank you for this, Excellent Work!

    By chance do you have any other romsets available? Specifically, I am looking for the following additional romsets:

    Neo-Geo
    CPS 1, 2, 3
    MS-DOS
    Scummvm (I think these are the same as ms-dos?)

    If you have other romsets, could you post a the link?

    Regards,
    Brian

    1. No, this was based on the No-Intro set. However, if you have additional ROM sets, you could add them to the scripts as long as the ROMs follow a naming scheme. In this case:

      1_Clean-NoIntroRoms.ps1: Add your ROM set to the $global:romNoIntroHashTable & your source ROM files should be in the No-IntroDirName

      Next, create a filter file that matches the directory name on Retropie.

      If we use “NeoGeo” as an example, add it to the $global:romNoIntroHashTable variable like:

      “neogeo” = “NeoGeo”

      Then in the filters folder, create a file named “neogeo.ps1”. You would then need to customize that file and you can use one of the other existing filter files as an example.

  1. […] ← Previous […]

  2. […] is intended to be used as the supplement script 2_CompareFolderResults.ps1 to the 1_Clean-NoIntroRoms.ps1 script. This script allows you to compare the files/roms in 2 directories to show the differences […]

  3. […] 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 […]

Comments have been disabled.