winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

ConfigurationDynamicRuntimeFactory.cpp (25361B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "Public/ConfigurationSetProcessorFactoryRemoting.h"
      5 #include <AppInstallerErrors.h>
      6 #include <AppInstallerLanguageUtilities.h>
      7 #include <AppInstallerLogging.h>
      8 #include <AppInstallerStrings.h>
      9 #include <winget/ILifetimeWatcher.h>
     10 #include <winget/Security.h>
     11 #include <winrt/Microsoft.Management.Configuration.SetProcessorFactory.h>
     12 
     13 using namespace winrt::Windows::Foundation;
     14 using namespace winrt::Microsoft::Management::Configuration;
     15 using namespace winrt::Windows::Storage;
     16 
     17 namespace AppInstaller::CLI::ConfigurationRemoting
     18 {
     19     namespace anonymous
     20     {
     21 #ifndef AICLI_DISABLE_TEST_HOOKS
     22         constexpr std::wstring_view EnableTestModeTestGuid = L"1e62d683-2999-44e7-81f7-6f8f35e8d731";
     23         constexpr std::wstring_view ForceHighIntegrityLevelUnitsTestGuid = L"f698d20f-3584-4f28-bc75-28037e08e651";
     24         constexpr std::wstring_view EnableRestrictedIntegrityLevelTestGuid = L"5cae3226-185f-4289-815c-3c089d238dc6";
     25 
     26         // Checks the configuration set metadata for a specific test guid that controls the behavior flow.
     27         bool GetConfigurationSetMetadataOverride(const ConfigurationSet& configurationSet, const std::wstring_view& testGuid)
     28         {
     29             auto metadataOverride = configurationSet.Metadata().TryLookup(testGuid);
     30             if (metadataOverride)
     31             {
     32                 auto metadataOverrideProperty = metadataOverride.try_as<IPropertyValue>();
     33                 if (metadataOverrideProperty && metadataOverrideProperty.Type() == PropertyType::Boolean)
     34                 {
     35                     return metadataOverrideProperty.GetBoolean();
     36                 }
     37             }
     38 
     39             return false;
     40         }
     41 #endif
     42 
     43         // This is implemented completely in the packaged context for now, if we want to make it more configurable, we will probably want to move it to configuration and
     44         // have this implementation leverage that one with an event handler for the packaged specifics.
     45         // TODO: Add SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties and pass values along to sets on creation
     46         //       In turn, any properties must only be set via the command line (or eventual UI requests to the user).
     47         struct DynamicFactory : winrt::implements<DynamicFactory, IConfigurationSetProcessorFactory, SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties, Collections::IMap<winrt::hstring, winrt::hstring>, winrt::cloaked<WinRT::ILifetimeWatcher>>, WinRT::LifetimeWatcherBase
     48         {
     49             DynamicFactory(ProcessorEngine processorEngine);
     50 
     51             IConfigurationSetProcessor CreateSetProcessor(const ConfigurationSet& configurationSet);
     52 
     53             winrt::event_token Diagnostics(const EventHandler<IDiagnosticInformation>& handler);
     54             void Diagnostics(const winrt::event_token& token) noexcept;
     55 
     56             DiagnosticLevel MinimumLevel();
     57             void MinimumLevel(DiagnosticLevel value);
     58 
     59             HRESULT STDMETHODCALLTYPE SetLifetimeWatcher(IUnknown* watcher);
     60 
     61             IConfigurationSetProcessorFactory& DefaultFactory();
     62 
     63             void SendDiagnostics(const IDiagnosticInformation& information);
     64 
     65             Collections::IVectorView<winrt::hstring> AdditionalModulePaths() const
     66             {
     67                 THROW_HR(E_NOTIMPL);
     68             }
     69 
     70             void AdditionalModulePaths(const Collections::IVectorView<winrt::hstring>&)
     71             {
     72                 THROW_HR(E_NOTIMPL);
     73             }
     74 
     75             SetProcessorFactory::PwshConfigurationProcessorPolicy Policy() const
     76             {
     77                 THROW_HR(E_NOTIMPL);
     78             }
     79 
     80             void Policy(SetProcessorFactory::PwshConfigurationProcessorPolicy)
     81             {
     82                 THROW_HR(E_NOTIMPL);
     83             }
     84 
     85             SetProcessorFactory::PwshConfigurationProcessorLocation Location() const
     86             {
     87                 return m_location;
     88             }
     89 
     90             void Location(SetProcessorFactory::PwshConfigurationProcessorLocation value)
     91             {
     92                 auto pwshFactory = m_defaultRemoteFactory.as<SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties>();
     93                 pwshFactory.Location(value);
     94                 m_location = value;
     95             }
     96 
     97             winrt::hstring CustomLocation() const
     98             {
     99                 return m_customLocation;
    100             }
    101 
    102             void CustomLocation(winrt::hstring value)
    103             {
    104                 auto pwshFactory = m_defaultRemoteFactory.as<SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties>();
    105                 pwshFactory.CustomLocation(value);
    106                 m_customLocation = value;
    107             }
    108 
    109             // Implement a subset of IMap to enable property bag semantics
    110             uint32_t Size() { THROW_HR(E_NOTIMPL); }
    111             void Clear() { THROW_HR(E_NOTIMPL); }
    112             Collections::IMapView<winrt::hstring, winrt::hstring> GetView() { THROW_HR(E_NOTIMPL); }
    113             bool HasKey(winrt::hstring) { THROW_HR(E_NOTIMPL); }
    114             void Remove(winrt::hstring) { THROW_HR(E_NOTIMPL); }
    115 
    116             bool Insert(winrt::hstring key, winrt::hstring value)
    117             {
    118                 auto result = m_defaultRemoteFactory.as<Collections::IMap<winrt::hstring, winrt::hstring>>().Insert(key, value);
    119                 m_factoryMapValues[key] = value;
    120                 return result;
    121             }
    122 
    123             winrt::hstring Lookup(winrt::hstring key)
    124             {
    125                 return m_defaultRemoteFactory.as<Collections::IMap<winrt::hstring, winrt::hstring>>().Lookup(key);
    126             }
    127 
    128             ProcessorEngine Engine() const
    129             {
    130                 return m_processorEngine;
    131             }
    132 
    133             std::optional<winrt::hstring> GetFactoryMapValue(winrt::hstring key)
    134             {
    135                 auto itr = m_factoryMapValues.find(key);
    136                 return itr != m_factoryMapValues.end() ? std::make_optional(itr->second) : std::nullopt;
    137             }
    138 
    139         private:
    140             IConfigurationSetProcessorFactory m_defaultRemoteFactory;
    141             winrt::event<EventHandler<IDiagnosticInformation>> m_diagnostics;
    142             IConfigurationSetProcessorFactory::Diagnostics_revoker m_factoryDiagnosticsEventRevoker;
    143             std::mutex m_diagnosticsMutex;
    144             DiagnosticLevel m_minimumLevel = DiagnosticLevel::Informational;
    145             SetProcessorFactory::PwshConfigurationProcessorLocation m_location = SetProcessorFactory::PwshConfigurationProcessorLocation::Default;
    146             winrt::hstring m_customLocation;
    147             ProcessorEngine m_processorEngine;
    148             std::map<winrt::hstring, winrt::hstring> m_factoryMapValues;
    149         };
    150 
    151         struct DynamicProcessorInfo
    152         {
    153             IConfigurationSetProcessorFactory Factory;
    154             IConfigurationSetProcessor Processor;
    155             IConfigurationSetProcessorFactory::Diagnostics_revoker DiagnosticsEventRevoker;
    156         };
    157 
    158         struct DynamicSetProcessor : winrt::implements<DynamicSetProcessor, IConfigurationSetProcessor, IFindUnitProcessorsSetProcessor>
    159         {
    160             using ProcessorMap = std::map<Security::IntegrityLevel, DynamicProcessorInfo>;
    161 
    162             DynamicSetProcessor(winrt::com_ptr<DynamicFactory> dynamicFactory, IConfigurationSetProcessor defaultRemoteSetProcessor, const ConfigurationSet& configurationSet) :
    163                 m_dynamicFactory(std::move(dynamicFactory)), m_configurationSet(configurationSet)
    164             {
    165 #ifndef AICLI_DISABLE_TEST_HOOKS
    166                 if (m_configurationSet)
    167                 {
    168                     m_enableTestMode = GetConfigurationSetMetadataOverride(m_configurationSet, EnableTestModeTestGuid);
    169                     m_enableRestrictedIntegrityLevel = GetConfigurationSetMetadataOverride(m_configurationSet, EnableRestrictedIntegrityLevelTestGuid);
    170                     m_forceHighIntegrityLevelUnits = GetConfigurationSetMetadataOverride(m_configurationSet, ForceHighIntegrityLevelUnitsTestGuid);
    171                 }
    172 
    173                 m_currentIntegrityLevel = m_enableTestMode ? Security::IntegrityLevel::Medium : Security::GetEffectiveIntegrityLevel();
    174 #else
    175                 m_currentIntegrityLevel = Security::GetEffectiveIntegrityLevel();
    176 #endif
    177 
    178                 m_setIntegrityLevel = m_currentIntegrityLevel;
    179 
    180                 if (m_configurationSet)
    181                 {
    182                     m_setIntegrityLevel = SecurityContextToIntegrityLevel(m_configurationSet.Environment().Context());
    183 
    184                     // Check for multiple integrity level requirements
    185                     bool multipleIntegrityLevels = false;
    186                     bool higherIntegrityLevelsThanCurrent = false;
    187                     for (const auto& environment : m_configurationSet.GetUnitEnvironments())
    188                     {
    189                         auto integrityLevel = SecurityContextToIntegrityLevel(environment.Context());
    190                         if (integrityLevel != m_currentIntegrityLevel)
    191                         {
    192                             multipleIntegrityLevels = true;
    193 
    194                             if (ToIntegral(m_currentIntegrityLevel) < ToIntegral(integrityLevel))
    195                             {
    196                                 higherIntegrityLevelsThanCurrent = true;
    197                                 break;
    198                             }
    199                         }
    200                     }
    201 
    202                     // Prevent supplied parameters from crossing integrity levels
    203                     for (const auto& parameter : m_configurationSet.Parameters())
    204                     {
    205                         if (parameter.ProvidedValue() != nullptr)
    206                         {
    207                             THROW_HR_IF(WINGET_CONFIG_ERROR_PARAMETER_INTEGRITY_BOUNDARY, higherIntegrityLevelsThanCurrent || (multipleIntegrityLevels && parameter.IsSecure()));
    208                         }
    209                     }
    210                 }
    211 
    212                 m_setProcessors.emplace(m_currentIntegrityLevel, DynamicProcessorInfo{ m_dynamicFactory->DefaultFactory(), defaultRemoteSetProcessor});
    213             }
    214 
    215             IConfigurationUnitProcessorDetails GetUnitProcessorDetails(const ConfigurationUnit& unit, ConfigurationUnitDetailFlags detailFlags)
    216             {
    217                 // Always get processor details from the current integrity level
    218                 return m_setProcessors[m_currentIntegrityLevel].Processor.GetUnitProcessorDetails(unit, detailFlags);
    219             }
    220 
    221             // Creates a configuration unit processor for the given unit.
    222             IConfigurationUnitProcessor CreateUnitProcessor(const ConfigurationUnit& unit)
    223             {
    224                 // Determine and create set processors for all required integrity levels.
    225                 // Doing this here avoids creating them if the only call is going to be for details (ex. `configure show`) 
    226                 std::call_once(m_createUnitSetProcessorsOnce,
    227                     [&]()
    228                     {
    229                         if (m_configurationSet)
    230                         {
    231                             for (const auto& environment : m_configurationSet.GetUnitEnvironments())
    232                             {
    233                                 Security::IntegrityLevel requiredIntegrityLevel = SecurityContextToIntegrityLevel(environment.Context());
    234 
    235                                 if (m_setProcessors.find(requiredIntegrityLevel) == m_setProcessors.end())
    236                                 {
    237                                     CreateSetProcessorForIntegrityLevel(requiredIntegrityLevel);
    238                                 }
    239                             }
    240                         }
    241                     });
    242 
    243                 // Create set and unit processor for current unit.
    244 #ifndef AICLI_DISABLE_TEST_HOOKS
    245                 Security::IntegrityLevel requiredIntegrityLevel = m_forceHighIntegrityLevelUnits ? Security::IntegrityLevel::High : GetIntegrityLevelForUnit(unit);
    246 #else
    247                 Security::IntegrityLevel requiredIntegrityLevel = GetIntegrityLevelForUnit(unit);
    248 #endif
    249 
    250                 auto itr = m_setProcessors.find(requiredIntegrityLevel);
    251                 if (itr == m_setProcessors.end())
    252                 {
    253                     THROW_WIN32_IF_MSG(ERROR_NOT_SUPPORTED, !m_configurationSet, "Using configuration unit integrity level other than current level without a configuration set is not supported.");
    254                     itr = CreateSetProcessorForIntegrityLevel(requiredIntegrityLevel);
    255                 }
    256 
    257                 return itr->second.Processor.CreateUnitProcessor(unit);
    258             }
    259 
    260             Collections::IVector<IConfigurationUnitProcessorDetails> FindUnitProcessors(const FindUnitProcessorsOptions& findOptions)
    261             {
    262                 IFindUnitProcessorsSetProcessor findUnitProcessorsSetProcessor;
    263 
    264                 if (m_setProcessors[m_currentIntegrityLevel].Processor.try_as<IFindUnitProcessorsSetProcessor>(findUnitProcessorsSetProcessor))
    265                 {
    266                     return findUnitProcessorsSetProcessor.FindUnitProcessors(findOptions);
    267                 }
    268                 else
    269                 {
    270                     AICLI_LOG(Config, Error, << "Set Processor does not support FindUnitProcessors operation");
    271                     THROW_HR(WINGET_CONFIG_ERROR_NOT_SUPPORTED_BY_PROCESSOR);
    272                 }
    273             }
    274 
    275         private:
    276             // Converts the string representation of SecurityContext to the target integrity level for this instance
    277             Security::IntegrityLevel SecurityContextToIntegrityLevel(SecurityContext securityContext)
    278             {
    279                 switch (securityContext)
    280                 {
    281                 case SecurityContext::Current:
    282                     return m_setIntegrityLevel;
    283                 case SecurityContext::Restricted:
    284 #ifndef AICLI_DISABLE_TEST_HOOKS
    285                     if (m_enableRestrictedIntegrityLevel)
    286                     {
    287                         return Security::IntegrityLevel::Medium;
    288                     }
    289                     else
    290 #endif
    291                     {
    292                         // Not supporting elevated callers downgrading at the moment.
    293                         THROW_WIN32(ERROR_NOT_SUPPORTED);
    294 
    295                         // Technically this means the default level of the user token, so if UAC is disabled it would be the only integrity level (aka current).
    296                         // return Security::IntegrityLevel::Medium;
    297                     }
    298                 case SecurityContext::Elevated:
    299                     return Security::IntegrityLevel::High;
    300                 default:
    301                     THROW_WIN32(ERROR_NOT_SUPPORTED);
    302                 }
    303             }
    304 
    305             // Gets the integrity level that the given unit should be run at
    306             Security::IntegrityLevel GetIntegrityLevelForUnit(const ConfigurationUnit& unit)
    307             {
    308                 return SecurityContextToIntegrityLevel(unit.Environment().Context());
    309             }
    310 
    311             // Serializes the set properties to be sent to the remote server
    312             std::string SerializeSetProperties()
    313             {
    314                 Json::Value json{ Json::ValueType::objectValue };
    315 
    316                 json["path"] = winrt::to_string(m_configurationSet.Path());
    317 
    318                 std::string locationString;
    319                 switch (m_dynamicFactory->Location())
    320                 {
    321                 case SetProcessorFactory::PwshConfigurationProcessorLocation::AllUsers:
    322                     locationString = "AllUsers";
    323                     break;
    324                 case SetProcessorFactory::PwshConfigurationProcessorLocation::CurrentUser:
    325                     locationString = "CurrentUser";
    326                     break;
    327                 case SetProcessorFactory::PwshConfigurationProcessorLocation::Custom:
    328                     locationString = Utility::ConvertToUTF8(m_dynamicFactory->CustomLocation());
    329                     break;
    330                 case SetProcessorFactory::PwshConfigurationProcessorLocation::Default:
    331                     break;
    332                 }
    333 
    334                 if (!locationString.empty())
    335                 {
    336                     json["modulePath"] = locationString;
    337                 }
    338 
    339                 // Ensure that we always pass a path to the executable
    340                 if (m_dynamicFactory->Engine() == ProcessorEngine::DSCv3)
    341                 {
    342                     winrt::hstring dscExecutablePathPropertyName = ToHString(PropertyName::DscExecutablePath);
    343                     std::optional<winrt::hstring> dscExecutablePath = m_dynamicFactory->GetFactoryMapValue(dscExecutablePathPropertyName);
    344 
    345                     if (!dscExecutablePath)
    346                     {
    347                         dscExecutablePath = m_dynamicFactory->Lookup(ToHString(PropertyName::FoundDscExecutablePath));
    348                     }
    349 
    350                     if (dscExecutablePath->empty())
    351                     {
    352                         // This is backstop to prevent a case where dsc.exe not found.
    353                         AICLI_LOG(Config, Error, << "Could not find dsc.exe, it must be provided by the user.");
    354                         THROW_WIN32(ERROR_FILE_NOT_FOUND);
    355                     }
    356 
    357                     json["processorPath"] = Utility::ConvertToUTF8(dscExecutablePath.value());
    358                 }
    359 
    360                 Json::StreamWriterBuilder writerBuilder;
    361                 writerBuilder.settings_["indentation"] = "\t";
    362                 return Json::writeString(writerBuilder, json);
    363             }
    364 
    365             /// <summary>
    366             /// Creates a separate configuration set containing high integrity units and returns the serialized string value.
    367             /// </summary>
    368             /// <returns>Serialized string value.</returns>
    369             std::string SerializeHighIntegrityLevelSet()
    370             {
    371                 ConfigurationSet highIntegritySet;
    372                 highIntegritySet.SchemaVersion(m_configurationSet.SchemaVersion());
    373                 highIntegritySet.Metadata(m_configurationSet.Metadata());
    374                 highIntegritySet.Parameters(m_configurationSet.Parameters());
    375                 highIntegritySet.Variables(m_configurationSet.Variables());
    376 
    377                 std::vector<ConfigurationUnit> highIntegrityUnits;
    378                 auto units = m_configurationSet.Units();
    379 
    380                 for (auto unit : units)
    381                 {
    382                     if (unit.IsActive() && GetIntegrityLevelForUnit(unit) == Security::IntegrityLevel::High)
    383                     {
    384                         highIntegrityUnits.emplace_back(unit);
    385                     }
    386                 }
    387 
    388                 highIntegritySet.Units(std::move(highIntegrityUnits));
    389 
    390                 // Serialize high integrity set and return output string.
    391                 Streams::InMemoryRandomAccessStream memoryStream;
    392                 highIntegritySet.Serialize(memoryStream);
    393 
    394                 Streams::DataReader reader(memoryStream.GetInputStreamAt(0));
    395                 THROW_HR_IF(E_UNEXPECTED, memoryStream.Size() > std::numeric_limits<uint32_t>::max());
    396                 uint32_t streamSize = (uint32_t)memoryStream.Size();
    397                 std::vector<uint8_t> bytes;
    398                 bytes.resize(streamSize);
    399                 reader.LoadAsync(streamSize);
    400                 reader.ReadBytes(bytes);
    401                 reader.DetachStream();
    402                 memoryStream.Close();
    403 
    404                 return { bytes.begin(), bytes.end() };
    405             }
    406 
    407             ProcessorMap::iterator CreateSetProcessorForIntegrityLevel(Security::IntegrityLevel integrityLevel)
    408             {
    409                 IConfigurationSetProcessorFactory factory;
    410                 IConfigurationSetProcessorFactory::Diagnostics_revoker factoryDiagnosticsEventRevoker;
    411 
    412                 // If we got here, the only option is that the current integrity level is not High.
    413                 if (integrityLevel == Security::IntegrityLevel::High)
    414                 {
    415                     bool useRunAs = true;
    416 #ifndef AICLI_DISABLE_TEST_HOOKS
    417                     useRunAs = !m_enableTestMode;
    418 #endif
    419 
    420                     factory = CreateOutOfProcessFactory(m_dynamicFactory->Engine(), useRunAs, SerializeSetProperties(), SerializeHighIntegrityLevelSet());
    421                 }
    422                 else
    423                 {
    424                     THROW_WIN32(ERROR_NOT_SUPPORTED);
    425                 }
    426 
    427                 if (factory)
    428                 {
    429                     factory.MinimumLevel(m_dynamicFactory->MinimumLevel());
    430                     factoryDiagnosticsEventRevoker = factory.Diagnostics(winrt::auto_revoke,
    431                         [weak_this{ get_weak() }](const IInspectable&, const IDiagnosticInformation& information)
    432                         {
    433                             if (auto strong_this{ weak_this.get() })
    434                             {
    435                                 strong_this->m_dynamicFactory->SendDiagnostics(information);
    436                             }
    437                         });
    438 
    439                     winrt::hstring propertyName = ConfigurationRemoting::ToHString(ConfigurationRemoting::PropertyName::DiagnosticTraceEnabled);
    440                     if (auto propertyValue = m_dynamicFactory->GetFactoryMapValue(propertyName))
    441                     {
    442                         factory.as<Collections::IMap<winrt::hstring, winrt::hstring>>().Insert(propertyName, propertyValue.value());
    443                     }
    444                 }
    445 
    446                 return m_setProcessors.emplace(integrityLevel, DynamicProcessorInfo{ factory, factory.CreateSetProcessor(m_configurationSet), std::move(factoryDiagnosticsEventRevoker) }).first;
    447             }
    448 
    449             winrt::com_ptr<DynamicFactory> m_dynamicFactory;
    450             Security::IntegrityLevel m_currentIntegrityLevel;
    451             Security::IntegrityLevel m_setIntegrityLevel;
    452             ProcessorMap m_setProcessors;
    453             ConfigurationSet m_configurationSet;
    454             std::once_flag m_createUnitSetProcessorsOnce;
    455 
    456 #ifndef AICLI_DISABLE_TEST_HOOKS
    457             bool m_enableTestMode = false;
    458             bool m_enableRestrictedIntegrityLevel = false;
    459             bool m_forceHighIntegrityLevelUnits = false;
    460 #endif
    461         };
    462 
    463         DynamicFactory::DynamicFactory(ProcessorEngine processorEngine)
    464         {
    465             m_processorEngine = processorEngine;
    466             m_defaultRemoteFactory = CreateOutOfProcessFactory(processorEngine);
    467 
    468             if (m_defaultRemoteFactory)
    469             {
    470                 m_factoryDiagnosticsEventRevoker = m_defaultRemoteFactory.Diagnostics(winrt::auto_revoke,
    471                     [weak_this{ get_weak() }](const IInspectable&, const IDiagnosticInformation& information)
    472                     {
    473                         if (auto strong_this{ weak_this.get() })
    474                         {
    475                             strong_this->SendDiagnostics(information);
    476                         }
    477                     });
    478             }
    479         }
    480 
    481         IConfigurationSetProcessor DynamicFactory::CreateSetProcessor(const ConfigurationSet& configurationSet)
    482         {
    483             return winrt::make<DynamicSetProcessor>(get_strong(), m_defaultRemoteFactory.CreateSetProcessor(configurationSet), configurationSet);
    484         }
    485 
    486         winrt::event_token DynamicFactory::Diagnostics(const EventHandler<IDiagnosticInformation>& handler)
    487         {
    488             return m_diagnostics.add(handler);
    489         }
    490 
    491         void DynamicFactory::Diagnostics(const winrt::event_token& token) noexcept
    492         {
    493             m_diagnostics.remove(token);
    494         }
    495 
    496         DiagnosticLevel DynamicFactory::MinimumLevel()
    497         {
    498             return m_minimumLevel;
    499         }
    500 
    501         void DynamicFactory::MinimumLevel(DiagnosticLevel value)
    502         {
    503             m_minimumLevel = value;
    504 
    505             if (m_defaultRemoteFactory)
    506             {
    507                 m_defaultRemoteFactory.MinimumLevel(value);
    508             }
    509         }
    510 
    511         HRESULT STDMETHODCALLTYPE DynamicFactory::SetLifetimeWatcher(IUnknown* watcher)
    512         {
    513             return WinRT::LifetimeWatcherBase::SetLifetimeWatcher(watcher);
    514         }
    515 
    516         IConfigurationSetProcessorFactory& DynamicFactory::DefaultFactory()
    517         {
    518             return m_defaultRemoteFactory;
    519         }
    520 
    521         void DynamicFactory::SendDiagnostics(const IDiagnosticInformation& information) try
    522         {
    523             if (information.Level() >= m_minimumLevel)
    524             {
    525                 std::lock_guard<std::mutex> lock{ m_diagnosticsMutex };
    526                 m_diagnostics(*this, information);
    527             }
    528         }
    529         // While diagnostics can be important, a failure to send them should not cause additional issues.
    530         catch (...) {}
    531     }
    532 
    533     winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory CreateDynamicRuntimeFactory(ProcessorEngine processorEngine)
    534     {
    535         return winrt::make<anonymous::DynamicFactory>(processorEngine);
    536     }
    537 }