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); } }
/// <summary> /// Main entry point for handling an install operation /// </summary> /// <param name="portal">DevicePortal reference for communicating with the device.</param> /// <param name="parameters">Parsed command line parameters.</param> public static void HandleOperation(DevicePortal portal, ParameterHelper parameters) { if (parameters.HasFlag(ParameterHelper.HelpFlag)) { Console.WriteLine(XblInstallUsageMessage); return; } InstallOperation operation = new InstallOperation(portal); portal.AppInstallStatus += operation.AppInstallStatusHandler; if (parameters.HasFlag(ParameterHelper.VerboseFlag)) { operation.verbose = true; } List <string> dependencies = new List <string>(); // Build up the list of dependencies. if (parameters.HasParameter("depend")) { dependencies.AddRange(parameters.GetParameterValue("depend").Split(';')); } string certificate = parameters.GetParameterValue("cer"); string appxFile = parameters.GetParameterValue("appx"); string folderPath = parameters.GetParameterValue("folder"); string registerPath = parameters.GetParameterValue("register"); try { if (!string.IsNullOrEmpty(appxFile)) { operation.mreAppInstall.Reset(); Task installTask = portal.InstallApplicationAsync(null, appxFile, dependencies, certificate); operation.mreAppInstall.WaitOne(); if (operation.installResults.Status == ApplicationInstallStatus.Completed) { Console.WriteLine("Install complete."); } else { Console.WriteLine("Install failed in phase {0}. {1}", operation.installResults.Phase, operation.installResults.Message); } } else if (!string.IsNullOrEmpty(folderPath)) { // Install all dependencies one at a time (loose folder doesn't handle dependencies well). foreach (string dependency in dependencies) { operation.mreAppInstall.Reset(); Task installTask = portal.InstallApplicationAsync(null, dependency, new List <string>()); operation.mreAppInstall.WaitOne(); if (operation.installResults.Status != ApplicationInstallStatus.Completed) { Console.WriteLine("Deploy failed during dependency installation. {0}", operation.installResults.Message); return; } } if (!Directory.Exists(folderPath)) { Console.WriteLine("Failed to find provided loose folder."); Console.WriteLine(); Console.WriteLine(XblInstallUsageMessage); return; } // Remove any trailing slash if (folderPath.EndsWith("\\")) { folderPath = folderPath.Remove(folderPath.Length - 1); } string destinationFolderName = parameters.GetParameterValue("destfoldername"); if (string.IsNullOrEmpty(destinationFolderName)) { // Get just the folder name string folderName = folderPath.Substring(folderPath.LastIndexOf('\\') + 1); destinationFolderName = folderName; } string transferType = parameters.GetParameterValue("transfer"); if (string.IsNullOrEmpty(transferType) || string.Equals(transferType, "smb", StringComparison.OrdinalIgnoreCase)) { string shareName = Path.Combine("\\\\", parameters.GetParameterValue(ParameterHelper.IpOrHostname), "DevelopmentFiles"); string destinationFolder = Path.Combine(shareName, "LooseApps", destinationFolderName); try { operation.CopyDirectory(folderPath, destinationFolder); } catch (IOException e) { if (e.HResult == ErrorLogonFailureHresult) { Task <SmbInfo> smbTask = portal.GetSmbShareInfoAsync(); smbTask.Wait(); // Set the username/password for accessing the share. NetworkShare.DisconnectFromShare(shareName, true); int connected = NetworkShare.ConnectToShare(shareName, smbTask.Result.Username, smbTask.Result.Password); if (connected != 0) { Console.WriteLine(string.Format("Failed to connect to the network share: {0}", connected)); return; } operation.CopyDirectory(folderPath, destinationFolder); NetworkShare.DisconnectFromShare(shareName, false); } else { Console.WriteLine(string.Format("Unexpected exception encountered: {0}", e.Message)); return; } } } else if (string.Equals(transferType, "http", StringComparison.OrdinalIgnoreCase)) { operation.UploadDirectoryOverHttp(folderPath, destinationFolderName); } else { Console.WriteLine(string.Format("Unexpected transfer type received: {0}. Expecting one of SMB or HTTP.", transferType)); return; } Task registerTask = portal.RegisterApplicationAsync(destinationFolderName); registerTask.Wait(); Console.WriteLine("Install complete."); } else if (!string.IsNullOrEmpty(registerPath)) { Task registerTask = portal.RegisterApplicationAsync(registerPath); registerTask.Wait(); Console.WriteLine("Registration complete."); } else { Console.WriteLine("Must provide an appx package, loose folder, or path to register."); Console.WriteLine(); Console.WriteLine(XblInstallUsageMessage); return; } } catch (AggregateException e) { if (e.InnerException is DevicePortalException) { DevicePortalException innerException = e.InnerException as DevicePortalException; Console.WriteLine(string.Format("Exception encountered: {0}, hr = 0x{1:X} : {2}", innerException.StatusCode, innerException.HResult, innerException.Reason)); } else if (e.InnerException is OperationCanceledException) { Console.WriteLine("The operation was cancelled."); } else { Console.WriteLine(string.Format("Unexpected exception encountered: {0}", e.Message)); } return; } }