private bool TryRetrieveInstalledPackages(AppPackageIdentity packageId, out List <PackageInfo> matchingPackages)
        {
            if (_verbose)
            {
                Console.Out.WriteLine("Attempting to query installed packages matching app");
            }

            matchingPackages = null;
            bool successful = false;

            try
            {
                Task <AppPackages> packagesTask = _portal.GetInstalledAppPackagesAsync();
                packagesTask.Wait();

                // We want to find all packages that *loosely* match our appx in case something like
                // architecture or configuration changed
                matchingPackages =
                    (from package in packagesTask.Result.Packages
                     where
                     package.AppId == packageId.LaunchId &&
                     package.Publisher == package.Publisher
                     select package).ToList();

                successful = true;
            }
            catch (Exception ex)
            {
                if (_verbose)
                {
                    Console.Out.WriteLine("Failed to acquire list of installed apps from device: " + ex.Message);
                }
            }

            if (_verbose)
            {
                if (!successful)
                {
                    Console.Out.WriteLine("Failed to retrieve installed packages from the device");
                }
                else
                {
                    Console.Out.WriteLine("Successfully retrieved installed packages matching app from the device");
                }
            }

            return(successful);
        }
        private bool TryRetrievePackageNameAndLaunchIdFromDevice(AppPackageIdentity packageId, int numAttempts, out string packageFullName, out string launchId)
        {
            // Already have the info locally and don't need to query from device
            if (packageId.CompleteIdentity)
            {
                packageFullName = packageId.PackageFullName;
                launchId        = packageId.LaunchId;
                return(true);
            }

            if (_verbose)
            {
                Console.Out.WriteLine("Attempting to query PackageFullName and AUMID from remote device");
            }

            packageFullName = String.Empty;
            launchId        = String.Empty;
            bool successful = false;

            while (numAttempts > 0 && !successful)
            {
                numAttempts--;

                try
                {
                    Task <AppPackages> packagesTask = _portal.GetInstalledAppPackagesAsync();
                    packagesTask.Wait();

                    // This basic query should provide the matching package in most cases
                    //  -PackageName must exactly match
                    //  -Publisher must exactly match
                    //  -AUMID (called "AppId" in PackageInfo class) must contain our AppId value (registered app entry point)
                    //  -Version string must exactly match
                    var matchingPackages =
                        (from package in packagesTask.Result.Packages
                         where
                         package.Name == packageId.PackageName &&
                         package.Publisher == package.Publisher &&
                         package.AppId.Contains(package.AppId) &&            // AppId from PackageInfo is actually full AUMID
                         package.Version.ToString() == packageId.Version
                         select package).ToList();

                    PackageInfo matchingPackage = null;

                    if (matchingPackages.Count() == 0)
                    {
                        if (_verbose)
                        {
                            Console.Out.Write("Failed to find '" + packageId.PackageName + "' package installed on the device...");
                            Console.Out.WriteLine((numAttempts > 0) ? "trying again" : "giving up");
                        }
                    }
                    else if (matchingPackages.Count() > 1)
                    {
                        // It's technically possible for the above query to return multiple packages, in which case we need to
                        // disambiguate using the optional package identifiers (CPU architecture and ResourceId).
                        // Since PackageInfo doesn't provide this fields directly, need to split PackageFullName
                        // into component its component parts =>
                        //  [0] PackageName
                        //  [1] Version
                        //  [2] CPU architecture
                        //  [3] ResourceId (if present)
                        //  [4] Publisher name hash

                        foreach (var package in matchingPackages)
                        {
                            var nameParts = package.FullName.Split(new char[] { '_' }, 5);
                            if (nameParts.Length < 5)
                            {
                                continue;
                            }

                            // ResoruceId will be an empty string if not present, which should match our manifest data
                            if (nameParts[2] == packageId.CpuArchitecture && nameParts[3] == packageId.ResourceId)
                            {
                                matchingPackage = package;
                                break;
                            }
                        }
                    }
                    else
                    {
                        matchingPackage = matchingPackages.First();
                    }

                    if (matchingPackage != null)
                    {
                        packageFullName = matchingPackage.FullName;
                        launchId        = matchingPackage.AppId;
                        successful      = true;
                    }

                    // Query attempt may failed because it a few seconds before newly installed apps are reported
                    // So if we have more attempts then wait a bit before trying again
                    if (numAttempts > 0 && !successful)
                    {
                        Thread.Sleep(2000);
                    }
                }
                catch (Exception ex)
                {
                    if (_verbose)
                    {
                        Console.Out.WriteLine("Failed to acquire list of installed apps from device: " + ex.Message);
                    }
                }
            }

            if (_verbose)
            {
                if (!successful)
                {
                    Console.Out.WriteLine("Failed to retrieve FullPackageName and AUMID from remote device");
                }
                else
                {
                    Console.Out.WriteLine("Successfully retrieved FullPackageName and AUMID from remote device");
                }
            }

            return(successful);
        }
        private void ExecuteInstallAppx(ParameterHelper parameters, string appxFile, string certificate)
        {
            if (_verbose)
            {
                Console.Out.WriteLine("Starting Appx installation...");
            }

            var file = new FileInfo(Path.GetFullPath(appxFile));

            if (!file.Exists)
            {
                throw new System.IO.FileNotFoundException("Specified appx file '" + appxFile + "' wasn't found");
            }

            if (!String.IsNullOrWhiteSpace(certificate))
            {
                var certFile = new FileInfo(certificate);
                if (!certFile.Exists)
                {
                    throw new System.IO.FileNotFoundException("Specified certificate file '" + certFile + "' wasn't found");
                }
                certificate = certFile.FullName;
            }
            else
            {
                // Must pass in null instead of empty string if certificate is omitted
                certificate = null;
            }

            // Parse the AppxManfest contained in the Appx file to extract the package name, dependencies, AppID, etc.
            AppxManifest appxData;

            try
            {
                appxData = AppxManifest.Get(appxFile);
            }
            catch (Exception ex)
            {
                Console.Out.WriteLine("Failed to parse Appx manifest: " + ex.Message);
                throw;
            }
            if (!appxData.IsValid)
            {
                throw new System.ArgumentException("Specified Appx '" + appxFile + "' contains an invalid AppxManifest");
            }

            // Construct an "identity" object from the AppxManifest data which can be referenced later to launch the installed app
            var appIdentity = new AppPackageIdentity(appxData);

            // Query for app packages already installed on the device and uninstall them if necessary
            // NOTE: Check for any uninstall any package matching this appx PackageName and Publisher to
            //  ensure a clean install of the new build

            List <PackageInfo> matchingPackages;

            if (TryRetrieveInstalledPackages(appIdentity, out matchingPackages) && matchingPackages.Count() > 0)
            {
                if (_verbose)
                {
                    Console.Out.WriteLine("Uninstalling previous app..");
                }

                foreach (var package in matchingPackages)
                {
                    try
                    {
                        if (_verbose)
                        {
                            Console.Out.WriteLine("Uninstalling package: " + package.FullName);
                        }

                        _portal.UninstallApplicationAsync(package.FullName).Wait();
                    }
                    catch (AggregateException ex)
                    {
                        // NOTE: We really shouldn't continue with installation if we failed to remove a previous version of the app.
                        // If a version of the app remains on the device, the Install API will NOT replace it but still reports "success",
                        // meaning the user could be running old code and not know it. A hard fail is the only way to ensure this doesn't happen.
                        Console.Out.WriteLine("Uninstall of package '" + package.FullName + "' failed: " + ex.InnerException.Message);
                        System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
                    }
                }

                if (_verbose)
                {
                    Console.Out.WriteLine("Finished uninstalling previous app packages");
                }
            }

            Task installTask = _portal.InstallApplicationAsync(null, file.FullName, appxData.Dependencies, certificate, 500, 1, false);

            try
            {
                installTask.Wait();
                Console.Out.WriteLine("Installation completed successfully");
            }
            catch (AggregateException ex)
            {
                Console.Out.WriteLine("Installation of Appx failed!");

                HandleInstallOperationException(ex);
                System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
            }

            // Save AppIdentity to field after successful installation
            _installedAppId = appIdentity;

            // If the app Identity is "complete" we have the FullPackageName and AUMID parameters, so we'll
            // add them to our parameter set to later launch the app; no need to query package info from the device
            if (_installedAppId.CompleteIdentity)
            {
                parameters.AddOrUpdateParameter(parameterPackage, _installedAppId.PackageFullName);
                parameters.AddOrUpdateParameter(ParameterAumid, _installedAppId.LaunchId);
            }
        }