Skip to content

Commit 317ae7f

Browse files
committed
Apply required modules
1 parent 933ff23 commit 317ae7f

2 files changed

Lines changed: 72 additions & 10 deletions

File tree

src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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
{

src/AppInstallerCLIE2ETests/ConfigureExportCommand.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ public void ExportAll()
154154
var showResult = TestCommon.RunAICLICommand(ShowCommand, $"-f {exportFile}", timeOut: 1200000);
155155
Assert.AreEqual(Constants.ErrorCode.S_OK, showResult.ExitCode);
156156

157+
Assert.True(showResult.StdOut.Contains("Microsoft.PowerShell"));
158+
157159
Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/UserSettingsFile"));
160+
Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/AdminSettings"));
158161
Assert.True(showResult.StdOut.Contains("Microsoft.Windows.Settings/WindowsSettings"));
159162

160163
Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/Source"));

0 commit comments

Comments
 (0)