Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add experimental feature support for enabling Windows Feature dependencies #3005

Merged
merged 31 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ contractversion
count'th
countof
countryregion
cplusplus
createmanifestmetadata
ctc
DACL
Expand All @@ -81,6 +82,7 @@ deigh
deleteifnotneeded
desktopappinstaller
diskfull
dismapi
dllimport
DMPAs
dnld
Expand Down Expand Up @@ -220,6 +222,7 @@ mysilentwithprogress
nameof
nativehandle
NESTEDINSTALLER
netfx
netlify
Newtonsoft
NOEXPAND
Expand Down Expand Up @@ -386,6 +389,7 @@ websites
WERSJA
wesome
Whatif
winapifamily
windir
windowsdeveloper
winerror
Expand Down
11 changes: 11 additions & 0 deletions doc/Settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,14 @@ You can enable the feature as shown below.
"pinning": true
},
```

### windowsFeature

This feature enables the ability to enable Windows Feature dependencies during installation.
You can enable the feature as shown below.

```json
"experimentalFeatures": {
"windowsFeature": true
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
},
```
4 changes: 4 additions & 0 deletions src/AppInstallerCLICore/Argument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ namespace AppInstaller::CLI
return { type, "ignore-security-hash"_liv, ArgTypeCategory::InstallerBehavior | ArgTypeCategory::CopyFlagToSubContext };
case Execution::Args::Type::IgnoreLocalArchiveMalwareScan:
return { type, "ignore-local-archive-malware-scan"_liv, ArgTypeCategory::InstallerBehavior | ArgTypeCategory::CopyFlagToSubContext };
case Execution::Args::Type::IgnoreMissingDependencies:
return { type, "ignore-missing-dependencies"_liv, ArgTypeCategory::InstallerBehavior | ArgTypeCategory::CopyFlagToSubContext };
case Execution::Args::Type::AcceptPackageAgreements:
return { type, "accept-package-agreements"_liv, ArgTypeCategory::InstallerBehavior };
case Execution::Args::Type::Rename:
Expand Down Expand Up @@ -277,6 +279,8 @@ namespace AppInstaller::CLI
return Argument{ type, Resource::String::HelpArgumentDescription, ArgumentType::Flag };
case Args::Type::IgnoreLocalArchiveMalwareScan:
return Argument{ type, Resource::String::IgnoreLocalArchiveMalwareScanArgumentDescription, ArgumentType::Flag, Settings::TogglePolicy::Policy::LocalArchiveMalwareScanOverride, Settings::AdminSetting::LocalArchiveMalwareScanOverride };
case Args::Type::IgnoreMissingDependencies:
return Argument{ type, Resource::String::IgnoreMissingDependenciesArgumentDescription, ArgumentType::Flag, false };
case Args::Type::SourceName:
return Argument{ type, Resource::String::SourceNameArgumentDescription, ArgumentType::Positional, false };
case Args::Type::SourceArg:
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/Commands/InstallCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace AppInstaller::CLI
Argument::ForType(Args::Type::InstallLocation),
Argument::ForType(Args::Type::HashOverride),
Argument::ForType(Args::Type::IgnoreLocalArchiveMalwareScan),
Argument::ForType(Args::Type::IgnoreMissingDependencies),
Argument::ForType(Args::Type::DependencySource),
Argument::ForType(Args::Type::AcceptPackageAgreements),
Argument::ForType(Args::Type::NoUpgrade),
Expand Down
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/ExecutionArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace AppInstaller::CLI::Execution
AcceptPackageAgreements, // Accept all license agreements for packages
Rename, // Renames the file of the executable. Only applies to the portable installerType
NoUpgrade, // Install flow should not try to convert to upgrade flow upon finding existing installed version
IgnoreMissingDependencies, // Ignores missing Windows Feature dependencies.
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved

// Uninstall behavior
Purge, // Removes all files and directories related to a package during an uninstall. Only applies to the portable installerType.
Expand Down
7 changes: 7 additions & 0 deletions src/AppInstallerCLICore/Resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(Done);
WINGET_DEFINE_RESOURCE_STRINGID(Downloading);
WINGET_DEFINE_RESOURCE_STRINGID(EnableAdminSettingFailed);
WINGET_DEFINE_RESOURCE_STRINGID(EnablingWindowsFeatures);
WINGET_DEFINE_RESOURCE_STRINGID(ExactArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(ExperimentalArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(ExperimentalCommandLongDescription);
Expand All @@ -82,6 +83,8 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(ExtractArchiveSucceeded);
WINGET_DEFINE_RESOURCE_STRINGID(ExtractingArchive);
WINGET_DEFINE_RESOURCE_STRINGID(ExtraPositionalError);
WINGET_DEFINE_RESOURCE_STRINGID(FailedToEnableWindowsFeatureOverridden);
WINGET_DEFINE_RESOURCE_STRINGID(FailedToEnableWindowsFeatureOverrideRequired);
WINGET_DEFINE_RESOURCE_STRINGID(FeatureDisabledByAdminSettingMessage);
WINGET_DEFINE_RESOURCE_STRINGID(FeatureDisabledMessage);
WINGET_DEFINE_RESOURCE_STRINGID(FeaturesCommandLongDescription);
Expand Down Expand Up @@ -112,6 +115,7 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(HelpLinkPreamble);
WINGET_DEFINE_RESOURCE_STRINGID(IdArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(IgnoreLocalArchiveMalwareScanArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(IgnoreMissingDependenciesArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(ImportCommandLongDescription);
WINGET_DEFINE_RESOURCE_STRINGID(ImportCommandReportDependencies);
WINGET_DEFINE_RESOURCE_STRINGID(ImportCommandShortDescription);
Expand Down Expand Up @@ -291,6 +295,7 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(PurgeInstallDirectory);
WINGET_DEFINE_RESOURCE_STRINGID(QueryArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(RainbowArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(RebootRequiredForEnablingWindowsFeature);
WINGET_DEFINE_RESOURCE_STRINGID(RelatedLink);
WINGET_DEFINE_RESOURCE_STRINGID(RenameArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(ReparsePointsNotSupportedError);
Expand Down Expand Up @@ -460,6 +465,8 @@ namespace AppInstaller::CLI::Resource
WINGET_DEFINE_RESOURCE_STRINGID(VersionArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(VersionsArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(WaitArgumentDescription);
WINGET_DEFINE_RESOURCE_STRINGID(WindowsFeatureNotFoundOverride);
WINGET_DEFINE_RESOURCE_STRINGID(WindowsFeatureNotFoundOverrideRequired);
WINGET_DEFINE_RESOURCE_STRINGID(WindowsFeaturesDependencies);
WINGET_DEFINE_RESOURCE_STRINGID(WindowsLibrariesDependencies);
WINGET_DEFINE_RESOURCE_STRINGID(WindowsStoreTerms);
Expand Down
105 changes: 105 additions & 0 deletions src/AppInstallerCLICore/Workflows/DependenciesFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#include "ManifestComparator.h"
#include "InstallFlow.h"
#include "winget\DependenciesGraph.h"
#include "winget\WindowsFeature.h"
#include "DependencyNodeProcessor.h"

using namespace AppInstaller::Repository;
using namespace AppInstaller::Manifest;
using namespace AppInstaller::WindowsFeature;

namespace AppInstaller::CLI::Workflow
{
Expand Down Expand Up @@ -133,6 +135,109 @@ namespace AppInstaller::CLI::Workflow
}
}

void EnableWindowsFeaturesDependencies(Execution::Context& context)
{
if (!Settings::ExperimentalFeature::IsEnabled(Settings::ExperimentalFeature::Feature::WindowsFeature))
{
return;
}

const auto& rootDependencies = context.Get<Execution::Data::Installer>()->Dependencies;

if (rootDependencies.Empty())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this already handled by HasAnyOf ? If not, should it be?

{
return;
}

if (rootDependencies.HasAnyOf(DependencyType::WindowsFeature))
{
context << Workflow::EnsureRunningAsAdmin;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Installer dependencies are known before this workflow is ever executed; Specific dependency types are also checked for in the ReportDependencies workflow.

I'm wondering, now that multiple dependency types will be supported, if it makes more sense to set an execution flag for "Contains Package Dependencies" or "Contains Windows Features Dependencies" in the ReportDependencies flow.

With the flags, then would be possible to have a separate workflow around CheckSupportForWindowsFeatures that checks the flag ensures the experimental feature is enabled and user is running as admin, to avoid creating copies of the dependencies data in memory unnecessarily

if (context.IsTerminated())
{
return;
}

std::vector<std::string> invalidFeatures;

rootDependencies.ApplyToType(DependencyType::WindowsFeature, [&invalidFeatures](Dependency dependency)
{
const auto& name = dependency.Id();
WindowsFeature::WindowsFeature windowsFeature{ name };
if (!windowsFeature.DoesExist())
{
invalidFeatures.emplace_back(name);

This comment was marked as resolved.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no longer create vector to aggregate missing dependencies, they will be reported at the end after each windows feature is processed

}
});

if (!invalidFeatures.empty())
{
bool shouldTerminate = true;
auto warn = context.Reporter.Warn();
if (context.Args.Contains(Execution::Args::Type::IgnoreMissingDependencies))
{
warn << Resource::String::WindowsFeatureNotFoundOverride << std::endl;
shouldTerminate = false;
}
else
{
warn << Resource::String::WindowsFeatureNotFoundOverrideRequired << std::endl;
}

warn << " - " << Resource::String::WindowsFeaturesDependencies << std::endl;

for (const auto& feature : invalidFeatures)
{
warn << " " << feature << std::endl;
}

if (shouldTerminate)
{
AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_INSTALL_MISSING_DEPENDENCY);
}
}

HRESULT hr = S_OK;
bool continueOnFailure = context.Args.Contains(Execution::Args::Type::Force);
bool rebootRequired = false;

context.Reporter.Info() << Resource::String::EnablingWindowsFeatures << std::endl;

This comment was marked as resolved.

rootDependencies.ApplyToType(DependencyType::WindowsFeature, [&hr, &continueOnFailure, &rebootRequired](Dependency dependency)
{
if (SUCCEEDED(hr) || continueOnFailure)
{
auto featureName = dependency.Id();
WindowsFeature::WindowsFeature windowsFeature{ featureName };
if (windowsFeature.DoesExist() && !windowsFeature.IsEnabled())
{
hr = windowsFeature.EnableFeature();
AICLI_LOG(Core, Info, << "Enabling Windows Feature " << featureName << " returned with HRESULT: " << hr);
if (hr == ERROR_SUCCESS_REBOOT_REQUIRED)
{
rebootRequired = true;
}
}
}
});

if (FAILED(hr))
{
if (continueOnFailure)
{
context.Reporter.Warn() << Resource::String::FailedToEnableWindowsFeatureOverridden << std::endl;

This comment was marked as resolved.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to report each feature that failed to enable

}
else
{
context.Reporter.Error() << Resource::String::FailedToEnableWindowsFeatureOverrideRequired << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@denelon - I may be asking the wrong (scope creep) questions here, so forgive me, but would we want any sort of telemetry around these?

  1. Which features are requested to be enabled
  2. The success / fail rates of enabling features

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be showing each feature as its own item and not aggregating them as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed so that each windows feature is represented as its own item.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good; I'm presuming any telemetry needs can be added once support is no longer experimental

AICLI_TERMINATE_CONTEXT(hr);
}
}
else if (rebootRequired)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this neglects the case where one feature fails to enable, and another has a reboot required. I don't know if we care about that case or not, or if that's even a possibility with the way hr gets handled.

If --force isn't present, I don't think it matters, since both the reboot and the fail would cause the context to terminate, and the termination reason doesn't make much of a difference. If --force is present, the user would only be informed they are bypassing the failed install, and they wouldn't be informed they are also bypassing the reboot requirement.

{
context.Reporter.Warn() << Resource::String::RebootRequiredForEnablingWindowsFeature << std::endl;
}
}
}

void ManagePackageDependencies::operator()(Execution::Context& context) const
{
if (!Settings::ExperimentalFeature::IsEnabled(Settings::ExperimentalFeature::Feature::Dependencies))
Expand Down
2 changes: 2 additions & 0 deletions src/AppInstallerCLICore/Workflows/DependenciesFlow.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,6 @@ namespace AppInstaller::CLI::Workflow
// Inputs: PackageVersion, Manifest
// Outputs: DependencySource
void OpenDependencySource(Execution::Context& context);

void EnableWindowsFeaturesDependencies(Execution::Context& context);
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
}
1 change: 1 addition & 0 deletions src/AppInstallerCLICore/Workflows/InstallFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ namespace AppInstaller::CLI::Workflow
Workflow::GetDependenciesFromInstaller <<
Workflow::ReportDependencies(Resource::String::InstallAndUpgradeCommandsReportDependencies) <<
Workflow::ManagePackageDependencies(Resource::String::InstallAndUpgradeCommandsReportDependencies) <<
Workflow::EnableWindowsFeaturesDependencies <<
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole thing doesn't seem like the right way to handle dependencies. At least, "download" is not consistent with "and also, handle getting all dependencies squared away". So at least maybe change the name of this task?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this out of "download" to the step right before InstallPackageInstaller.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In reality, this is a larger issue than your feature work, and I think it really needs to be addressed before we can enable dependencies on the whole. Neither of us considered that in retrospect.

You should move the workflow task back here (for now); and probably put it before package dependencies. I say that because one of the packages may actually be dependent on the Windows feature (although it really should have declared it). But maybe it is an optional dependency that affects the install time behavior. It is not likely the case that the Windows feature is dependent on any package though.

The issue is that multiple "downloads" are currently allowed via COM, but if dependencies are actually installed as part of "download", then multiple installs are allowed concurrently. So either we need to change the download/install phase split to download everything, then install everything, or we need to support going back and forth between download and install phases as we handle each dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation, I didn't know that COM allowed for multiple downloads. I moved the task back to the suggested location and added a TODO comment explaining the issue that needs to be addressed.

Workflow::DownloadInstaller;
}

Expand Down
32 changes: 32 additions & 0 deletions src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw
Original file line number Diff line number Diff line change
Expand Up @@ -1677,4 +1677,36 @@ Please specify one of them using the --source option to proceed.</value>
<value>{0} package(s) have pins that prevent upgrade. Use the 'winget pin' command to view and edit pins. Using the --include-pinned argument may show more results.</value>
<comment>{Locked="winget pin","--include-pinned"} {0} is a placeholder replaced by an integer number of packages</comment>
</data>
<data name="WindowsFeatureNotFoundOverride" xml:space="preserve">
<value>The following Windows Feature(s) were not found; proceeding due to --ignore-missing-dependencies.</value>
<comment>"Windows Feature(s)" is the name of the options Windows features setting.
{Locked="--force"}
{Locked="--ignore-missing-dependencies"}</comment>
</data>
<data name="WindowsFeatureNotFoundOverrideRequired" xml:space="preserve">
<value>The following Windows Feature(s) were not found. To proceed with installation, use --ignore-missing-dependencies.</value>
<comment>"Windows Feature(s)" is the name of the options Windows features setting.
{Locked="--force"}
{Locked="--ignore-missing-dependencies"}</comment>
</data>
<data name="IgnoreMissingDependenciesArgumentDescription" xml:space="preserve">
<value>Ignores missing Windows Feature dependencies</value>
<comment>"Windows Feature" is the name of the options Windows features setting.</comment>
</data>
<data name="EnablingWindowsFeatures" xml:space="preserve">
<value>Enabling Windows Feature dependencies...</value>

This comment was marked as resolved.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a symbolic name and a friendly (localized) name. I don't know how easy it is to get the friendly name from the symbolic name. Which do you expect to see (or both)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think either would work; If it's easy to get the friendly name, that would be great, but I would expect most users could google the symbolic name to find the friendly name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to showing friendly name as well as the symbolic name such as [netfx3]

</data>
<data name="FailedToEnableWindowsFeatureOverrideRequired" xml:space="preserve">
<value>Failed to enable Windows Feature dependencies. To proceed with installation, use --force</value>
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
<comment>{Locked="--force"}</comment>
</data>
<data name="RebootRequiredForEnablingWindowsFeature" xml:space="preserve">
<value>Reboot required to fully enable the Windows Feature(s)</value>
<comment>"Windows Feature(s)" is the name of the options Windows features setting.</comment>
</data>
<data name="FailedToEnableWindowsFeatureOverridden" xml:space="preserve">
<value>Failed to enable Windows Feature dependencies; proceeding due to --force</value>
JohnMcPMS marked this conversation as resolved.
Show resolved Hide resolved
<comment>"Windows Feature(s)" is the name of the options Windows features setting.
{Locked="--force"}</comment>
</data>
</root>
7 changes: 7 additions & 0 deletions src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@
<ClCompile Include="UpdateFlow.cpp" />
<ClCompile Include="UserSettings.cpp" />
<ClCompile Include="Versions.cpp" />
<ClCompile Include="WindowsFeature.cpp" />
<ClCompile Include="WorkFlow.cpp" />
<ClCompile Include="LanguageUtilities.cpp" />
<ClCompile Include="main.cpp">
Expand Down Expand Up @@ -327,6 +328,12 @@
<CopyFileToFolders Include="TestData\InstallFlowTest_UnsupportedArguments.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\InstallFlowTest_WindowsFeatures.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\InstallFlowTest_InvalidWindowsFeatures.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\InstallFlowTest_Zip_Exe.yaml">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,9 @@
<ClCompile Include="Argument.cpp">
<Filter>Source Files\CLI</Filter>
</ClCompile>
<ClCompile Include="WindowsFeature.cpp">
<Filter>Source Files\CLI</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
Expand Down Expand Up @@ -606,6 +609,12 @@
<CopyFileToFolders Include="TestData\InstallFlowTest_UnsupportedArguments.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\InstallFlowTest_WindowsFeatures.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\InstallFlowTest_InvalidWindowsFeatures.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="TestData\InstallFlowTest_Zip_Exe.yaml">
<Filter>TestData</Filter>
</CopyFileToFolders>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
PackageIdentifier: AppInstallerCliTest.TestExeInstaller.InvalidWindowsFeatures
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Installer
ShortDescription: Installs exe installer with invalid Windows Features dependencies
Publisher: Microsoft Corporation
Moniker: AICLITestZip
License: Test
Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: exe
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
InstallerSwitches:
Custom: /custom /scope=machine
SilentWithProgress: /silentwithprogress
Silent: /silence
Update: /update
Dependencies:
WindowsFeatures:
- netfx3
- invalidFeature
- badFeature
ManifestType: singleton
ManifestVersion: 1.4.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
PackageIdentifier: AppInstallerCliTest.TestExeInstaller.WindowsFeatures
PackageVersion: 1.0.0.0
PackageLocale: en-US
PackageName: AppInstaller Test Installer
ShortDescription: Installs exe installer with invalid Windows Features dependencies
Publisher: Microsoft Corporation
Moniker: AICLITestZip
License: Test
Installers:
- Architecture: x86
InstallerUrl: https://ThisIsNotUsed
InstallerType: exe
InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B
InstallerSwitches:
Custom: /custom /scope=machine
SilentWithProgress: /silentwithprogress
Silent: /silence
Update: /update
Dependencies:
WindowsFeatures:
- netfx3
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
ManifestType: singleton
ManifestVersion: 1.4.0
Loading