From 1807452ac8049b52609b1d180461872bd3ea6761 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Thu, 7 Nov 2024 04:11:48 +0100 Subject: [PATCH 01/12] Only Windows.Setting.Language --- pipelines/azure-pipelines.yml | 34 +-- .../DisplayLanguage.md | 36 +++ .../Language.md | 36 +++ .../Microsoft.Windows.Setting.Language.psd1 | 135 +++++++++++ .../Microsoft.Windows.Setting.Language.psm1 | 216 ++++++++++++++++++ ...crosoft.Windows.Setting.Language.Tests.ps1 | 70 ++++++ 6 files changed, 512 insertions(+), 15 deletions(-) create mode 100644 resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md create mode 100644 resources/Help/Microsoft.Windows.Setting.Language/Language.md create mode 100644 resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 create mode 100644 resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 create mode 100644 tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 diff --git a/pipelines/azure-pipelines.yml b/pipelines/azure-pipelines.yml index e68067ed..88448380 100644 --- a/pipelines/azure-pipelines.yml +++ b/pipelines/azure-pipelines.yml @@ -1,5 +1,5 @@ # winget-dsc pipeline to publish artifacts -name: '$(Build.DefinitionName)-$(Build.DefinitionVersion)-$(Date:yyyyMMdd)-$(Rev:r)' +name: "$(Build.DefinitionName)-$(Build.DefinitionVersion)-$(Date:yyyyMMdd)-$(Rev:r)" # Commit triggers trigger: @@ -41,43 +41,47 @@ extends: - stage: WinGet_DSC_Artifacts_Publish jobs: - job: Publish_WinGet_DSC_Resources - displayName: 'Publish WinGet DSC Resources' + displayName: "Publish WinGet DSC Resources" templateContext: outputs: - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.Windows.Developer' + displayName: "Publish Pipeline Microsoft.Windows.Developer" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.Windows.Developer\ artifactName: Microsoft.Windows.Developer - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.Windows.Setting.Accessibility' + displayName: "Publish Pipeline Microsoft.Windows.Setting.Accessibility" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.Windows.Setting.Accessibility\ artifactName: Microsoft.Windows.Setting.Accessibility - output: pipelineArtifact - displayName: 'Publish Pipeline PythonPip3Dsc' + displayName: "Publish Pipeline PythonPip3Dsc" targetPath: $(Build.SourcesDirectory)\resources\PythonPip3Dsc\ artifactName: PythonPip3Dsc - output: pipelineArtifact - displayName: 'Publish Pipeline YarnDsc' + displayName: "Publish Pipeline YarnDsc" targetPath: $(Build.SourcesDirectory)\resources\YarnDsc\ artifactName: YarnDsc - output: pipelineArtifact - displayName: 'Publish Pipeline NpmDsc' + displayName: "Publish Pipeline NpmDsc" targetPath: $(Build.SourcesDirectory)\resources\NpmDsc\ artifactName: NpmDsc - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.WindowsSandbox.DSC' + displayName: "Publish Pipeline Microsoft.Windows.Setting.Language" + targetPath: $(Build.SourcesDirectory)\resources\Microsoft.Windows.Setting.Language\ + artifactName: Microsoft.Windows.Setting.Language + - output: pipelineArtifact + displayName: "Publish Pipeline Microsoft.WindowsSandbox.DSC" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.WindowsSandbox.DSC\ artifactName: Microsoft.WindowsSandbox.DSC - output: pipelineArtifact - displayName: 'Publish Pipeline GitDsc' + displayName: "Publish Pipeline GitDsc" targetPath: $(Build.SourcesDirectory)\resources\GitDsc\ artifactName: GitDsc - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.VSCode.Dsc' + displayName: "Publish Pipeline Microsoft.VSCode.Dsc" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.VSCode.Dsc\ artifactName: Microsoft.VSCode.Dsc - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.DotNet.Dsc' + displayName: "Publish Pipeline Microsoft.DotNet.Dsc" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.DotNet.Dsc\ artifactName: Microsoft.DotNet.Dsc @@ -87,10 +91,10 @@ extends: fetchTags: false - task: PowerShell@2 - displayName: 'Run Pester tests for DSC modules' + displayName: "Run Pester tests for DSC modules" inputs: pwsh: true - targetType: 'inline' + targetType: "inline" script: | $env:PSModulePath += ";$(Build.SourcesDirectory)\resources" Invoke-Pester -CI @@ -99,6 +103,6 @@ extends: - task: PublishTestResults@2 inputs: - testResultsFormat: 'NUnit' - testResultsFiles: '**/Test*.xml' + testResultsFormat: "NUnit" + testResultsFiles: "**/Test*.xml" failTaskOnFailedTests: true diff --git a/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md b/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md new file mode 100644 index 00000000..6c42959b --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md @@ -0,0 +1,36 @@ +--- +external help file: Microsoft.Windows.Setting.Language.psm1-Help.xml +Module Name: Microsoft.Windows.Setting.Language +ms.date: 11/04/2024 +online version: +schema: 2.0.0 +title: DisplayLanguage +--- + +# DisplayLanguage + +## SYNOPSIS + +The `DisplayLanguage` DSC Resource allows you to set the display language on your local Windows machine. + +## DESCRIPTION + +The `DisplayLanguage` DSC Resource allows you to set the display language on your local Windows machine. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| ------------- | ------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| `LocaleName` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-WinUserLanguageList` to see what language pack have been installed. | +| `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 + +```powershell +$params = @{ + LocaleName = 'en-US' +} +Invoke-DscResource -Name DisplayLanguage -Method Set -Property $params -ModuleName Microsoft.Windows.Setting.Language +``` diff --git a/resources/Help/Microsoft.Windows.Setting.Language/Language.md b/resources/Help/Microsoft.Windows.Setting.Language/Language.md new file mode 100644 index 00000000..79439791 --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Language/Language.md @@ -0,0 +1,36 @@ +--- +external help file: Microsoft.Windows.Setting.Language.psm1-Help.xml +Module Name: Microsoft.Windows.Setting.Language +ms.date: 11/04/2024 +online version: +schema: 2.0.0 +title: Language +--- + +# Language + +## SYNOPSIS + +The `Language` DSC Resource allows you to install, update, and uninstall languages on your local Windows machine. + +## DESCRIPTION + +The `Language` DSC Resource allows you to install, update, and uninstall languages on your local Windows machine. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| ------------- | ------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| `LocaleName` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-LocaleList` function or Export() method to get a list of allowed values. | +| `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 + +```powershell +$params = @{ + LocaleName = 'en-US' +} +Invoke-DscResource -Name Language -Method Set -Property $params -ModuleName Microsoft.Windows.Setting.Language +``` diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 new file mode 100644 index 00000000..656ffdba --- /dev/null +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 @@ -0,0 +1,135 @@ +# +# Module manifest for module 'Microsoft.Windows.Setting.Language' +# +# Generated by: Microsoft Corporation +# +# Generated on: 04/11/2024 +# + +@{ + + # Script module or binary module file associated with this manifest. + RootModule = 'Microsoft.Windows.Setting.Language.psm1' + + # Version number of this module. + ModuleVersion = '0.1.0' + + # Supported PSEditions + # CompatiblePSEditions = @() + + # ID used to uniquely identify this module + GUID = '6ab8bbf6-ce28-4d33-a3ce-04c1cc16f139' + + # Author of this module + Author = 'Microsoft Corporation' + + # Company or vendor of this module + CompanyName = 'Microsoft Corporation' + + # Copyright statement for this module + Copyright = '(c) Microsoft Corporation. All rights reserved.' + + # Description of the functionality provided by this module + Description = 'DSC Resource for Windows Setting Language' + + # Minimum version of the PowerShell engine required by this module + PowerShellVersion = '7.2' + + # Name of the PowerShell host required by this module + # PowerShellHostName = '' + + # Minimum version of the PowerShell host required by this module + # PowerShellHostVersion = '' + + # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # DotNetFrameworkVersion = '' + + # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # ClrVersion = '' + + # Processor architecture (None, X86, Amd64) required by this module + # ProcessorArchitecture = '' + + # Modules that must be imported into the global environment prior to importing this module + # RequiredModules = @() + + # Assemblies that must be loaded prior to importing this module + # RequiredAssemblies = @() + + # Script files (.ps1) that are run in the caller's environment prior to importing this module. + # ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + # TypesToProcess = @() + + # Format files (.ps1xml) to be loaded when importing this module + # FormatsToProcess = @() + + # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess + # NestedModules = @() + + # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. + # FunctionsToExport = '*' + + # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. + # CmdletsToExport = '*' + + # Variables to export from this module + # VariablesToExport = '*' + + # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. + # AliasesToExport = '*' + + # DSC resources to export from this module + DscResourcesToExport = @('Language', 'DisplayLanguage') + + # List of all modules packaged with this module + # ModuleList = @() + + # List of all files packaged with this module + # FileList = @() + + # 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 = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + Tags = @( + 'PSDscResource_Language', + 'PSDscResource_DisplayLanguage' + ) + + # A URL to the license for this module. + LicenseUri = 'https://github.com/microsoft/winget-dsc/blob/main/LICENSE' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/microsoft/winget-dsc' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + Prerelease = 'alpha' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + + } # End of PrivateData hashtable + + # HelpInfo URI of this module + # HelpInfoURI = '' + + # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. + # DefaultCommandPrefix = '' + +} + diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 new file mode 100644 index 00000000..de78552a --- /dev/null +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 @@ -0,0 +1,216 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +using namespace System.Collections.Generic + +$global:LocaleNameRegistryPath = 'HKCU:\Control Panel\International' +$global:LocaleUserProfilePath = 'HKCU:\Control Panel\International\User Profile' + +if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { + $global:LocaleNameRegistryPath = 'HKCU:\Control Panel\International' + $global:LocaleUserProfilePath = 'HKCU:\Control Panel\International\User Profile' +} else { + $global:LocaleNameRegistryPath = $global:LocaleUserProfilePath = $env:TestRegistryPath +} + +#region Functions +function Get-OsBuildVersion { + return [System.Environment]::OSVersion.Version.Build +} + +function TryGetRegistryValue { + param ( + [Parameter(Mandatory = $true)] + [string]$Key, + + [Parameter(Mandatory = $true)] + [string]$Property + ) + + if (Test-Path -Path $Key) { + try { + return (Get-ItemProperty -Path $Key | Select-Object -ExpandProperty $Property) + } catch { + Write-Verbose "Property `"$($Property)`" could not be found." + } + } else { + Write-Verbose 'Registry key does not exist.' + } +} + +function Get-LocaleList { + $localeList = Get-WinUserLanguageList + $out = [List[Language]]::new() + + foreach ($locale in $localeList) { + $langague = [Language]::new($locale.LanguageTag, $true) + $out.Add($langague) + } + + # section to include other languages that can be installed + # helpful for users to discover what packages can be installed + $allLangues = [System.Globalization.CultureInfo]::GetCultures('AllCultures') + foreach ($culture in $allLangues) { + if ($out.LocaleName -notcontains $culture.Name -and -not ([string]::IsNullOrEmpty($culture.Name))) { + $langague = [Language]::new($culture.Name, $false) + $out.Add($langague) + } + } + + return $out +} +#endregion Functions + +#region Classes +<# +.SYNOPSIS + The `Language` DSC Resource allows you to install, update, and uninstall languages on your local Windows machine. + +.PARAMETER LocaleName + The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). + To get a full list of languages available, use the `Get-LocaleList` function or Export() method. + +.PARAMETER Exist + Indicates whether the package should exist. Defaults to $true. + +.EXAMPLE + PS C:\> Invoke-DscResource -ModuleName Microsoft.Windows.Setting.Language -Name Language -Method Set -Property @{ LocaleName = 'en-US' } + + This example installs the English (United States) language on the local machine. +#> +[DscResource()] +class Language { + [DscProperty(Key)] + [string] $LocaleName + + [DscProperty()] + [bool] $Exist = $true + + static [hashtable] $InstalledLocality + + Language() { + [Language]::GetInstalledLocality() + } + + Language([string] $LocaleName, [bool] $Exist) { + $this.LocaleName = $LocaleName + $this.Exist = $Exist + } + + [Language] Get() { + $keyExist = [Language]::InstalledLocality.ContainsKey(($this.LocaleName)) + + $currentState = [Language]::InstalledLocality[$this.LocaleName] + + if (-not $keyExist) { + return [Language]::new($this.LocaleName, $false) + } + + return $currentState + } + + [void] Set() { + if ($this.Test()) { + return + } + + if ($this.Exist) { + # use the LanguagePackManagement module to install the language (requires elevation). International does not have a cmdlet to install language + Install-Language -Language $this.LocaleName + } else { + Uninstall-Language -Language $this.LocaleName + } + } + + [bool] Test() { + $currentState = $this.Get() + + if ($currentState.Exist -ne $this.Exist) { + return $false + } + + return $true + } + + static [Language[]] Export() { + return Get-LocaleList + } + + #region Language helper functions + static [void] GetInstalledLocality() { + [Language]::InstalledLocality = @{} + + foreach ($locality in [Language]::Export()) { + [Language]::InstalledLocality[$locality.LocaleName] = $locality + } + } + #endRegion Language helper functions +} + +<# +.SYNOPSIS + The `DisplayLanguage` DSC Resource allows you to set the display language on your local Windows machine. + +.PARAMETER LocaleName + The name of the display language. This is the language tag that represents the language. For example, `en-US` represents English (United States). + +.PARAMETER Exist + Indicates whether the display language should be set. Defaults to $true. + +.EXAMPLE + PS C:\> Invoke-DscResource -ModuleName Microsoft.Windows.Setting.Language -Name DisplayLanguage -Method Set -Property @{ LocaleName = 'en-US' } + + This example sets the display language to English (United States) on the user. +#> +[DscResource()] +class DisplayLanguage { + + [DscProperty(Key)] + [string] $LocaleName + + [DscProperty()] + [bool] $Exist = $true + + hidden [string] $KeyName = 'LocaleName' + + DisplayLanguage() { + } + + [DisplayLanguage] Get() { + $currentState = [DisplayLanguage]::new() + + # check if user profile contains display language + $userProfileLanguageDict = TryGetRegistryValue -Key (Join-Path $global:LocaleUserProfilePath $this.LocaleName) -Property 'CachedLanguageName' + if ((TryGetRegistryValue -Key $global:LocaleNameRegistryPath -Property $this.KeyName) -ne $this.LocaleName -and ($null -ne $userProfileLanguageDict)) { + $currentState.Exist = $false + return $currentState + } + + return @{ + LocaleName = $this.LocaleName + Exist = $true + } + } + + [void] Set() { + if ($this.Test()) { + return + } + + # TODO: How do we handle sign out and sign in? + Set-WinUserLanguageList -Language $this.LocaleName + + # TODO: Exist does not make sense here, we always want a language to exist + } + + [bool] Test() { + $currentState = $this.Get() + + if ($currentState.Exist -ne $this.Exist) { + return $false + } + + return $true + } +} +#endRegion classes diff --git a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 new file mode 100644 index 00000000..8565fbfc --- /dev/null +++ b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 @@ -0,0 +1,70 @@ +using module Microsoft.Windows.Setting.Language + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version Latest + +<# +.Synopsis + Pester tests related to the Microsoft.Windows.Setting.Language PowerShell module. +#> + +BeforeAll { + Import-Module Microsoft.Windows.Setting.Language -Force -ErrorAction SilentlyContinue +} + +Describe 'List available DSC resources' { + It 'Shows DSC Resources' { + $expectedDSCResources = @("Language", "DisplayLanguage") + $availableDSCResources = (Get-DscResource -Module Microsoft.Windows.Setting.Language).Name + $availableDSCResources.count | Should -Be 2 + $availableDSCResources | Where-Object { $expectedDSCResources -notcontains $_ } | Should -BeNullOrEmpty -ErrorAction Stop + } +} + +Describe 'Language' { + It 'Install a preferred language' -Skip:(!$IsWindows) { + $desiredState = @{ + LocaleName = 'en-GB' + } + + Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState + $finalState.Exist | Should -BeTrue + } + + It 'Uninstall a preferred language' -Skip:(!$IsWindows) { + $desiredState = @{ + LocaleName = 'en-GB' + } + + Invoke-DscResource -Name Pip3Package -ModuleName PythonPip3Dsc -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Pip3Package -ModuleName PythonPip3Dsc -Method Get -Property $desiredState + $finalState.Exist | Should -BeFalse + } + + It 'Export all languages' -Skip:(!$IsWindows) { + + $class = [Language]::new() + + $currentLanguages = $class::Export() + $currentLanguages | Should -Not -BeNullOrEmpty + $currentLanguages.Count | Should -BeGreaterThan 0 + } + + # TODO: Add test if LocaleName is not found +} + +Describe 'DisplayLanguage' { + It 'Set a preferred language' -Skip:(!$IsWindows) { + $desiredState = @{ + LocaleName = 'en-US' + } + + Invoke-DscResource -Name DisplayLanguage -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState + $finalState.Exist | Should -BeTrue + } +} \ No newline at end of file From 43d1ca41f65f99e9d971e3e1117690c2303f759a Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Thu, 7 Nov 2024 04:15:05 +0100 Subject: [PATCH 02/12] Fix spelling --- .../Microsoft.Windows.Setting.Language.psm1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 index de78552a..1b6f14df 100644 --- a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 @@ -43,8 +43,8 @@ function Get-LocaleList { $out = [List[Language]]::new() foreach ($locale in $localeList) { - $langague = [Language]::new($locale.LanguageTag, $true) - $out.Add($langague) + $language = [Language]::new($locale.LanguageTag, $true) + $out.Add($language) } # section to include other languages that can be installed @@ -52,8 +52,8 @@ function Get-LocaleList { $allLangues = [System.Globalization.CultureInfo]::GetCultures('AllCultures') foreach ($culture in $allLangues) { if ($out.LocaleName -notcontains $culture.Name -and -not ([string]::IsNullOrEmpty($culture.Name))) { - $langague = [Language]::new($culture.Name, $false) - $out.Add($langague) + $language = [Language]::new($culture.Name, $false) + $out.Add($language) } } From b3506dd982ccb2e3054a0abd5b80390866184f9e Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Thu, 7 Nov 2024 04:16:47 +0100 Subject: [PATCH 03/12] Remove variables --- .../Microsoft.Windows.Setting.Language.psm1 | 3 --- 1 file changed, 3 deletions(-) diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 index 1b6f14df..04afd6f2 100644 --- a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 @@ -3,9 +3,6 @@ using namespace System.Collections.Generic -$global:LocaleNameRegistryPath = 'HKCU:\Control Panel\International' -$global:LocaleUserProfilePath = 'HKCU:\Control Panel\International\User Profile' - if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { $global:LocaleNameRegistryPath = 'HKCU:\Control Panel\International' $global:LocaleUserProfilePath = 'HKCU:\Control Panel\International\User Profile' From 37762b25bd157743d3c1915f8a7358bfe9cbc30b Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Thu, 7 Nov 2024 04:11:48 +0100 Subject: [PATCH 04/12] Only Windows.Setting.Language --- pipelines/azure-pipelines.yml | 34 +-- .../DisplayLanguage.md | 36 +++ .../Language.md | 36 +++ .../Microsoft.Windows.Setting.Language.psd1 | 135 +++++++++++ .../Microsoft.Windows.Setting.Language.psm1 | 216 ++++++++++++++++++ ...crosoft.Windows.Setting.Language.Tests.ps1 | 70 ++++++ 6 files changed, 512 insertions(+), 15 deletions(-) create mode 100644 resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md create mode 100644 resources/Help/Microsoft.Windows.Setting.Language/Language.md create mode 100644 resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 create mode 100644 resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 create mode 100644 tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 diff --git a/pipelines/azure-pipelines.yml b/pipelines/azure-pipelines.yml index e68067ed..88448380 100644 --- a/pipelines/azure-pipelines.yml +++ b/pipelines/azure-pipelines.yml @@ -1,5 +1,5 @@ # winget-dsc pipeline to publish artifacts -name: '$(Build.DefinitionName)-$(Build.DefinitionVersion)-$(Date:yyyyMMdd)-$(Rev:r)' +name: "$(Build.DefinitionName)-$(Build.DefinitionVersion)-$(Date:yyyyMMdd)-$(Rev:r)" # Commit triggers trigger: @@ -41,43 +41,47 @@ extends: - stage: WinGet_DSC_Artifacts_Publish jobs: - job: Publish_WinGet_DSC_Resources - displayName: 'Publish WinGet DSC Resources' + displayName: "Publish WinGet DSC Resources" templateContext: outputs: - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.Windows.Developer' + displayName: "Publish Pipeline Microsoft.Windows.Developer" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.Windows.Developer\ artifactName: Microsoft.Windows.Developer - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.Windows.Setting.Accessibility' + displayName: "Publish Pipeline Microsoft.Windows.Setting.Accessibility" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.Windows.Setting.Accessibility\ artifactName: Microsoft.Windows.Setting.Accessibility - output: pipelineArtifact - displayName: 'Publish Pipeline PythonPip3Dsc' + displayName: "Publish Pipeline PythonPip3Dsc" targetPath: $(Build.SourcesDirectory)\resources\PythonPip3Dsc\ artifactName: PythonPip3Dsc - output: pipelineArtifact - displayName: 'Publish Pipeline YarnDsc' + displayName: "Publish Pipeline YarnDsc" targetPath: $(Build.SourcesDirectory)\resources\YarnDsc\ artifactName: YarnDsc - output: pipelineArtifact - displayName: 'Publish Pipeline NpmDsc' + displayName: "Publish Pipeline NpmDsc" targetPath: $(Build.SourcesDirectory)\resources\NpmDsc\ artifactName: NpmDsc - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.WindowsSandbox.DSC' + displayName: "Publish Pipeline Microsoft.Windows.Setting.Language" + targetPath: $(Build.SourcesDirectory)\resources\Microsoft.Windows.Setting.Language\ + artifactName: Microsoft.Windows.Setting.Language + - output: pipelineArtifact + displayName: "Publish Pipeline Microsoft.WindowsSandbox.DSC" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.WindowsSandbox.DSC\ artifactName: Microsoft.WindowsSandbox.DSC - output: pipelineArtifact - displayName: 'Publish Pipeline GitDsc' + displayName: "Publish Pipeline GitDsc" targetPath: $(Build.SourcesDirectory)\resources\GitDsc\ artifactName: GitDsc - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.VSCode.Dsc' + displayName: "Publish Pipeline Microsoft.VSCode.Dsc" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.VSCode.Dsc\ artifactName: Microsoft.VSCode.Dsc - output: pipelineArtifact - displayName: 'Publish Pipeline Microsoft.DotNet.Dsc' + displayName: "Publish Pipeline Microsoft.DotNet.Dsc" targetPath: $(Build.SourcesDirectory)\resources\Microsoft.DotNet.Dsc\ artifactName: Microsoft.DotNet.Dsc @@ -87,10 +91,10 @@ extends: fetchTags: false - task: PowerShell@2 - displayName: 'Run Pester tests for DSC modules' + displayName: "Run Pester tests for DSC modules" inputs: pwsh: true - targetType: 'inline' + targetType: "inline" script: | $env:PSModulePath += ";$(Build.SourcesDirectory)\resources" Invoke-Pester -CI @@ -99,6 +103,6 @@ extends: - task: PublishTestResults@2 inputs: - testResultsFormat: 'NUnit' - testResultsFiles: '**/Test*.xml' + testResultsFormat: "NUnit" + testResultsFiles: "**/Test*.xml" failTaskOnFailedTests: true diff --git a/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md b/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md new file mode 100644 index 00000000..6c42959b --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md @@ -0,0 +1,36 @@ +--- +external help file: Microsoft.Windows.Setting.Language.psm1-Help.xml +Module Name: Microsoft.Windows.Setting.Language +ms.date: 11/04/2024 +online version: +schema: 2.0.0 +title: DisplayLanguage +--- + +# DisplayLanguage + +## SYNOPSIS + +The `DisplayLanguage` DSC Resource allows you to set the display language on your local Windows machine. + +## DESCRIPTION + +The `DisplayLanguage` DSC Resource allows you to set the display language on your local Windows machine. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| ------------- | ------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| `LocaleName` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-WinUserLanguageList` to see what language pack have been installed. | +| `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 + +```powershell +$params = @{ + LocaleName = 'en-US' +} +Invoke-DscResource -Name DisplayLanguage -Method Set -Property $params -ModuleName Microsoft.Windows.Setting.Language +``` diff --git a/resources/Help/Microsoft.Windows.Setting.Language/Language.md b/resources/Help/Microsoft.Windows.Setting.Language/Language.md new file mode 100644 index 00000000..79439791 --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Language/Language.md @@ -0,0 +1,36 @@ +--- +external help file: Microsoft.Windows.Setting.Language.psm1-Help.xml +Module Name: Microsoft.Windows.Setting.Language +ms.date: 11/04/2024 +online version: +schema: 2.0.0 +title: Language +--- + +# Language + +## SYNOPSIS + +The `Language` DSC Resource allows you to install, update, and uninstall languages on your local Windows machine. + +## DESCRIPTION + +The `Language` DSC Resource allows you to install, update, and uninstall languages on your local Windows machine. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| ------------- | ------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| `LocaleName` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-LocaleList` function or Export() method to get a list of allowed values. | +| `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 + +```powershell +$params = @{ + LocaleName = 'en-US' +} +Invoke-DscResource -Name Language -Method Set -Property $params -ModuleName Microsoft.Windows.Setting.Language +``` diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 new file mode 100644 index 00000000..656ffdba --- /dev/null +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 @@ -0,0 +1,135 @@ +# +# Module manifest for module 'Microsoft.Windows.Setting.Language' +# +# Generated by: Microsoft Corporation +# +# Generated on: 04/11/2024 +# + +@{ + + # Script module or binary module file associated with this manifest. + RootModule = 'Microsoft.Windows.Setting.Language.psm1' + + # Version number of this module. + ModuleVersion = '0.1.0' + + # Supported PSEditions + # CompatiblePSEditions = @() + + # ID used to uniquely identify this module + GUID = '6ab8bbf6-ce28-4d33-a3ce-04c1cc16f139' + + # Author of this module + Author = 'Microsoft Corporation' + + # Company or vendor of this module + CompanyName = 'Microsoft Corporation' + + # Copyright statement for this module + Copyright = '(c) Microsoft Corporation. All rights reserved.' + + # Description of the functionality provided by this module + Description = 'DSC Resource for Windows Setting Language' + + # Minimum version of the PowerShell engine required by this module + PowerShellVersion = '7.2' + + # Name of the PowerShell host required by this module + # PowerShellHostName = '' + + # Minimum version of the PowerShell host required by this module + # PowerShellHostVersion = '' + + # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # DotNetFrameworkVersion = '' + + # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # ClrVersion = '' + + # Processor architecture (None, X86, Amd64) required by this module + # ProcessorArchitecture = '' + + # Modules that must be imported into the global environment prior to importing this module + # RequiredModules = @() + + # Assemblies that must be loaded prior to importing this module + # RequiredAssemblies = @() + + # Script files (.ps1) that are run in the caller's environment prior to importing this module. + # ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + # TypesToProcess = @() + + # Format files (.ps1xml) to be loaded when importing this module + # FormatsToProcess = @() + + # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess + # NestedModules = @() + + # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. + # FunctionsToExport = '*' + + # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. + # CmdletsToExport = '*' + + # Variables to export from this module + # VariablesToExport = '*' + + # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. + # AliasesToExport = '*' + + # DSC resources to export from this module + DscResourcesToExport = @('Language', 'DisplayLanguage') + + # List of all modules packaged with this module + # ModuleList = @() + + # List of all files packaged with this module + # FileList = @() + + # 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 = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + Tags = @( + 'PSDscResource_Language', + 'PSDscResource_DisplayLanguage' + ) + + # A URL to the license for this module. + LicenseUri = 'https://github.com/microsoft/winget-dsc/blob/main/LICENSE' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/microsoft/winget-dsc' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + Prerelease = 'alpha' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + + } # End of PrivateData hashtable + + # HelpInfo URI of this module + # HelpInfoURI = '' + + # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. + # DefaultCommandPrefix = '' + +} + diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 new file mode 100644 index 00000000..de78552a --- /dev/null +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 @@ -0,0 +1,216 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +using namespace System.Collections.Generic + +$global:LocaleNameRegistryPath = 'HKCU:\Control Panel\International' +$global:LocaleUserProfilePath = 'HKCU:\Control Panel\International\User Profile' + +if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { + $global:LocaleNameRegistryPath = 'HKCU:\Control Panel\International' + $global:LocaleUserProfilePath = 'HKCU:\Control Panel\International\User Profile' +} else { + $global:LocaleNameRegistryPath = $global:LocaleUserProfilePath = $env:TestRegistryPath +} + +#region Functions +function Get-OsBuildVersion { + return [System.Environment]::OSVersion.Version.Build +} + +function TryGetRegistryValue { + param ( + [Parameter(Mandatory = $true)] + [string]$Key, + + [Parameter(Mandatory = $true)] + [string]$Property + ) + + if (Test-Path -Path $Key) { + try { + return (Get-ItemProperty -Path $Key | Select-Object -ExpandProperty $Property) + } catch { + Write-Verbose "Property `"$($Property)`" could not be found." + } + } else { + Write-Verbose 'Registry key does not exist.' + } +} + +function Get-LocaleList { + $localeList = Get-WinUserLanguageList + $out = [List[Language]]::new() + + foreach ($locale in $localeList) { + $langague = [Language]::new($locale.LanguageTag, $true) + $out.Add($langague) + } + + # section to include other languages that can be installed + # helpful for users to discover what packages can be installed + $allLangues = [System.Globalization.CultureInfo]::GetCultures('AllCultures') + foreach ($culture in $allLangues) { + if ($out.LocaleName -notcontains $culture.Name -and -not ([string]::IsNullOrEmpty($culture.Name))) { + $langague = [Language]::new($culture.Name, $false) + $out.Add($langague) + } + } + + return $out +} +#endregion Functions + +#region Classes +<# +.SYNOPSIS + The `Language` DSC Resource allows you to install, update, and uninstall languages on your local Windows machine. + +.PARAMETER LocaleName + The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). + To get a full list of languages available, use the `Get-LocaleList` function or Export() method. + +.PARAMETER Exist + Indicates whether the package should exist. Defaults to $true. + +.EXAMPLE + PS C:\> Invoke-DscResource -ModuleName Microsoft.Windows.Setting.Language -Name Language -Method Set -Property @{ LocaleName = 'en-US' } + + This example installs the English (United States) language on the local machine. +#> +[DscResource()] +class Language { + [DscProperty(Key)] + [string] $LocaleName + + [DscProperty()] + [bool] $Exist = $true + + static [hashtable] $InstalledLocality + + Language() { + [Language]::GetInstalledLocality() + } + + Language([string] $LocaleName, [bool] $Exist) { + $this.LocaleName = $LocaleName + $this.Exist = $Exist + } + + [Language] Get() { + $keyExist = [Language]::InstalledLocality.ContainsKey(($this.LocaleName)) + + $currentState = [Language]::InstalledLocality[$this.LocaleName] + + if (-not $keyExist) { + return [Language]::new($this.LocaleName, $false) + } + + return $currentState + } + + [void] Set() { + if ($this.Test()) { + return + } + + if ($this.Exist) { + # use the LanguagePackManagement module to install the language (requires elevation). International does not have a cmdlet to install language + Install-Language -Language $this.LocaleName + } else { + Uninstall-Language -Language $this.LocaleName + } + } + + [bool] Test() { + $currentState = $this.Get() + + if ($currentState.Exist -ne $this.Exist) { + return $false + } + + return $true + } + + static [Language[]] Export() { + return Get-LocaleList + } + + #region Language helper functions + static [void] GetInstalledLocality() { + [Language]::InstalledLocality = @{} + + foreach ($locality in [Language]::Export()) { + [Language]::InstalledLocality[$locality.LocaleName] = $locality + } + } + #endRegion Language helper functions +} + +<# +.SYNOPSIS + The `DisplayLanguage` DSC Resource allows you to set the display language on your local Windows machine. + +.PARAMETER LocaleName + The name of the display language. This is the language tag that represents the language. For example, `en-US` represents English (United States). + +.PARAMETER Exist + Indicates whether the display language should be set. Defaults to $true. + +.EXAMPLE + PS C:\> Invoke-DscResource -ModuleName Microsoft.Windows.Setting.Language -Name DisplayLanguage -Method Set -Property @{ LocaleName = 'en-US' } + + This example sets the display language to English (United States) on the user. +#> +[DscResource()] +class DisplayLanguage { + + [DscProperty(Key)] + [string] $LocaleName + + [DscProperty()] + [bool] $Exist = $true + + hidden [string] $KeyName = 'LocaleName' + + DisplayLanguage() { + } + + [DisplayLanguage] Get() { + $currentState = [DisplayLanguage]::new() + + # check if user profile contains display language + $userProfileLanguageDict = TryGetRegistryValue -Key (Join-Path $global:LocaleUserProfilePath $this.LocaleName) -Property 'CachedLanguageName' + if ((TryGetRegistryValue -Key $global:LocaleNameRegistryPath -Property $this.KeyName) -ne $this.LocaleName -and ($null -ne $userProfileLanguageDict)) { + $currentState.Exist = $false + return $currentState + } + + return @{ + LocaleName = $this.LocaleName + Exist = $true + } + } + + [void] Set() { + if ($this.Test()) { + return + } + + # TODO: How do we handle sign out and sign in? + Set-WinUserLanguageList -Language $this.LocaleName + + # TODO: Exist does not make sense here, we always want a language to exist + } + + [bool] Test() { + $currentState = $this.Get() + + if ($currentState.Exist -ne $this.Exist) { + return $false + } + + return $true + } +} +#endRegion classes diff --git a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 new file mode 100644 index 00000000..8565fbfc --- /dev/null +++ b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 @@ -0,0 +1,70 @@ +using module Microsoft.Windows.Setting.Language + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version Latest + +<# +.Synopsis + Pester tests related to the Microsoft.Windows.Setting.Language PowerShell module. +#> + +BeforeAll { + Import-Module Microsoft.Windows.Setting.Language -Force -ErrorAction SilentlyContinue +} + +Describe 'List available DSC resources' { + It 'Shows DSC Resources' { + $expectedDSCResources = @("Language", "DisplayLanguage") + $availableDSCResources = (Get-DscResource -Module Microsoft.Windows.Setting.Language).Name + $availableDSCResources.count | Should -Be 2 + $availableDSCResources | Where-Object { $expectedDSCResources -notcontains $_ } | Should -BeNullOrEmpty -ErrorAction Stop + } +} + +Describe 'Language' { + It 'Install a preferred language' -Skip:(!$IsWindows) { + $desiredState = @{ + LocaleName = 'en-GB' + } + + Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState + $finalState.Exist | Should -BeTrue + } + + It 'Uninstall a preferred language' -Skip:(!$IsWindows) { + $desiredState = @{ + LocaleName = 'en-GB' + } + + Invoke-DscResource -Name Pip3Package -ModuleName PythonPip3Dsc -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Pip3Package -ModuleName PythonPip3Dsc -Method Get -Property $desiredState + $finalState.Exist | Should -BeFalse + } + + It 'Export all languages' -Skip:(!$IsWindows) { + + $class = [Language]::new() + + $currentLanguages = $class::Export() + $currentLanguages | Should -Not -BeNullOrEmpty + $currentLanguages.Count | Should -BeGreaterThan 0 + } + + # TODO: Add test if LocaleName is not found +} + +Describe 'DisplayLanguage' { + It 'Set a preferred language' -Skip:(!$IsWindows) { + $desiredState = @{ + LocaleName = 'en-US' + } + + Invoke-DscResource -Name DisplayLanguage -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState + $finalState.Exist | Should -BeTrue + } +} \ No newline at end of file From 53cf7fd503f0e610818a12379ff44a6a56338f5b Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Thu, 7 Nov 2024 04:15:05 +0100 Subject: [PATCH 05/12] Fix spelling --- .../Microsoft.Windows.Setting.Language.psm1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 index de78552a..1b6f14df 100644 --- a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 @@ -43,8 +43,8 @@ function Get-LocaleList { $out = [List[Language]]::new() foreach ($locale in $localeList) { - $langague = [Language]::new($locale.LanguageTag, $true) - $out.Add($langague) + $language = [Language]::new($locale.LanguageTag, $true) + $out.Add($language) } # section to include other languages that can be installed @@ -52,8 +52,8 @@ function Get-LocaleList { $allLangues = [System.Globalization.CultureInfo]::GetCultures('AllCultures') foreach ($culture in $allLangues) { if ($out.LocaleName -notcontains $culture.Name -and -not ([string]::IsNullOrEmpty($culture.Name))) { - $langague = [Language]::new($culture.Name, $false) - $out.Add($langague) + $language = [Language]::new($culture.Name, $false) + $out.Add($language) } } From 41a4038dff293ad57c6a692fd24655678dbdfa7b Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Thu, 7 Nov 2024 04:16:47 +0100 Subject: [PATCH 06/12] Remove variables --- .../Microsoft.Windows.Setting.Language.psm1 | 3 --- 1 file changed, 3 deletions(-) diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 index 1b6f14df..04afd6f2 100644 --- a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 @@ -3,9 +3,6 @@ using namespace System.Collections.Generic -$global:LocaleNameRegistryPath = 'HKCU:\Control Panel\International' -$global:LocaleUserProfilePath = 'HKCU:\Control Panel\International\User Profile' - if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { $global:LocaleNameRegistryPath = 'HKCU:\Control Panel\International' $global:LocaleUserProfilePath = 'HKCU:\Control Panel\International\User Profile' From e86892860a234a30dfd386d121f35ea9b34f3121 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Mon, 2 Dec 2024 01:38:01 +0100 Subject: [PATCH 07/12] Address partial fixes --- .../DisplayLanguage.md | 2 +- .../Language.md | 20 +++++++++---------- .../Microsoft.Windows.Setting.Language.psm1 | 7 ++----- ...crosoft.Windows.Setting.Language.Tests.ps1 | 8 ++++---- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md b/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md index 6c42959b..95298cfc 100644 --- a/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md +++ b/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md @@ -21,7 +21,7 @@ The `DisplayLanguage` DSC Resource allows you to set the display language on you | **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | | ------------- | ------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -| `LocaleName` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-WinUserLanguageList` to see what language pack have been installed. | +| `LocaleName` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-WinUserLanguageList` to see which language packs have been installed. | | `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | ## EXAMPLES diff --git a/resources/Help/Microsoft.Windows.Setting.Language/Language.md b/resources/Help/Microsoft.Windows.Setting.Language/Language.md index 79439791..d2e158cd 100644 --- a/resources/Help/Microsoft.Windows.Setting.Language/Language.md +++ b/resources/Help/Microsoft.Windows.Setting.Language/Language.md @@ -1,11 +1,11 @@ ---- -external help file: Microsoft.Windows.Setting.Language.psm1-Help.xml -Module Name: Microsoft.Windows.Setting.Language -ms.date: 11/04/2024 -online version: -schema: 2.0.0 -title: Language ---- +-------- ---------- ---------------------------------- ------------------------------------------------ +external help file: Microsoft.Windows.Setting.Language.psm1-Help.xml +Module Name: Microsoft.Windows.Setting.Language +ms.date: 11/04/2024 +online version: +schema: 2.0.0 +title: Language +-------- ---------- ---------------------------------- ------------------------------------------------ # Language @@ -19,10 +19,10 @@ The `Language` DSC Resource allows you to install, update, and uninstall languag ## PARAMETERS -| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | | ------------- | ------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `LocaleName` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-LocaleList` function or Export() method to get a list of allowed values. | -| `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | +| `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | ## EXAMPLES diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 index 04afd6f2..48d51698 100644 --- a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 @@ -11,9 +11,6 @@ if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { } #region Functions -function Get-OsBuildVersion { - return [System.Environment]::OSVersion.Version.Build -} function TryGetRegistryValue { param ( @@ -46,8 +43,8 @@ function Get-LocaleList { # section to include other languages that can be installed # helpful for users to discover what packages can be installed - $allLangues = [System.Globalization.CultureInfo]::GetCultures('AllCultures') - foreach ($culture in $allLangues) { + $allLanguages = [System.Globalization.CultureInfo]::GetCultures('AllCultures') + foreach ($culture in $allLanguages) { if ($out.LocaleName -notcontains $culture.Name -and -not ([string]::IsNullOrEmpty($culture.Name))) { $language = [Language]::new($culture.Name, $false) $out.Add($language) diff --git a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 index 8565fbfc..890c6b30 100644 --- a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 @@ -1,6 +1,6 @@ using module Microsoft.Windows.Setting.Language -$ErrorActionPreference = "Stop" +$ErrorActionPreference = 'Stop' Set-StrictMode -Version Latest <# @@ -14,7 +14,7 @@ BeforeAll { Describe 'List available DSC resources' { It 'Shows DSC Resources' { - $expectedDSCResources = @("Language", "DisplayLanguage") + $expectedDSCResources = @('Language', 'DisplayLanguage') $availableDSCResources = (Get-DscResource -Module Microsoft.Windows.Setting.Language).Name $availableDSCResources.count | Should -Be 2 $availableDSCResources | Where-Object { $expectedDSCResources -notcontains $_ } | Should -BeNullOrEmpty -ErrorAction Stop @@ -38,9 +38,9 @@ Describe 'Language' { LocaleName = 'en-GB' } - Invoke-DscResource -Name Pip3Package -ModuleName PythonPip3Dsc -Method Set -Property $desiredState + Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState - $finalState = Invoke-DscResource -Name Pip3Package -ModuleName PythonPip3Dsc -Method Get -Property $desiredState + $finalState = Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState $finalState.Exist | Should -BeFalse } From 1bca14b9949ec207fa780c4428ae509133367cad Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Mon, 2 Dec 2024 01:39:52 +0100 Subject: [PATCH 08/12] Fix linter --- .../Language.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/Help/Microsoft.Windows.Setting.Language/Language.md b/resources/Help/Microsoft.Windows.Setting.Language/Language.md index d2e158cd..fb2b071d 100644 --- a/resources/Help/Microsoft.Windows.Setting.Language/Language.md +++ b/resources/Help/Microsoft.Windows.Setting.Language/Language.md @@ -1,11 +1,11 @@ --------- ---------- ---------------------------------- ------------------------------------------------ -external help file: Microsoft.Windows.Setting.Language.psm1-Help.xml -Module Name: Microsoft.Windows.Setting.Language -ms.date: 11/04/2024 -online version: -schema: 2.0.0 -title: Language --------- ---------- ---------------------------------- ------------------------------------------------ +--- +external help file: Microsoft.Windows.Setting.Language.psm1-Help.xml +Module Name: Microsoft.Windows.Setting.Language +ms.date: 11/04/2024 +online version: +schema: 2.0.0 +title: Language +--- # Language From 657d5b03a00ff8aa99ebe784716fb7ee10ff2c03 Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Sun, 8 Dec 2024 19:09:57 +0100 Subject: [PATCH 09/12] Use LanguagePackManagement --- .../DisplayLanguage.md | 12 +- .../Language.md | 6 +- .../Region.md | 34 +++ .../Microsoft.Windows.Setting.Language.psd1 | 2 +- .../Microsoft.Windows.Setting.Language.psm1 | 224 ++++++++++++------ ...crosoft.Windows.Setting.Language.Tests.ps1 | 39 +-- 6 files changed, 217 insertions(+), 100 deletions(-) create mode 100644 resources/Help/Microsoft.Windows.Setting.Language/Region.md diff --git a/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md b/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md index 95298cfc..81741c43 100644 --- a/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md +++ b/resources/Help/Microsoft.Windows.Setting.Language/DisplayLanguage.md @@ -19,18 +19,18 @@ The `DisplayLanguage` DSC Resource allows you to set the display language on you ## PARAMETERS -| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | -| ------------- | ------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -| `LocaleName` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-WinUserLanguageList` to see which language packs have been installed. | -| `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| ------------- | ------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | +| `Name` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-WinUserLanguageList` to see which language packs have been installed. | +| `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | ## EXAMPLES -### EXAMPLE 1 +### EXAMPLE 1 - Set the display language to English (United States) ```powershell $params = @{ - LocaleName = 'en-US' + Name = 'en-US' } Invoke-DscResource -Name DisplayLanguage -Method Set -Property $params -ModuleName Microsoft.Windows.Setting.Language ``` diff --git a/resources/Help/Microsoft.Windows.Setting.Language/Language.md b/resources/Help/Microsoft.Windows.Setting.Language/Language.md index fb2b071d..d749200b 100644 --- a/resources/Help/Microsoft.Windows.Setting.Language/Language.md +++ b/resources/Help/Microsoft.Windows.Setting.Language/Language.md @@ -21,16 +21,16 @@ The `Language` DSC Resource allows you to install, update, and uninstall languag | **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | | ------------- | ------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | -| `LocaleName` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | Use the `Get-LocaleList` function or Export() method to get a list of allowed values. | +| `LanguageId` | Mandatory | String | The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). | To get a full list of languages available, use the `[System.Globalization.CultureInfo]::GetCultures('AllCultures')` method. | | `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | ## EXAMPLES -### EXAMPLE 1 +### EXAMPLE 1 - Install the English (United States) language ```powershell $params = @{ - LocaleName = 'en-US' + LanguageId = 'en-US' } Invoke-DscResource -Name Language -Method Set -Property $params -ModuleName Microsoft.Windows.Setting.Language ``` diff --git a/resources/Help/Microsoft.Windows.Setting.Language/Region.md b/resources/Help/Microsoft.Windows.Setting.Language/Region.md new file mode 100644 index 00000000..9d48258c --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Language/Region.md @@ -0,0 +1,34 @@ +--- +external help file: Microsoft.Windows.Setting.Language.psm1-Help.xml +Module Name: Microsoft.Windows.Setting.Language +ms.date: 11/04/2024 +online version: +schema: 2.0.0 +title: Region +--- + +# Region + +## SYNOPSIS + +The `Region` DSC Resource allows you to set the region settings on your local Windows machine. + +## DESCRIPTION + +The `Region` DSC Resource allows you to set the region settings on your local Windows machine. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| -------------- | --------------- | ------------ | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `GeoId` | Mandatory | String | The geographical ID that represents the region. This is used to set the home location. | For a full list of geographical IDs, refer to the following link: https://learn.microsoft.com/en-us/windows/win32/intl/table-of-geographical-locations | +| `HomeLocation` | NonConfigurable | String | The home location of the region. This is a read-only property. | | +| `Exist` | Optional | Boolean | Indicates whether the language should exist. The default value is `$true`. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 - Set the region to United States + +```powershell +Invoke-DscResource -ModuleName Microsoft.Windows.Setting.Language -Name Region -Method Set -Property @{ GeoId = '244' } +``` diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 index 656ffdba..778595fe 100644 --- a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psd1 @@ -81,7 +81,7 @@ # AliasesToExport = '*' # DSC resources to export from this module - DscResourcesToExport = @('Language', 'DisplayLanguage') + DscResourcesToExport = @('Language', 'DisplayLanguage', 'Region') # List of all modules packaged with this module # ModuleList = @() diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 index 48d51698..0d87dea2 100644 --- a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 @@ -3,54 +3,54 @@ using namespace System.Collections.Generic -if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { - $global:LocaleNameRegistryPath = 'HKCU:\Control Panel\International' - $global:LocaleUserProfilePath = 'HKCU:\Control Panel\International\User Profile' -} else { - $global:LocaleNameRegistryPath = $global:LocaleUserProfilePath = $env:TestRegistryPath -} +function Test-LanguagePackAvailability { + param ( + [Parameter(Mandatory = $true)] + [string]$Language + ) + + # Do not rely on Get-WindowsCapability as it requires elevation + it can take time to run + $languagePacks = Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -ExpandProperty MUILanguages + + if ($null -eq $languagePacks) { + return $false + } -#region Functions + if ($languagePacks -notcontains $Language) { + return $false + } -function TryGetRegistryValue { + return $true +} + +function Test-UserLanguageList { param ( [Parameter(Mandatory = $true)] - [string]$Key, + [string]$Language + ) - [Parameter(Mandatory = $true)] - [string]$Property - ) - - if (Test-Path -Path $Key) { - try { - return (Get-ItemProperty -Path $Key | Select-Object -ExpandProperty $Property) - } catch { - Write-Verbose "Property `"$($Property)`" could not be found." - } - } else { - Write-Verbose 'Registry key does not exist.' + $localeList = Get-WinUserLanguageList + + if ($null -eq $localeList) { + return $false + } + + if ($localeList.LanguageTag -notcontains $Language) { + return $false } + + return $false } -function Get-LocaleList { - $localeList = Get-WinUserLanguageList +function Get-LanguageList { + $languageList = Get-Language $out = [List[Language]]::new() - foreach ($locale in $localeList) { - $language = [Language]::new($locale.LanguageTag, $true) + foreach ($language in $languageList) { + $language = [Language]::new($language.LanguageId, $true) $out.Add($language) } - # section to include other languages that can be installed - # helpful for users to discover what packages can be installed - $allLanguages = [System.Globalization.CultureInfo]::GetCultures('AllCultures') - foreach ($culture in $allLanguages) { - if ($out.LocaleName -notcontains $culture.Name -and -not ([string]::IsNullOrEmpty($culture.Name))) { - $language = [Language]::new($culture.Name, $false) - $out.Add($language) - } - } - return $out } #endregion Functions @@ -60,47 +60,48 @@ function Get-LocaleList { .SYNOPSIS The `Language` DSC Resource allows you to install, update, and uninstall languages on your local Windows machine. -.PARAMETER LocaleName - The name of the language. This is the language tag that represents the language. For example, `en-US` represents English (United States). - To get a full list of languages available, use the `Get-LocaleList` function or Export() method. +.PARAMETER LanguageId + The name of the language ID. This is the language tag that represents the language. For example, `en-US` represents English (United States). + To get a full list of languages available, use the `[System.Globalization.CultureInfo]::GetCultures('AllCultures')` method. .PARAMETER Exist Indicates whether the package should exist. Defaults to $true. .EXAMPLE - PS C:\> Invoke-DscResource -ModuleName Microsoft.Windows.Setting.Language -Name Language -Method Set -Property @{ LocaleName = 'en-US' } + PS C:\> Invoke-DscResource -ModuleName Microsoft.Windows.Setting.Language -Name Language -Method Set -Property @{ LanguageId = 'en-GB' } - This example installs the English (United States) language on the local machine. + This example installs the English (United Kingdom) language pack on the user's machine. #> [DscResource()] class Language { [DscProperty(Key)] - [string] $LocaleName + [string] $LanguageId [DscProperty()] [bool] $Exist = $true - static [hashtable] $InstalledLocality + static [hashtable] $InstalledLanguages Language() { - [Language]::GetInstalledLocality() + [Language]::GetInstalledLanguages() } - Language([string] $LocaleName, [bool] $Exist) { - $this.LocaleName = $LocaleName + Language([string] $LanguageId, [bool] $Exist) { + $this.LanguageId = $LanguageId $this.Exist = $Exist } [Language] Get() { - $keyExist = [Language]::InstalledLocality.ContainsKey(($this.LocaleName)) + $currentState = [Language]::InstalledLanguages[$this.LanguageId] - $currentState = [Language]::InstalledLocality[$this.LocaleName] + if ($null -ne $currentState) { + return $currentState + } - if (-not $keyExist) { - return [Language]::new($this.LocaleName, $false) + return @{ + LanguageId = $this.LanguageId + Exist = $false } - - return $currentState } [void] Set() { @@ -110,9 +111,9 @@ class Language { if ($this.Exist) { # use the LanguagePackManagement module to install the language (requires elevation). International does not have a cmdlet to install language - Install-Language -Language $this.LocaleName + Install-Language -Language $this.LanguageId } else { - Uninstall-Language -Language $this.LocaleName + Uninstall-Language -Language $this.LanguageId } } @@ -122,20 +123,20 @@ class Language { if ($currentState.Exist -ne $this.Exist) { return $false } - + return $true } static [Language[]] Export() { - return Get-LocaleList + return Get-LanguageList } #region Language helper functions - static [void] GetInstalledLocality() { - [Language]::InstalledLocality = @{} + static [void] GetInstalledLanguages() { + [Language]::InstalledLanguages = @{} - foreach ($locality in [Language]::Export()) { - [Language]::InstalledLocality[$locality.LocaleName] = $locality + foreach ($language in [Language]::Export()) { + [Language]::InstalledLanguages[$language.LanguageId] = $language } } #endRegion Language helper functions @@ -145,7 +146,7 @@ class Language { .SYNOPSIS The `DisplayLanguage` DSC Resource allows you to set the display language on your local Windows machine. -.PARAMETER LocaleName +.PARAMETER Name The name of the display language. This is the language tag that represents the language. For example, `en-US` represents English (United States). .PARAMETER Exist @@ -158,32 +159,27 @@ class Language { #> [DscResource()] class DisplayLanguage { - + [DscProperty(Key)] - [string] $LocaleName + [string] $Name [DscProperty()] [bool] $Exist = $true - hidden [string] $KeyName = 'LocaleName' - DisplayLanguage() { + # Don't rely on the registry key to determine the current display language nor the user locale + $this.Name = (Get-WinSystemLocale).Name + $this.Exist = $true } [DisplayLanguage] Get() { $currentState = [DisplayLanguage]::new() - # check if user profile contains display language - $userProfileLanguageDict = TryGetRegistryValue -Key (Join-Path $global:LocaleUserProfilePath $this.LocaleName) -Property 'CachedLanguageName' - if ((TryGetRegistryValue -Key $global:LocaleNameRegistryPath -Property $this.KeyName) -ne $this.LocaleName -and ($null -ne $userProfileLanguageDict)) { + if ($currentState.Name -ne $this.Name) { $currentState.Exist = $false - return $currentState } - return @{ - LocaleName = $this.LocaleName - Exist = $true - } + return $currentState } [void] Set() { @@ -191,10 +187,86 @@ class DisplayLanguage { return } - # TODO: How do we handle sign out and sign in? - Set-WinUserLanguageList -Language $this.LocaleName + if (Test-LanguagePackAvailability -Language $this.Name) { + if (-not (Test-UserLanguageList)) { + # The language is installed through different means + # To reflect the language in the immersive control panel, we need to add it to the user language list + $existingList = Get-WinUserLanguageList + $existingList.Add($this.Name) + Set-WinUserLanguageList -LanguageList $existingList + } + Set-WinUILanguageOverride -Language $this.Name + } + } - # TODO: Exist does not make sense here, we always want a language to exist + [bool] Test() { + $currentState = $this.Get() + + if ($currentState.Exist -ne $this.Exist) { + return $false + } + + return $true + } +} + +<# +.SYNOPSIS + The `Region` DSC Resource allows you to set the region settings on your local Windows machine. + +.PARAMETER GeoId + The geographical ID that represents the region. This is used to set the home location. + +.PARAMETER HomeLocation + The home location of the region. This is a read-only property. + +.PARAMETER Exist + Indicates whether the region settings should exist. Defaults to $true. + +.EXAMPLE + PS C:\> Invoke-DscResource -ModuleName Microsoft.Windows.Setting.Language -Name Region -Method Set -Property @{ GeoId = '244' } + + This example sets the region to the geographical ID 244 on the user's machine, which is the United States. + +.NOTES + For a full list of geographical IDs, refer to the following link: https://learn.microsoft.com/en-us/windows/win32/intl/table-of-geographical-locations +#> +[DscResource()] +class Region { + [DscProperty(Key)] + [string] $GeoId + + [DscProperty(NotConfigurable)] + [string] $HomeLocation + + [DscProperty()] + [bool] $Exist = $true + + Region() { + # Get the current region settings + $region = Get-WinHomeLocation + + # Set the properties + $this.GeoId = $region.GeoId + $this.HomeLocation = $region.HomeLocation + $this.Exist = $true + } + + [Region] Get() { + $currentState = [Region]::new() + + if ($currentState.GeoId -ne $this.GeoId) { + $currentState.Exist = $false + } + + return $currentState + } + + [void] Set() { + if ($this.Test()) { + return + } + Set-WinHomeLocation -GeoId $this.GeoId } [bool] Test() { @@ -203,7 +275,7 @@ class DisplayLanguage { if ($currentState.Exist -ne $this.Exist) { return $false } - + return $true } } diff --git a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 index 890c6b30..a88f3104 100644 --- a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 @@ -14,9 +14,9 @@ BeforeAll { Describe 'List available DSC resources' { It 'Shows DSC Resources' { - $expectedDSCResources = @('Language', 'DisplayLanguage') + $expectedDSCResources = @('Language', 'DisplayLanguage', 'Region') $availableDSCResources = (Get-DscResource -Module Microsoft.Windows.Setting.Language).Name - $availableDSCResources.count | Should -Be 2 + $availableDSCResources.count | Should -Be 3 $availableDSCResources | Where-Object { $expectedDSCResources -notcontains $_ } | Should -BeNullOrEmpty -ErrorAction Stop } } @@ -26,9 +26,9 @@ Describe 'Language' { $desiredState = @{ LocaleName = 'en-GB' } - + Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState - + $finalState = Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState $finalState.Exist | Should -BeTrue } @@ -37,23 +37,21 @@ Describe 'Language' { $desiredState = @{ LocaleName = 'en-GB' } - + Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState - + $finalState = Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState $finalState.Exist | Should -BeFalse } - It 'Export all languages' -Skip:(!$IsWindows) { - + It 'Export all languages' -Skip:(!$IsWindows) { + $class = [Language]::new() $currentLanguages = $class::Export() $currentLanguages | Should -Not -BeNullOrEmpty $currentLanguages.Count | Should -BeGreaterThan 0 } - - # TODO: Add test if LocaleName is not found } Describe 'DisplayLanguage' { @@ -61,10 +59,23 @@ Describe 'DisplayLanguage' { $desiredState = @{ LocaleName = 'en-US' } - + Invoke-DscResource -Name DisplayLanguage -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState - - $finalState = Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState + + $finalState = Invoke-DscResource -Name DisplayLanguage -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState $finalState.Exist | Should -BeTrue } -} \ No newline at end of file +} + +Describe 'Region' { + It 'Set a preferred region' -Skip:(!$IsWindows) { + $desiredState = @{ + GeoId = '244' + } + + Invoke-DscResource -Name Region -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Region -ModuleName Microsoft.Windows.Setting.Language -Method Get -Property $desiredState + $finalState.Exist | Should -BeTrue + } +} From 7daf2b05ac175dbcd8a1e06a795f81702c5974d8 Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Sun, 8 Dec 2024 19:12:00 +0100 Subject: [PATCH 10/12] Resolve spelling --- .github/actions/spelling/expect/generic_terms.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/expect/generic_terms.txt b/.github/actions/spelling/expect/generic_terms.txt index 870c3e87..29768290 100644 --- a/.github/actions/spelling/expect/generic_terms.txt +++ b/.github/actions/spelling/expect/generic_terms.txt @@ -20,3 +20,4 @@ usr versioning VGpu ADDLOCAL +Cim From e473da6c41ade10e72cf05a56c0e870da0336bf2 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 11 Dec 2024 09:25:29 +0100 Subject: [PATCH 11/12] Import module and fix test --- .../Microsoft.Windows.Setting.Language.psm1 | 4 ++++ .../Microsoft.Windows.Setting.Language.Tests.ps1 | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 index 0d87dea2..5b5fb7b4 100644 --- a/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 +++ b/resources/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.psm1 @@ -3,6 +3,10 @@ using namespace System.Collections.Generic +# Import the LanguagePackManagement module for helper functions +Import-Module LanguagePackManagement -Force -ErrorAction SilentlyContinue + +#region Functions function Test-LanguagePackAvailability { param ( [Parameter(Mandatory = $true)] diff --git a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 index a88f3104..62ea07b0 100644 --- a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 @@ -10,6 +10,8 @@ Set-StrictMode -Version Latest BeforeAll { Import-Module Microsoft.Windows.Setting.Language -Force -ErrorAction SilentlyContinue + # Import the lanuage pack for functions + Import-Module LanguagePackManagement -Force -ErrorAction SilentlyContinue } Describe 'List available DSC resources' { @@ -24,7 +26,7 @@ Describe 'List available DSC resources' { Describe 'Language' { It 'Install a preferred language' -Skip:(!$IsWindows) { $desiredState = @{ - LocaleName = 'en-GB' + LanguageId = 'en-GB' } Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState @@ -35,7 +37,7 @@ Describe 'Language' { It 'Uninstall a preferred language' -Skip:(!$IsWindows) { $desiredState = @{ - LocaleName = 'en-GB' + LanguageId = 'en-GB' } Invoke-DscResource -Name Language -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState @@ -57,7 +59,7 @@ Describe 'Language' { Describe 'DisplayLanguage' { It 'Set a preferred language' -Skip:(!$IsWindows) { $desiredState = @{ - LocaleName = 'en-US' + Name = 'en-US' } Invoke-DscResource -Name DisplayLanguage -ModuleName Microsoft.Windows.Setting.Language -Method Set -Property $desiredState From c5469fc95504d6d1f1cd46879ee3c6f14a54a04a Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 11 Dec 2024 09:27:31 +0100 Subject: [PATCH 12/12] Fix spelling --- .../Microsoft.Windows.Setting.Language.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 index 62ea07b0..520d5ac5 100644 --- a/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Language/Microsoft.Windows.Setting.Language.Tests.ps1 @@ -10,7 +10,7 @@ Set-StrictMode -Version Latest BeforeAll { Import-Module Microsoft.Windows.Setting.Language -Force -ErrorAction SilentlyContinue - # Import the lanuage pack for functions + # Import the language pack for functions Import-Module LanguagePackManagement -Force -ErrorAction SilentlyContinue }