winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit e4a232ada6f4a0300c9904464fe5867e1b24cccd
parent be0be282cc5b38533bfb5958ff96cabd40e00d54
Author: KEINOS <github+fork-qiita-news@keinos.com>
Date:   Tue, 27 May 2025 19:21:58 +0000

Merge remote-tracking branch 'upstream/master'

Diffstat:
Mazure-pipelines.yml | 11+++++++++++
Msrc/PowerShell/Microsoft.WinGet.Client.Cmdlets/Properties/AssemblyInfo.cs | 4++--
Msrc/PowerShell/Microsoft.WinGet.Client.Engine/Properties/AssemblyInfo.cs | 4++--
Msrc/PowerShell/Microsoft.WinGet.Configuration.Cmdlets/Cmdlets/Common/OpenConfiguration.cs | 6++++++
Msrc/PowerShell/Microsoft.WinGet.Configuration.Cmdlets/Cmdlets/GetWinGetConfigurationCmdlet.cs | 3+++
Msrc/PowerShell/Microsoft.WinGet.Configuration.Cmdlets/Properties/AssemblyInfo.cs | 2+-
Msrc/PowerShell/Microsoft.WinGet.Configuration.Engine/Commands/ConfigurationCommand.cs | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/PowerShell/Microsoft.WinGet.Configuration.Engine/Helpers/OpenConfigurationParameters.cs | 18++++++++++++++++++
Msrc/PowerShell/Microsoft.WinGet.Configuration.Engine/Microsoft.WinGet.Configuration.Engine.csproj | 4++++
Msrc/PowerShell/Microsoft.WinGet.Configuration.Engine/PSObjects/PSConfigurationProcessor.cs | 6+++---
Msrc/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.Designer.cs | 36++++++++++++++++++++++++++++++++++++
Msrc/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.resx | 20+++++++++++++++++---
Msrc/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1 | 15++++++++++++---
Msrc/PowerShell/tests/Microsoft.WinGet.Configuration.Tests.ps1 | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/PowerShell/tests/RunTests.ps1 | 4++--
15 files changed, 330 insertions(+), 28 deletions(-)

diff --git a/azure-pipelines.yml b/azure-pipelines.yml @@ -603,6 +603,17 @@ jobs: failTaskOnFailedTests: true condition: succeededOrFailed() + - task: PowerShell@2 + displayName: Copy WinGet Logs + inputs: + pwsh: true + targetType: inline + script: | + $sourceDir = Join-Path $env:LocalAppData Packages\WinGetDevCLI_8wekyb3d8bbwe\LocalState\DiagOutputDir + $destinationDir = Join-Path $(Build.ArtifactStagingDirectory) WinGetLogs + Copy-Item -Path $sourceDir -Destination $destinationDir -Recurse -Force + condition: succeededOrFailed() + - task: PublishPipelineArtifact@1 displayName: Publish PowerShell Module Artifacts inputs: diff --git a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Properties/AssemblyInfo.cs b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="AssemblyInfo.cs" company="Microsoft Corporation"> // Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> @@ -10,7 +10,7 @@ using System.Runtime.Versioning; // Forcibly set the target and supported platforms due to the internal build setup. // Keep in sync with project versions. -[assembly: TargetPlatform("Windows10.0.22000.0")] +[assembly: TargetPlatform("Windows10.0.26100.0")] [assembly: SupportedOSPlatform("Windows10.0.18362.0")] #endif diff --git a/src/PowerShell/Microsoft.WinGet.Client.Engine/Properties/AssemblyInfo.cs b/src/PowerShell/Microsoft.WinGet.Client.Engine/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="AssemblyInfo.cs" company="Microsoft Corporation"> // Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> @@ -10,7 +10,7 @@ using System.Runtime.Versioning; // Forcibly set the target and supported platforms due to the internal build setup. // Keep in sync with project versions. -[assembly: TargetPlatform("Windows10.0.22000.0")] +[assembly: TargetPlatform("Windows10.0.26100.0")] [assembly: SupportedOSPlatform("Windows10.0.18362.0")] #endif diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Cmdlets/Cmdlets/Common/OpenConfiguration.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Cmdlets/Cmdlets/Common/OpenConfiguration.cs @@ -52,6 +52,12 @@ namespace Microsoft.WinGet.Configuration.Cmdlets.Common public string ModulePath { get; set; } /// <summary> + /// Gets or sets custom DSCv3 processor path. + /// </summary> + [Parameter(ValueFromPipelineByPropertyName = true)] + public string ProcessorPath { get; set; } + + /// <summary> /// Gets the execution policy to use. /// </summary> protected ExecutionPolicy ExecutionPolicy { get; private set; } = ExecutionPolicy.Undefined; diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Cmdlets/Cmdlets/GetWinGetConfigurationCmdlet.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Cmdlets/Cmdlets/GetWinGetConfigurationCmdlet.cs @@ -31,6 +31,7 @@ namespace Microsoft.WinGet.Configuration.Cmdlets this.File, this.ModulePath, this.ExecutionPolicy, + this.ProcessorPath, this.CanUseTelemetry); } else if (this.ParameterSetName == Helpers.Constants.ParameterSet.OpenConfigurationSetFromHistory) @@ -39,6 +40,7 @@ namespace Microsoft.WinGet.Configuration.Cmdlets this.InstanceIdentifier, this.ModulePath, this.ExecutionPolicy, + this.ProcessorPath, this.CanUseTelemetry); } else if (this.ParameterSetName == Helpers.Constants.ParameterSet.OpenAllConfigurationSetsFromHistory) @@ -46,6 +48,7 @@ namespace Microsoft.WinGet.Configuration.Cmdlets configCommand.GetAllFromHistory( this.ModulePath, this.ExecutionPolicy, + this.ProcessorPath, this.CanUseTelemetry); } } diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Cmdlets/Properties/AssemblyInfo.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Cmdlets/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.Versioning; // Forcibly set the target and supported platforms due to the internal build setup. // Keep in sync with project versions. -[assembly: TargetPlatform("Windows10.0.22000.0")] +[assembly: TargetPlatform("Windows10.0.26100.0")] [assembly: SupportedOSPlatform("Windows10.0.18362.0")] #endif diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Commands/ConfigurationCommand.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Commands/ConfigurationCommand.cs @@ -11,6 +11,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands using System.IO; using System.Linq; using System.Management.Automation; + using System.Management.Automation.Runspaces; using System.Text; using System.Threading.Tasks; using Microsoft.Management.Configuration; @@ -31,6 +32,19 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands /// </summary> public sealed class ConfigurationCommand : PowerShellCmdlet { + private const string ProcessorEngineDSCv3 = "dscv3"; + private const string ProcessorEnginePowerShell = "pwsh"; + + private const string DSCv3FactoryMapKeyDscExecutablePath = "DscExecutablePath"; + private const string DSCv3FactoryMapKeyFoundDscExecutablePath = "FoundDscExecutablePath"; + + private const string WinGetClientModule = "Microsoft.WinGet.Client"; +#if USE_PROD_CLSIDS + private const string DSCv3PackageId = "9NVTPZWRC6KQ"; +#else + private const string DSCv3PackageId = "9PCX3HX4HZ0Z"; +#endif + /// <summary> /// Initializes a new instance of the <see cref="ConfigurationCommand"/> class. /// </summary> @@ -83,15 +97,17 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands /// <param name="configFile">Configuration file path.</param> /// <param name="modulePath">The module path to use.</param> /// <param name="executionPolicy">Execution policy.</param> + /// <param name="processorPath">The processor path to use.</param> /// <param name="canUseTelemetry">If telemetry can be used.</param> public void Get( string configFile, string modulePath, ExecutionPolicy executionPolicy, + string processorPath, bool canUseTelemetry) { var openParams = new OpenConfigurationParameters( - this, configFile, modulePath, executionPolicy, canUseTelemetry); + this, configFile, modulePath, executionPolicy, processorPath, canUseTelemetry); // Start task. var runningTask = this.RunOnMTA<PSConfigurationSet>( @@ -110,15 +126,17 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands /// <param name="instanceIdentifier">Instance identifier.</param> /// <param name="modulePath">The module path to use.</param> /// <param name="executionPolicy">Execution policy.</param> + /// <param name="processorPath">The processor path to use.</param> /// <param name="canUseTelemetry">If telemetry can be used.</param> public void GetFromHistory( string instanceIdentifier, string modulePath, ExecutionPolicy executionPolicy, + string processorPath, bool canUseTelemetry) { var openParams = new OpenConfigurationParameters( - this, instanceIdentifier, modulePath, executionPolicy, canUseTelemetry, fromHistory: true); + this, instanceIdentifier, modulePath, executionPolicy, processorPath, canUseTelemetry, fromHistory: true); // Start task. var runningTask = this.RunOnMTA<PSConfigurationSet?>( @@ -139,14 +157,16 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands /// </summary> /// <param name="modulePath">The module path to use.</param> /// <param name="executionPolicy">Execution policy.</param> + /// <param name="processorPath">The processor path to use.</param> /// <param name="canUseTelemetry">If telemetry can be used.</param> public void GetAllFromHistory( string modulePath, ExecutionPolicy executionPolicy, + string processorPath, bool canUseTelemetry) { var openParams = new OpenConfigurationParameters( - this, modulePath, executionPolicy, canUseTelemetry); + this, modulePath, executionPolicy, processorPath, canUseTelemetry); // Start task. var runningTask = this.RunOnMTA<PSConfigurationSet[]>( @@ -361,7 +381,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands this.Write(StreamType.Object, psConfigurationJob.ApplyConfigurationTask.Result); } - private IConfigurationSetProcessorFactory CreateFactory(OpenConfigurationParameters openParams) + private IConfigurationSetProcessorFactory CreatePowerShellProcessorFactory(OpenConfigurationParameters openParams) { var factory = new PowerShellConfigurationSetProcessorFactory(); @@ -377,18 +397,90 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands return factory; } + private async Task<IConfigurationSetProcessorFactory> CreateDSCv3ProcessorFactory(OpenConfigurationParameters openParams) + { + var factory = new DSCv3ConfigurationSetProcessorFactory(); + + var factoryMap = factory.As<IDictionary<string, string>>(); + if (!string.IsNullOrEmpty(openParams.ProcessorPath)) + { + factoryMap.Add(DSCv3FactoryMapKeyDscExecutablePath, openParams.ProcessorPath); + } + else + { + string? foundProcessorPath = null; + if (!factoryMap.TryGetValue(DSCv3FactoryMapKeyFoundDscExecutablePath, out foundProcessorPath) || + string.IsNullOrEmpty(foundProcessorPath)) + { + await this.InstallDSCv3Package(openParams); + } + } + + return factory; + } + + private async Task InstallDSCv3Package(OpenConfigurationParameters openParams) + { + this.Write(StreamType.Information, Resources.ConfigurationInstallDscPackage); + + InitialSessionState initialSessionState = InitialSessionState.CreateDefault(); + initialSessionState.ExecutionPolicy = openParams.ExecutionPolicy; + Runspace runspace = RunspaceFactory.CreateRunspace(initialSessionState); + runspace.Open(); + PowerShell installDSCv3 = PowerShell.Create(runspace).AddScript( + $@" + if (-not (Get-Module -ListAvailable -Name {WinGetClientModule})) + {{ + Install-Module -Name {WinGetClientModule} -Confirm:$False -Force + }} + + $installResult = Install-WingetPackage -Id {DSCv3PackageId} -Source msstore + if ($installResult.Status -ne 'Ok') + {{ + Write-Error ""Failed to install DSCv3 package. Status: $($installResult.Status). ExtendedErrorCode: $($installResult.ExtendedErrorCode)."" -ErrorAction Stop + }} + "); + + await installDSCv3.InvokeAsync(); + + if (installDSCv3.HadErrors) + { + this.Write(StreamType.Error, Resources.ConfigurationInstallDscPackageFailed); + throw new FileNotFoundException(Resources.DscExeNotFound, "dsc.exe"); + } + } + + private async Task<PSConfigurationProcessor> CreateConfigurationProcessorWithSet(OpenConfigurationParameters openParams, ConfigurationSet set) + { + string processorIdentifier = set.Environment.ProcessorIdentifier; + + if (string.IsNullOrEmpty(processorIdentifier) || ProcessorEnginePowerShell.Equals(processorIdentifier, StringComparison.OrdinalIgnoreCase)) + { + // Default to PowerShell + return new PSConfigurationProcessor(this.CreatePowerShellProcessorFactory(openParams), this, openParams.CanUseTelemetry); + } + else if (ProcessorEngineDSCv3.Equals(processorIdentifier, StringComparison.OrdinalIgnoreCase)) + { + return new PSConfigurationProcessor(await this.CreateDSCv3ProcessorFactory(openParams), this, openParams.CanUseTelemetry); + } + else + { + throw new NotSupportedException(string.Format(Resources.ProcessorEngineNotSupported, processorIdentifier)); + } + } + private async Task<PSConfigurationSet?> OpenConfigurationSetAsync(OpenConfigurationParameters openParams) { this.Write(StreamType.Verbose, Resources.ConfigurationInitializing); - var psProcessor = new PSConfigurationProcessor(this.CreateFactory(openParams), this, openParams.CanUseTelemetry); + var processorWithoutFactory = new PSConfigurationProcessor(null, this, openParams.CanUseTelemetry); if (!openParams.FromHistory) { this.Write(StreamType.Verbose, Resources.ConfigurationReadingConfigFile); var stream = await FileRandomAccessStream.OpenAsync(openParams.ConfigFile, FileAccessMode.Read); - OpenConfigurationSetResult openResult = await psProcessor.Processor.OpenConfigurationSetAsync(stream); + OpenConfigurationSetResult openResult = await processorWithoutFactory.Processor.OpenConfigurationSetAsync(stream); if (openResult.ResultCode != null) { throw new OpenConfigurationSetException(openResult, openParams.ConfigFile); @@ -402,7 +494,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands set.Origin = Path.GetDirectoryName(openParams.ConfigFile); set.Path = openParams.ConfigFile; - return new PSConfigurationSet(psProcessor, set); + return new PSConfigurationSet(await this.CreateConfigurationProcessorWithSet(openParams, set), set); } else { @@ -410,7 +502,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands this.Write(StreamType.Verbose, Resources.ConfigurationReadingConfigHistory); - var historySets = await psProcessor.Processor.GetConfigurationHistoryAsync(); + var historySets = await processorWithoutFactory.Processor.GetConfigurationHistoryAsync(); ConfigurationSet? result = null; foreach (var historySet in historySets) @@ -422,7 +514,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands } } - return result != null ? new PSConfigurationSet(psProcessor, result) : null; + return result != null ? new PSConfigurationSet(await this.CreateConfigurationProcessorWithSet(openParams, result), result) : null; } } @@ -430,16 +522,16 @@ namespace Microsoft.WinGet.Configuration.Engine.Commands { this.Write(StreamType.Verbose, Resources.ConfigurationInitializing); - var psProcessor = new PSConfigurationProcessor(this.CreateFactory(openParams), this, openParams.CanUseTelemetry); + var processorWithoutFactory = new PSConfigurationProcessor(null, this, openParams.CanUseTelemetry); this.Write(StreamType.Verbose, Resources.ConfigurationReadingConfigHistory); - var historySets = await psProcessor.Processor.GetConfigurationHistoryAsync(); + var historySets = await processorWithoutFactory.Processor.GetConfigurationHistoryAsync(); PSConfigurationSet[] result = new PSConfigurationSet[historySets.Count]; for (int i = 0; i < historySets.Count; ++i) { - result[i] = new PSConfigurationSet(psProcessor, historySets[i]); + result[i] = new PSConfigurationSet(await this.CreateConfigurationProcessorWithSet(openParams, historySets[i]), historySets[i]); } return result; diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Helpers/OpenConfigurationParameters.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Helpers/OpenConfigurationParameters.cs @@ -30,6 +30,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Helpers /// <param name="file">The configuration file.</param> /// <param name="modulePath">The module path to use.</param> /// <param name="executionPolicy">Execution policy.</param> + /// <param name="processorPath">The processor path to use.</param> /// <param name="canUseTelemetry">If telemetry can be used.</param> /// <param name="fromHistory">If the configuration is from history; changes the meaning of `ConfigFile` to the instance identifier.</param> public OpenConfigurationParameters( @@ -37,6 +38,7 @@ namespace Microsoft.WinGet.Configuration.Engine.Helpers string file, string modulePath, ExecutionPolicy executionPolicy, + string processorPath, bool canUseTelemetry, bool fromHistory = false) { @@ -50,7 +52,9 @@ namespace Microsoft.WinGet.Configuration.Engine.Helpers } this.InitializeModulePath(modulePath); + this.ExecutionPolicy = executionPolicy; this.Policy = this.GetConfigurationProcessorPolicy(executionPolicy); + this.ProcessorPath = processorPath; this.CanUseTelemetry = canUseTelemetry; this.FromHistory = fromHistory; } @@ -61,16 +65,20 @@ namespace Microsoft.WinGet.Configuration.Engine.Helpers /// <param name="pwshCmdlet">PowerShellCmdlet.</param> /// <param name="modulePath">The module path to use.</param> /// <param name="executionPolicy">Execution policy.</param> + /// <param name="processorPath">The processor path to use.</param> /// <param name="canUseTelemetry">If telemetry can be used.</param> public OpenConfigurationParameters( PowerShellCmdlet pwshCmdlet, string modulePath, ExecutionPolicy executionPolicy, + string processorPath, bool canUseTelemetry) { this.ConfigFile = string.Empty; this.InitializeModulePath(modulePath); + this.ExecutionPolicy = executionPolicy; this.Policy = this.GetConfigurationProcessorPolicy(executionPolicy); + this.ProcessorPath = processorPath; this.CanUseTelemetry = canUseTelemetry; } @@ -90,11 +98,21 @@ namespace Microsoft.WinGet.Configuration.Engine.Helpers public string? CustomLocation { get; private set; } /// <summary> + /// Gets the original ExecutionPolicy value. + /// </summary> + public ExecutionPolicy ExecutionPolicy { get; private set; } = ExecutionPolicy.Undefined; + + /// <summary> /// Gets execution policy of the processor. /// </summary> public PowerShellConfigurationProcessorPolicy Policy { get; } /// <summary> + /// Gets DSCv3 processor path. + /// </summary> + public string ProcessorPath { get; } + + /// <summary> /// Gets a value indicating whether to use telemetry or not. /// </summary> public bool CanUseTelemetry { get; } diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Microsoft.WinGet.Configuration.Engine.csproj b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Microsoft.WinGet.Configuration.Engine.csproj @@ -12,6 +12,10 @@ <Configurations>Debug;Release;ReleaseStatic</Configurations> </PropertyGroup> + <PropertyGroup Condition="'$(UseProdCLSIDs)' == 'true'"> + <DefineConstants>$(DefineConstants);USE_PROD_CLSIDS</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Release'"> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> </PropertyGroup> diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/PSObjects/PSConfigurationProcessor.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/PSObjects/PSConfigurationProcessor.cs @@ -1,4 +1,4 @@ -// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="PSConfigurationProcessor.cs" company="Microsoft Corporation"> // Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> @@ -27,10 +27,10 @@ namespace Microsoft.WinGet.Configuration.Engine.PSObjects /// <summary> /// Initializes a new instance of the <see cref="PSConfigurationProcessor"/> class. /// </summary> - /// <param name="factory">Factory.</param> + /// <param name="factory">Processor Factory. If null, the functions (i.e. set/unit operations) may be limited.</param> /// <param name="diagnosticCommand">AsyncCommand to use for diagnostics.</param> /// <param name="canUseTelemetry">If telemetry can be used.</param> - internal PSConfigurationProcessor(IConfigurationSetProcessorFactory factory, PowerShellCmdlet diagnosticCommand, bool canUseTelemetry) + internal PSConfigurationProcessor(IConfigurationSetProcessorFactory? factory, PowerShellCmdlet diagnosticCommand, bool canUseTelemetry) { this.Processor = new ConfigurationProcessor(factory); this.Processor.MinimumLevel = DiagnosticLevel.Verbose; diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.Designer.cs b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.Designer.cs @@ -223,6 +223,24 @@ namespace Microsoft.WinGet.Resources { } /// <summary> + /// Looks up a localized string similar to Desired State Configuration package not found on the system. Installing the package.... + /// </summary> + internal static string ConfigurationInstallDscPackage { + get { + return ResourceManager.GetString("ConfigurationInstallDscPackage", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Failed to install Desired State Configuration package. Install the package manually or provide the path to dsc.exe through -ProcessorPath argument.. + /// </summary> + internal static string ConfigurationInstallDscPackageFailed { + get { + return ResourceManager.GetString("ConfigurationInstallDscPackageFailed", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to Local. /// </summary> internal static string ConfigurationLocal { @@ -538,6 +556,15 @@ namespace Microsoft.WinGet.Resources { } /// <summary> + /// Looks up a localized string similar to Cannot find dsc.exe.. + /// </summary> + internal static string DscExeNotFound { + get { + return ResourceManager.GetString("DscExeNotFound", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to Completed. /// </summary> internal static string OperationCompleted { @@ -556,6 +583,15 @@ namespace Microsoft.WinGet.Resources { } /// <summary> + /// Looks up a localized string similar to Processor engine not supported. Processor engine: {0}. + /// </summary> + internal static string ProcessorEngineNotSupported { + get { + return ResourceManager.GetString("ProcessorEngineNotSupported", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to See line {0}, column {1} in the file.. /// </summary> internal static string SeeLineAndColumn { diff --git a/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.resx b/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Resources/Resources.resx @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <root> <!-- Microsoft ResX Schema @@ -318,4 +318,19 @@ <data name="ConfigurationReadingConfigHistory" xml:space="preserve"> <value>Reading configuration history</value> </data> -</root>- \ No newline at end of file + <data name="ConfigurationInstallDscPackage" xml:space="preserve"> + <value>Desired State Configuration package not found on the system. Installing the package...</value> + </data> + <data name="ConfigurationInstallDscPackageFailed" xml:space="preserve"> + <value>Failed to install Desired State Configuration package. Install the package manually or provide the path to dsc.exe through -ProcessorPath argument.</value> + <comment>{Locked="dsc.exe","-ProcessorPath"}</comment> + </data> + <data name="ProcessorEngineNotSupported" xml:space="preserve"> + <value>Processor engine not supported. Processor engine: {0}</value> + <comment>{Locked="{0}"}</comment> + </data> + <data name="DscExeNotFound" xml:space="preserve"> + <value>Cannot find dsc.exe.</value> + <comment>{Locked="{dsc.exe}"}</comment> + </data> +</root> diff --git a/src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1 b/src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1 @@ -24,6 +24,7 @@ BeforeAll { } $settingsFilePath = (ConvertFrom-Json (& $wingetExeName settings export)).userSettingsFile + $originalSettingsContent = Get-Content -Path $settingsFilePath -Raw $deviceGroupPolicyRoot = "HKLM:\Software\Policies\Microsoft\Windows" $wingetPolicyKeyName = "AppInstaller" @@ -36,6 +37,10 @@ BeforeAll { Set-Content -Path $settingsFilePath -Value $content } + function RestoreWinGetSettings() { + Set-Content -Path $settingsFilePath -Value $originalSettingsContent + } + # Source Add requires admin privileges, this will only execute successfully in an elevated PowerShell. function AddTestSource { try { @@ -640,6 +645,10 @@ Describe 'Get-WinGetUserSetting' { Set-Content -Path $settingsFilePath -Value "Hi, im not a json. Thank you, Test." { Get-WinGetUserSetting } | Should -Throw } + + AfterAll { + RestoreWinGetSettings + } } Describe 'Test-WinGetUserSetting' { @@ -743,10 +752,9 @@ Describe 'Test-WinGetUserSetting' { $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=4 ; experimentalCmd=$true}} Test-WinGetUserSetting -UserSettings $inputSettings -IgnoreNotSet | Should -Be $false } - AfterAll { - SetWinGetSettingsHelper @{ debugging= @{ enableSelfInitiatedMinidump=$true ; keepAllLogFiles=$true } } + RestoreWinGetSettings } } @@ -817,7 +825,7 @@ Describe 'Set-WinGetUserSetting' { } AfterAll { - SetWinGetSettingsHelper @{ debugging= @{ enableSelfInitiatedMinidump=$true ; keepAllLogFiles=$true } } + RestoreWinGetSettings } } @@ -959,5 +967,6 @@ Describe 'WindowsPackageManagerServer' -Skip:($PSEdition -eq "Desktop") { } AfterAll { + RestoreWinGetSettings RemoveTestSource } diff --git a/src/PowerShell/tests/Microsoft.WinGet.Configuration.Tests.ps1 b/src/PowerShell/tests/Microsoft.WinGet.Configuration.Tests.ps1 @@ -22,6 +22,17 @@ BeforeAll { Import-Module Microsoft.WinGet.Configuration + # TODO: Installing within the test run on the build server (only) somehow causes below error: + # [CORE] Started MSStore package execution. ProductId: 9PCX3HX4HZ0Z PackageFamilyName: Microsoft.DesiredStateConfiguration-Preview_8wekyb3d8bbwe + # [CLI ] MSStore install failed. ProductId: 9PCX3HX4HZ0Z HResult: 0x80010002 + # So install the DSCv3 package here. + Import-Module Microsoft.WinGet.Client + $installResult = Install-WingetPackage -Id 9PCX3HX4HZ0Z -Source msstore + if ($installResult.Status -ne 'Ok') + { + Write-Error "Failed to install DSCv3 package. Status: $($installResult.Status). ExtendedErrorCode: $($installResult.ExtendedErrorCode)." -ErrorAction Stop + } + function CreatePolicyKeyIfNotExists() { $registryExists = test-path -Path $wingetGroupPolicyRegistryRoot @@ -210,6 +221,16 @@ BeforeAll { CleanupPsModulePath } + + function EnsureDSCv3TestResourcePresence() + { + $localAppDataPath = [Environment]::GetFolderPath([Environment+SpecialFolder]::LocalApplicationData) + $resourcePath = Join-Path $localAppDataPath "Microsoft\WindowsApps\test-file.dsc.resource.json" + if (-not (Test-Path $resourcePath)) + { + wingetdev dscv3 test-file --manifest -o $resourcePath + } + } } Describe 'Test-GroupPolicies' { @@ -283,6 +304,17 @@ Describe 'Get configuration' { $set | Should -Not -BeNullOrEmpty } + It 'Get configuration and details DSCv3' { + EnsureDSCv3TestResourcePresence + + $testFile = GetConfigTestDataFile "ShowDetails_DSCv3.yml" + $set = Get-WinGetConfiguration -File $testFile + $set | Should -Not -BeNullOrEmpty + + $set = Get-WinGetConfigurationDetails -Set $set + $set | Should -Not -BeNullOrEmpty + } + It 'Get details piped' { EnsureModuleState $e2eTestModule $false @@ -441,6 +473,25 @@ Describe 'Invoke-WinGetConfiguration' { Test-Path $expectedModule | Should -Be $true } + It 'From DSCv3' { + EnsureDSCv3TestResourcePresence + + $testFile = GetConfigTestDataFile "ShowDetails_DSCv3.yml" + $set = Get-WinGetConfiguration -File $testFile + $set | Should -Not -BeNullOrEmpty + + $result = Invoke-WinGetConfiguration -AcceptConfigurationAgreements -Set $set + $result | Should -Not -BeNullOrEmpty + $result.ResultCode | Should -Be 0 + $result.UnitResults.Count | Should -Be 1 + $result.UnitResults[0].State | Should -Be "Completed" + $result.UnitResults[0].ResultCode | Should -Be 0 + + $expectedFile = Join-Path $(GetConfigTestDataPath) "ShowDetails_DSCv3.txt" + Test-Path $expectedFile | Should -Be $true + Get-Content $expectedFile -Raw | Should -Be "DSCv3 Contents!" + } + It 'Piped' { $testFile = GetConfigTestDataFile "Configure_TestRepo.yml" $result = Get-WinGetConfiguration -File $testFile | Invoke-WinGetConfiguration -AcceptConfigurationAgreements @@ -629,6 +680,31 @@ Describe 'Start|Complete-WinGetConfiguration' { Test-Path $expectedModule | Should -Be $true } + It 'From DSCv3' { + EnsureDSCv3TestResourcePresence + + $testFile = GetConfigTestDataFile "ShowDetails_DSCv3.yml" + $set = Get-WinGetConfiguration -File $testFile + $set | Should -Not -BeNullOrEmpty + + $job = Start-WinGetConfiguration -AcceptConfigurationAgreements -Set $set + $job | Should -Not -BeNullOrEmpty + + $result = Complete-WinGetConfiguration -ConfigurationJob $job + $result | Should -Not -BeNullOrEmpty + $result.ResultCode | Should -Be 0 + $result.UnitResults.Count | Should -Be 1 + $result.UnitResults[0].State | Should -Be "Completed" + $result.UnitResults[0].ResultCode | Should -Be 0 + + $expectedFile = Join-Path $(GetConfigTestDataPath) "ShowDetails_DSCv3.txt" + Test-Path $expectedFile | Should -Be $true + Get-Content $expectedFile -Raw | Should -Be "DSCv3 Contents!" + + # Verify can't be used after. + { Start-WinGetConfiguration -AcceptConfigurationAgreements -Set $set } | Should -Throw "Operation is not valid due to the current state of the object." + } + It 'Piped' { DeleteConfigTxtFiles $testFile = GetConfigTestDataFile "Configure_TestRepo.yml" @@ -765,6 +841,39 @@ Describe 'Test-WinGetConfiguration' { $result.UnitResults[0].ResultCode | Should -Be 0 } + It 'Negative DSCv3' { + EnsureDSCv3TestResourcePresence + + $testFile = GetConfigTestDataFile "ShowDetails_DSCv3.yml" + $set = Get-WinGetConfiguration -File $testFile + $set | Should -Not -BeNullOrEmpty + + $result = Test-WinGetConfiguration -AcceptConfigurationAgreements -Set $set + $result | Should -Not -BeNullOrEmpty + $result.TestResult | Should -Be "Negative" + $result.UnitResults.Count | Should -Be 1 + $result.UnitResults[0].TestResult | Should -Be "Negative" + $result.UnitResults[0].ResultCode | Should -Be 0 + } + + It 'Positive DSCv3' { + EnsureDSCv3TestResourcePresence + + $testFile = GetConfigTestDataFile "ShowDetails_DSCv3.yml" + $set = Get-WinGetConfiguration -File $testFile + $set | Should -Not -BeNullOrEmpty + + $expectedFile = Join-Path $(GetConfigTestDataPath) "ShowDetails_DSCv3.txt" + Set-Content -Path $expectedFile -Value "DSCv3 Contents!" -NoNewline + + $result = Test-WinGetConfiguration -AcceptConfigurationAgreements -Set $set + $result | Should -Not -BeNullOrEmpty + $result.TestResult | Should -Be "Positive" + $result.UnitResults.Count | Should -Be 1 + $result.UnitResults[0].TestResult | Should -Be "Positive" + $result.UnitResults[0].ResultCode | Should -Be 0 + } + It 'Piped' { $testFile = GetConfigTestDataFile "Configure_TestRepo.yml" $result = Get-WinGetConfiguration -File $testFile | Test-WinGetConfiguration -AcceptConfigurationAgreements diff --git a/src/PowerShell/tests/RunTests.ps1 b/src/PowerShell/tests/RunTests.ps1 @@ -44,10 +44,10 @@ if (-not [System.String]::IsNullOrEmpty($packageLayoutPath)) { $local:wingetExeName = "wingetdev.exe" } - + $local:settingsExport = ConvertFrom-Json (& $local:wingetExeName settings export) $local:settingsFilePath = $local:settingsExport.userSettingsFile - $local:settingsFileContent = ConvertTo-Json @{ debugging= @{ enableSelfInitiatedMinidump=$true ; keepAllLogFiles=$true } } + $local:settingsFileContent = ConvertTo-Json @{ debugging= @{ enableSelfInitiatedMinidump=$true ; keepAllLogFiles=$true }; experimentalFeatures= @{ dsc3=$true } } Set-Content -Path $local:settingsFilePath -Value $local:settingsFileContent }