Skip to content
214 changes: 173 additions & 41 deletions resources/Microsoft.Windows.Settings/Microsoft.Windows.Settings.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ if ([string]::IsNullOrEmpty($env:TestRegistryPath)) {
$global:ExplorerRegistryPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\'
$global:PersonalizeRegistryPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\'
$global:AppModelUnlockRegistryPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock\'
$global:LongPathsRegistryPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem\'
} else {
$global:ExplorerRegistryPath = $global:PersonalizeRegistryPath = $global:AppModelUnlockRegistryPath = $env:TestRegistryPath
$global:ExplorerRegistryPath = $global:PersonalizeRegistryPath = $global:AppModelUnlockRegistryPath = $global:LongPathsRegistryPath = $env:TestRegistryPath
}

[DSCResource()]
Expand All @@ -30,11 +31,35 @@ class WindowsSettings {
[DscProperty()]
[Nullable[bool]] $DeveloperMode

[DscProperty()]
[System.Version] $OsVersion

[DscProperty()]
[Nullable[bool]] $HideFileExt

[DscProperty()]
[Nullable[bool]] $ShowHiddenFiles

[DscProperty()]
[Nullable[bool]] $LongPathsEnabled

hidden [bool] $RestartExplorer = $false
hidden [string] $TaskbarAl = 'TaskbarAl'
hidden [string] $AppsUseLightTheme = 'AppsUseLightTheme'
hidden [string] $SystemUsesLightTheme = 'SystemUsesLightTheme'
hidden [string] $DeveloperModePropertyName = 'AllowDevelopmentWithoutDevLicense'

# Registry keys
hidden [string] $TaskbarAlignmentRegKey = 'TaskbarAl'
hidden [string] $AppsUseLightThemeRegKey = 'AppsUseLightTheme'
hidden [string] $SystemUsesLightThemeRegKey = 'SystemUsesLightTheme'
hidden [string] $DeveloperModeRegKey = 'AllowDevelopmentWithoutDevLicense'
hidden [string] $HideFileExtRegKey = 'HideFileExt'
hidden [string] $HiddenRegKey = 'Hidden'
hidden [string] $LongPathsEnabledRegKey = 'LongPathsEnabled'

# Property values
hidden [string] $LeftValue = 'Left'
hidden [string] $CenterValue = 'Center'
hidden [string] $DarkValue = 'Dark'
hidden [string] $LightValue = 'Light'
hidden [string] $UnknownValue = 'Unknown'

[WindowsSettings] Get() {
$currentState = [WindowsSettings]::new()
Expand All @@ -49,34 +74,56 @@ class WindowsSettings {
# Get DeveloperMode
$currentState.DeveloperMode = $this.IsDeveloperModeEnabled()

# Get OS Version
$currentState.OsVersion = $this.GetOsVersion()

# Get File Extensions visibility
$currentState.HideFileExt = $this.IsFileExtensionsHidden()

# Get Hidden Files visibility
$currentState.ShowHiddenFiles = $this.AreHiddenFilesShown()

# Get Long Paths Enabled
$currentState.LongPathsEnabled = $this.IsLongPathsEnabled()

return $currentState
}

[bool] Test() {
$currentState = $this.Get()
return $this.TestTaskbarAlignment($currentState) -and $this.TestAppColorMode($currentState) -and $this.TestSystemColorMode($currentState) -and $this.TestDeveloperMode($currentState)

return (
$this.TestTaskbarAlignment($currentState) -and
$this.TestAppColorMode($currentState) -and
$this.TestSystemColorMode($currentState) -and
$this.TestDeveloperMode($currentState) -and
$this.TestOsVersion($currentState) -and
$this.TestHideFileExt($currentState) -and
$this.TestHiddenFilesShown($currentState) -and
$this.TestLongPathsEnabled($currentState)
)
}

[void] Set() {
$currentState = $this.Get()

# Set TaskbarAlignment
if (!$this.TestTaskbarAlignment($currentState)) {
$desiredAlignment = $this.TaskbarAlignment -eq "Left" ? 0 : 1
Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.TaskbarAl -Value $desiredAlignment
if (!$this.TestTaskbarAlignment($currentState) -and @($this.LeftValue, $this.CenterValue) -contains $this.TaskbarAlignment) {
$desiredAlignment = $this.TaskbarAlignment -eq $this.LeftValue ? 0 : 1
Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.TaskbarAlignmentRegKey -Value $desiredAlignment
}

# Set ColorMode
$colorModeChanged = $false
if (!$this.TestAppColorMode($currentState)) {
$desiredColorMode = $this.AppColorMode -eq "Dark" ? 0 : 1
Set-ItemProperty -Path $global:PersonalizeRegistryPath -Name $this.AppsUseLightTheme -Value $desiredColorMode
if (!$this.TestAppColorMode($currentState) -and @($this.DarkValue, $this.LightValue) -contains $this.AppColorMode) {
$desiredColorMode = $this.AppColorMode -eq $this.DarkValue ? 0 : 1
Set-ItemProperty -Path $global:PersonalizeRegistryPath -Name $this.AppsUseLightThemeRegKey -Value $desiredColorMode
$colorModeChanged = $true
}

if (!$this.TestSystemColorMode($currentState)) {
$desiredColorMode = $this.SystemColorMode -eq "Dark" ? 0 : 1
Set-ItemProperty -Path $global:PersonalizeRegistryPath -Name $this.SystemUsesLightTheme -Value $desiredColorMode
if (!$this.TestSystemColorMode($currentState) -and @($this.DarkValue, $this.LightValue) -contains $this.SystemColorMode) {
$desiredColorMode = $this.SystemColorMode -eq $this.DarkValue ? 0 : 1
Set-ItemProperty -Path $global:PersonalizeRegistryPath -Name $this.SystemUsesLightThemeRegKey -Value $desiredColorMode
$colorModeChanged = $true
}

Expand All @@ -93,63 +140,108 @@ class WindowsSettings {

# Set DeveloperMode
if (!$this.TestDeveloperMode($currentState)) {
$windowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$windowsPrincipal = New-Object -TypeName 'System.Security.Principal.WindowsPrincipal' -ArgumentList @( $windowsIdentity )
AdministratorRequired -Name "DeveloperMode"
$value = $this.DeveloperMode ? 1 : 0
Set-ItemProperty -Path $global:AppModelUnlockRegistryPath -Name $this.DeveloperModeRegKey -Value $value
}

if (-not $windowsPrincipal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) {
throw 'Toggling Developer Mode requires this resource to be run as an Administrator.'
}
# Set HideFileExt
if (!$this.TestHideFileExt($currentState)) {
$value = $this.HideFileExt ? 1 : 0
Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.HideFileExtRegKey -Value $value
SendShellStateMessage
}

# 1 == enabled // 0 == disabled
$value = $this.DeveloperMode ? 1 : 0
Set-ItemProperty -Path $global:AppModelUnlockRegistryPath -Name $this.DeveloperModePropertyName -Value $value
# Set ShowHiddenFiles
if (!$this.TestHiddenFilesShown($currentState)) {
$value = $this.ShowHiddenFiles ? 1 : 0
Set-ItemProperty -Path $global:ExplorerRegistryPath -Name $this.HiddenRegKey -Value $value
SendShellStateMessage
}

# Set LongPathsEnabled
if (!$this.TestLongPathsEnabled($currentState)) {
AdministratorRequired -Name "LongPathsEnabled"
$value = $this.LongPathsEnabled ? 1 : 0
Set-ItemProperty -Path $global:LongPathsRegistryPath -Name $this.LongPathsEnabledRegKey -Value $value
}
}

[string] GetTaskbarAlignment() {
if (-not(DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.TaskbarAl)) {
return "Center"
if (-not(DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.TaskbarAlignmentRegKey)) {
return $this.CenterValue
}

$value = [int](Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.TaskbarAl)
return $value -eq 0 ? "Left" : "Center"
$value = [int](Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.TaskbarAlignmentRegKey)
return $value -eq 0 ? $this.LeftValue : $this.CenterValue
}

[string] GetAppColorMode() {
if (-not(DoesRegistryKeyPropertyExist -Path $global:PersonalizeRegistryPath -Name $this.AppsUseLightTheme)) {
return "Unknown"
if (-not(DoesRegistryKeyPropertyExist -Path $global:PersonalizeRegistryPath -Name $this.AppsUseLightThemeRegKey)) {
return $this.UnknownValue
}

$appsUseLightModeValue = Get-ItemPropertyValue -Path $global:PersonalizeRegistryPath -Name $this.AppsUseLightTheme
$appsUseLightModeValue = Get-ItemPropertyValue -Path $global:PersonalizeRegistryPath -Name $this.AppsUseLightThemeRegKey
if ($appsUseLightModeValue -eq 0) {
return "Dark"
return $this.DarkValue
}

return "Light"
return $this.LightValue
}

[string] GetSystemColorMode() {
if (-not(DoesRegistryKeyPropertyExist -Path $global:PersonalizeRegistryPath -Name $this.SystemUsesLightTheme)) {
return "Unknown"
if (-not(DoesRegistryKeyPropertyExist -Path $global:PersonalizeRegistryPath -Name $this.SystemUsesLightThemeRegKey)) {
return $this.UnknownValue
}

$systemUsesLightModeValue = Get-ItemPropertyValue -Path $global:PersonalizeRegistryPath -Name $this.SystemUsesLightTheme
$systemUsesLightModeValue = Get-ItemPropertyValue -Path $global:PersonalizeRegistryPath -Name $this.SystemUsesLightThemeRegKey
if ($systemUsesLightModeValue -eq 0) {
return "Dark"
return $this.DarkValue
}

return "Light"
return $this.LightValue
}

[bool] IsDeveloperModeEnabled() {
$regExists = DoesRegistryKeyPropertyExist -Path $global:AppModelUnlockRegistryPath -Name $this.DeveloperModePropertyName
$regExists = DoesRegistryKeyPropertyExist -Path $global:AppModelUnlockRegistryPath -Name $this.DeveloperModeRegKey

# If the registry key does not exist, we assume developer mode is not enabled.
if (-not($regExists)) {
return $false
}

return Get-ItemPropertyValue -Path $global:AppModelUnlockRegistryPath -Name $this.DeveloperModePropertyName
return Get-ItemPropertyValue -Path $global:AppModelUnlockRegistryPath -Name $this.DeveloperModeRegKey
}

[System.Version] GetOsVersion() {
return (Get-ComputerInfo | Select-Object OsVersion).OsVersion
}

[bool] IsFileExtensionsHidden() {
$regExists = DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.HideFileExtRegKey
if (-not($regExists)) {
return $false
}

return Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.HideFileExtRegKey
}

[bool] AreHiddenFilesShown() {
$regExists = DoesRegistryKeyPropertyExist -Path $global:ExplorerRegistryPath -Name $this.HiddenRegKey
if (-not($regExists)) {
return $true
}

return Get-ItemPropertyValue -Path $global:ExplorerRegistryPath -Name $this.HiddenRegKey
}

[bool] IsLongPathsEnabled() {
$regExists = DoesRegistryKeyPropertyExist -Path $global:LongPathsRegistryPath -Name $this.LongPathsEnabledRegKey
if (-not($regExists)) {
return $false
}

return Get-ItemPropertyValue -Path $global:LongPathsRegistryPath -Name $this.LongPathsEnabledRegKey
}

[bool] TestDeveloperMode([WindowsSettings] $currentState) {
Expand All @@ -167,6 +259,35 @@ class WindowsSettings {
[bool] TestSystemColorMode([WindowsSettings] $currentState) {
return $this.SystemColorMode -eq $null -or $currentState.SystemColorMode -eq $this.SystemColorMode
}

[bool] TestOsVersion([WindowsSettings] $currentState) {
return $this.OsVersion -eq $null -or $currentState.OsVersion -eq $this.OsVersion
}

[bool] TestHideFileExt([WindowsSettings] $currentState) {
return $this.HideFileExt -eq $null -or $currentState.HideFileExt -eq $this.HideFileExt
}

[bool] TestHiddenFilesShown([WindowsSettings] $currentState) {
return $this.ShowHiddenFiles -eq $null -or $currentState.ShowHiddenFiles -eq $this.ShowHiddenFiles
}

[bool] TestLongPathsEnabled([WindowsSettings] $currentState) {
return $this.LongPathsEnabled -eq $null -or $currentState.LongPathsEnabled -eq $this.LongPathsEnabled
}
}

function AdministratorRequired {
param (
[Parameter(Mandatory = $true)]
[string]$Name
)
$windowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$windowsPrincipal = New-Object -TypeName 'System.Security.Principal.WindowsPrincipal' -ArgumentList @( $windowsIdentity )

if (-not $windowsPrincipal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) {
throw "This operation on $Name requires Administrator privileges."
}
}

function DoesRegistryKeyPropertyExist {
Expand All @@ -184,7 +305,18 @@ function DoesRegistryKeyPropertyExist {
}

function SendImmersiveColorSetMessage {
param()
SendMessageTimeout -Message "ImmersiveColorSet"
}

function SendShellStateMessage {
SendMessageTimeout -Message "ShellState"
}

function SendMessageTimeout {
param(
[Parameter(Mandatory)]
[string]$Message
)

Add-Type @"
using System;
Expand All @@ -210,7 +342,7 @@ public class NativeMethods {
$HWND_BROADCAST,
$WM_SETTINGCHANGE,
[UIntPtr]::Zero,
"ImmersiveColorSet",
$Message,
$SMTO_ABORTIFHUNG,
$timeout,
[ref]$result
Expand Down
44 changes: 22 additions & 22 deletions samples/DscResources/Microsoft.Windows.Settings/README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
# Microsoft.WindowsSandbox.DSC
The [Microsoft.Windows.settings](https://www.powershellgallery.com/packages/Microsoft.Windows.Settings) PowerShell module contains the Windows Settings DSC Resource.
> [!NOTE]
> Changing some Windows Settings requires elevation.
## How to use the WinGet Configuration File
The following two options are available for running a WinGet Configuration file on your device.
### 1. File Explorer
1. Download the `ChangeWindowsSettings.winget` and/or `DefaultWindowsSettings.winget` file to your computer.
2. Double-click the `ChangeWindowsSettings.winget` or the `DefaultWindowsSettings.winget` file (depending on which one you downloaded).
### 2. Windows Package Manager
1. Download the `ChangeWindowsSettings.winget` and/or `DefaultWindowsSettings.winget` file to your computer.
2. Open your Windows Start Menu, search and launch "_Windows Terminal_".
3. Type the following: `CD <C:\Users\User\Download>`
4. Type the following: `winget configure --file .\ChangeWindowsSettings.winget`
# Microsoft.WindowsSandbox.DSC

The [Microsoft.Windows.settings](https://www.powershellgallery.com/packages/Microsoft.Windows.Settings) PowerShell module contains the Windows Settings DSC Resource.

> [!NOTE]
> Changing some Windows Settings requires elevation.

## How to use the WinGet Configuration File

The following two options are available for running a WinGet Configuration file on your device.

### 1. File Explorer

1. Download the `ChangeWindowsSettings.winget` and/or `DefaultWindowsSettings.winget` file to your computer.
2. Double-click the `ChangeWindowsSettings.winget` or the `DefaultWindowsSettings.winget` file (depending on which one you downloaded).

### 2. Windows Package Manager

1. Download the `ChangeWindowsSettings.winget` and/or `DefaultWindowsSettings.winget` file to your computer.
2. Open your Windows Start Menu, search and launch "_Windows Terminal_".
3. Type the following: `CD <C:\Users\User\Download>`
4. Type the following: `winget configure --file .\ChangeWindowsSettings.winget`
Loading