public async Task <IReadOnlyList <GameFinder_BaseResult> > FindGamesAsync()
    {
        if (HasRun)
        {
            throw new Exception("The FindGames method can only be called once per instance");
        }

        HasRun = true;

        try
        {
            // Split finders into groups
            var ubiIniGameFinders = GameFinderItems.Where(x => !FoundGames.Contains(x.Game) && x.FinderItem.UbiIniSectionName != null).ToArray();

            // Search the ubi.ini file
            if (ubiIniGameFinders.Any() && GamesToFind.Any())
            {
                IDictionary <string, string> iniLocations = null;

                Logger.Info("The game finder has ubi.ini finder");

                try
                {
                    // Make sure the file exists
                    if (AppFilePaths.UbiIniPath1.FileExists)
                    {
                        // Get the sections and the directory for each one
                        iniLocations = GetUbiIniData();
                        Logger.Info("The ubi.ini file data was parsed for the game finder");
                    }
                }
                catch (Exception ex)
                {
                    Logger.Warn(ex, "Reading ubi.ini file for game finder");
                }

                // If we retrieved ini data, search it
                if (iniLocations != null)
                {
                    await SearchIniDataAsync(iniLocations, ubiIniGameFinders);
                }
                else
                {
                    Logger.Info("The ubi.ini file data was null");
                }
            }

            // Split finders into groups
            var regUninstallGameFinders = GameFinderItems.Where(x => !FoundGames.Contains(x.Game) && x.FinderItem.PossibleWin32Names?.Any() == true).ToList();
            var regUninstallFinders     = FinderItems.Where(x => !FoundFinderItems.Contains(x) && x.PossibleWin32Names?.Any() == true).ToList();
            var steamGameFinders        = GameFinderItems.Where(x => !FoundGames.Contains(x.Game) && x.FinderItem.SteamID != null).ToList();

            // Search Registry uninstall programs
            if ((regUninstallGameFinders.Any() || steamGameFinders.Any() || regUninstallFinders.Any()) && GamesToFind.Any())
            {
                Logger.Info("The Registry uninstall programs are being searched...");

                try
                {
                    // Get the enumerator for installed programs
                    var installedPrograms = EnumerateRegistryUninstallPrograms();

                    // Search installed programs
                    await SearchRegistryUninstallAsync(installedPrograms, regUninstallGameFinders, steamGameFinders, regUninstallFinders);
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, "Searching Registry uninstall programs for game finder");
                }
            }

            // Split finders into groups
            var programShortcutGameFinders = GameFinderItems.Where(x => !FoundGames.Contains(x.Game) && x.FinderItem.ShortcutName != null).ToList();
            var programShortcutFinders     = FinderItems.Where(x => !FoundFinderItems.Contains(x) && x.ShortcutName != null).ToList();

            // Search Win32 shortcuts
            if ((programShortcutGameFinders.Any() || programShortcutFinders.Any()) && GamesToFind.Any())
            {
                Logger.Info("The program shortcuts are being searched...");

                try
                {
                    // Get the enumerator for the shortcuts
                    var shortcuts = EnumerateProgramShortcuts();

                    // Search the shortcuts
                    await SearchWin32ShortcutsAsync(shortcuts, programShortcutGameFinders, programShortcutFinders);
                }
                catch (Exception ex)
                {
                    Logger.Warn(ex, "Searching program shortcuts for game finder");
                }
            }

            // Run custom game finders
            foreach (var game in GameFinderItems.Where(x => !FoundGames.Contains(x.Game) && x.FinderItem.CustomFinderAction != null))
            {
                // Run the custom action and get the result
                var result = game.FinderItem.CustomFinderAction();

                // Make sure we got a result
                if (result == null)
                {
                    continue;
                }

                // Add the game
                await AddGameAsync(game, result.InstallDir, result.Parameter);
            }

            // Run custom finders
            foreach (var item in FinderItems.Where(x => !FoundFinderItems.Contains(x) && x.CustomFinderAction != null))
            {
                // Run the custom action and get the result
                var result = item.CustomFinderAction();

                // Make sure we got a result
                if (result == null)
                {
                    continue;
                }

                // Add the game
                AddItem(item, result.InstallDir, result.Parameter);
            }

            Logger.Info("The game finder found {0} games", Results.Count);

            // Return the found games
            return(Results.AsReadOnly());
        }
        catch (Exception ex)
        {
            Logger.Error(ex, "Game finder");
            throw;
        }
    }