public static void DumpAppDesiredState(AppxManagementDataContract.AppDesiredState appDesiredState)
 {
     Logger.Log("- Desired App State ------------------------------------------------", LoggingLevel.Verbose);
     Logger.Log("    packageFamilyId     = " + appDesiredState.packageFamilyId, LoggingLevel.Verbose);
     Logger.Log("    packageFamilyName   = " + appDesiredState.packageFamilyName, LoggingLevel.Verbose);
     Logger.Log("    action              = " + appDesiredState.action.ToString(), LoggingLevel.Verbose);
     Logger.Log("    version             = " + appDesiredState.version?.ToString(), LoggingLevel.Verbose);
     Logger.Log("    startUp             = " + appDesiredState.startUp.ToString(), LoggingLevel.Verbose);
     Logger.Log("    appxSource          = " + appDesiredState.appxSource, LoggingLevel.Verbose);
     Logger.Log("    depsSources         = " + appDesiredState.depsSources, LoggingLevel.Verbose);
     Logger.Log("    certSource          = " + appDesiredState.certSource, LoggingLevel.Verbose);
     Logger.Log("    certStore           = " + appDesiredState.certStore, LoggingLevel.Verbose);
     if (appDesiredState.errorCode != 0)
     {
         Logger.Log("    errorCode           = " + appDesiredState.errorCode, LoggingLevel.Verbose);
         Logger.Log("    errorMessage        = " + appDesiredState.errorMessage, LoggingLevel.Verbose);
     }
     Logger.Log("    ----------------------------------------------------------------", LoggingLevel.Verbose);
 }
        private static void ReportQueriedApp(
            AppInfo installedAppInfo,
            AppxManagementDataContract.AppDesiredState desiredState,
            Dictionary <string, AppxManagementDataContract.AppReportedState> stateToReport)
        {
            Logger.Log("Processing query request...", LoggingLevel.Verbose);

            AppxManagementDataContract.AppReportedState appReportedState;
            if (installedAppInfo == null)
            {
                Logger.Log("    Couldn't find an installed version...", LoggingLevel.Verbose);

                appReportedState = new AppxManagementDataContract.AppReportedState(
                    desiredState.packageFamilyId,
                    desiredState.packageFamilyName,
                    AppxManagementDataContract.VersionNotInstalled,
                    AppUtils.StartUpTypeFromMessage(StartUpType.None),
                    null,
                    0,
                    null,
                    JsonReport.Report);
            }
            else
            {
                Logger.Log("    Found an installed version...", LoggingLevel.Verbose);

                appReportedState = new AppxManagementDataContract.AppReportedState(
                    desiredState.packageFamilyId,
                    desiredState.packageFamilyName,
                    installedAppInfo.Version,
                    AppUtils.StartUpTypeFromMessage(installedAppInfo.StartUp),
                    installedAppInfo.InstallDate,
                    0,
                    null,
                    JsonReport.Report);
            }
            stateToReport[desiredState.packageFamilyId] = appReportedState;
        }
        private async Task <CommandStatus> ApplyAppDesiredState(string connectionString, IDictionary <string, AppInfo> installedApps, AppxManagementDataContract.AppDesiredState desiredState)
        {
            CommandStatus commandStatus       = CommandStatus.NotStarted;
            Version       installedAppVersion = null;
            AppInfo       installedAppInfo    = FindInstalledAppInfo(installedApps, desiredState.packageFamilyName);

            if (installedAppInfo != null)
            {
                installedAppVersion = new Version(installedAppInfo.Version);
            }

            switch (desiredState.action)
            {
            case AppDesiredAction.Install:
            {
                commandStatus = await InstallAppAsync(installedAppInfo, installedAppVersion, connectionString, installedApps, desiredState);
            }
            break;

            case AppDesiredAction.Uninstall:
            {
                await UninstallAppAsync(installedAppInfo,
                                        packageFamilyId : desiredState.packageFamilyId,
                                        packageFamilyName : desiredState.packageFamilyName);
            }
            break;

            case AppDesiredAction.Query:
            {
                ReportQueriedApp(installedAppInfo, desiredState, _stateToReport);
            }
            break;

            case AppDesiredAction.Unreport:
            {
                Logger.Log("Processing unreport request...", LoggingLevel.Verbose);

                AppxManagementDataContract.AppReportedState appReportedState = new AppxManagementDataContract.AppReportedState(
                    desiredState.packageFamilyId,
                    desiredState.packageFamilyName,
                    null,           // no version
                    AppUtils.StartUpTypeFromMessage(StartUpType.None),
                    null,           // no install date
                    0,
                    null,           // no error
                    JsonReport.Unreport);

                _stateToReport[desiredState.packageFamilyId] = appReportedState;
            }
            break;

            case AppDesiredAction.Undefined:
            {
                Logger.Log("Processing unknown request...", LoggingLevel.Verbose);

                AppxManagementDataContract.AppReportedState appReportedState = new AppxManagementDataContract.AppReportedState(
                    desiredState.packageFamilyId,
                    desiredState.packageFamilyName,
                    null,           // no version
                    AppUtils.StartUpTypeFromMessage(StartUpType.None),
                    null,           // no install date
                    ErrorCodes.INVALID_DESIRED_APPX_OPERATION,
                    "Invalid application operation.",
                    JsonReport.Report);

                _stateToReport[desiredState.packageFamilyId] = appReportedState;
            }
            break;
            }

            return(commandStatus);
        }
        private async Task <CommandStatus> InstallAppAsync(
            AppInfo installedAppInfo,
            Version installedAppVersion,
            string connectionString,
            IDictionary <string, AppInfo> installedApps,
            AppxManagementDataContract.AppDesiredState desiredState)
        {
            Logger.Log("Processing install request for " + desiredState.packageFamilyId, LoggingLevel.Verbose);

            if (installedAppInfo == null)
            {
                // It is a new application.
                Logger.Log("    Can't find an installed version... Installing a fresh copy...", LoggingLevel.Verbose);
                await InstallAppFromAzureAsync(installedAppInfo, connectionString, desiredState, false /*not self update*/);       // ---> InstallAppFromAzureAsync
            }
            else
            {
                Windows.ApplicationModel.PackageId thisPackage = Windows.ApplicationModel.Package.Current.Id;
                Debug.WriteLine("FamilyName = " + thisPackage.FamilyName);
                Debug.WriteLine("Name       = " + thisPackage.Name);

                bool isSelf = desiredState.packageFamilyName == thisPackage.FamilyName;

                // A version of this application is installed.
                Logger.Log("    Found an installed version...", LoggingLevel.Verbose);

                if (desiredState.version == installedAppVersion)
                {
                    Logger.Log("        Same version is installed...", LoggingLevel.Verbose);
                    AppxManagementDataContract.AppReportedState appReportedState = null;

                    if (AppUtils.StartUpTypeToMessage(desiredState.startUp) == installedAppInfo.StartUp)
                    {
                        Logger.Log("        App StartUp is the same: desired = " + desiredState.startUp, LoggingLevel.Verbose);

                        appReportedState = new AppxManagementDataContract.AppReportedState(
                            desiredState.packageFamilyId,
                            desiredState.packageFamilyName,
                            installedAppVersion.ToString(),
                            AppUtils.StartUpTypeFromMessage(installedAppInfo.StartUp),
                            installedAppInfo.InstallDate,
                            0,
                            null,                 // no error
                            JsonReport.Report);
                    }
                    else
                    {
                        Logger.Log("        App StartUp is different: desired = " + desiredState.startUp.ToString() + ", current = " + installedAppInfo.StartUp.ToString(), LoggingLevel.Verbose);

                        switch (desiredState.startUp)
                        {
                        case AppxStartUpType.None:
                        {
                            bool background = installedAppInfo.StartUp == StartUpType.Background;
                            if (background)
                            {
                                Logger.Log("            Removing app from background apps.", LoggingLevel.Verbose);
                                StartupAppInfo startupAppInfo = new StartupAppInfo(desiredState.packageFamilyName, background);
                                await RemoveStartupAppAsync(startupAppInfo);
                            }
                            else
                            {
                                Logger.Log("            App is no longer marked to be start-up app. Change takes effect when another app is set to be the start-up app.", LoggingLevel.Verbose);
                            }
                        }
                        break;

                        case AppxStartUpType.Foreground:
                        {
                            Logger.Log("            Setting app to be the foreground app.", LoggingLevel.Verbose);
                            StartupAppInfo startupAppInfo = new StartupAppInfo(desiredState.packageFamilyName, false /*background*/);
                            await AddStartupAppAsync(startupAppInfo);
                        }
                        break;

                        case AppxStartUpType.Background:
                        {
                            Logger.Log("            Adding app to the background apps.", LoggingLevel.Verbose);
                            StartupAppInfo startupAppInfo = new StartupAppInfo(desiredState.packageFamilyName, true /*background*/);
                            await AddStartupAppAsync(startupAppInfo);
                        }
                        break;
                        }

                        AppxStartUpType appStartUp = await GetAppStartup(desiredState.packageFamilyName);

                        Logger.Log("            Querying returned app startup: " + appStartUp.ToString(), LoggingLevel.Verbose);

                        appReportedState = new AppxManagementDataContract.AppReportedState(
                            desiredState.packageFamilyId,
                            desiredState.packageFamilyName,
                            installedAppVersion.ToString(),
                            appStartUp,
                            installedAppInfo.InstallDate,
                            0,
                            null,                 // no error
                            JsonReport.Report);
                    }

                    _stateToReport[desiredState.packageFamilyId] = appReportedState;
                }
                else if (desiredState.version > installedAppVersion)
                {
                    Logger.Log("        Older version is installed...", LoggingLevel.Verbose);

                    if (!String.IsNullOrEmpty(desiredState.appxSource))
                    {
                        // Trigger the update...
                        await InstallAppFromAzureAsync(installedAppInfo, connectionString, desiredState, isSelf);

                        if (isSelf)
                        {
                            // If isSelf == true, it means that SystemConfigurator will force this application to exit very soon.
                            // Let's stop processing any further desired properties.
                            return(CommandStatus.PendingDMAppRestart);
                        }
                    }
                    else
                    {
                        // Note that store updates are not control through DM desired properties.
                        // Instead, they are triggered by the system scan for all store applications.
                        throw new Error(ErrorCodes.INVALID_DESIRED_APPX_SRC, "Appx package is required to update " + desiredState.packageFamilyName);
                    }
                }
                else
                {
                    // desiredState.version < installedAppVersion
                    Logger.Log("       Newer version is installed...rolling back.", LoggingLevel.Verbose);

                    if (String.IsNullOrEmpty(desiredState.appxSource))
                    {
                        AppxManagementDataContract.AppReportedState appReportedState = new AppxManagementDataContract.AppReportedState(
                            desiredState.packageFamilyId,
                            desiredState.packageFamilyName,
                            installedAppVersion.ToString(),
                            AppUtils.StartUpTypeFromMessage(installedAppInfo.StartUp),
                            installedAppInfo.InstallDate,
                            ErrorCodes.INVALID_DESIRED_APPX_SRC,
                            "Cannot install appx without a source.",
                            JsonReport.Report);

                        _stateToReport[desiredState.packageFamilyId] = appReportedState;

                        throw new Exception("Failed to roll back application version.");
                    }

                    if (isSelf)
                    {
                        // The reverting is implemented as an 'uninstall' followed by an 'install'.
                        // The package to be installed is downloaded in the 'install' step.
                        // So, if we were to revert self to an older version, we would have to:
                        //  - (1) download the old version first,
                        //  - (2) send an atomic uninstall-install request to SystemConfigurator to
                        //        uninstall and follow with an install and re-launch.
                        //  The above two steps are not implemented yet.
                        throw new Error(ErrorCodes.CANNOT_REVERT_DM_APPLICATION, "Reverting to an older version of the device management application (" + desiredState.packageFamilyName + ") is not supported.");
                    }
                    // Note that UninstallAppAsync will throw if it fails - and correctly avoid launching the install...
                    await UninstallAppAsync(installedAppInfo,
                                            packageFamilyId : desiredState.packageFamilyId,
                                            packageFamilyName : desiredState.packageFamilyName);
                    await InstallAppFromAzureAsync(installedAppInfo, connectionString, desiredState, isSelf);
                }
            }

            return(CommandStatus.Committed);
        }
        private async Task InstallAppFromAzureAsync(AppInfo currentState, string connectionString, AppxManagementDataContract.AppDesiredState desiredState, bool selfUpdate)
        {
            // Is this a fresh installation?
            if (currentState == null)
            {
                currentState = new AppInfo();
                currentState.PackageFamilyName = desiredState.packageFamilyName;
                currentState.Version           = AppxManagementDataContract.VersionNotInstalled;
                currentState.InstallDate       = "";
            }

            AppxManagementDataContract.AppReportedState reportedState = null;
            try
            {
                Logger.Log("-> installing " + desiredState.packageFamilyName + " from " + desiredState.appxSource, LoggingLevel.Verbose);
                if (String.IsNullOrEmpty(desiredState.appxSource))
                {
                    throw new Error(ErrorCodes.INVALID_DESIRED_APPX_SRC, "Cannot install appx without a source.");
                }

                var requestData = new AppInstallRequestData();
                requestData.PackageFamilyName = desiredState.packageFamilyName;
                requestData.StartUp           = AppUtils.StartUpTypeToMessage(desiredState.startUp);

                // Downloading dependencies...
                Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Downloading...", LoggingLevel.Verbose);
                if (!String.IsNullOrEmpty(desiredState.depsSources))
                {
                    string[] depsSources = desiredState.depsSources.Split(';');

                    for (int i = 0; i < depsSources.Length; ++i)
                    {
                        IoTDMClient.BlobInfo dependencyBlob = IoTDMClient.BlobInfo.BlobInfoFromSource(connectionString, depsSources[i]);
                        Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Downloading " + dependencyBlob.BlobName, LoggingLevel.Verbose);

                        var dependencyPath = await dependencyBlob.DownloadToTempAsync(this._systemConfiguratorProxy);

                        Logger.Log(dependencyPath, LoggingLevel.Verbose);
                        requestData.Dependencies.Add(dependencyPath);
                    }
                }

                // Downloading certificates...
                Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Downloading appx certificate...", LoggingLevel.Verbose);
                IoTDMClient.BlobInfo certificateBlob = IoTDMClient.BlobInfo.BlobInfoFromSource(connectionString, desiredState.certSource);
                requestData.CertFile = await certificateBlob.DownloadToTempAsync(this._systemConfiguratorProxy);

                requestData.CertStore = desiredState.certStore;

                // Downloading appx...
                Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Downloading appx...", LoggingLevel.Verbose);
                IoTDMClient.BlobInfo appxBlob = IoTDMClient.BlobInfo.BlobInfoFromSource(connectionString, desiredState.appxSource);
                requestData.AppxPath = await appxBlob.DownloadToTempAsync(this._systemConfiguratorProxy);

                requestData.IsDMSelfUpdate = selfUpdate;

                // Installing appx...
                Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Installing appx...", LoggingLevel.Verbose);
                AppInstallResponse response = await InstallAppAsync(requestData);

                if (response.data.pending)
                {
                    Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Installing appx is pending...", LoggingLevel.Verbose);
                    Debug.Assert(selfUpdate);

                    reportedState = new AppxManagementDataContract.AppReportedState(desiredState.packageFamilyId,
                                                                                    desiredState.packageFamilyName,
                                                                                    CommonDataContract.JsonPending,
                                                                                    AppUtils.StartUpTypeFromMessage(response.data.startUp),
                                                                                    response.data.installDate,
                                                                                    0,
                                                                                    null,
                                                                                    JsonReport.Report);
                    _stateToReport[desiredState.packageFamilyId] = reportedState;
                    return;
                }
                else
                {
                    Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Done installing appx...", LoggingLevel.Verbose);

                    Error e = null;
                    if (desiredState.version.ToString() != response.data.version)
                    {
                        if (currentState.Version == response.data.version)
                        {
                            e = new Error(ErrorCodes.INVALID_INSTALLED_APP_VERSION_UNCHANGED, "Installating the supplied appx succeeded, but the new app version is not the desired version, and is the same as the old app version.");
                        }
                        else
                        {
                            e = new Error(ErrorCodes.INVALID_INSTALLED_APP_VERSION_UNEXPECTED, "Installating the supplied appx succeeded, but the new app version is not the desired version.");
                        }
                    }

                    reportedState = new AppxManagementDataContract.AppReportedState(desiredState.packageFamilyId,
                                                                                    desiredState.packageFamilyName,
                                                                                    response.data.version,
                                                                                    AppUtils.StartUpTypeFromMessage(response.data.startUp),
                                                                                    response.data.installDate,
                                                                                    (e != null? e.HResult : 0),
                                                                                    (e != null ? e.Message : null),
                                                                                    JsonReport.Report);
                    _stateToReport[desiredState.packageFamilyId] = reportedState;
                    return;
                }
            }
            catch (Error e)
            {
                reportedState = new AppxManagementDataContract.AppReportedState(desiredState.packageFamilyId,
                                                                                desiredState.packageFamilyName,
                                                                                currentState.Version,
                                                                                AppUtils.StartUpTypeFromMessage(currentState.StartUp),
                                                                                currentState.InstallDate, // install date
                                                                                e.HResult,
                                                                                e.Message,
                                                                                JsonReport.Report);
            }
            catch (Exception e)
            {
                reportedState = new AppxManagementDataContract.AppReportedState(desiredState.packageFamilyId,
                                                                                desiredState.packageFamilyName,
                                                                                currentState.Version,
                                                                                AppUtils.StartUpTypeFromMessage(currentState.StartUp),
                                                                                currentState.InstallDate, // install date
                                                                                e.HResult,
                                                                                e.Message,
                                                                                JsonReport.Report);
            }
            _stateToReport[desiredState.packageFamilyId] = reportedState;
            throw new Exception("Failed to install " + desiredState.packageFamilyName);
        }
        private void ReorderAndValidate(List <AppxManagementDataContract.AppDesiredState> appDesiredStates, IDictionary <string, AppInfo> installedApps)
        {
            // If we are switching the foreground app from App1 to App2, App2 must be processed first.
            // For example:
            // - Startup is set to App1.
            // - Desired state is:
            //   - App1 : none
            //   - App2 : foreground
            // We have to process App2 first and that will implicitly apply App1 : none.

            // Note that appDesiredStates are not only the just-changed ones - but all the desired states for all apps.
            // This covers the case where the user sets a new foreground app and forgets to set the old one to 'none'.

            AppxManagementDataContract.AppDesiredState desiredForegroundApp = null;
            var foregroundApps = from state in appDesiredStates
                                 where state.startUp == AppxStartUpType.Foreground
                                 select state;

            foreach (AppxManagementDataContract.AppDesiredState state in foregroundApps)
            {
                Logger.Log("Found foreground app: " + state.packageFamilyName, LoggingLevel.Verbose);
                desiredForegroundApp = state;
            }

            if (foregroundApps.Count <AppxManagementDataContract.AppDesiredState>() > 1)
            {
                StringBuilder sb = new StringBuilder();
                foreach (AppxManagementDataContract.AppDesiredState s in foregroundApps)
                {
                    if (sb.Length > 0)
                    {
                        sb.Append(", ");
                    }
                    sb.Append(s.packageFamilyName);
                }

                throw new Error(ErrorCodes.INVALID_DESIRED_MULTIPLE_FOREGROUND_APPS, "Cannot set more than one application to be the foreground application! Package Family Names = " + sb.ToString());
            }

            // Make sure the foreground application is not being uninstalled.
            if (desiredForegroundApp != null &&
                desiredForegroundApp.startUp == AppxStartUpType.Foreground &&
                desiredForegroundApp.action == AppDesiredAction.Uninstall)
            {
                // This means that no other application has been set to replace the one about to be uninstalled.
                throw new Error(ErrorCodes.INVALID_DESIRED_CONFLICT_UNINSTALL_FOREGROUND_APP, "Cannot configure an application to the foreground application and uninstall it. Package Family Name = " + desiredForegroundApp.packageFamilyName);
            }

            // Make sure that the application being uninstalled is not the foreground app as marked by the system (i.e. installedApps).
            // This is to catch the case where the desired state does not say anything about foreground apps - but the system does.
            // So, we want to make sure the desired state does not conflict with the system state.
            var uninstallForegroundApps = from desiredState in appDesiredStates
                                          join installedState in installedApps on desiredState.packageFamilyName equals installedState.Value.PackageFamilyName
                                          where desiredState.action == AppDesiredAction.Uninstall && installedState.Value.StartUp == Message.StartUpType.Foreground
                                          select desiredState;

            if (uninstallForegroundApps.Count <AppxManagementDataContract.AppDesiredState>() > 0)
            {
                // There should be at most one application matching since the foreground setting on the system allows only one foreground application.
                string foregroundAppToUninstall = uninstallForegroundApps.First <AppxManagementDataContract.AppDesiredState>().packageFamilyName;

                // Note that it is okay to uninstall the foreground app if another one is being set as the foreground in the same transaction.
                if (desiredForegroundApp.packageFamilyName == foregroundAppToUninstall)
                {
                    // This means that an application is marked for uninstallation, and
                    throw new Error(ErrorCodes.INVALID_DESIRED_CONFLICT_UNINSTALL_FOREGROUND_APP, "Cannot uninstall a foreground application. Package Family Name = " + foregroundAppToUninstall);
                }
            }

            if (desiredForegroundApp != null)
            {
                // Move to the front.
                appDesiredStates.Remove(desiredForegroundApp);
                appDesiredStates.Insert(0, desiredForegroundApp);
            }

            Logger.Log("Ordered:", LoggingLevel.Verbose);
            foreach (AppxManagementDataContract.AppDesiredState state in appDesiredStates)
            {
                Logger.Log("App: " + state.packageFamilyName + " " + state.startUp.ToString(), LoggingLevel.Verbose);
            }
        }