diff --git a/doc/windows/package-manager/winget/returnCodes.md b/doc/windows/package-manager/winget/returnCodes.md index 6f01c97940..51c2375884 100644 --- a/doc/windows/package-manager/winget/returnCodes.md +++ b/doc/windows/package-manager/winget/returnCodes.md @@ -192,4 +192,6 @@ Installation failed. Restart your PC then try again. | | 0x8A15C106 | -1978285818 | WINGET_CONFIG_ERROR_UNIT_INVOKE_SET | The configuration unit failed while attempting to apply the desired state. | | 0x8A15C107 | -1978285817 | WINGET_CONFIG_ERROR_UNIT_MODULE_CONFLICT | The module for the configuration unit is available in multiple locations with the same version. | | 0x8A15C108 | -1978285816 | WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE | Loading the module for the configuration unit failed. | -| 0x8A15C109 | -1978285815 | WINGET_CONFIG_ERROR_UNIT_INVOKE_INVALID_RESULT | The configuration unit returned an unexpected result during execution. | \ No newline at end of file +| 0x8A15C109 | -1978285815 | WINGET_CONFIG_ERROR_UNIT_INVOKE_INVALID_RESULT | The configuration unit returned an unexpected result during execution. | +| 0x8A15C110 | -1978285814 | WINGET_CONFIG_ERROR_UNIT_SETTING_CONFIG_ROOT | A unit contains a setting that requires the config root. | +| 0x8A15C111 | -1978285813 | WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE_ADMIN | Loading the module for the configuration unit failed because it requires administrator privileges to run. | \ No newline at end of file diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index e00683ec22..1822c2a995 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -104,6 +104,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitFailedUnitProcessing); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitHasDuplicateIdentifier); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitHasMissingDependency); + WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitImportModuleAdmin); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitIsPartOfDependencyCycle); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitManuallySkipped); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitModuleConflict); @@ -118,6 +119,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitNotRunDueToDependency); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitNotRunDueToFailedAssert); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitReturnedInvalidResult); + WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitSettingConfigRoot); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationUnitSkipped); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationValidationFoundNoIssues); WINGET_DEFINE_RESOURCE_STRINGID(ConfigurationWaitingOnAnother); diff --git a/src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp b/src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp index d693e86bd2..39704041f8 100644 --- a/src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp @@ -407,8 +407,10 @@ namespace AppInstaller::CLI::Workflow case WINGET_CONFIG_ERROR_UNIT_INVOKE_TEST: return { Resource::String::ConfigurationUnitFailedDuringTest(), true }; case WINGET_CONFIG_ERROR_UNIT_INVOKE_SET: return { Resource::String::ConfigurationUnitFailedDuringSet(), true }; case WINGET_CONFIG_ERROR_UNIT_MODULE_CONFLICT: return { Resource::String::ConfigurationUnitModuleConflict(), false }; - case WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE: return { Resource::String::ConfigurationUnitModuleImportFailed(), true }; + case WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE: return { Resource::String::ConfigurationUnitModuleImportFailed(), false }; case WINGET_CONFIG_ERROR_UNIT_INVOKE_INVALID_RESULT: return { Resource::String::ConfigurationUnitReturnedInvalidResult(), false }; + case WINGET_CONFIG_ERROR_UNIT_SETTING_CONFIG_ROOT: return { Resource::String::ConfigurationUnitSettingConfigRoot(), false }; + case WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE_ADMIN: return { Resource::String::ConfigurationUnitImportModuleAdmin(), false }; } switch (resultInformation.ResultSource()) diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs index 5c5e793278..ae7ac3f6a2 100644 --- a/src/AppInstallerCLIE2ETests/Constants.cs +++ b/src/AppInstallerCLIE2ETests/Constants.cs @@ -317,6 +317,7 @@ public class ErrorCode public const int CONFIG_ERROR_UNIT_IMPORT_MODULE = unchecked((int)0x8A15C108); public const int CONFIG_ERROR_UNIT_INVOKE_INVALID_RESULT = unchecked((int)0x8A15C109); public const int CONFIG_ERROR_UNIT_SETTING_CONFIG_ROOT = unchecked((int)0x8A15C110); + public const int CONFIG_ERROR_UNIT_IMPORT_MODULE_ADMIN = unchecked((int)0x8A15C111); } #pragma warning restore SA1310 // Field names should not contain underscore diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index cef16113e7..b2b6f7a8c6 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -2587,6 +2587,15 @@ Please specify one of them using the --source option to proceed. Successfully enabled Windows Features dependencies + + Loading the module for the configuration unit failed because it requires administrator privileges to run. + + + A unit contains a setting that requires the config root. + + + Loading the module for the configuration unit failed because it requires administrator privileges to run. + Resumes execution of a previously saved command by passing in the unique identifier of the saved command. This is used to resume an executed command that may have been terminated due to a reboot. diff --git a/src/AppInstallerSharedLib/Errors.cpp b/src/AppInstallerSharedLib/Errors.cpp index 082985cab3..e3a8ac743c 100644 --- a/src/AppInstallerSharedLib/Errors.cpp +++ b/src/AppInstallerSharedLib/Errors.cpp @@ -261,7 +261,8 @@ namespace AppInstaller WINGET_HRESULT_INFO(WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE, "Loading the module for the configuration unit failed."), WINGET_HRESULT_INFO(WINGET_CONFIG_ERROR_UNIT_INVOKE_INVALID_RESULT, "The configuration unit returned an unexpected result during execution."), WINGET_HRESULT_INFO(WINGET_CONFIG_ERROR_UNIT_SETTING_CONFIG_ROOT, "A unit contains a setting that requires the config root."), - + WINGET_HRESULT_INFO(WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE_ADMIN, "Loading the module for the configuration unit failed because it requires administrator privileges to run."), + // Errors without the error bit set WINGET_HRESULT_INFO(WINGET_INSTALLED_STATUS_INSTALL_LOCATION_NOT_APPLICABLE, "The install location is not applicable."), WINGET_HRESULT_INFO(WINGET_INSTALLED_STATUS_FILE_FOUND_WITHOUT_HASH_CHECK, "The file was found but the hash was not checked."), diff --git a/src/AppInstallerSharedLib/Public/AppInstallerErrors.h b/src/AppInstallerSharedLib/Public/AppInstallerErrors.h index 6702ab5227..7b27c311b9 100644 --- a/src/AppInstallerSharedLib/Public/AppInstallerErrors.h +++ b/src/AppInstallerSharedLib/Public/AppInstallerErrors.h @@ -194,6 +194,7 @@ #define WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE ((HRESULT)0x8A15C108) #define WINGET_CONFIG_ERROR_UNIT_INVOKE_INVALID_RESULT ((HRESULT)0x8A15C109) #define WINGET_CONFIG_ERROR_UNIT_SETTING_CONFIG_ROOT ((HRESULT)0x8A15C110) +#define WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE_ADMIN ((HRESULT)0x8A15C111) namespace AppInstaller { diff --git a/src/Microsoft.Management.Configuration.Processor/Exceptions/ErrorCodes.cs b/src/Microsoft.Management.Configuration.Processor/Exceptions/ErrorCodes.cs index 89b32996c8..40ee9560cd 100644 --- a/src/Microsoft.Management.Configuration.Processor/Exceptions/ErrorCodes.cs +++ b/src/Microsoft.Management.Configuration.Processor/Exceptions/ErrorCodes.cs @@ -65,5 +65,10 @@ internal static class ErrorCodes /// The unit contains a setting that requires config root. /// internal const int WinGetConfigUnitSettingConfigRoot = unchecked((int)0x8A15C110); + + /// + /// The module where the DSC resource is implemented requires admin. + /// + internal const int WinGetConfigUnitImportModuleAdmin = unchecked((int)0x8A15C111); } } diff --git a/src/Microsoft.Management.Configuration.Processor/Exceptions/ImportModuleException.cs b/src/Microsoft.Management.Configuration.Processor/Exceptions/ImportModuleException.cs index 05c8f541a0..22e771555d 100644 --- a/src/Microsoft.Management.Configuration.Processor/Exceptions/ImportModuleException.cs +++ b/src/Microsoft.Management.Configuration.Processor/Exceptions/ImportModuleException.cs @@ -7,6 +7,7 @@ namespace Microsoft.Management.Configuration.Processor.Exceptions { using System; + using System.Management.Automation; /// /// Import-Module threw an exception. @@ -17,11 +18,11 @@ internal class ImportModuleException : Exception /// Initializes a new instance of the class. /// /// Module name. - /// Inner exception. - public ImportModuleException(string? moduleName, Exception inner) - : base($"Could not import module: {moduleName?.ToString() ?? ""}", inner) + /// Inner exception. + public ImportModuleException(string? moduleName, Exception pwshEx) + : base($"Could not import module: {moduleName?.ToString() ?? ""}", pwshEx) { - this.HResult = ErrorCodes.WinGetConfigUnitImportModule; + this.HResult = this.GetHResult(pwshEx); this.ModuleName = moduleName; } @@ -29,5 +30,22 @@ public ImportModuleException(string? moduleName, Exception inner) /// Gets the module name. /// public string? ModuleName { get; } + + private int GetHResult(Exception pwshEx) + { + if (pwshEx.InnerException is not null) + { + var scriptEx = pwshEx.InnerException as ScriptRequiresException; + if (scriptEx is not null) + { + if (scriptEx.ErrorRecord.CategoryInfo.Category == ErrorCategory.PermissionDenied) + { + return ErrorCodes.WinGetConfigUnitImportModuleAdmin; + } + } + } + + return ErrorCodes.WinGetConfigUnitImportModule; + } } } diff --git a/src/Microsoft.Management.Configuration.UnitTests/Microsoft.Management.Configuration.UnitTests.csproj b/src/Microsoft.Management.Configuration.UnitTests/Microsoft.Management.Configuration.UnitTests.csproj index 679ba79949..797abac6dc 100644 --- a/src/Microsoft.Management.Configuration.UnitTests/Microsoft.Management.Configuration.UnitTests.csproj +++ b/src/Microsoft.Management.Configuration.UnitTests/Microsoft.Management.Configuration.UnitTests.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -53,7 +53,7 @@ - + @@ -63,6 +63,12 @@ + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/Microsoft.Management.Configuration.UnitTests/TestCollateral/PowerShellModules/xAdminTestResource/xAdminTestResource.psd1 b/src/Microsoft.Management.Configuration.UnitTests/TestCollateral/PowerShellModules/xAdminTestResource/xAdminTestResource.psd1 new file mode 100644 index 0000000000..014cc57c30 --- /dev/null +++ b/src/Microsoft.Management.Configuration.UnitTests/TestCollateral/PowerShellModules/xAdminTestResource/xAdminTestResource.psd1 @@ -0,0 +1,37 @@ +# +# Module manifest for module 'xAdminTestResource' +# +# Generated by: Luffytaro +# +# Generated on: 10/11/2023 +# + +@{ + +RootModule = 'xAdminTestResource.psm1' +ModuleVersion = '0.0.0.1' +GUID = 'a0be43e8-ac22-4244-8efc-7263dfa58b8c' +CompatiblePSEditions = 'Core' +Author = 'Luffytaro' +CompanyName = 'Microsoft Corporation' +Copyright = '(c) Microsoft Corporation. All rights reserved.' +Description = 'PowerShell module with DSC resources for unit tests that requires admin' +PowerShellVersion = '7.2' +FunctionsToExport = @() +CmdletsToExport = @() +DscResourcesToExport = @( + 'AdminResource' +) +HelpInfoURI = 'https://www.contoso.com/help' + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + ProjectUri = 'https://github.com/microsoft/winget-cli' + IconUri = 'https://www.contoso.com/icons/icon.png' + } + +} + +} diff --git a/src/Microsoft.Management.Configuration.UnitTests/TestCollateral/PowerShellModules/xAdminTestResource/xAdminTestResource.psm1 b/src/Microsoft.Management.Configuration.UnitTests/TestCollateral/PowerShellModules/xAdminTestResource/xAdminTestResource.psm1 new file mode 100644 index 0000000000..7e8b9b2aca --- /dev/null +++ b/src/Microsoft.Management.Configuration.UnitTests/TestCollateral/PowerShellModules/xAdminTestResource/xAdminTestResource.psm1 @@ -0,0 +1,29 @@ +# Simple module that requires admin. +#Requires -RunAsAdministrator +enum Ensure +{ + Absent + Present +} + +[DscResource()] +class AdminResource +{ + [DscProperty(Key)] + [string] $key + + [AdminResource] Get() + { + return $this + } + + [bool] Test() + { + return $false + } + + [void] Set() + { + } +} + diff --git a/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationSetProcessorTests.cs b/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationSetProcessorTests.cs index c2f62d4192..ee3c7860b1 100644 --- a/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationSetProcessorTests.cs +++ b/src/Microsoft.Management.Configuration.UnitTests/Tests/ConfigurationSetProcessorTests.cs @@ -791,6 +791,30 @@ public void CreateUnitProcessor_TestTypes() unitProcessor.TestSettings(); } + /// + /// Tests a module that requires admin is loaded from non admin. + /// + [FactSkipIfCI] + public void CreateUnitProcessor_ModuleRequiresAdmin() + { + var processorEnv = this.fixture.PrepareTestProcessorEnvironment(); + + var setProcessor = new ConfigurationSetProcessor(processorEnv, new ConfigurationSet()); + + var unit = new ConfigurationUnit + { + Type = "AdminResource", + Intent = ConfigurationUnitIntent.Assert, + }; + unit.Metadata.Add("module", "xAdminTestResource"); + unit.Metadata.Add("version", "0.0.0.1"); + + unit.Settings.Add("key", "key"); + + var importModuleException = Assert.Throws(() => setProcessor.CreateUnitProcessor(unit)); + Assert.Equal(ErrorCodes.WinGetConfigUnitImportModuleAdmin, importModuleException.HResult); + } + private ConfigurationUnit CreateConfigurationUnit() { var unit = new ConfigurationUnit(); diff --git a/src/Microsoft.Management.Configuration/ConfigurationUnitResultInformation.cpp b/src/Microsoft.Management.Configuration/ConfigurationUnitResultInformation.cpp index 7a303aa018..97cb9040b1 100644 --- a/src/Microsoft.Management.Configuration/ConfigurationUnitResultInformation.cpp +++ b/src/Microsoft.Management.Configuration/ConfigurationUnitResultInformation.cpp @@ -16,6 +16,8 @@ namespace winrt::Microsoft::Management::Configuration::implementation case WINGET_CONFIG_ERROR_UNIT_NOT_FOUND_REPOSITORY: case WINGET_CONFIG_ERROR_UNIT_MULTIPLE_MATCHES: case WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE: + case WINGET_CONFIG_ERROR_UNIT_SETTING_CONFIG_ROOT: + case WINGET_CONFIG_ERROR_UNIT_IMPORT_MODULE_ADMIN: return ConfigurationUnitResultSource::ConfigurationSet; case WINGET_CONFIG_ERROR_UNIT_MODULE_CONFLICT: return ConfigurationUnitResultSource::SystemState; diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Exceptions/ErrorCodes.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Exceptions/ErrorCodes.cs index 14b010c6fe..9b6d9abf72 100644 --- a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Exceptions/ErrorCodes.cs +++ b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Exceptions/ErrorCodes.cs @@ -39,6 +39,8 @@ internal static class ErrorCodes internal const int WinGetConfigUnitModuleConflict = unchecked((int)0x8A15C107); internal const int WinGetConfigUnitImportModule = unchecked((int)0x8A15C108); internal const int WinGetConfigUnitInvokeInvalidResult = unchecked((int)0x8A15C109); + internal const int WinGetConfigUnitSettingConfigRoot = unchecked((int)0x8A15C110); + internal const int WinGetConfigUnitImportModuleAdmin = unchecked((int)0x8A15C111); #pragma warning restore SA1310 // Field names should not contain underscore #pragma warning restore SA1600 // ElementsMustBeDocumented } diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/PSObjects/PSUnitResult.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/PSObjects/PSUnitResult.cs index ec22ebc304..8e78eb118a 100644 --- a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/PSObjects/PSUnitResult.cs +++ b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/PSObjects/PSUnitResult.cs @@ -101,6 +101,10 @@ private string GetUnitMessage(ConfigurationUnit unit, IConfigurationUnitResultIn return Resources.ConfigurationUnitManuallySkipped; case ErrorCodes.WingetConfigErrorDependencyUnsatisfied: return Resources.ConfigurationUnitNotRunDueToDependency; + case ErrorCodes.WinGetConfigUnitSettingConfigRoot: + return Resources.WinGetConfigUnitSettingConfigRoot; + case ErrorCodes.WinGetConfigUnitImportModuleAdmin: + return Resources.WinGetConfigUnitImportModuleAdmin; } switch (resultInfo.ResultSource) diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.Designer.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.Designer.cs index 804e43e4ec..1b0d7b7892 100644 --- a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.Designer.cs +++ b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.Designer.cs @@ -554,5 +554,23 @@ internal static string SeeLineAndColumn { return ResourceManager.GetString("SeeLineAndColumn", resourceCulture); } } + + /// + /// Looks up a localized string similar to Loading the module for the configuration unit failed because it requires administrator privileges to run.. + /// + internal static string WinGetConfigUnitImportModuleAdmin { + get { + return ResourceManager.GetString("WinGetConfigUnitImportModuleAdmin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A unit contains a setting that requires the config root.. + /// + internal static string WinGetConfigUnitSettingConfigRoot { + get { + return ResourceManager.GetString("WinGetConfigUnitSettingConfigRoot", resourceCulture); + } + } } } diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.resx b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.resx index ba6966f185..56a39d0835 100644 --- a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.resx +++ b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.resx @@ -309,4 +309,10 @@ Have you reviewed the configuration and would you like to proceed verifying it against the system? + + Loading the module for the configuration unit failed because it requires administrator privileges to run. + + + A unit contains a setting that requires the config root. + \ No newline at end of file