@@ -53,7 +53,6 @@ namespace AppInstaller::CLI::Workflow
5353 constexpr std::wstring_view s_UnitType_WinGetSource_DSCv3 = WINGET_DSCV3_MODULE_NAME_WIDE L" /Source" ;
5454 constexpr std::wstring_view s_UnitType_WinGetUserSettingsFile_DSCv3 = WINGET_DSCV3_MODULE_NAME_WIDE L" /UserSettingsFile" ;
5555 constexpr std::wstring_view s_UnitType_WinGetAdminSettings_DSCv3 = WINGET_DSCV3_MODULE_NAME_WIDE L" /AdminSettings" ;
56- constexpr std::wstring_view s_UnitType_PowerShellModuleGet = L" PowerShellGet/PSModule" ;
5756
5857 constexpr std::wstring_view s_Module_WinGetClient = L" Microsoft.WinGet.DSC" ;
5958
@@ -65,8 +64,6 @@ namespace AppInstaller::CLI::Workflow
6564 constexpr std::wstring_view s_Setting_WinGetSource_Arg = L" argument" ;
6665 constexpr std::wstring_view s_Setting_WinGetSource_Type = L" type" ;
6766
68- constexpr std::wstring_view s_Setting_PowerShellGet_ModuleName = L" name" ;
69-
7067 struct PredefinedResourceInfo
7168 {
7269 std::wstring_view UnitType;
@@ -1246,14 +1243,55 @@ namespace AppInstaller::CLI::Workflow
12461243 return unit;
12471244 }
12481245
1249- ConfigurationUnit CreatePowerShellModuleGetUnit (const std::wstring& moduleName)
1246+ ConfigurationUnit CreatePowerShellPackageUnit ()
1247+ {
1248+ ConfigurationUnit unit = CreateConfigurationUnitFromUnitType (s_UnitType_WinGetPackage_DSCv3, " Microsoft.PowerShell" );
1249+
1250+ ValueSet settings;
1251+ settings.Insert (s_Setting_WinGetPackage_Id, PropertyValue::CreateString (L" Microsoft.PowerShell" ));
1252+ settings.Insert (s_Setting_WinGetPackage_Source, PropertyValue::CreateString (L" winget" ));
1253+ unit.Settings (settings);
1254+
1255+ return unit;
1256+ }
1257+
1258+ ValueSet CreateValueSetFromStringArray (const std::vector<std::wstring>& values)
1259+ {
1260+ ValueSet result;
1261+ size_t index = 0 ;
1262+
1263+ for (const auto & value : values)
1264+ {
1265+ std::wostringstream strstr;
1266+ strstr << index++;
1267+ result.Insert (strstr.str (), PropertyValue::CreateString (value));
1268+ }
1269+
1270+ result.Insert (L" treatAsArray" , PropertyValue::CreateBoolean (true ));
1271+ return result;
1272+ }
1273+
1274+ // TODO: This is a work around unit to ensure v2 dsc resource modules. Move to dsc v3 resource when available.
1275+ ConfigurationUnit CreateRequiredModuleUnit (std::wstring_view moduleName, const ConfigurationUnit& dependentUnit)
12501276 {
1251- ConfigurationUnit unit = CreateConfigurationUnitFromUnitType (s_UnitType_PowerShellModuleGet, Utility::ConvertToUTF8 (moduleName));
1277+ std::wstring moduleNameString{ moduleName };
1278+
1279+ ConfigurationUnit unit = CreateConfigurationUnitFromUnitType (L" Microsoft.DSC.Transitional/RunCommandOnSet" , Utility::ConvertToUTF8 (moduleName));
12521280
12531281 ValueSet settings;
1254- settings.Insert (s_Setting_PowerShellGet_ModuleName, PropertyValue::CreateString (moduleName));
1282+ settings.Insert (L" executable" , PropertyValue::CreateString (L" pwsh" ));
1283+ std::vector<std::wstring> arguments =
1284+ {
1285+ L" -NoProfile" ,
1286+ L" -NoLogo" ,
1287+ L" -Command" ,
1288+ L" if (-not (Get-Module -ListAvailable -Name " + moduleNameString + L" )) { Install-Module -Name " + moduleNameString + L" -Confirm:$False -Force -AllowPrerelease -AllowClobber }"
1289+ };
1290+ settings.Insert (L" arguments" , CreateValueSetFromStringArray (arguments));
12551291 unit.Settings (settings);
12561292
1293+ unit.Dependencies ().Append (dependentUnit.Identifier ());
1294+
12571295 return unit;
12581296 }
12591297
@@ -1536,15 +1574,37 @@ namespace AppInstaller::CLI::Workflow
15361574 {
15371575 ConfigurationContext& configContext = context.Get <Data::ConfigurationContext>();
15381576
1577+ // PowerShell package needs to be present for later certain predefined modules to work.
1578+ std::optional<ConfigurationUnit> powerShellPackageUnit = CreatePowerShellPackageUnit ();
1579+
1580+ // Apply the unit to make sure it's on the system.
1581+ context.Reporter .Info () << Resource::String::ConfigurationExportInstallRequiredModule (Utility::LocIndView{ " Microsoft PowerShell" }) << std::endl;
1582+ auto applyPowerShellResult = ApplyUnit (context, powerShellPackageUnit.value ());
1583+ if (SUCCEEDED (applyPowerShellResult.ResultInformation ().ResultCode ()))
1584+ {
1585+ configContext.Set ().Units ().Append (powerShellPackageUnit.value ());
1586+ }
1587+ else
1588+ {
1589+ AICLI_LOG (Config, Warning, << " Failed to ensure module. [Microsoft PowerShell] Related settings will not be exported." );
1590+ LogFailedGetConfigurationUnitDetails (powerShellPackageUnit.value (), applyPowerShellResult.ResultInformation ());
1591+ context.Reporter .Warn () << Resource::String::ConfigurationExportInstallRequiredModuleFailed << std::endl;
1592+ powerShellPackageUnit = std::nullopt ;
1593+ }
1594+
15391595 for (const auto & resources : PredefinedResourcesForExport ())
15401596 {
15411597 std::optional<ConfigurationUnit> requiredModuleUnit;
15421598
1543- /* The PowershellGet/PSModule does not work under dsc v3 adaptor yet.
1544- * Uncomment if still applicable after the issue is fixed.
15451599 if (!resources.RequiredModule .empty ())
15461600 {
1547- requiredModuleUnit = CreatePowerShellModuleGetUnit(resources.RequiredModule);
1601+ if (!powerShellPackageUnit)
1602+ {
1603+ // PowerShell package not present, skip.
1604+ continue ;
1605+ }
1606+
1607+ requiredModuleUnit = CreateRequiredModuleUnit (resources.RequiredModule , powerShellPackageUnit.value ());
15481608
15491609 // Apply the unit to make sure it's on the system.
15501610 context.Reporter .Info () << Resource::String::ConfigurationExportInstallRequiredModule (Utility::LocIndView{ Utility::ConvertToUTF8 (resources.RequiredModule ) }) << std::endl;
@@ -1561,7 +1621,6 @@ namespace AppInstaller::CLI::Workflow
15611621 continue ;
15621622 }
15631623 }
1564- */
15651624
15661625 for (const auto & resourceInfo : resources.ResourceInfos )
15671626 {
0 commit comments