@@ -101,16 +101,29 @@ namespace AppInstaller::CLI::Workflow
101101 return {
102102 L" Microsoft.WinGet/" ,
103103 L" Microsoft.WinGet.Dev/" ,
104- L" Microsoft.DSC.Debug/" ,
104+ };
105+ };
106+
107+ // Returns unit type prefixes that identify resources known to be shipped with DSC.
108+ // These are used both to exclude the resources themselves and to discover the DSC
109+ // installation location, so that any co-located resources are also excluded.
110+ std::vector<std::wstring_view> DscShippedResourcePrefixes ()
111+ {
112+ return {
105113 L" Microsoft.DSC/" ,
114+ L" Microsoft.DSC.Debug/" ,
106115 L" Microsoft.DSC.Transitional/" ,
107- L" Microsoft.Windows/RebootPending" ,
108- L" Microsoft.Windows/Registry" ,
109- L" Microsoft.Windows/WMI" ,
110- L" Microsoft.Windows/WindowsPowerShell" ,
111- L" Microsoft/OSInfo"
116+ L" Microsoft/OSInfo" ,
112117 };
113- };
118+ }
119+
120+ // Returns unit type prefixes for DSC-shipped resources that are still allowed to
121+ // appear in the exported configuration. All other DSC-shipped resources are excluded by default.
122+ std::vector<std::wstring_view> DscShippedResourcesAllowList ()
123+ {
124+ // Currently empty: all DSC-shipped resources are excluded from export by default.
125+ return {};
126+ }
114127
115128 Logging::Level ConvertLevel (DiagnosticLevel level)
116129 {
@@ -1582,10 +1595,10 @@ namespace AppInstaller::CLI::Workflow
15821595 }
15831596 }
15841597
1585- std::vector<IConfigurationUnitProcessorDetails> GetAllUnitProcessors (Execution::Context& context)
1598+ std::vector<IConfigurationUnitProcessorDetails3> GetAllUnitProcessors3 (Execution::Context& context)
15861599 {
15871600 ConfigurationContext& configContext = context.Get <Data::ConfigurationContext>();
1588- std::vector<IConfigurationUnitProcessorDetails > result;
1601+ std::vector<IConfigurationUnitProcessorDetails3 > result;
15891602
15901603 // Only supported by dsc v3 processor.
15911604 if (ConfigurationRemoting::ProcessorEngine::DSCv3 == ConfigurationRemoting::DetermineProcessorEngine (configContext.Set ()))
@@ -1601,7 +1614,11 @@ namespace AppInstaller::CLI::Workflow
16011614 auto cancellationScope = progressScope->Callback ().SetCancellationFunction ([&]() { findAction.Cancel (); });
16021615 for (auto unitProcessor : findAction.get ())
16031616 {
1604- result.emplace_back (std::move (unitProcessor));
1617+ IConfigurationUnitProcessorDetails3 processor3;
1618+ if (unitProcessor.try_as (processor3))
1619+ {
1620+ result.emplace_back (std::move (processor3));
1621+ }
16051622 }
16061623 }
16071624
@@ -1683,19 +1700,13 @@ namespace AppInstaller::CLI::Workflow
16831700 struct UnitProcessorTree
16841701 {
16851702 private:
1686- struct SourceAndPackage
1687- {
1688- PackageCollection::Source Source;
1689- PackageCollection::Package Package;
1690- };
1691-
16921703 struct Node
16931704 {
16941705 // Packages whose installed location is at this node
1695- std::vector<SourceAndPackage > Packages;
1706+ std::vector<PackageCollection::Package > Packages;
16961707
16971708 // Units whose location is at this node.
1698- std::vector<IConfigurationUnitProcessorDetails > Units;
1709+ std::vector<IConfigurationUnitProcessorDetails3 > Units;
16991710 };
17001711
17011712 Filesystem::PathTree<Node> m_pathTree;
@@ -1707,33 +1718,29 @@ namespace AppInstaller::CLI::Workflow
17071718 }
17081719
17091720 public:
1710- UnitProcessorTree (std::vector<IConfigurationUnitProcessorDetails >&& unitProcessors)
1721+ UnitProcessorTree (std::vector<IConfigurationUnitProcessorDetails3 >&& unitProcessors)
17111722 {
17121723 for (auto && unit : unitProcessors)
17131724 {
1714- IConfigurationUnitProcessorDetails3 unitProcessor3;
1715- if (unit.try_as (unitProcessor3))
1716- {
1717- winrt::hstring unitPath = unitProcessor3.Path ();
1718- AICLI_LOG (Config, Verbose, << " Found unit `" << Utility::ConvertToUTF8 (unit.UnitType ()) << " ` at: " << Utility::ConvertToUTF8 (unitPath));
1719- Node& node = FindNodeForFilePath (unitPath);
1720- node.Units .emplace_back (std::move (unit));
1721- }
1725+ winrt::hstring unitPath = unit.Path ();
1726+ AICLI_LOG (Config, Verbose, << " Found unit `" << Utility::ConvertToUTF8 (unit.UnitType ()) << " ` at: " << Utility::ConvertToUTF8 (unitPath));
1727+ Node& node = FindNodeForFilePath (unitPath);
1728+ node.Units .emplace_back (std::move (unit));
17221729 }
17231730 }
17241731
1725- void PlacePackage (const PackageCollection::Source& source, const PackageCollection:: Package& package)
1732+ void PlacePackage (const PackageCollection::Package& package)
17261733 {
17271734 Node* node = m_pathTree.Find (package.InstalledLocation );
17281735 if (node)
17291736 {
1730- node->Packages .emplace_back (SourceAndPackage{ source, package } );
1737+ node->Packages .emplace_back (package);
17311738 }
17321739 }
17331740
1734- std::vector<IConfigurationUnitProcessorDetails > GetResourcesForPackage (const PackageCollection::Package& package) const
1741+ std::vector<IConfigurationUnitProcessorDetails3 > GetResourcesForPackage (const PackageCollection::Package& package) const
17351742 {
1736- std::vector<IConfigurationUnitProcessorDetails > result;
1743+ std::vector<IConfigurationUnitProcessorDetails3 > result;
17371744
17381745 m_pathTree.VisitIf (
17391746 package.InstalledLocation ,
@@ -1760,10 +1767,10 @@ namespace AppInstaller::CLI::Workflow
17601767 std::wstring packageUnitType = GetWinGetPackageUnitType (configContext);
17611768
17621769 // This will be later used by per package settings export.
1763- std::vector<IConfigurationUnitProcessorDetails > unitProcessors;
1770+ std::vector<IConfigurationUnitProcessorDetails3 > unitProcessors;
17641771 try
17651772 {
1766- unitProcessors = GetAllUnitProcessors (context);
1773+ unitProcessors = GetAllUnitProcessors3 (context);
17671774 }
17681775 catch (...)
17691776 {
@@ -1776,11 +1783,13 @@ namespace AppInstaller::CLI::Workflow
17761783 // Filter out processors in exclusion list.
17771784 for (auto itr = unitProcessors.begin (); itr != unitProcessors.end (); /* itr incremented in the logic */ )
17781785 {
1786+ std::wstring unitType{ itr->UnitType () };
17791787 bool processorRemoved = false ;
17801788 for (const auto & exclusionItem : exclusionList)
17811789 {
1782- if (Utility::CaseInsensitiveStartsWith (itr-> UnitType () , exclusionItem))
1790+ if (Utility::CaseInsensitiveStartsWith (unitType , exclusionItem))
17831791 {
1792+ AICLI_LOG (Config, Verbose, << " Filtering excluded resource `" << Utility::ConvertToUTF8 (itr->UnitType ()) << " ` from export" );
17841793 itr = unitProcessors.erase (itr);
17851794 processorRemoved = true ;
17861795 break ;
@@ -1793,14 +1802,95 @@ namespace AppInstaller::CLI::Workflow
17931802 }
17941803 }
17951804
1805+ // Filter out DSC-shipped resources and any resources co-located with them.
1806+ // First pass: find the parent directory of each known DSC resource to identify the DSC
1807+ // installation location(s), handling both packaged and unpackaged (PATH-based) DSC installs.
1808+ // Second pass: remove any resource that either matches a known DSC prefix or resides in one
1809+ // of those locations, unless the resource type appears in DscShippedResourcesAllowList().
1810+ {
1811+ const auto dscPrefixes = DscShippedResourcePrefixes ();
1812+ const auto dscAllowList = DscShippedResourcesAllowList ();
1813+
1814+ std::set<std::filesystem::path> dscLocations;
1815+ for (const auto & processor : unitProcessors)
1816+ {
1817+ std::wstring unitType{ processor.UnitType () };
1818+ for (const auto & prefix : dscPrefixes)
1819+ {
1820+ if (Utility::CaseInsensitiveStartsWith (unitType, prefix))
1821+ {
1822+ std::filesystem::path location = std::filesystem::weakly_canonical (
1823+ std::filesystem::path{ std::wstring{ processor.Path () } }.parent_path ());
1824+ dscLocations.emplace (std::move (location));
1825+ break ;
1826+ }
1827+ }
1828+ }
1829+
1830+ for (auto itr = unitProcessors.begin (); itr != unitProcessors.end (); /* itr incremented in the logic */ )
1831+ {
1832+ std::wstring unitType{ itr->UnitType () };
1833+
1834+ // Check the allow list first.
1835+ bool inAllowList = false ;
1836+ for (const auto & allowedPrefix : dscAllowList)
1837+ {
1838+ if (Utility::CaseInsensitiveStartsWith (unitType, allowedPrefix))
1839+ {
1840+ inAllowList = true ;
1841+ break ;
1842+ }
1843+ }
1844+
1845+ if (inAllowList)
1846+ {
1847+ ++itr;
1848+ continue ;
1849+ }
1850+
1851+ // Check if the resource type is a known DSC-shipped prefix.
1852+ bool isDscResource = false ;
1853+ for (const auto & prefix : dscPrefixes)
1854+ {
1855+ if (Utility::CaseInsensitiveStartsWith (unitType, prefix))
1856+ {
1857+ isDscResource = true ;
1858+ break ;
1859+ }
1860+ }
1861+
1862+ // If not matched by prefix, check whether it shares a location with a known DSC resource.
1863+ if (!isDscResource && !dscLocations.empty ())
1864+ {
1865+ std::filesystem::path location = std::filesystem::weakly_canonical (
1866+ std::filesystem::path{ std::wstring{ itr->Path () } }.parent_path ());
1867+
1868+ if (dscLocations.find (location) != dscLocations.end ())
1869+ {
1870+ isDscResource = true ;
1871+ }
1872+ }
1873+
1874+ if (isDscResource)
1875+ {
1876+ AICLI_LOG (Config, Verbose, << " Filtering DSC-shipped resource `" << Utility::ConvertToUTF8 (itr->UnitType ()) << " ` from export" );
1877+ itr = unitProcessors.erase (itr);
1878+ }
1879+ else
1880+ {
1881+ ++itr;
1882+ }
1883+ }
1884+ }
1885+
17961886 // Build a tree of the unit processors and place packages onto it to indicate nearest ownership.
17971887 UnitProcessorTree unitProcessorTree{ std::move (unitProcessors) };
17981888
17991889 for (const auto & source : context.Get <Execution::Data::PackageCollection>().Sources )
18001890 {
18011891 for (const auto & package : source.Packages )
18021892 {
1803- unitProcessorTree.PlacePackage (source, package);
1893+ unitProcessorTree.PlacePackage (package);
18041894 }
18051895 }
18061896
0 commit comments