Skip to content

Commit b57977b

Browse files
authored
Experimental support for DSC v3 processing (#5252)
## Change Adds experimental support for DSC v3 processing of configurations. When enabled, one can use DSC v3 instead of PowerShell DSC v2 by setting their processor to `dscv3` for the configuration like: ```yaml $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json metadata: winget: processor: dscv3 resources: <continue with schema 0.3 resource definitions> ``` This is currently on-par with DSC v2 in terms of functionality, except for 2 things: 1. It does not attempt to ensure dsc.exe is present. It will find and use the preview MSIX packaged version of dsc.exe (Store ID: `9PCX3HX4HZ0Z`) if installed. Otherwise, you can specify the `--processor-path` to dsc.exe. 2. Resources for DSC v3 must be present on the system. There is not currently any mechanism to find and install new resources, as the paradigm is that they are part of the configurable item. There is no special handling of DSC v2 resources in the configuration; that could potentially come later. Also makes 0.3 schema not experimental and fixes configuration history for environments.
1 parent c20c717 commit b57977b

File tree

94 files changed

+3067
-215
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+3067
-215
lines changed

.github/actions/spelling/allow.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ MAKEINTRESOURCE
167167
makemsix
168168
MANIFESTSCHEMA
169169
MANIFESTVERSION
170+
Memberwise
170171
meme
171172
metadatas
172173
Minimatch

.github/actions/spelling/expect.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ ICONDIRENTRY
219219
ICONIMAGE
220220
icu
221221
idl
222+
IDSC
222223
idx
223224
IFACEMETHODIMP
224225
iid

azure-pipelines.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,12 @@ jobs:
374374
displayName: Clean up Sysinternals PsTools
375375
condition: succeededOrFailed()
376376
377+
# Install DSC v3 preview until the DSC v3 processor handles that on its own
378+
- powershell: |
379+
Install-WinGetPackage -Id Microsoft.DSC.Preview -Source winget
380+
displayName: Install DSC v3
381+
condition: succeededOrFailed()
382+
377383
- task: PowerShell@2
378384
displayName: Run Unit Tests Packaged
379385
inputs:

doc/Settings.md

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -355,25 +355,14 @@ You can enable the feature as shown below.
355355
},
356356
```
357357

358-
### configuration03
358+
### dsc3
359359

360-
This feature enables the configuration schema 0.3.
360+
This feature enables support for DSC v3 integration.
361361
You can enable the feature as shown below.
362362

363363
```json
364364
"experimentalFeatures": {
365-
"configuration03": true
366-
},
367-
```
368-
369-
### configureSelfElevate
370-
371-
This feature enables configure commands to request elevation as needed.
372-
Currently, this means that properly attributed configuration units (and only those) will be run through an elevated process while the rest are run from the current context.
373-
374-
```json
375-
"experimentalFeatures": {
376-
"configureSelfElevate": true
365+
"dsc3": true
377366
},
378367
```
379368

src/AppInstallerCLICore/Argument.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ namespace AppInstaller::CLI
217217
return { type, "disable"_liv, ArgTypeCategory::None, ArgTypeExclusiveSet::StubType };
218218
case Execution::Args::Type::ConfigurationModulePath:
219219
return { type, "module-path"_liv };
220+
case Execution::Args::Type::ConfigurationProcessorPath:
221+
return { type, "processor-path"_liv };
220222
case Execution::Args::Type::ConfigurationExportPackageId:
221223
return { type, "package-id"_liv };
222224
case Execution::Args::Type::ConfigurationExportModule:

src/AppInstallerCLICore/Commands/ConfigureCommand.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace AppInstaller::CLI
3737
return {
3838
Argument{ Execution::Args::Type::ConfigurationFile, Resource::String::ConfigurationFileArgumentDescription, ArgumentType::Positional },
3939
Argument{ Execution::Args::Type::ConfigurationModulePath, Resource::String::ConfigurationModulePath, ArgumentType::Positional },
40+
Argument{ Execution::Args::Type::ConfigurationProcessorPath, Resource::String::ConfigurationProcessorPath, ArgumentType::Standard, Argument::Visibility::Help },
4041
Argument{ Execution::Args::Type::ConfigurationHistoryItem, Resource::String::ConfigurationHistoryItemArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help },
4142
Argument{ Execution::Args::Type::ConfigurationAcceptWarning, Resource::String::ConfigurationAcceptWarningArgumentDescription, ArgumentType::Flag },
4243
Argument{ Execution::Args::Type::ConfigurationSuppressPrologue, Resource::String::ConfigurationSuppressPrologueArgumentDescription, ArgumentType::Flag, Argument::Visibility::Help },
@@ -77,8 +78,9 @@ namespace AppInstaller::CLI
7778
context <<
7879
VerifyIsFullPackage <<
7980
VerifyFileOrUri(Execution::Args::Type::ConfigurationFile) <<
80-
CreateConfigurationProcessor <<
81+
CreateConfigurationProcessorWithoutFactory <<
8182
OpenConfigurationSet <<
83+
CreateConfigurationProcessor <<
8284
ShowConfigurationSet <<
8385
ShowConfigurationSetConflicts <<
8486
ConfirmConfigurationProcessing(true) <<

src/AppInstallerCLICore/Commands/ConfigureShowCommand.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace AppInstaller::CLI
1515
// Required for now, make exclusive when history implemented
1616
Argument{ Execution::Args::Type::ConfigurationFile, Resource::String::ConfigurationFileArgumentDescription, ArgumentType::Positional },
1717
Argument{ Execution::Args::Type::ConfigurationModulePath, Resource::String::ConfigurationModulePath, ArgumentType::Positional },
18+
Argument{ Execution::Args::Type::ConfigurationProcessorPath, Resource::String::ConfigurationProcessorPath, ArgumentType::Standard, Argument::Visibility::Help },
1819
Argument{ Execution::Args::Type::ConfigurationHistoryItem, Resource::String::ConfigurationHistoryItemArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help },
1920
};
2021
}
@@ -39,8 +40,9 @@ namespace AppInstaller::CLI
3940
context <<
4041
VerifyIsFullPackage <<
4142
VerifyFileOrUri(Execution::Args::Type::ConfigurationFile) <<
42-
CreateConfigurationProcessor <<
43+
CreateConfigurationProcessorWithoutFactory <<
4344
OpenConfigurationSet <<
45+
CreateConfigurationProcessor <<
4446
ShowConfigurationSet;
4547
}
4648

src/AppInstallerCLICore/Commands/ConfigureTestCommand.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace AppInstaller::CLI
1414
return {
1515
Argument{ Execution::Args::Type::ConfigurationFile, Resource::String::ConfigurationFileArgumentDescription, ArgumentType::Positional },
1616
Argument{ Execution::Args::Type::ConfigurationModulePath, Resource::String::ConfigurationModulePath, ArgumentType::Positional },
17+
Argument{ Execution::Args::Type::ConfigurationProcessorPath, Resource::String::ConfigurationProcessorPath, ArgumentType::Standard, Argument::Visibility::Help },
1718
Argument{ Execution::Args::Type::ConfigurationHistoryItem, Resource::String::ConfigurationHistoryItemArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help },
1819
Argument{ Execution::Args::Type::ConfigurationAcceptWarning, Resource::String::ConfigurationAcceptWarningArgumentDescription, ArgumentType::Flag },
1920
};
@@ -39,8 +40,9 @@ namespace AppInstaller::CLI
3940
context <<
4041
VerifyIsFullPackage <<
4142
VerifyFileOrUri(Execution::Args::Type::ConfigurationFile) <<
42-
CreateConfigurationProcessor <<
43+
CreateConfigurationProcessorWithoutFactory <<
4344
OpenConfigurationSet <<
45+
CreateConfigurationProcessor <<
4446
ShowConfigurationSet <<
4547
ShowConfigurationSetConflicts <<
4648
ConfirmConfigurationProcessing(false) <<

src/AppInstallerCLICore/Commands/ConfigureValidateCommand.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace AppInstaller::CLI
1414
return {
1515
Argument{ Execution::Args::Type::ConfigurationFile, Resource::String::ConfigurationFileArgumentDescription, ArgumentType::Positional, true },
1616
Argument{ Execution::Args::Type::ConfigurationModulePath, Resource::String::ConfigurationModulePath, ArgumentType::Positional },
17+
Argument{ Execution::Args::Type::ConfigurationProcessorPath, Resource::String::ConfigurationProcessorPath, ArgumentType::Standard, Argument::Visibility::Help },
1718
};
1819
}
1920

@@ -37,8 +38,9 @@ namespace AppInstaller::CLI
3738
context <<
3839
VerifyIsFullPackage <<
3940
VerifyFileOrUri(Execution::Args::Type::ConfigurationFile) <<
40-
CreateConfigurationProcessor <<
41+
CreateConfigurationProcessorWithoutFactory <<
4142
OpenConfigurationSet <<
43+
CreateConfigurationProcessor <<
4244
ValidateConfigurationSetSemantics <<
4345
ValidateConfigurationSetUnitProcessors <<
4446
ValidateConfigurationSetUnitContents <<

src/AppInstallerCLICore/ConfigurationDynamicRuntimeFactory.cpp

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "Public/ConfigurationSetProcessorFactoryRemoting.h"
55
#include <AppInstallerErrors.h>
66
#include <AppInstallerLanguageUtilities.h>
7+
#include <AppInstallerLogging.h>
78
#include <AppInstallerStrings.h>
89
#include <winget/ILifetimeWatcher.h>
910
#include <winget/Security.h>
@@ -43,9 +44,9 @@ namespace AppInstaller::CLI::ConfigurationRemoting
4344
// have this implementation leverage that one with an event handler for the packaged specifics.
4445
// TODO: Add SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties and pass values along to sets on creation
4546
// In turn, any properties must only be set via the command line (or eventual UI requests to the user).
46-
struct DynamicFactory : winrt::implements<DynamicFactory, IConfigurationSetProcessorFactory, SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties, winrt::cloaked<WinRT::ILifetimeWatcher>>, WinRT::LifetimeWatcherBase
47+
struct DynamicFactory : winrt::implements<DynamicFactory, IConfigurationSetProcessorFactory, SetProcessorFactory::IPwshConfigurationSetProcessorFactoryProperties, Collections::IMap<winrt::hstring, winrt::hstring>, winrt::cloaked<WinRT::ILifetimeWatcher>>, WinRT::LifetimeWatcherBase
4748
{
48-
DynamicFactory();
49+
DynamicFactory(ProcessorEngine processorEngine);
4950

5051
IConfigurationSetProcessor CreateSetProcessor(const ConfigurationSet& configurationSet);
5152

@@ -105,6 +106,36 @@ namespace AppInstaller::CLI::ConfigurationRemoting
105106
m_customLocation = value;
106107
}
107108

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+
winrt::hstring GetFactoryMapValue(winrt::hstring key)
134+
{
135+
auto itr = m_factoryMapValues.find(key);
136+
return itr != m_factoryMapValues.end() ? itr->second : winrt::hstring{};
137+
}
138+
108139
private:
109140
IConfigurationSetProcessorFactory m_defaultRemoteFactory;
110141
winrt::event<EventHandler<IDiagnosticInformation>> m_diagnostics;
@@ -113,6 +144,8 @@ namespace AppInstaller::CLI::ConfigurationRemoting
113144
DiagnosticLevel m_minimumLevel = DiagnosticLevel::Informational;
114145
SetProcessorFactory::PwshConfigurationProcessorLocation m_location = SetProcessorFactory::PwshConfigurationProcessorLocation::Default;
115146
winrt::hstring m_customLocation;
147+
ProcessorEngine m_processorEngine;
148+
std::map<winrt::hstring, winrt::hstring> m_factoryMapValues;
116149
};
117150

118151
struct DynamicProcessorInfo
@@ -277,6 +310,27 @@ namespace AppInstaller::CLI::ConfigurationRemoting
277310
json["modulePath"] = locationString;
278311
}
279312

313+
// Ensure that we always pass a path to the executable
314+
if (m_dynamicFactory->Engine() == ProcessorEngine::DSCv3)
315+
{
316+
winrt::hstring dscExecutablePathPropertyName = ToHString(PropertyName::DscExecutablePath);
317+
winrt::hstring dscExecutablePath = m_dynamicFactory->GetFactoryMapValue(dscExecutablePathPropertyName);
318+
319+
if (dscExecutablePath.empty())
320+
{
321+
dscExecutablePath = m_dynamicFactory->Lookup(ToHString(PropertyName::FoundDscExecutablePath));
322+
}
323+
324+
if (dscExecutablePath.empty())
325+
{
326+
// This is backstop to prevent a case where dsc.exe not found.
327+
AICLI_LOG(Config, Error, << "Could not find dsc.exe, it must be provided by the user.");
328+
THROW_WIN32(ERROR_FILE_NOT_FOUND);
329+
}
330+
331+
json["processorPath"] = Utility::ConvertToUTF8(dscExecutablePath);
332+
}
333+
280334
Json::StreamWriterBuilder writerBuilder;
281335
writerBuilder.settings_["indentation"] = "\t";
282336
return Json::writeString(writerBuilder, json);
@@ -337,7 +391,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting
337391
useRunAs = !m_enableTestMode;
338392
#endif
339393

340-
factory = CreateOutOfProcessFactory(useRunAs, SerializeSetProperties(), SerializeHighIntegrityLevelSet());
394+
factory = CreateOutOfProcessFactory(m_dynamicFactory->Engine(), useRunAs, SerializeSetProperties(), SerializeHighIntegrityLevelSet());
341395
}
342396
else
343397
{
@@ -346,6 +400,7 @@ namespace AppInstaller::CLI::ConfigurationRemoting
346400

347401
if (factory)
348402
{
403+
factory.MinimumLevel(m_dynamicFactory->MinimumLevel());
349404
factoryDiagnosticsEventRevoker = factory.Diagnostics(winrt::auto_revoke,
350405
[weak_this{ get_weak() }](const IInspectable&, const IDiagnosticInformation& information)
351406
{
@@ -373,9 +428,10 @@ namespace AppInstaller::CLI::ConfigurationRemoting
373428
#endif
374429
};
375430

376-
DynamicFactory::DynamicFactory()
431+
DynamicFactory::DynamicFactory(ProcessorEngine processorEngine)
377432
{
378-
m_defaultRemoteFactory = CreateOutOfProcessFactory();
433+
m_processorEngine = processorEngine;
434+
m_defaultRemoteFactory = CreateOutOfProcessFactory(processorEngine);
379435

380436
if (m_defaultRemoteFactory)
381437
{
@@ -413,6 +469,11 @@ namespace AppInstaller::CLI::ConfigurationRemoting
413469
void DynamicFactory::MinimumLevel(DiagnosticLevel value)
414470
{
415471
m_minimumLevel = value;
472+
473+
if (m_defaultRemoteFactory)
474+
{
475+
m_defaultRemoteFactory.MinimumLevel(value);
476+
}
416477
}
417478

418479
HRESULT STDMETHODCALLTYPE DynamicFactory::SetLifetimeWatcher(IUnknown* watcher)
@@ -437,8 +498,8 @@ namespace AppInstaller::CLI::ConfigurationRemoting
437498
catch (...) {}
438499
}
439500

440-
winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory CreateDynamicRuntimeFactory()
501+
winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory CreateDynamicRuntimeFactory(ProcessorEngine processorEngine)
441502
{
442-
return winrt::make<anonymous::DynamicFactory>();
503+
return winrt::make<anonymous::DynamicFactory>(processorEngine);
443504
}
444505
}

0 commit comments

Comments
 (0)