From fbd69e2487192df4b1abdad66b4b9b2a8c588b8e Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Fri, 17 Jan 2025 10:46:59 +0100 Subject: [PATCH 01/21] Init bluetooth module --- .../Microsoft.Windows.Setting.Bluetooth.psd1 | 32 + .../Microsoft.Windows.Setting.Bluetooth.psm1 | 671 ++++++++++++++++++ ...rosoft.Windows.Setting.Bluetooth.Tests.ps1 | 82 +++ 3 files changed, 785 insertions(+) create mode 100644 resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 create mode 100644 resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 create mode 100644 tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 new file mode 100644 index 00000000..47983206 --- /dev/null +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 @@ -0,0 +1,32 @@ +@{ + RootModule = 'Microsoft.Windows.Setting.Bluetooth.psm1' + ModuleVersion = '0.1.0' + GUID = '65990ca0-278d-47b4-bc00-8fe47567e42d' + Author = 'Microsoft Corporation' + CompanyName = 'Microsoft Corporation' + Copyright = '(c) Microsoft Corporation. All rights reserved.' + Description = 'DSC Resource for Windows Setting Bluetooth' + PowerShellVersion = '7.2' + DscResourcesToExport = @( + 'USB', + 'PenWindowsInk' + ) + PrivateData = @{ + PSData = @{ + # Tags applied to this module. These help with module discovery in online galleries. + Tags = @( + 'PSDscResource_USB', + 'PSDscResource_PenWindowsInk' + ) + + # Prerelease string of this module + Prerelease = 'alpha' + + # 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' + } + } +} diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 new file mode 100644 index 00000000..95670108 --- /dev/null +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -0,0 +1,671 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { + $global:USBShellPath = 'HKCU:\Software\Microsoft\Shell\USB\' + $global:USBMachinePath = 'HKLM:\SYSTEM\CurrentControlSet\Control\USB\AutomaticSurpriseRemoval\' + $global:TabletTipPath = 'HKCU:\Software\Microsoft\TabletTip\EmbeddedInkControl\' + $global:MousePath = 'HKCU:\Control Panel\Mouse\' + $global:DesktopPath = 'HKCU:\Control Panel\Desktop\' +} else { + $global:USBShellPath = $env:TestRegistryPath +} + +#region Enums +enum FingerTipFont { + InkFree + SegoeUI +} + +enum PrimaryButton { + Left + Right +} + +enum ScrollDirection { + Down + Up +} +#endregion Enums + +#region Functions +function DoesRegistryKeyPropertyExist { + param ( + [Parameter(Mandatory)] + [string]$Path, + + [Parameter(Mandatory)] + [string]$Name + ) + + # Get-ItemProperty will return $null if the registry key property does not exist. + $itemProperty = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue + return $null -ne $itemProperty +} + +function Test-Assembly { + param ( + [Parameter(Mandatory)] + [string] $AssemblyName + ) + + $assembly = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq $AssemblyName } + return $null -ne $assembly +} + +function Import-Type { + param ( + [Parameter(Mandatory)] + [string] $AssemblyName + ) + + switch ($AssemblyName) { + 'Touchpad32Functions' { + Add-Type -TypeDefinition @' +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +public enum LEGACY_TOUCHPAD_FEATURES +{ + LEGACY_TOUCHPAD_FEATURE_NONE = 0x00000000, + LEGACY_TOUCHPAD_FEATURE_ENABLE_DISABLE = 0x00000001, + LEGACY_TOUCHPAD_FEATURE_REVERSE_SCROLL_DIRECTION = 0x00000004 +} + +public enum TOUCHPAD_SENSITIVITY_LEVEL +{ + TOUCHPAD_SENSITIVITY_LEVEL_MOST_SENSITIVE = 0x00000000, + TOUCHPAD_SENSITIVITY_LEVEL_HIGH_SENSITIVITY = 0x00000001, + TOUCHPAD_SENSITIVITY_LEVEL_MEDIUM_SENSITIVITY = 0x00000002, + TOUCHPAD_SENSITIVITY_LEVEL_LOW_SENSITIVITY = 0x00000003, + TOUCHPAD_SENSITIVITY_LEVEL_LEAST_SENSITIVE = 0x00000004 +} + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] +public struct TOUCHPAD +{ + public uint versionNumber; + public uint maxSupportedContacts; + public LEGACY_TOUCHPAD_FEATURES legacyTouchpadFeatures; + public bool touchpadPresent; + public bool legacyTouchpadPresent; + public bool externalMousePresent; + public bool touchpadEnabled; + public bool touchpadActive; + public bool feedbackSupported; + public bool clickForceSupported; + public bool Reserved1; + public bool allowActiveWhenMousePresent; + public bool feedbackEnabled; + public bool tapEnabled; + public bool tapAndDragEnabled; + public bool twoFingerTapEnabled; + public bool rightClickZoneEnabled; + public bool mouseAccelSettingHonored; + public bool panEnabled; + public bool zoomEnabled; + public bool scrollDirectionReversed; + public bool Reserved2; + public TOUCHPAD_SENSITIVITY_LEVEL sensitivityLevel; + public uint cursorSpeed; + public uint feedbackIntensity; + public uint clickForceSensitivity; + public uint rightClickZoneWidth; + public uint rightClickZoneHeight; +} + +public class Touchpad32Functions +{ + [DllImport("user32.dll", EntryPoint = "SystemParametersInfo", SetLastError = true)] + public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref TOUCHPAD pvParam, uint fWinIni); +} +'@ + } + 'MousePrecision' { + Add-Type -TypeDefinition @' +using System; +using System.Runtime.InteropServices; + +public class MousePrecision +{ + [DllImport("user32.dll", EntryPoint = "SystemParametersInfo", SetLastError = true)] + public static extern bool SystemParametersInfoGet(uint action, uint param, IntPtr vparam, uint fWinIni); + public const UInt32 SPI_GETMOUSE = 0x0003; + + [DllImport("user32.dll", EntryPoint = "SystemParametersInfo", SetLastError = true)] + public static extern bool SystemParametersInfoSet(uint action, uint param, IntPtr vparam, uint fWinIni); + public const UInt32 SPI_SETMOUSE = 0x0004; + + public const uint SPIF_SENDCHANGE = 0x02; + + public static bool ToggleEnhancePointerPrecision(bool b) + { + int[] mouseParams = new int[3]; + GCHandle handle = GCHandle.Alloc(mouseParams, GCHandleType.Pinned); + try + { + // Get the current values. + SystemParametersInfoGet(SPI_GETMOUSE, 0, handle.AddrOfPinnedObject(), 0); + // Modify the acceleration value as directed. + mouseParams[2] = b ? 1 : 0; + // Update the system setting. + return SystemParametersInfoSet(SPI_SETMOUSE, 0, handle.AddrOfPinnedObject(), SPIF_SENDCHANGE); + } + catch + { + // Get the last Win32 error code. + int errorCode = Marshal.GetLastWin32Error(); + Console.WriteLine("Error: " + errorCode); + return false; + } + finally + { + handle.Free(); + } + } +} +'@ + } + 'PrimaryButton' { + $type = Add-Type -MemberDefinition @' +[DllImport("user32.dll")] +public static extern bool SwapMouseButton(bool swap); +'@ -Name 'NativeMethods' -Namespace 'PInvoke' -PassThru + + } + } + + if ($type) { + # Used for smaller input functions. + return $type + } +} + +function Get-TouchpadSettings { + param ( + [Parameter()] + [int] $VersionNumber = 1, + + [Parameter()] + [string] $AssemblyName = 'Touchpad32Functions' + ) + + if (-not (Test-Assembly -AssemblyName $AssemblyName)) { + Import-Type -AssemblyName $AssemblyName + } + + $touchpad = New-Object TOUCHPAD + $touchpad.versionNumber = $VersionNumber + + # TODO: Does not work, error code 87. See: https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- + # TODO: Might also require checking if touchpad is present on machine, and if result can be captured as C++ acts different + $result = [Touchpad32Functions]::SystemParametersInfo(0x00AE, 0, [ref]$touchpad, 0) # SPI_GETTOUCHPADPARAMETERS + $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + if ($err -ne 0) { + throw [System.ComponentModel.Win32Exception]::new($err) + } + + # TODO: Convert object? + return $result +} + +function Set-EnhancePointerPrecision { + param ( + [switch] $Enable + ) + + if (-not (Test-Assembly -AssemblyName 'MousePrecision')) { + Import-Type -AssemblyName 'MousePrecision' + } + + [void][MousePrecision]::ToggleEnhancePointerPrecision($Enable.IsPresent) + + # Write the registry key for the MouseSpeed value. + $pointerPrecisionValue = $Enable.IsPresent ? 1 : 0 + if (-not (DoesRegistryKeyPropertyExist -Path $global:MousePath -Name 'MouseSpeed')) { + New-ItemProperty -Path $global:MousePath -Name 'MouseSpeed' -Value $pointerPrecisionValue -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:MousePath -Name 'MouseSpeed' -Value $pointerPrecisionValue +} + +function Set-PrimaryButton { + param ( + [switch] $Enable + ) + + if (-not (Test-Assembly -AssemblyName 'PrimaryButton')) { + $swapButtons = Import-Type -AssemblyName 'PrimaryButton' + } + + # Use $false for right-handed users, $true for left-handed users. + [void]$swapButtons::SwapMouseButton($Enable.IsPresent) +} + +function Set-MouseSetting { + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [PrimaryButton] $PrimaryButton, + + [Parameter(Mandatory)] + [int] $CursorSpeed, + + [Parameter()] + [nullable[bool]] $PointerPrecision, + + [Parameter()] + [nullable[bool]] $RollMouseScroll, + + [Parameter()] + [int] $LinesToScroll, + + [Parameter()] + [nullable[bool]] $ScrollInactiveWindows, + + [Parameter()] + [ScrollDirection] $ScrollDirection + ) + + switch ($PrimaryButton) { + 'Left' { + # Still making sure registry is set otherwise Test() will not work. + if (-not (DoesRegistryKeyPropertyExist -Path $global:MousePath -Name 'SwapMouseButtons')) { + New-ItemProperty -Path $global:MousePath -Name 'SwapMouseButtons' -Value 0 -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:MousePath -Name 'SwapMouseButtons' -Value 0 + Set-PrimaryButton -Enable:$false + } + 'Right' { + if (-not (DoesRegistryKeyPropertyExist -Path $global:MousePath -Name 'SwapMouseButtons')) { + New-ItemProperty -Path $global:MousePath -Name 'SwapMouseButtons' -Value 1 -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:MousePath -Name 'SwapMouseButtons' -Value 1 + Set-PrimaryButton -Enable:$true + } + } + + if ($null -ne $PointerPrecision) { + Set-EnhancePointerPrecision -Enable:$PointerPrecision + } +} +#endregion Functions + +#region Classes +[DscResource()] +class USB { + [DscProperty(Key)] + [string]$SID + + [DscProperty()] + [nullable[bool]] $ConnectionNotifications + [DscProperty()] + [nullable[bool]] $SlowChargingNotification + [DscProperty()] + [nullable[bool]] $BatterySaver + + static hidden [string] $ConnectionNotificationsProperty = 'NotifyOnUsbErrors' + static hidden [string] $SlowChargingNotificationProperty = 'NotifyOnWeakCharger' + static hidden [string] $BatterySaverProperty = 'AttemptRecoveryFromUsbPowerDrain' + + [USB] Get() { + $currentState = [USB]::new() + $currentState.ConnectionNotifications = [USB]::GetConnectionNotificationStatus() + $currentState.SlowChargingNotification = [USB]::GetSlowChargingNotificationStatus() + $currentState.BatterySaver = [USB]::GetBatterySaverStatus() + + return $currentState + } + + [bool] Test() { + $currentState = $this.Get() + + if (($null -ne $this.ConnectionNotifications) -and ($this.ConnectionNotifications -ne $currentState.ConnectionNotifications)) { + return $false + } + + if (($null -ne $this.SlowChargingNotification) -and ($this.SlowChargingNotification -ne $currentState.SlowChargingNotification)) { + return $false + } + + if (($null -ne $this.BatterySaver) -and ($this.BatterySaver -ne $currentState.BatterySaver)) { + return $false + } + + return $true + } + + [void] Set() { + if (-not ($this.Test())) { + if ($null -ne $this.ConnectionNotifications) { + if (-not (DoesRegistryKeyPropertyExist -Path $global:USBShellPath -Name ([USB]::ConnectionNotificationsProperty))) { + New-ItemProperty -Path $global:USBShellPath -Name ([USB]::ConnectionNotificationsProperty) -Value ([int]$this.ConnectionNotifications) -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:USBShellPath -Name ([USB]::ConnectionNotificationsProperty) -Value ([int]$this.ConnectionNotifications) + } + + if ($null -ne $this.SlowChargingNotification) { + if (-not (DoesRegistryKeyPropertyExist -Path $global:USBShellPath -Name ([USB]::SlowChargingNotificationProperty))) { + New-ItemProperty -Path $global:USBShellPath -Name ([USB]::SlowChargingNotificationProperty) -Value ([int]$this.SlowChargingNotification) -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:USBShellPath -Name ([USB]::SlowChargingNotificationProperty) -Value ([int]$this.SlowChargingNotification) + } + + if ($null -ne $this.BatterySaver) { + if (-not (DoesRegistryKeyPropertyExist -Path $global:USBMachinePath -Name ([USB]::BatterySaverProperty))) { + New-ItemProperty -Path $global:USBMachinePath -Name ([USB]::BatterySaverProperty) -Value ([int]$this.BatterySaver) -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:USBMachinePath -Name ([USB]::BatterySaverProperty) -Value ([int]$this.BatterySaver) + } + } + } + + #region USB helper functions + static [bool] GetConnectionNotificationStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:USBShellPath -Name ([USB]::ConnectionNotificationsProperty))) { + return $true + } else { + $ConnectionNotificationsValue = (Get-ItemProperty -Path $global:USBShellPath -Name ([USB]::ConnectionNotificationsProperty)).NotifyOnUsbErrors + return ($ConnectionNotificationsValue -eq 1) + } + } + + static [bool] GetSlowChargingNotificationStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:USBShellPath -Name ([USB]::SlowChargingNotificationProperty))) { + return $true + } else { + $SlowChargingNotificationValue = (Get-ItemProperty -Path $global:USBShellPath -Name ([USB]::SlowChargingNotificationProperty)).NotifyOnWeakCharger + return ($SlowChargingNotificationValue -eq 1) + } + } + + static [bool] GetBatterySaverStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:USBMachinePath -Name ([USB]::BatterySaverProperty))) { + return $false # It is not enabled by default if the registry key does not exist. + } else { + $BatterySaverValue = (Get-ItemProperty -Path $global:USBMachinePath -Name ([USB]::BatterySaverProperty)).AttemptRecoveryFromUsbPowerDrain + return ($BatterySaverValue -eq 1) + } + } + #endregion USB helper functions +} + +[DscResource()] +class PenWindowsInk { + [DscProperty(Key)] + [FingerTipFont] $FingerTipFont + + [DscProperty()] + [nullable[bool]] $WriteFingerTip + + static hidden [string] $FingerTipFontProperty = 'LatinFontName' + static hidden [string] $WriteFingerTipProperty = 'EnableInkingWithTouch' + + PenWindowsInk() { + $this.FingerTipFont = [PenWindowsInk]::GetFingerTipFont() + $this.WriteFingerTip = [PenWindowsInk]::GetWriteFingertipStatus() + } + + [PenWindowsInk] Get() { + $currentState = [PenWindowsInk]::new() + + return $currentState + } + + [bool] Test() { + $currentState = $this.Get() + + if (($null -ne $this.FingerTipFont) -and ($this.FingerTipFont -ne $currentState.FingerTipFont)) { + return $false + } + + if (($null -ne $this.WriteFingerTip) -and ($this.WriteFingerTip -ne $currentState.WriteFingerTip)) { + return $false + } + + return $true + } + + [void] Set() { + if (-not ($this.Test())) { + if ($null -ne $this.FingerTipFont) { + # Don't use enums in the registry, use the actual string value. + $FingerTipValue = switch ($this.FingerTipFont) { + 'InkFree' { 'Ink Free' } + 'SegoeUI' { 'Segoe UI' } + default { 'Ink Free' } + } + + if (-not (DoesRegistryKeyPropertyExist -Path $global:TabletTipPath -Name ([PenWindowsInk]::FingerTipFontProperty))) { + New-ItemProperty -Path $global:TabletTipPath -Name ([PenWindowsInk]::FingerTipFontProperty) -Value $FingerTipValue -PropertyType String | Out-Null + } + Set-ItemProperty -Path $global:TabletTipPath -Name ([PenWindowsInk]::FingerTipFontProperty) -Value $FingerTipValue + } + + if ($null -ne $this.WriteFingerTip) { + if (-not (DoesRegistryKeyPropertyExist -Path $global:TabletTipPath -Name ([PenWindowsInk]::WriteFingerTipProperty))) { + New-ItemProperty -Path $global:TabletTipPath -Name ([PenWindowsInk]::WriteFingerTipProperty) -Value ([int]$this.WriteFingerTip) -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:TabletTipPath -Name ([PenWindowsInk]::WriteFingerTipProperty) -Value ([int]$this.WriteFingerTip) + } + } + } + + #region PenWindowsInk helper functions + static [FingerTipFont] GetFingerTipFont() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:TabletTipPath -Name ([PenWindowsInk]::FingerTipFontProperty))) { + return [FingerTipFont]::InkFree + } else { + $FingerTipValue = switch (((Get-ItemProperty -Path $global:TabletTipPath -Name ([PenWindowsInk]::FingerTipFontProperty)).LatinFontName)) { + 'Ink Free' { [FingerTipFont]::InkFree } + 'Segoe UI' { [FingerTipFont]::SegoeUI } + default { [FingerTipFont]::InkFree } + } + + return $FingerTipValue + } + } + + static [bool] GetWriteFingertipStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:TabletTipPath -Name ([PenWindowsInk]::WriteFingertipProperty))) { + return $true + } else { + $WriteWFingertipValue = (Get-ItemProperty -Path $global:TabletTipPath -Name ([PenWindowsInk]::WriteFingerTipProperty)).EnableInkingWithTouch + return ($WriteWFingertipValue -eq 1) + } + } + #endregion PenWindowsInk helper functions +} + +[DscResource()] +class Mouse { + + [DscProperty(Key)] + [string]$SID + + [DscProperty()] + [PrimaryButton] $PrimaryButton + + [DscProperty()] + [int] $CursorSpeed + + [DscProperty()] + [nullable[bool]] $PointerPrecision + + [DscProperty()] + [nullable[bool]] $RollMouseScroll + + [DscProperty()] + [int] $LinesToScroll + + [DscProperty()] + [nullable[bool]] $ScrollInactiveWindows + + [DscProperty()] + [ScrollDirection] $ScrollDirection + + static hidden [string] $PrimaryButtonProperty = 'SwapMouseButtons' + static hidden [string] $CursorSpeedProperty = 'MouseSensitivity' + static hidden [string] $PointerPrecisionProperty = 'MouseSpeed' + static hidden [string] $LinesToScrollProperty = 'WheelScrollLines' + static hidden [string] $ScrollInactiveWindowsProperty = 'MouseWheelRouting' + static hidden [string] $ScrollDirectionProperty = 'ReverseMouseWheelDirection' + + Mouse() { + } + + [Mouse] Get() { + $currentState = [Mouse]::new() + $currentState.PrimaryButton = [Mouse]::GetPrimaryMouseStatus() + $currentState.CursorSpeed = [Mouse]::GetCursorSpeed() + $currentState.PointerPrecision = [Mouse]::GetPointerPrecisionStatus() + # Capture the RollMouseScroll and LinesToScroll values in a hashtable. + $roleMouseStatus = [Mouse]::GetRollMouseScrollStatus() + # Set the values. + $currentState.RollMouseScroll = $roleMouseStatus.RollMouseScroll + $currentState.LinesToScroll = $roleMouseStatus.LinesToScroll + $currentState.ScrollInactiveWindows = [Mouse]::GetScrollInactiveWindowsStatus() + $currentState.ScrollDirection = [Mouse]::GetScrollDirectionStatus() + + return $currentState + } + + [bool] Test() { + $currentState = $this.Get() + + if ($currentState.PrimaryButton -ne $this.PrimaryButton) { + return $false + } + + if ((0 -eq $currentState.CursorSpeed) -and ($currentState.CursorSpeed -ne $this.CursorSpeed)) { + return $false + } + + if (($null -ne $this.PointerPrecision) -and ($this.PointerPrecision -ne $currentState.PointerPrecision)) { + return $false + } + + if (($null -ne $this.RollMouseScroll) -and ($this.RollMouseScroll -ne $currentState.RollMouseScroll)) { + return $false + } + + if ((0 -eq $currentState.LinesToScroll) -and ($this.LinesToScroll -ne $currentState.LinesToScroll)) { + return $false + } + + if ($currentState.ScrollDirection -ne $this.ScrollDirection) { + return $false + } + + return $true + } + + [void] Set() { + if (-not ($this.Test())) { + Set-MouseSetting -PrimaryButton $this.PrimaryButton ` + -CursorSpeed $this.CursorSpeed ` + -PointerPrecision $this.PointerPrecision ` + -RollMouseScroll $this.RollMouseScroll ` + -LinesToScroll $this.LinesToScroll ` + -ScrollInactiveWindows $this.ScrollInactiveWindows ` + -ScrollDirection $this.ScrollDirection + } + } + + #region Mouse helper functions + static [PrimaryButton] GetPrimaryMouseStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:MousePath -Name ([Mouse]::PrimaryButtonProperty))) { + return [PrimaryButton]::Left + } else { + $MouseButtonValue = (Get-ItemProperty -Path $global:MousePath -Name ([Mouse]::PrimaryButtonProperty)).SwapMouseButtons + return (($MouseButtonValue -eq 0) ? [PrimaryButton]::Left : [PrimaryButton]::Right) + } + } + + static [int] GetCursorSpeed() { + $CursorSpeedValue = (Get-ItemPropertyValue -Path $global:MousePath -Name ([Mouse]::CursorSpeedProperty) -ErrorAction SilentlyContinue) # MouseSensitivity should always be present + if ($null -eq $CursorSpeedValue) { + $CursorSpeedValue = 10 + } + + return $CursorSpeedValue + } + + static [bool] GetPointerPrecisionStatus() { + # Note: MouseThreshold1 and MouseThreshold2 are also set but not checked here. + $PointerPrecisionValue = (Get-ItemPropertyValue -Path $global:MousePath -Name ([Mouse]::PointerPrecisionProperty) -ErrorAction SilentlyContinue) # MouseSpeed should always be present + if ($null -eq $PointerPrecisionValue) { + $PointerPrecisionValue = 1 + } + + return ($PointerPrecisionValue -eq 1) + } + + static [hashtable] GetRollMouseScrollStatus() { + $RollMouseScrollValue = (Get-ItemPropertyValue -Path $global:DesktopPath -Name ([Mouse]::LinesToScrollProperty) -ErrorAction SilentlyContinue) # WheelScrollLines should always be present + if ($null -eq $RollMouseScrollValue) { + throw [System.Configuration.ConfigurationException]::new("'{0}' could not be found. Please make sure the key exists in the registry." -f ([Mouse]::RollMouseScrollProperty)) + } + + return @{ + 'RollMouseScroll' = ($RollMouseScrollValue -gt 0) # If it is -1, it means single line scrolling + 'LinesToScroll' = $RollMouseScrollValue + } + } + + static [bool] GetScrollInactiveWindowsStatus() { + $ScrollInactiveWindowsValue = (Get-ItemPropertyValue -Path $global:DesktopPath -Name ([Mouse]::ScrollInactiveWindowsProperty) -ErrorAction SilentlyContinue) + + if ($null -eq $ScrollInactiveWindowsValue) { + return $true + } + + return ($ScrollInactiveWindowsValue -eq 2) + } + + static [ScrollDirection] GetScrollDirectionStatus() { + $ScrollDirectionValue = switch ((Get-ItemPropertyValue -Path $global:MousePath -Name ([Mouse]::ScrollDirectionProperty) -ErrorAction SilentlyContinue)) { + 0 { [ScrollDirection]::Down } + 1 { [ScrollDirection]::Up } + default { [ScrollDirection]::Down } + } + + return $ScrollDirectionValue + } + #endregion Mouse helper functions +} + +# TODO: Does not work (yet). Check comments in Get-TouchpadSettings function. +# [DscResource()] +# class Touchpad { +# [DscProperty(Key)] +# [string]$DeviceID + +# [Touchpad] Get() { +# $currentState = [Touchpad]::new() + +# return $currentState +# } + +# [bool] Test() { +# $currentState = $this.Get() + +# return $true +# } + +# [void] Set() { + +# } + +# #region Touchpad helper functions +# static [PSObject] GetTouchpadSettingStatus() { +# $TouchpadSetting = Get-TouchpadSetting + +# return $TouchpadSetting +# } +# #endregion Touchpad helper functions +# } +#endregion Classes diff --git a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 new file mode 100644 index 00000000..a10a9266 --- /dev/null +++ b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 @@ -0,0 +1,82 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +using module Microsoft.Windows.Setting.Bluetooth + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +<# +.Synopsis + Pester tests related to the Microsoft.Windows.Setting.Bluetooth PowerShell module. +#> + +BeforeAll { + if ((Get-Module -ListAvailable -Name PSDesiredStateConfiguration -ErrorAction SilentlyContinue).Version -eq '2.0.7') { + Install-Module -Name PSDesiredStateConfiguration -Force -SkipPublisherCheck + } + + Import-Module Microsoft.Windows.Setting.Bluetooth -Force +} + +Describe 'List available DSC resources' { + It 'Shows DSC Resources' { + $expectedDSCResources = 'USB', 'PenWindowsInk' + $availableDSCResources = (Get-DscResource -Module Microsoft.Windows.Setting.Bluetooth).Name + $availableDSCResources.Count | Should -Be 2 + $availableDSCResources | Where-Object { $expectedDSCResources -notcontains $_ } | Should -BeNullOrEmpty -ErrorAction Stop + } +} + +Describe 'USB' { + It 'Set connection notifications on' { + $desiredState = @{ + ConnectionNotifications = $true + } + Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.ConnectionNotifications | Should -Be $true + } + + It 'Set slow charging notification off' { + $desiredState = @{ + SlowChargingNotification = $false + } + Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.SlowChargingNotification | Should -Be $false + } + + It 'Set battery saver on' { + $desiredState = @{ + BatterySaver = $true + } + Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.BatterySaver | Should -Be $true + } +} + +Describe 'PenWindowsInk' { + It 'Set finger tip font to SegoeUI' { + $desiredState = @{ + FingerTipFont = 'SegoeUI' + } + Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.FingerTipFont | Should -Be 'SegoeUI' + } + + It 'Set write with your finger tip off' { + $desiredState = @{ + WriteFingerTip = $false + } + Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.WriteFingerTip | Should -Be $false + } +} From 0a40c01b1e332a497f4a44914901b0d06409839a Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 13:34:50 +0100 Subject: [PATCH 02/21] New Set-MouseScrollLines function --- .../Microsoft.Windows.Setting.Bluetooth.psm1 | 131 ++++++++++++++++-- test.ps1 | 70 ++++++++++ 2 files changed, 190 insertions(+), 11 deletions(-) create mode 100644 test.ps1 diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index 95670108..4ab32482 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -62,6 +62,9 @@ function Import-Type { [string] $AssemblyName ) + # Used for larger input functions. + New-Variable -Name Type -Value $null -Scope Script -Force + switch ($AssemblyName) { 'Touchpad32Functions' { Add-Type -TypeDefinition @' @@ -177,12 +180,25 @@ public static extern bool SwapMouseButton(bool swap); '@ -Name 'NativeMethods' -Namespace 'PInvoke' -PassThru } + 'ScrollLines' { + Add-Type -TypeDefinition @' +using System; +using System.Runtime.InteropServices; + +public class ScrollLines +{ + [DllImport("User32.dll",CharSet=CharSet.Unicode)] + public static extern int SystemParametersInfo( + Int32 uAction, + Int32 uParam, + String lpvParam, + Int32 fuWinIni); +} +'@ + } } - if ($type) { - # Used for smaller input functions. - return $type - } + return $type } function Get-TouchpadSettings { @@ -245,6 +261,71 @@ function Set-PrimaryButton { [void]$swapButtons::SwapMouseButton($Enable.IsPresent) } +function Set-MouseSpeed() { + param( + [Parameter(ValueFromPipeline = $true)] + [ValidateRange(1, 20)] + [int] $Speed = 10 + ) + + $MethodDefinition = @' + [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] + public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni); +'@ + Set-ItemProperty -Path $global:MousePath -Name MouseSensitivity -Value $Speed + $User32 = Add-Type -MemberDefinition $MethodDefinition -Name 'User32MouseSpeed' -Namespace Win32Functions -PassThru + $User32::SystemParametersInfo(0x0071, 0, $Speed, 0) | Out-Null +} + +function Set-MouseWheelRouting() { + param( + [Parameter()] + [switch] $Enable + ) + + $MethodDefinition = @' + [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] + public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni); +'@ + $WheelRoute = $Enable.IsPresent ? 2 : 0 + $User32 = Add-Type -MemberDefinition $MethodDefinition -Name 'User32MouseWheelRouting' -Namespace Win32Functions -PassThru + $User32::SystemParametersInfo(0x201D, 0, $WheelRoute, 0) | Out-Null + Set-ItemProperty -Path $global:DesktopPath -Name MouseWheelRouting -Value $WheelRoute +} + +function Set-MouseScrollLines { + param ( + [Parameter()] + [switch] $Enable, + + [Parameter()] + [int] $Lines + ) + + if (-not (Test-Assembly -AssemblyName 'ScrollLines')) { + Import-Type -AssemblyName 'ScrollLines' + } + + + if (-not ($Enable.IsPresent)) { + # If the -Enable switch is not present, we set the number to -1, meaning one screen at a time + $Lines = -1 + } + + # Action: SPI_SETWHEELSCROLLLINES + $Action = 0x0069 + $UpdateIniFile = 0x01 + $SendChangeEvent = 0x02 + + $Options = $UpdateIniFile -bor $SendChangeEvent + + $Res = [ScrollLines]::SystemParametersInfo($Action, $Lines, 0, $options) + + if ($Res -ne 1) { + throw [System.Configuration.ConfigurationException]::new('Failed to set the number of lines to scroll.') + } +} + function Set-MouseSetting { [CmdletBinding()] param ( @@ -288,9 +369,26 @@ function Set-MouseSetting { } } + # Note: The pointer precision setting is visible from 23H2 onwards in the settings screen, else you can find it in the Control Panel -> Mouse -> Pointer Options. if ($null -ne $PointerPrecision) { Set-EnhancePointerPrecision -Enable:$PointerPrecision } + + # Set the cursor speed. + if ($CursorSpeed -ne 0) { + Set-MouseSpeed -Speed $CursorSpeed + } + + # Set the number of lines to scroll. + if ($LinesToScroll -ne 0 -or ($null -ne $RollMouseScroll -and $RollMouseScroll -ne $true)) { + Write-Host "Calling Set-MouseScrollLines with RollMouseScroll: $RollMouseScroll and LinesToScroll: $LinesToScroll" + Set-MouseScrollLines -Enable:$RollMouseScroll -Lines $LinesToScroll + } + + # Set the mouse wheel routing e.g. scroll inactive windows when I hover over them. + if ($null -ne $ScrollInactiveWindows) { + Set-MouseWheelRouting -Enable:$ScrollInactiveWindows + } } #endregion Functions @@ -540,8 +638,10 @@ class Mouse { return $false } - if ((0 -eq $currentState.CursorSpeed) -and ($currentState.CursorSpeed -ne $this.CursorSpeed)) { - return $false + if ($this.CursorSpeed -ne 0) { + if ($currentState.CursorSpeed -ne $this.CursorSpeed) { + return $false + } } if (($null -ne $this.PointerPrecision) -and ($this.PointerPrecision -ne $currentState.PointerPrecision)) { @@ -552,7 +652,13 @@ class Mouse { return $false } - if ((0 -eq $currentState.LinesToScroll) -and ($this.LinesToScroll -ne $currentState.LinesToScroll)) { + if ($this.LinesToScroll -ne 0) { + if ($currentState.LinesToScroll -ne $this.LinesToScroll) { + return $false + } + } + + if (($null -ne $this.ScrollInactiveWindows) -and ($this.ScrollInactiveWindows -ne $currentState.ScrollInactiveWindows)) { return $false } @@ -627,10 +733,13 @@ class Mouse { } static [ScrollDirection] GetScrollDirectionStatus() { - $ScrollDirectionValue = switch ((Get-ItemPropertyValue -Path $global:MousePath -Name ([Mouse]::ScrollDirectionProperty) -ErrorAction SilentlyContinue)) { - 0 { [ScrollDirection]::Down } - 1 { [ScrollDirection]::Up } - default { [ScrollDirection]::Down } + $ScrollDirectionValue = try { + switch ((Get-ItemPropertyValue -Path $global:MousePath -Name ([Mouse]::ScrollDirectionProperty) -ErrorAction SilentlyContinue)) { + 0 { [ScrollDirection]::Down } + 1 { [ScrollDirection]::Up } + } + } catch { + [ScrollDirection]::Down } return $ScrollDirectionValue diff --git a/test.ps1 b/test.ps1 new file mode 100644 index 00000000..a60ee820 --- /dev/null +++ b/test.ps1 @@ -0,0 +1,70 @@ +function Get-MouseSpeed() { + + $MethodDefinition = @' + [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] + public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref uint pvParam, uint fWinIni); +'@ + $User32 = Add-Type -MemberDefinition $MethodDefinition -Name 'User32Get' -Namespace Win32Functions -PassThru + + [Int32] $ScrollLines = 0 + $User32::SystemParametersInfo(0x0068, 0, [ref]$ScrollLines, 0) | Out-Null + return $ScrollLines +} + + +function Set-MouseScrollLines { + param ( + [Parameter()] + [switch] $Enable, + + [Parameter()] + [int] $Lines + ) + + $MethodDefinition = @' + [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] + public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref uint pvParam, uint fWinIni); +'@ + $User32 = Add-Type -MemberDefinition $MethodDefinition -Name 'User32MouseScrollLines' -Namespace Win32Functions -PassThru + + if (-not ($Enable.IsPresent)) { + # If the -Enable switch is not present, we set the number to -1, meaning one screen at a time + $Lines = -1 + } + + # Action: SPI_SETWHEELSCROLLLINES + $Action = 0x0069 + $UpdateIniFile = 0x01 + $SendChangeEvent = 0x02 + + $Options = $UpdateIniFile -bor $SendChangeEvent + $Res = $User32::SystemParametersInfo($Action, $Lines, 0, $Options) + + if ($Res -ne 1) { + throw [System.Configuration.ConfigurationException]::new('Failed to set the number of lines to scroll.') + } +} + +Add-Type -TypeDefinition @' +using System; +using System.Runtime.InteropServices; + +public class SystemParameters +{ + [DllImport("User32.dll",CharSet=CharSet.Unicode)] + public static extern int SystemParametersInfo( + Int32 uAction, + Int32 uParam, + String lpvParam, + Int32 fuWinIni); +} +'@ + +# 0x0014 = SPI_SETDESKWALLPAPER +$setWallpaperAction = 0x0069 +$UpdateIniFile = 0x01 +$SendChangeEvent = 0x02 + +$options = $UpdateIniFile -bor $SendChangeEvent + +[SystemParameters]::SystemParametersInfo($setWallpaperAction, -1, 0, $options) \ No newline at end of file From 5d6cad24b607d9fac1bc223ed5502741b36019d0 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:08:26 +0100 Subject: [PATCH 03/21] Create tests for mouse --- .../Microsoft.Windows.Setting.Bluetooth.psd1 | 6 +- .../Microsoft.Windows.Setting.Bluetooth.psm1 | 29 ++- ...rosoft.Windows.Setting.Bluetooth.Tests.ps1 | 167 ++++++++++++++---- 3 files changed, 165 insertions(+), 37 deletions(-) diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 index 47983206..1736cb89 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 @@ -9,14 +9,16 @@ PowerShellVersion = '7.2' DscResourcesToExport = @( 'USB', - 'PenWindowsInk' + 'PenWindowsInk', + 'Mouse' ) PrivateData = @{ PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. Tags = @( 'PSDscResource_USB', - 'PSDscResource_PenWindowsInk' + 'PSDscResource_PenWindowsInk', + 'PSDscResource_Mouse' ) # Prerelease string of this module diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index 4ab32482..ce824f50 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -11,7 +11,7 @@ if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { $global:MousePath = 'HKCU:\Control Panel\Mouse\' $global:DesktopPath = 'HKCU:\Control Panel\Desktop\' } else { - $global:USBShellPath = $env:TestRegistryPath + $global:USBShellPath = $global:USBMachinePath = $global:TabletTipPath = $global:MousePath = $global:DesktopPath = $env:TestRegistryPath } #region Enums @@ -272,9 +272,11 @@ function Set-MouseSpeed() { [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni); '@ + # Action: SPI_SETMOUSESPEED + $Action = 0x0071 Set-ItemProperty -Path $global:MousePath -Name MouseSensitivity -Value $Speed $User32 = Add-Type -MemberDefinition $MethodDefinition -Name 'User32MouseSpeed' -Namespace Win32Functions -PassThru - $User32::SystemParametersInfo(0x0071, 0, $Speed, 0) | Out-Null + $User32::SystemParametersInfo($Action, 0, $Speed, 0) | Out-Null } function Set-MouseWheelRouting() { @@ -287,9 +289,11 @@ function Set-MouseWheelRouting() { [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni); '@ + # Action: SPI_SETMOUSEWHEELROUTING + $Action = 0x201D $WheelRoute = $Enable.IsPresent ? 2 : 0 $User32 = Add-Type -MemberDefinition $MethodDefinition -Name 'User32MouseWheelRouting' -Namespace Win32Functions -PassThru - $User32::SystemParametersInfo(0x201D, 0, $WheelRoute, 0) | Out-Null + $User32::SystemParametersInfo($Action, 0, $WheelRoute, 0) | Out-Null Set-ItemProperty -Path $global:DesktopPath -Name MouseWheelRouting -Value $WheelRoute } @@ -381,7 +385,6 @@ function Set-MouseSetting { # Set the number of lines to scroll. if ($LinesToScroll -ne 0 -or ($null -ne $RollMouseScroll -and $RollMouseScroll -ne $true)) { - Write-Host "Calling Set-MouseScrollLines with RollMouseScroll: $RollMouseScroll and LinesToScroll: $LinesToScroll" Set-MouseScrollLines -Enable:$RollMouseScroll -Lines $LinesToScroll } @@ -389,6 +392,24 @@ function Set-MouseSetting { if ($null -ne $ScrollInactiveWindows) { Set-MouseWheelRouting -Enable:$ScrollInactiveWindows } + + # Set scroll direction. Only available in Windows 11 23H2 onwards. + switch ($ScrollDirection) { + 'Down' { + if (-not (DoesRegistryKeyPropertyExist -Path $global:MousePath -Name 'ReverseMouseWheelDirection')) { + New-ItemProperty -Path $global:MousePath -Name 'ReverseMouseWheelDirection' -Value 0 -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:MousePath -Name 'ReverseMouseWheelDirection' -Value 0 + } + 'Up' { + if (-not (DoesRegistryKeyPropertyExist -Path $global:MousePath -Name 'ReverseMouseWheelDirection')) { + New-ItemProperty -Path $global:MousePath -Name 'ReverseMouseWheelDirection' -Value 1 -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:MousePath -Name 'ReverseMouseWheelDirection' -Value 1 + } + + # TODO: There is no refresh win32_api, so users have to logout and login to see the changes. + } } #endregion Functions diff --git a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 index a10a9266..a9381fd7 100644 --- a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 @@ -20,63 +20,168 @@ BeforeAll { Describe 'List available DSC resources' { It 'Shows DSC Resources' { - $expectedDSCResources = 'USB', 'PenWindowsInk' + $expectedDSCResources = 'USB', 'PenWindowsInk', 'Mouse' $availableDSCResources = (Get-DscResource -Module Microsoft.Windows.Setting.Bluetooth).Name - $availableDSCResources.Count | Should -Be 2 + $availableDSCResources.Count | Should -Be 3 $availableDSCResources | Where-Object { $expectedDSCResources -notcontains $_ } | Should -BeNullOrEmpty -ErrorAction Stop } } -Describe 'USB' { - It 'Set connection notifications on' { +# Describe 'USB' { +# It 'Set connection notifications on' { +# $desiredState = @{ +# ConnectionNotifications = $true +# } +# Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + +# $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} +# $finalState.ConnectionNotifications | Should -Be $true +# } + +# It 'Set slow charging notification off' { +# $desiredState = @{ +# SlowChargingNotification = $false +# } +# Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + +# $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} +# $finalState.SlowChargingNotification | Should -Be $false +# } + +# It 'Set battery saver on' { +# $desiredState = @{ +# BatterySaver = $true +# } +# Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + +# $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} +# $finalState.BatterySaver | Should -Be $true +# } +# } + +# Describe 'PenWindowsInk' { +# It 'Set finger tip font to SegoeUI' { +# $desiredState = @{ +# FingerTipFont = 'SegoeUI' +# } +# Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + +# $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} +# $finalState.FingerTipFont | Should -Be 'SegoeUI' +# } + +# It 'Set write with your finger tip off' { +# $desiredState = @{ +# WriteFingerTip = $false +# } +# Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + +# $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} +# $finalState.WriteFingerTip | Should -Be $false +# } +# } + +Describe 'Mouse' { + BeforeAll { + $class = [Mouse]::new() + + $script:currentState = $class.Get() + Write-Verbose -Message ('Current mouse settings') -Verbose + Write-Verbose -Message ($script:currentState | ConvertTo-Json | Out-String) -Verbose + } + It 'Set cursor speed to 15' { $desiredState = @{ - ConnectionNotifications = $true + CursorSpeed = 15 } - Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} - $finalState.ConnectionNotifications | Should -Be $true + $finalState = Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.CursorSpeed | Should -Be 15 } - It 'Set slow charging notification off' { + It 'Should throw error when cursor speed is higher than 20' { $desiredState = @{ - SlowChargingNotification = $false + CursorSpeed = 21 } - Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + { Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState } | Should -Throw + } - $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} - $finalState.SlowChargingNotification | Should -Be $false + It 'Should set primary button to right' { + $desiredState = @{ + PrimaryButton = 'Right' + } + Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.PrimaryButton | Should -Be 'Right' } - It 'Set battery saver on' { + It 'Should set the pointer precision off' { $desiredState = @{ - BatterySaver = $true + PointerPrecision = $false } - Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} - $finalState.BatterySaver | Should -Be $true + $finalState = Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.PointerPrecision | Should -Be $false } -} -Describe 'PenWindowsInk' { - It 'Set finger tip font to SegoeUI' { + It 'Should set the mouse scroll to single screen at time' { $desiredState = @{ - FingerTipFont = 'SegoeUI' + RollMouseScroll = $false } - Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} - $finalState.FingerTipFont | Should -Be 'SegoeUI' + $finalState = Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.RollMouseScroll | Should -Be $false + $finalState.LinesToScroll | Should -Be -1 } - It 'Set write with your finger tip off' { + It 'Should set the mouse scroll length even lines to scroll are set to 5' { $desiredState = @{ - WriteFingerTip = $false + RollMouseScroll = $false + LinesToScroll = 5 } - Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} - $finalState.WriteFingerTip | Should -Be $false + $finalState = Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.LinesToScroll | Should -Be -1 } -} + + It 'Should set the mouse scroll length to 5' { + $desiredState = @{ + RollMouseScroll = $true + LinesToScroll = 5 + } + Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.LinesToScroll | Should -Be 5 + } + + It 'Should set the scroll inactive window' { + $desiredState = @{ + ScrollInactiveWindows = $true + } + Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.ScrollInactiveWindows | Should -Be $true + } + + It 'Should set the scroll direction to up' { + $desiredState = @{ + ScrollDirection = 'Up' + } + Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.ScrollDirection | Should -Be 'Up' + } + + AfterAll { + Write-Verbose -Message ('Restoring mouse settings to original state with') -Verbose + Write-Verbose -Message ($script:currentState | ConvertTo-Json | Out-String) -Verbose + $currentState.Set() + } +} \ No newline at end of file From a3e09d7d9d1b28a38745068b717e77c6f057047b Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:20:32 +0100 Subject: [PATCH 04/21] Add first synopsis --- .../Microsoft.Windows.Setting.Bluetooth.psm1 | 81 +++++++++++++ ...rosoft.Windows.Setting.Bluetooth.Tests.ps1 | 106 +++++++++--------- 2 files changed, 134 insertions(+), 53 deletions(-) diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index ce824f50..0094aa04 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -303,6 +303,7 @@ function Set-MouseScrollLines { [switch] $Enable, [Parameter()] + [ValidateRange(1, 100)] [int] $Lines ) @@ -414,6 +415,27 @@ function Set-MouseSetting { #endregion Functions #region Classes +<# +.SYNOPSIS + The `USB` class is a DSC resource that allows you to manage the USB settings on your Windows device. + +.PARAMETER SID + The security identifier. This is a key property and should not be set manually. + +.PARAMETER ConnectionNotifications + Show a notification if there are issues connection to a USB device. + +.PARAMETER SlowChargingNotification + Will show a notification if the PC is charging slowly over USB. + +.PARAMETER BatterySaver + Stops USB devices from draining power when the screen is off. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name USB -Method Set -Property @{ ConnectionNotifications = $false } + + This example sets the `ConnectionNotifications` property to `$false`. +#> [DscResource()] class USB { [DscProperty(Key)] @@ -512,6 +534,21 @@ class USB { #endregion USB helper functions } +<# +.SYNOPSIS + The `PenWindowsInk` class is a DSC resource that allows you to manage the Pen and Windows Ink settings on your Windows device. + +.PARAMETER FingerTipFont + The font used for the finger tip. + +.PARAMETER WriteFingerTip + Enable inking with touch. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name PenWindowsInk -Method Set -Property @{ FingerTipFont = 'SegoeUI' } + + This example sets the `FingerTipFont` property to `SegoeUI`. +#> [DscResource()] class PenWindowsInk { [DscProperty(Key)] @@ -599,6 +636,50 @@ class PenWindowsInk { #endregion PenWindowsInk helper functions } +<# + +.SYNOPSIS + The `Mouse` class is a DSC resource that allows you to manage the mouse settings on your Windows device. + +.PARAMETER SID + The security identifier. This is a key property and should not be set manually. + +.PARAMETER PrimaryButton + The primary button of the mouse. This can be either `Left` or `Right`. + +.PARAMETER CursorSpeed + The cursor speed of the mouse. This value should be between `1` and `20`. + +.PARAMETER PointerPrecision + The pointer precision of the mouse. + +.PARAMETER RollMouseScroll + The roll mouse scroll of the mouse. When using in combination with `LinesToScroll`, this will enable or disable the lines to scroll at a time. + +.PARAMETER LinesToScroll + The number of lines to scroll. This value should be between `1` and `100`. + +.PARAMETER ScrollInactiveWindows + The scroll inactive windows when hovering over them. + +.PARAMETER ScrollDirection + The motion to scroll down or up. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name Mouse -Method Set -Property @{ PrimaryButton = 'Right' } + + This example sets the `PrimaryButton` property to `Right`. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name Mouse -Method Set -Property @{ PointerPrecision = $true } + + This example sets the `PointerPrecision` property to `$true`. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name Mouse -Method Set -Property @{ RollMouseScroll = $true; LinesToScroll = 3 } + + This example sets the `RollMouseScroll` property to `$true` and the `LinesToScroll` property to `3`. +#> [DscResource()] class Mouse { diff --git a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 index a9381fd7..9bafaf0c 100644 --- a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 @@ -27,59 +27,59 @@ Describe 'List available DSC resources' { } } -# Describe 'USB' { -# It 'Set connection notifications on' { -# $desiredState = @{ -# ConnectionNotifications = $true -# } -# Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - -# $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} -# $finalState.ConnectionNotifications | Should -Be $true -# } - -# It 'Set slow charging notification off' { -# $desiredState = @{ -# SlowChargingNotification = $false -# } -# Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - -# $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} -# $finalState.SlowChargingNotification | Should -Be $false -# } - -# It 'Set battery saver on' { -# $desiredState = @{ -# BatterySaver = $true -# } -# Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - -# $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} -# $finalState.BatterySaver | Should -Be $true -# } -# } - -# Describe 'PenWindowsInk' { -# It 'Set finger tip font to SegoeUI' { -# $desiredState = @{ -# FingerTipFont = 'SegoeUI' -# } -# Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - -# $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} -# $finalState.FingerTipFont | Should -Be 'SegoeUI' -# } - -# It 'Set write with your finger tip off' { -# $desiredState = @{ -# WriteFingerTip = $false -# } -# Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - -# $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} -# $finalState.WriteFingerTip | Should -Be $false -# } -# } +Describe 'USB' { + It 'Set connection notifications on' { + $desiredState = @{ + ConnectionNotifications = $true + } + Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.ConnectionNotifications | Should -Be $true + } + + It 'Set slow charging notification off' { + $desiredState = @{ + SlowChargingNotification = $false + } + Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.SlowChargingNotification | Should -Be $false + } + + It 'Set battery saver on' { + $desiredState = @{ + BatterySaver = $true + } + Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name USB -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.BatterySaver | Should -Be $true + } +} + +Describe 'PenWindowsInk' { + It 'Set finger tip font to SegoeUI' { + $desiredState = @{ + FingerTipFont = 'SegoeUI' + } + Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.FingerTipFont | Should -Be 'SegoeUI' + } + + It 'Set write with your finger tip off' { + $desiredState = @{ + WriteFingerTip = $false + } + Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name PenWindowsInk -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.WriteFingerTip | Should -Be $false + } +} Describe 'Mouse' { BeforeAll { From f3afed4ce9ae1724feafa622656e26bef25c48c1 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:29:24 +0100 Subject: [PATCH 05/21] Markdown file USB --- .../USB.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 resources/Help/Microsoft.Windows.Setting.Bluetooth/USB.md diff --git a/resources/Help/Microsoft.Windows.Setting.Bluetooth/USB.md b/resources/Help/Microsoft.Windows.Setting.Bluetooth/USB.md new file mode 100644 index 00000000..88be2349 --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Bluetooth/USB.md @@ -0,0 +1,37 @@ +--- +external help file: Microsoft.Windows.Setting.Bluetooth-Help.xml +Module Name: Microsoft.Windows.Setting.Bluetooth +ms.date: 01/19/2025 +online version: +schema: 2.0.0 +title: USB +--- + +# USB + +## SYNOPSIS + +The `USB` DSC Resource allows you to manage USB settings on Windows. + +## DESCRIPTION + +The `USB` DSC Resource allows you to manage USB settings on Windows. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| -------------------------- | ------------- | ------------ | ------------------------------------------------------------------------------- | ------------------ | +| `SID` | Key | String | The security identifier. This is a key property and should not be set manually. | | +| `ConnectionNotifications` | Optional | Boolean | Show a notification if there are issues connection to a USB device. | `$true`, `$false` | +| `SlowChargingNotification` | Optional | Boolean | Will show a notification if the PC is charging slowly over USB. | `$true`, `$false` | +| `BatterySaver` | Optional | Boolean | Stops USB devices from draining power when the screen is off. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 - Disable notification when there are issues connection a USB device + +```powershell +Invoke-DscResource -Name USB -Method Set -Property @{ ConnectionNotifications = $false } + +# This example sets the `ConnectionNotifications` property to `$false`. +``` From 20b27ab69112d18c9cafe8c470487ede9791f4cc Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:32:19 +0100 Subject: [PATCH 06/21] Markdown file PenWindowsInk --- .github/actions/spelling/allow.txt | 2 +- .../PenWindowsInk.md | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 resources/Help/Microsoft.Windows.Setting.Bluetooth/PenWindowsInk.md diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 1c720079..ea3210e7 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -67,4 +67,4 @@ websites wekyb Hmmss MMdd -MMdd \ No newline at end of file +Segoe \ No newline at end of file diff --git a/resources/Help/Microsoft.Windows.Setting.Bluetooth/PenWindowsInk.md b/resources/Help/Microsoft.Windows.Setting.Bluetooth/PenWindowsInk.md new file mode 100644 index 00000000..ebba4b88 --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Bluetooth/PenWindowsInk.md @@ -0,0 +1,35 @@ +--- +external help file: Microsoft.Windows.Setting.Bluetooth-Help.xml +Module Name: Microsoft.Windows.Setting.Bluetooth +ms.date: 01/19/2025 +online version: +schema: 2.0.0 +title: PenWindowsInk +--- + +# PenWindowsInk + +## SYNOPSIS + +The `PenWindowsInk` class is a DSC resource that allows you to manage the Pen and Windows Ink settings on your Windows device. + +## DESCRIPTION + +The `PenWindowsInk` class is a DSC resource that allows you to manage the Pen and Windows Ink settings on your Windows device. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| ---------------- | ------------- | ------------ | --------------------------------- | ---------------------- | +| `FingerTipFont` | Key | String | The font used for the finger tip. | `InkFree` or `SegeoUI` | +| `WriteFingerTip` | Optional | Boolean | Enable inking with touch. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 - Sets the finger tip font to Segeo UI + +```powershell +Invoke-DscResource -Name PenWindowsInk -Method Set -Property @{ FingerTipFont = 'SegoeUI' } + +# This example sets the `FingerTipFont` property to `SegoeUI`. +``` From fdbe2f332b771a05ac8cf26f585ba3d3249dfd7a Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:38:43 +0100 Subject: [PATCH 07/21] Markdown file Mouse --- .../Mouse.md | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 resources/Help/Microsoft.Windows.Setting.Bluetooth/Mouse.md diff --git a/resources/Help/Microsoft.Windows.Setting.Bluetooth/Mouse.md b/resources/Help/Microsoft.Windows.Setting.Bluetooth/Mouse.md new file mode 100644 index 00000000..edb81168 --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Bluetooth/Mouse.md @@ -0,0 +1,57 @@ +--- +external help file: Microsoft.Windows.Setting.Bluetooth-Help.xml +Module Name: Microsoft.Windows.Setting.Bluetooth +ms.date: 01/19/2025 +online version: +schema: 2.0.0 +title: Mouse +--- + +# Mouse + +## SYNOPSIS + +The `Mouse` class is a DSC resource that allows you to manage the mouse settings on your Windows device. + +## DESCRIPTION + +The `Mouse` class is a DSC resource that allows you to manage the mouse settings on your Windows device. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| ----------------------- | ------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | +| `SID` | Key | String | The security identifier. This is a key property and should not be set manually. | | +| `PrimaryButton` | Optional | PrimaryButton | The primary button of the mouse. This can be either `Left` or `Right`. | `Left` or `Right` | +| `CursorSpeed` | Optional | Integer | The cursor speed of the mouse. | Between `1` and `20`. | +| `PointerPrecision` | Optional | Boolean | The pointer precision of the mouse. | `$true`, `$false` | +| `RollMouseScroll` | Optional | Boolean | The roll mouse scroll of the mouse. When using in combination with `LinesToScroll`, this will enable or disable the lines to scroll at a time. | `$true`, `$false` | +| `LinesToScroll` | Optional | Integer | The number of lines to scroll. This value should be between `1` and `100`. | Between `1` and `100` | +| `ScrollInactiveWindows` | Optional | Boolean | The scroll inactive windows when hovering over them. | `$true`, `$false` | +| `ScrollDirection` | Optional | Boolean | The motion to scroll down or up. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 - Set the mouse button to right + +```powershell +Invoke-DscResource -Name Mouse -Method Set -Property @{ PrimaryButton = 'Right' } + +# This example sets the `PrimaryButton` property to `Right`. +``` + +### EXAMPLE 2 - Enable the pointer precision + +```powershell +Invoke-DscResource -Name Mouse -Method Set -Property @{ PointerPrecision = $true } + +# This example sets the `PointerPrecision` property to `$true`. +``` + +### EXAMPLE 3 - Set the lines to scroll to 3 + +```powershell +Invoke-DscResource -Name Mouse -Method Set -Property @{ RollMouseScroll = $true; LinesToScroll = 3 } + +# This example sets the `RollMouseScroll` property to `$true` and the `LinesToScroll` property to `3`. +``` \ No newline at end of file From ab7570ae011cd65a9abda54fc34f0cc224d05e85 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:39:22 +0100 Subject: [PATCH 08/21] Typo --- .../Microsoft.Windows.Setting.Bluetooth.psm1 | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index 0094aa04..f0a3367e 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -637,7 +637,6 @@ class PenWindowsInk { } <# - .SYNOPSIS The `Mouse` class is a DSC resource that allows you to manage the mouse settings on your Windows device. From a725f3f3176761309fbf32f99c7d5e04157360cf Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:41:40 +0100 Subject: [PATCH 09/21] Remove line end --- resources/Help/Microsoft.Windows.Setting.Bluetooth/Mouse.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/Help/Microsoft.Windows.Setting.Bluetooth/Mouse.md b/resources/Help/Microsoft.Windows.Setting.Bluetooth/Mouse.md index edb81168..cc4b45b6 100644 --- a/resources/Help/Microsoft.Windows.Setting.Bluetooth/Mouse.md +++ b/resources/Help/Microsoft.Windows.Setting.Bluetooth/Mouse.md @@ -54,4 +54,4 @@ Invoke-DscResource -Name Mouse -Method Set -Property @{ PointerPrecision = $true Invoke-DscResource -Name Mouse -Method Set -Property @{ RollMouseScroll = $true; LinesToScroll = 3 } # This example sets the `RollMouseScroll` property to `$true` and the `LinesToScroll` property to `3`. -``` \ No newline at end of file +``` From 0816f3ae333cc559f761c57259a853617744af17 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:42:16 +0100 Subject: [PATCH 10/21] Resolve spelling --- .github/actions/spelling/allow.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index ea3210e7..16fa30ad 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -67,4 +67,13 @@ websites wekyb Hmmss MMdd -Segoe \ No newline at end of file +GETTOUCHPADPARAMETERS +lpv +PInvoke +Ptr +Segeo +Segoe +touchpad +Usb +vparam +WFingertip \ No newline at end of file From 5420a14320c57e036df85f13ad5efa656857daf7 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:43:24 +0100 Subject: [PATCH 11/21] Resolve spelling --- .github/actions/spelling/allow.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 16fa30ad..f057fa99 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -76,4 +76,5 @@ Segoe touchpad Usb vparam +WFingertip WFingertip \ No newline at end of file From 7718edcea802db6f221a3864111771350a3abf2f Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Sun, 19 Jan 2025 14:48:40 +0100 Subject: [PATCH 12/21] Remove unnecessary file --- test.ps1 | 70 -------------------------------------------------------- 1 file changed, 70 deletions(-) delete mode 100644 test.ps1 diff --git a/test.ps1 b/test.ps1 deleted file mode 100644 index a60ee820..00000000 --- a/test.ps1 +++ /dev/null @@ -1,70 +0,0 @@ -function Get-MouseSpeed() { - - $MethodDefinition = @' - [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] - public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref uint pvParam, uint fWinIni); -'@ - $User32 = Add-Type -MemberDefinition $MethodDefinition -Name 'User32Get' -Namespace Win32Functions -PassThru - - [Int32] $ScrollLines = 0 - $User32::SystemParametersInfo(0x0068, 0, [ref]$ScrollLines, 0) | Out-Null - return $ScrollLines -} - - -function Set-MouseScrollLines { - param ( - [Parameter()] - [switch] $Enable, - - [Parameter()] - [int] $Lines - ) - - $MethodDefinition = @' - [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] - public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref uint pvParam, uint fWinIni); -'@ - $User32 = Add-Type -MemberDefinition $MethodDefinition -Name 'User32MouseScrollLines' -Namespace Win32Functions -PassThru - - if (-not ($Enable.IsPresent)) { - # If the -Enable switch is not present, we set the number to -1, meaning one screen at a time - $Lines = -1 - } - - # Action: SPI_SETWHEELSCROLLLINES - $Action = 0x0069 - $UpdateIniFile = 0x01 - $SendChangeEvent = 0x02 - - $Options = $UpdateIniFile -bor $SendChangeEvent - $Res = $User32::SystemParametersInfo($Action, $Lines, 0, $Options) - - if ($Res -ne 1) { - throw [System.Configuration.ConfigurationException]::new('Failed to set the number of lines to scroll.') - } -} - -Add-Type -TypeDefinition @' -using System; -using System.Runtime.InteropServices; - -public class SystemParameters -{ - [DllImport("User32.dll",CharSet=CharSet.Unicode)] - public static extern int SystemParametersInfo( - Int32 uAction, - Int32 uParam, - String lpvParam, - Int32 fuWinIni); -} -'@ - -# 0x0014 = SPI_SETDESKWALLPAPER -$setWallpaperAction = 0x0069 -$UpdateIniFile = 0x01 -$SendChangeEvent = 0x02 - -$options = $UpdateIniFile -bor $SendChangeEvent - -[SystemParameters]::SystemParametersInfo($setWallpaperAction, -1, 0, $options) \ No newline at end of file From 9802b455df92f3c4457d1b8051a2844222ba792d Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Mon, 20 Jan 2025 11:56:08 +0100 Subject: [PATCH 13/21] New MobileDevices class --- .../MobileDevices.md | 37 +++++ .../Microsoft.Windows.Setting.Bluetooth.psd1 | 6 +- .../Microsoft.Windows.Setting.Bluetooth.psm1 | 139 +++++++++++++++++- ...rosoft.Windows.Setting.Bluetooth.Tests.ps1 | 52 +++++-- 4 files changed, 214 insertions(+), 20 deletions(-) create mode 100644 resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevices.md diff --git a/resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevices.md b/resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevices.md new file mode 100644 index 00000000..e6019c1f --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevices.md @@ -0,0 +1,37 @@ +--- +external help file: Microsoft.Windows.Setting.Bluetooth-Help.xml +Module Name: Microsoft.Windows.Setting.Bluetooth +ms.date: 01/19/2025 +online version: +schema: 2.0.0 +title: MobileDevices +--- + +# MobileDevices + +## SYNOPSIS + +The `MobileDevices` class is a DSC resource that allows you to manage the mobile devices settings on your Windows device. + +## DESCRIPTION + +The `MobileDevices` class is a DSC resource that allows you to manage the mobile devices settings on your Windows device. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| -------------------------- | ------------- | ------------ | ------------------------------------------------------------------------------- | ------------------ | +| `SID` | Key | String | The security identifier. This is a key property and should not be set manually. | | +| `AccessMobileDevice` | Optional | Boolean | Allow this PC to access the mobile device. | `$true`, `$false` | +| `PhoneLinkAccess` | Optional | Boolean | Allow access to Phone Link. For more information: https://support.microsoft.com/en-us/phone-link | `$true`, `$false` | +| `ShowMobileDeviceSuggestions` | Optional | Boolean | Show mobile device suggestions. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 - Allow your PC to access your mobile device + +```powershell +Invoke-DscResource -Name MobileDevices -Method Set -Property @{ AccessMobileDevice = $true } + +# This example allows your mobile devices to be accessed by your PC. +``` diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 index 1736cb89..5bbf1d8a 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 @@ -10,7 +10,8 @@ DscResourcesToExport = @( 'USB', 'PenWindowsInk', - 'Mouse' + 'Mouse', + 'MobileDevices' ) PrivateData = @{ PSData = @{ @@ -18,7 +19,8 @@ Tags = @( 'PSDscResource_USB', 'PSDscResource_PenWindowsInk', - 'PSDscResource_Mouse' + 'PSDscResource_Mouse', + 'PSDscResource_MobileDevices' ) # Prerelease string of this module diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index f0a3367e..fe6fe985 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -10,6 +10,7 @@ if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { $global:TabletTipPath = 'HKCU:\Software\Microsoft\TabletTip\EmbeddedInkControl\' $global:MousePath = 'HKCU:\Control Panel\Mouse\' $global:DesktopPath = 'HKCU:\Control Panel\Desktop\' + $global:MobilityPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Mobility\' } else { $global:USBShellPath = $global:USBMachinePath = $global:TabletTipPath = $global:MousePath = $global:DesktopPath = $env:TestRegistryPath } @@ -182,12 +183,12 @@ public static extern bool SwapMouseButton(bool swap); } 'ScrollLines' { Add-Type -TypeDefinition @' -using System; +using System; using System.Runtime.InteropServices; - + public class ScrollLines -{ - [DllImport("User32.dll",CharSet=CharSet.Unicode)] +{ + [DllImport("User32.dll",CharSet=CharSet.Unicode)] public static extern int SystemParametersInfo( Int32 uAction, Int32 uParam, @@ -264,7 +265,7 @@ function Set-PrimaryButton { function Set-MouseSpeed() { param( [Parameter(ValueFromPipeline = $true)] - [ValidateRange(1, 20)] + [ValidateRange(1, 20)] [int] $Speed = 10 ) @@ -301,7 +302,7 @@ function Set-MouseScrollLines { param ( [Parameter()] [switch] $Enable, - + [Parameter()] [ValidateRange(1, 100)] [int] $Lines @@ -316,7 +317,7 @@ function Set-MouseScrollLines { # If the -Enable switch is not present, we set the number to -1, meaning one screen at a time $Lines = -1 } - + # Action: SPI_SETWHEELSCROLLLINES $Action = 0x0069 $UpdateIniFile = 0x01 @@ -650,7 +651,7 @@ class PenWindowsInk { The cursor speed of the mouse. This value should be between `1` and `20`. .PARAMETER PointerPrecision - The pointer precision of the mouse. + The pointer precision of the mouse. .PARAMETER RollMouseScroll The roll mouse scroll of the mouse. When using in combination with `LinesToScroll`, this will enable or disable the lines to scroll at a time. @@ -848,6 +849,128 @@ class Mouse { #endregion Mouse helper functions } +<# +.SYNOPSIS + The `MobileDevices` class is a DSC resource that allows you to manage the mobile devices settings on your Windows device. + +.PARAMETER SID + The security identifier. This is a key property and should not be set manually. + +.PARAMETER AccessMobileDevice + Allow this PC to access the mobile device. + +.PARAMETER PhoneLinkAccess + Allow access to Phone Link. For more information: https://support.microsoft.com/en-us/phone-link + +.PARAMETER ShowMobileDeviceSuggestions + Show mobile device suggestions. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name MobileDevices -Method Set -Property @{ AccessMobileDevice = $true } + + This example allows your mobile devices to be accessed by your PC. +#> +[DscResource()] +class MobileDevices { + [DscProperty(Key)] + [string]$SID + + [DscProperty()] + [nullable[bool]] $AccessMobileDevice + + [DscProperty()] + [nullable[bool]] $PhoneLinkAccess + + [DscProperty()] + [nullable[bool]] $ShowMobileDeviceSuggestions + + static hidden [string] $AccessMobileDeviceProperty = 'CrossDeviceEnabled' + static hidden [string] $PhoneLinkAccessProperty = 'PhoneLinkEnabled' + static hidden [string] $ShowMobileDeviceSuggestionsProperty = 'OptedIn' + + [MobileDevices] Get() { + $currentState = [MobileDevices]::new() + $currentState.AccessMobileDevice = [MobileDevices]::GetAccessMobileDeviceStatus() + $currentState.PhoneLinkAccess = [MobileDevices]::GetPhoneLinkAccessStatus() + $currentState.ShowMobileDeviceSuggestions = [MobileDevices]::GetShowMobileDeviceSuggestionsStatus() + + return $currentState + } + + [bool] Test() { + $currentState = $this.Get() + + if (($null -ne $this.AccessMobileDevice) -and ($this.AccessMobileDevice -ne $currentState.AccessMobileDevice)) { + return $false + } + + if (($null -ne $this.PhoneLinkAccess) -and ($this.PhoneLinkAccess -ne $currentState.PhoneLinkAccess)) { + return $false + } + + if (($null -ne $this.ShowMobileDeviceSuggestions) -and ($this.ShowMobileDeviceSuggestions -ne $currentState.ShowMobileDeviceSuggestions)) { + return $false + } + + return $true + } + + [void] Set() { + if (-not ($this.Test())) { + if ($null -ne $this.AccessMobileDevice) { + if (-not (DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty))) { + New-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty) -Value ([int]$this.AccessMobileDevice) -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty) -Value ([int]$this.AccessMobileDevice) + } + + if ($null -ne $this.PhoneLinkAccess) { + if (-not (DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty))) { + New-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty) -Value ([int]$this.PhoneLinkAccess) -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty) -Value ([int]$this.PhoneLinkAccess) + } + + if ($null -ne $this.ShowMobileDeviceSuggestions) { + if (-not (DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty))) { + New-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty) -Value ([int]$this.ShowMobileDeviceSuggestions) -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty) -Value ([int]$this.ShowMobileDeviceSuggestions) + } + } + } + + #region MobileDevices helper functions + static [bool] GetAccessMobileDeviceStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty))) { + return $false + } else { + $AccessMobileDeviceStatus = (Get-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty)).CrossDeviceEnabled + return ($AccessMobileDeviceStatus -eq 1) + } + } + + static [bool] GetPhoneLinkAccessStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty))) { + return $false + } else { + $PhoneLinkAccessStatus = (Get-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty)).PhoneLinkEnabled + return ($PhoneLinkAccessStatus -eq 1) + } + } + + static [bool] GetShowMobileDeviceSuggestionsStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty))) { + return $false + } else { + $ShowMobileDeviceSuggestionsStatus = (Get-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty)).OptedIn + return ($ShowMobileDeviceSuggestionsStatus -eq 1) + } + } + + #endregion MobileDevices helper functions +} + # TODO: Does not work (yet). Check comments in Get-TouchpadSettings function. # [DscResource()] # class Touchpad { diff --git a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 index 9bafaf0c..71e2bde0 100644 --- a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 @@ -83,7 +83,7 @@ Describe 'PenWindowsInk' { Describe 'Mouse' { BeforeAll { - $class = [Mouse]::new() + $class = [Mouse]::new() $script:currentState = $class.Get() Write-Verbose -Message ('Current mouse settings') -Verbose @@ -106,7 +106,7 @@ Describe 'Mouse' { { Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState } | Should -Throw } - It 'Should set primary button to right' { + It 'Set primary button to right' { $desiredState = @{ PrimaryButton = 'Right' } @@ -116,7 +116,7 @@ Describe 'Mouse' { $finalState.PrimaryButton | Should -Be 'Right' } - It 'Should set the pointer precision off' { + It 'Set the pointer precision off' { $desiredState = @{ PointerPrecision = $false } @@ -126,7 +126,7 @@ Describe 'Mouse' { $finalState.PointerPrecision | Should -Be $false } - It 'Should set the mouse scroll to single screen at time' { + It 'Set the mouse scroll to single screen at time' { $desiredState = @{ RollMouseScroll = $false } @@ -137,9 +137,9 @@ Describe 'Mouse' { $finalState.LinesToScroll | Should -Be -1 } - It 'Should set the mouse scroll length even lines to scroll are set to 5' { + It 'Set the mouse scroll length even lines to scroll are set to 5' { $desiredState = @{ - RollMouseScroll = $false + RollMouseScroll = $false LinesToScroll = 5 } Invoke-DscResource -Name Mouse -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState @@ -148,7 +148,7 @@ Describe 'Mouse' { $finalState.LinesToScroll | Should -Be -1 } - It 'Should set the mouse scroll length to 5' { + It 'Set the mouse scroll length to 5' { $desiredState = @{ RollMouseScroll = $true LinesToScroll = 5 @@ -159,7 +159,7 @@ Describe 'Mouse' { $finalState.LinesToScroll | Should -Be 5 } - It 'Should set the scroll inactive window' { + It 'Set the scroll inactive window' { $desiredState = @{ ScrollInactiveWindows = $true } @@ -169,7 +169,7 @@ Describe 'Mouse' { $finalState.ScrollInactiveWindows | Should -Be $true } - It 'Should set the scroll direction to up' { + It 'Set the scroll direction to up' { $desiredState = @{ ScrollDirection = 'Up' } @@ -184,4 +184,36 @@ Describe 'Mouse' { Write-Verbose -Message ($script:currentState | ConvertTo-Json | Out-String) -Verbose $currentState.Set() } -} \ No newline at end of file +} + +Describe 'MobileDevices' { + It 'Set mobile devices access to this PC' { + $desiredState = @{ + AccessMobileDevice = $true + } + Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.AccessMobileDevice | Should -Be $true + } + + It 'Set Phone Link on' { + $desiredState = @{ + PhoneLinkAccess = $true + } + Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.PhoneLinkAccess | Should -Be $true + } + + It 'Set the suggestion for mobile device to Windows' { + $desiredState = @{ + ShowMobileDeviceSuggestions = $true + } + Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.ShowMobileDeviceSuggestions | Should -Be $true + } +} From c4cbce708fc04a0f5970f75c85be826e6d5aa4a2 Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Mon, 20 Jan 2025 13:55:39 +0100 Subject: [PATCH 14/21] Rename MobileDevices to MobileDevice --- .../{MobileDevices.md => MobileDevice.md} | 10 ++-- .../Microsoft.Windows.Setting.Bluetooth.psd1 | 4 +- .../Microsoft.Windows.Setting.Bluetooth.psm1 | 50 +++++++++---------- ...rosoft.Windows.Setting.Bluetooth.Tests.ps1 | 14 +++--- 4 files changed, 39 insertions(+), 39 deletions(-) rename resources/Help/Microsoft.Windows.Setting.Bluetooth/{MobileDevices.md => MobileDevice.md} (78%) diff --git a/resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevices.md b/resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevice.md similarity index 78% rename from resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevices.md rename to resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevice.md index e6019c1f..d69d6b42 100644 --- a/resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevices.md +++ b/resources/Help/Microsoft.Windows.Setting.Bluetooth/MobileDevice.md @@ -4,18 +4,18 @@ Module Name: Microsoft.Windows.Setting.Bluetooth ms.date: 01/19/2025 online version: schema: 2.0.0 -title: MobileDevices +title: MobileDevice --- -# MobileDevices +# MobileDevice ## SYNOPSIS -The `MobileDevices` class is a DSC resource that allows you to manage the mobile devices settings on your Windows device. +The `MobileDevice` class is a DSC resource that allows you to manage the mobile devices settings on your Windows device. ## DESCRIPTION -The `MobileDevices` class is a DSC resource that allows you to manage the mobile devices settings on your Windows device. +The `MobileDevice` class is a DSC resource that allows you to manage the mobile devices settings on your Windows device. ## PARAMETERS @@ -31,7 +31,7 @@ The `MobileDevices` class is a DSC resource that allows you to manage the mobile ### EXAMPLE 1 - Allow your PC to access your mobile device ```powershell -Invoke-DscResource -Name MobileDevices -Method Set -Property @{ AccessMobileDevice = $true } +Invoke-DscResource -Name MobileDevice -Method Set -Property @{ AccessMobileDevice = $true } # This example allows your mobile devices to be accessed by your PC. ``` diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 index 5bbf1d8a..ebc58e17 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 @@ -11,7 +11,7 @@ 'USB', 'PenWindowsInk', 'Mouse', - 'MobileDevices' + 'MobileDevice' ) PrivateData = @{ PSData = @{ @@ -20,7 +20,7 @@ 'PSDscResource_USB', 'PSDscResource_PenWindowsInk', 'PSDscResource_Mouse', - 'PSDscResource_MobileDevices' + 'PSDscResource_MobileDevice' ) # Prerelease string of this module diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index fe6fe985..47ccff99 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -851,7 +851,7 @@ class Mouse { <# .SYNOPSIS - The `MobileDevices` class is a DSC resource that allows you to manage the mobile devices settings on your Windows device. + The `MobileDevice` class is a DSC resource that allows you to manage the mobile devices settings on your Windows device. .PARAMETER SID The security identifier. This is a key property and should not be set manually. @@ -866,12 +866,12 @@ class Mouse { Show mobile device suggestions. .EXAMPLE - PS C:\> Invoke-DscResource -Name MobileDevices -Method Set -Property @{ AccessMobileDevice = $true } + PS C:\> Invoke-DscResource -Name MobileDevice -Method Set -Property @{ AccessMobileDevice = $true } This example allows your mobile devices to be accessed by your PC. #> [DscResource()] -class MobileDevices { +class MobileDevice { [DscProperty(Key)] [string]$SID @@ -888,11 +888,11 @@ class MobileDevices { static hidden [string] $PhoneLinkAccessProperty = 'PhoneLinkEnabled' static hidden [string] $ShowMobileDeviceSuggestionsProperty = 'OptedIn' - [MobileDevices] Get() { - $currentState = [MobileDevices]::new() - $currentState.AccessMobileDevice = [MobileDevices]::GetAccessMobileDeviceStatus() - $currentState.PhoneLinkAccess = [MobileDevices]::GetPhoneLinkAccessStatus() - $currentState.ShowMobileDeviceSuggestions = [MobileDevices]::GetShowMobileDeviceSuggestionsStatus() + [MobileDevice] Get() { + $currentState = [MobileDevice]::new() + $currentState.AccessMobileDevice = [MobileDevice]::GetAccessMobileDevicetatus() + $currentState.PhoneLinkAccess = [MobileDevice]::GetPhoneLinkAccessStatus() + $currentState.ShowMobileDeviceSuggestions = [MobileDevice]::GetShowMobileDeviceSuggestionsStatus() return $currentState } @@ -918,57 +918,57 @@ class MobileDevices { [void] Set() { if (-not ($this.Test())) { if ($null -ne $this.AccessMobileDevice) { - if (-not (DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty))) { - New-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty) -Value ([int]$this.AccessMobileDevice) -PropertyType DWord | Out-Null + if (-not (DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevice]::AccessMobileDeviceProperty))) { + New-ItemProperty -Path $global:MobilityPath -Name ([MobileDevice]::AccessMobileDeviceProperty) -Value ([int]$this.AccessMobileDevice) -PropertyType DWord | Out-Null } - Set-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty) -Value ([int]$this.AccessMobileDevice) + Set-ItemProperty -Path $global:MobilityPath -Name ([MobileDevice]::AccessMobileDeviceProperty) -Value ([int]$this.AccessMobileDevice) } if ($null -ne $this.PhoneLinkAccess) { - if (-not (DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty))) { - New-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty) -Value ([int]$this.PhoneLinkAccess) -PropertyType DWord | Out-Null + if (-not (DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevice]::PhoneLinkAccessProperty))) { + New-ItemProperty -Path $global:MobilityPath -Name ([MobileDevice]::PhoneLinkAccessProperty) -Value ([int]$this.PhoneLinkAccess) -PropertyType DWord | Out-Null } - Set-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty) -Value ([int]$this.PhoneLinkAccess) + Set-ItemProperty -Path $global:MobilityPath -Name ([MobileDevice]::PhoneLinkAccessProperty) -Value ([int]$this.PhoneLinkAccess) } if ($null -ne $this.ShowMobileDeviceSuggestions) { - if (-not (DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty))) { - New-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty) -Value ([int]$this.ShowMobileDeviceSuggestions) -PropertyType DWord | Out-Null + if (-not (DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevice]::ShowMobileDeviceSuggestionsProperty))) { + New-ItemProperty -Path $global:MobilityPath -Name ([MobileDevice]::ShowMobileDeviceSuggestionsProperty) -Value ([int]$this.ShowMobileDeviceSuggestions) -PropertyType DWord | Out-Null } - Set-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty) -Value ([int]$this.ShowMobileDeviceSuggestions) + Set-ItemProperty -Path $global:MobilityPath -Name ([MobileDevice]::ShowMobileDeviceSuggestionsProperty) -Value ([int]$this.ShowMobileDeviceSuggestions) } } } - #region MobileDevices helper functions + #region MobileDevice helper functions static [bool] GetAccessMobileDeviceStatus() { - if (-not(DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty))) { + if (-not(DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevice]::AccessMobileDeviceProperty))) { return $false } else { - $AccessMobileDeviceStatus = (Get-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::AccessMobileDeviceProperty)).CrossDeviceEnabled + $AccessMobileDeviceStatus = (Get-ItemProperty -Path $global:MobilityPath -Name ([MobileDevice]::AccessMobileDeviceProperty)).CrossDeviceEnabled return ($AccessMobileDeviceStatus -eq 1) } } static [bool] GetPhoneLinkAccessStatus() { - if (-not(DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty))) { + if (-not(DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevice]::PhoneLinkAccessProperty))) { return $false } else { - $PhoneLinkAccessStatus = (Get-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::PhoneLinkAccessProperty)).PhoneLinkEnabled + $PhoneLinkAccessStatus = (Get-ItemProperty -Path $global:MobilityPath -Name ([MobileDevice]::PhoneLinkAccessProperty)).PhoneLinkEnabled return ($PhoneLinkAccessStatus -eq 1) } } static [bool] GetShowMobileDeviceSuggestionsStatus() { - if (-not(DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty))) { + if (-not(DoesRegistryKeyPropertyExist -Path $global:MobilityPath -Name ([MobileDevice]::ShowMobileDeviceSuggestionsProperty))) { return $false } else { - $ShowMobileDeviceSuggestionsStatus = (Get-ItemProperty -Path $global:MobilityPath -Name ([MobileDevices]::ShowMobileDeviceSuggestionsProperty)).OptedIn + $ShowMobileDeviceSuggestionsStatus = (Get-ItemProperty -Path $global:MobilityPath -Name ([MobileDevice]::ShowMobileDeviceSuggestionsProperty)).OptedIn return ($ShowMobileDeviceSuggestionsStatus -eq 1) } } - #endregion MobileDevices helper functions + #endregion MobileDevice helper functions } # TODO: Does not work (yet). Check comments in Get-TouchpadSettings function. diff --git a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 index 71e2bde0..bd5c9de5 100644 --- a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 @@ -186,14 +186,14 @@ Describe 'Mouse' { } } -Describe 'MobileDevices' { +Describe 'MobileDevice' { It 'Set mobile devices access to this PC' { $desiredState = @{ AccessMobileDevice = $true } - Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + Invoke-DscResource -Name MobileDevice -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - $finalState = Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState = Invoke-DscResource -Name MobileDevice -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} $finalState.AccessMobileDevice | Should -Be $true } @@ -201,9 +201,9 @@ Describe 'MobileDevices' { $desiredState = @{ PhoneLinkAccess = $true } - Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + Invoke-DscResource -Name MobileDevice -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - $finalState = Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState = Invoke-DscResource -Name MobileDevice -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} $finalState.PhoneLinkAccess | Should -Be $true } @@ -211,9 +211,9 @@ Describe 'MobileDevices' { $desiredState = @{ ShowMobileDeviceSuggestions = $true } - Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + Invoke-DscResource -Name MobileDevice -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState - $finalState = Invoke-DscResource -Name MobileDevices -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState = Invoke-DscResource -Name MobileDevice -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} $finalState.ShowMobileDeviceSuggestions | Should -Be $true } } From 95254ac5a04797fdadafbf77fbb1a22057f447ee Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Mon, 20 Jan 2025 14:30:43 +0100 Subject: [PATCH 15/21] New AutoPlay class --- .../Microsoft.Windows.Setting.Bluetooth.psd1 | 6 +- .../Microsoft.Windows.Setting.Bluetooth.psm1 | 143 +++++++++++++++++- ...rosoft.Windows.Setting.Bluetooth.Tests.ps1 | 41 +++++ 3 files changed, 187 insertions(+), 3 deletions(-) diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 index ebc58e17..1d230768 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 @@ -11,7 +11,8 @@ 'USB', 'PenWindowsInk', 'Mouse', - 'MobileDevice' + 'MobileDevice', + 'AutoPlay' ) PrivateData = @{ PSData = @{ @@ -20,7 +21,8 @@ 'PSDscResource_USB', 'PSDscResource_PenWindowsInk', 'PSDscResource_Mouse', - 'PSDscResource_MobileDevice' + 'PSDscResource_MobileDevice', + 'PSDscResource_AutoPlay' ) # Prerelease string of this module diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index 47ccff99..66058448 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -11,8 +11,9 @@ if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { $global:MousePath = 'HKCU:\Control Panel\Mouse\' $global:DesktopPath = 'HKCU:\Control Panel\Desktop\' $global:MobilityPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Mobility\' + $global:AutoPlayPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers\' } else { - $global:USBShellPath = $global:USBMachinePath = $global:TabletTipPath = $global:MousePath = $global:DesktopPath = $env:TestRegistryPath + $global:USBShellPath = $global:USBMachinePath = $global:TabletTipPath = $global:MousePath = $global:DesktopPath = $global:MobilityPath = $global:AutoPlayPath = $env:TestRegistryPath } #region Enums @@ -30,6 +31,24 @@ enum ScrollDirection { Down Up } + +enum RemovableDrive { + KeepCurrentValue + MSStorageSense + MSTakeNoAction + MSOpenFolder + MSPromptEachTime +} + +enum MemoryCard { + KeepCurrentValue + MSPlayMediaOnArrival + MSTakeNoAction + MSOpenFolder + MSPromptEachTime + OneDriveAutoPlay + ImportPhotosAndVideos +} #endregion Enums #region Functions @@ -971,6 +990,128 @@ class MobileDevice { #endregion MobileDevice helper functions } +[DscResource()] +class AutoPlay { + [DscProperty(Key)] + [string]$SID + + [DscProperty()] + [nullable[bool]] $AutoPlay + + [DscProperty()] + [RemovableDrive] $RemovableDriveDefault = [RemovableDrive]::KeepCurrentValue + + [DscProperty()] + [MemoryCard] $MemoryCardDefault = [MemoryCard]::KeepCurrentValue + + static hidden [string] $AutoPlayProperty = 'DisableAutoplay' + + [AutoPlay] Get() { + $currentState = [AutoPlay]::new() + $currentState.AutoPlay = [AutoPlay]::GetAutoPlayStatus() + $currentState.RemovableDriveDefault = [AutoPlay]::GetRemovableDriveDefault() + $currentState.MemoryCardDefault = [AutoPlay]::GetMemoryCardDefault() + + return $currentState + } + + [bool] Test() { + $currentState = $this.Get() + + if (($null -ne $this.AutoPlay) -and ($this.AutoPlay -ne $currentState.AutoPlay)) { + return $false + } + + if ($this.RemovableDriveDefault -ne [RemovableDrive]::KeepCurrentValue -and $this.RemovableDriveDefault -ne $currentState.RemovableDriveDefault) { + return $false + } + + if ($this.MemoryCardDefault -ne [MemoryCard]::KeepCurrentValue -and $this.MemoryCardDefault -ne $currentState.MemoryCardDefault) { + return $false + } + + return $true + } + + [void] Set() { + if (-not ($this.Test())) { + if ($null -ne $this.AutoPlay) { + if (-not (DoesRegistryKeyPropertyExist -Path $global:AutoPlayPath -Name 'NoDriveTypeAutoRun')) { + New-ItemProperty -Path $global:AutoPlayPath -Name 'NoDriveTypeAutoRun' -Value ([int]$this.AutoPlay) -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:AutoPlayPath -Name 'NoDriveTypeAutoRun' -Value ([int]$this.AutoPlay) + } + + if ($this.RemovableDriveDefault -ne [RemovableDrive]::KeepCurrentValue) { + $regPath = "$global:AutoPlayPath\UserChosenExecuteHandlers\StorageOnArrival" + if (-not (Test-Path $regPath -ErrorAction SilentlyContinue)) { + New-Item -Path $regPath -Force | Out-Null + } + Set-ItemProperty -Path $regPath -Name '(Default)' -Value $this.RemovableDriveDefault + } + + if ($this.MemoryCardDefault -ne [MemoryCard]::KeepCurrentValue) { + $regPath = "$global:AutoPlayPath\UserChosenExecuteHandlers\CameraAlternate\ShowPicturesOnArrival" + if (-not (Test-Path $regPath -ErrorAction SilentlyContinue)) { + New-Item -Path $regPath -Force | Out-Null + } + + $regValue = $this.MemoryCardDefault + + if ($this.MemoryCardDefault -eq 'ImportPhotosAndVideos') { + # For information about this value, see: https://learn.microsoft.com/en-us/windows/apps/develop/settings/settings-common#supported-data-values-for-showpicturesonarrival + $regValue = 'dsd9eksajf9re3669zh5z2jykhws2jy42gypaqjh1qe66nyek1hg!desktopappxcontent!showshowpicturesonarrival' + } + Set-ItemProperty -Path $regPath -Name '(Default)' -Value $regValue + } + } + } + + #region AutoPlay helper functions + static [bool] GetAutoPlayStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:AutoPlayPath -Name ([AutoPlay]::AutoPlayProperty))) { + return $true + } else { + $AutoPlayStatus = (Get-ItemProperty -Path $global:AutoPlayPath -Name ([AutoPlay]::AutoPlayProperty)).DisableAutoplay + return ($AutoPlayStatus -eq 0) + } + } + + static [RemovableDrive] GetRemovableDriveDefault() { + $regPath = "$global:AutoPlayPath\UserChosenExecuteHandlers\StorageOnArrival" + if (-not (Test-Path $regPath -ErrorAction SilentlyContinue)) { + return [RemovableDrive]::KeepCurrentValue + } + + $RemovableDriveValue = (Get-ItemPropertyValue -Path $regPath -Name '(Default)' -ErrorAction SilentlyContinue) + if ($null -eq $RemovableDriveValue) { + return [RemovableDrive]::KeepCurrentValue + } + + return [RemovableDrive]::$RemovableDriveValue + } + + static [MemoryCard] GetMemoryCardDefault() { + $regPath = "$global:AutoPlayPath\UserChosenExecuteHandlers\CameraAlternate\ShowPicturesOnArrival" + if (-not (Test-Path $regPath -ErrorAction SilentlyContinue)) { + return [MemoryCard]::KeepCurrentValue + } + + $MemoryCardValue = (Get-ItemPropertyValue -Path $regPath -Name '(Default)' -ErrorAction SilentlyContinue) + if ($null -eq $MemoryCardValue) { + return [MemoryCard]::KeepCurrentValue + } + + if ([System.Enum]::GetNames([MemoryCard]) -notcontains $MemoryCardValue) { + $MemoryCardValue = 'ImportPhotosAndVideos' + } + + return [MemoryCard]::$MemoryCardValue + } + #endregion AutoPlay helper functions +} + + # TODO: Does not work (yet). Check comments in Get-TouchpadSettings function. # [DscResource()] # class Touchpad { diff --git a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 index bd5c9de5..32be9f6a 100644 --- a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 @@ -217,3 +217,44 @@ Describe 'MobileDevice' { $finalState.ShowMobileDeviceSuggestions | Should -Be $true } } + +Describe 'AutoPlay' { + It 'Keeps current value.' { + $initialState = Invoke-DscResource -Name AutoPlay -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + + $parameters = @{ RemovableDriveDefault = 'KeepCurrentValue'; MemoryCardDefault = 'KeepCurrentValue' } + + $testResult = Invoke-DscResource -Name AutoPlay -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Test -Property $parameters + $testResult.InDesiredState | Should -Be $true + + # Invoking set should not change these values. + Invoke-DscResource -Name AutoPlay -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $parameters + $finalState = Invoke-DscResource -Name AutoPlay -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.RemovableDriveDefault | Should -Be $initialState.RemovableDriveDefault + $finalState.MemoryCardDefault | Should -Be $initialState.MemoryCardDefault + } + + It 'Sets desired value for removable drive and memory card' { + $desiredState = @{ + RemovableDriveDefault = 'MSTakeNoAction' + MemoryCardDefault = 'MSTakeNoAction' + } + + Invoke-DscResource -Name AutoPlay -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name AutoPlay -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.RemovableDriveDefault | Should -Be 'MSTakeNoAction' + $finalState.MemoryCardDefault | Should -Be 'MSTakeNoAction' + } + + It 'Turns off auto play' { + $desiredState = @{ + AutoPlay = $false + } + + Invoke-DscResource -Name AutoPlay -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name AutoPlay -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.AutoPlay | Should -Be $false + } +} From 9a8bca26b5b3251dc02b10b64720a14ba610b698 Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Mon, 20 Jan 2025 14:32:32 +0100 Subject: [PATCH 16/21] Add synopsis --- .../Microsoft.Windows.Setting.Bluetooth.psm1 | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index 66058448..3dd6907e 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -990,6 +990,27 @@ class MobileDevice { #endregion MobileDevice helper functions } +<# +.SYNOPSIS + The `AutoPlay` class is a DSC resource that allows you to manage the AutoPlay settings on your Windows device. + +.PARAMETER SID + The security identifier. This is a key property and should not be set manually. + +.PARAMETER AutoPlay + Enable or disable AutoPlay. + +.PARAMETER RemovableDriveDefault + The default auto play action for removable drives. + +.PARAMETER MemoryCardDefault + The default auto play action for memory cards. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name AutoPlay -Method Set -Property @{ AutoPlay = $false } + + This example disables the AutoPlay feature. +#> [DscResource()] class AutoPlay { [DscProperty(Key)] From 81357fc6102536906129600948d408d5f27cef5b Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Mon, 20 Jan 2025 14:36:11 +0100 Subject: [PATCH 17/21] Add help file --- .../AutoPlay.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 resources/Help/Microsoft.Windows.Setting.Bluetooth/AutoPlay.md diff --git a/resources/Help/Microsoft.Windows.Setting.Bluetooth/AutoPlay.md b/resources/Help/Microsoft.Windows.Setting.Bluetooth/AutoPlay.md new file mode 100644 index 00000000..4a0e95cf --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Bluetooth/AutoPlay.md @@ -0,0 +1,37 @@ +--- +external help file: Microsoft.Windows.Setting.Bluetooth-Help.xml +Module Name: Microsoft.Windows.Setting.Bluetooth +ms.date: 01/19/2025 +online version: +schema: 2.0.0 +title: AutoPlay +--- + +# MobileDevice + +## SYNOPSIS + +The `AutoPlay` class is a DSC resource that allows you to manage the AutoPlay settings on your Windows device. + +## DESCRIPTION + +The `AutoPlay` class is a DSC resource that allows you to manage the AutoPlay settings on your Windows device. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| ----------------------- | ------------- | ------------ | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `SID` | Key | String | The security identifier. This is a key property and should not be set manually. | | +| `AutoPlay` | Optional | Boolean | Enable or disable AutoPlay. | `$true`, `$false` | +| `RemovableDriveDefault` | Optional | String | The default auto play action for removable drives. | Either any of the following values: `KeepCurrentValue`, `MSStorageSense`, `MSTakeNoAction`, `MSOpenFolder`, `MSPromptEachTime` | +| `MemoryCardDefault` | Optional | String | The default auto play action for memory cards. | Either any of the following values: `KeepCurrentValue`, `MSPlayMediaOnArrival`, `MSTakeNoAction`, `MSOpenFolder`, `MSPromptEachTime`, `OneDriveAutoPlay`, `ImportPhotosAndVideos` | + +## EXAMPLES + +### EXAMPLE 1 - Disable auto play for all media and devices + +```powershell +Invoke-DscResource -Name AutoPlay -Method Set -Property @{ AutoPlay = $false } + +# This example disables the AutoPlay feature. +``` From 9e74c3096466f864d2f613a809a686e8d1882bee Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Mon, 20 Jan 2025 15:04:41 +0100 Subject: [PATCH 18/21] Class for printers and scanners section --- .../Microsoft.Windows.Setting.Bluetooth.psm1 | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index 3dd6907e..1fdf6d04 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -12,6 +12,8 @@ if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { $global:DesktopPath = 'HKCU:\Control Panel\Desktop\' $global:MobilityPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Mobility\' $global:AutoPlayPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers\' + $global:DeviceSetupPath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\DeviceSetup\' + $global:WindowsNTPath = 'HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Windows\' } else { $global:USBShellPath = $global:USBMachinePath = $global:TabletTipPath = $global:MousePath = $global:DesktopPath = $global:MobilityPath = $global:AutoPlayPath = $env:TestRegistryPath } @@ -1132,6 +1134,82 @@ class AutoPlay { #endregion AutoPlay helper functions } +[DscResource()] +class PrinterAndScanner { + [DscProperty(Key)] + [string]$SID + + [DscProperty()] + [nullable[bool]] $LetWindowsManageDefaultPrinter + + [DscProperty()] + [nullable[bool]] $DriverDownloadOverMeteredConnection + + static hidden [string] $LetWindowsManageDefaultPrinterProperty = 'LegacyDefaultPrinterModer' + static hidden [string] $DriverDownloadOverMeteredConnectionProperty = 'CostedNetworkPolicy' + + [PrinterAndScanner] Get() { + $currentState = [PrinterAndScanner]::new() + $currentState.LetWindowsManageDefaultPrinter = [PrinterAndScanner]::GetLetWindowsManageDefaultPrinterStatus() + $currentState.DriverDownloadOverMeteredConnection = [PrinterAndScanner]::GetDriverDownloadOverMeteredConnectionStatus() + + return $currentState + } + + [bool] Test() { + $currentState = $this.Get() + + if (($null -ne $this.LetWindowsManageDefaultPrinter) -and ($this.LetWindowsManageDefaultPrinter -ne $currentState.LetWindowsManageDefaultPrinter)) { + return $false + } + + if (($null -ne $this.DriverDownloadOverMeteredConnection) -and ($this.DriverDownloadOverMeteredConnection -ne $currentState.DriverDownloadOverMeteredConnection)) { + return $false + } + + return $true + } + + [void] Set() { + if (-not ($this.Test())) { + if ($null -ne $this.LetWindowsManageDefaultPrinter) { + $letWindowsManageDefaultPrinterValue = $this.LetWindowsManageDefaultPrinter ? 0 : 1 + if (-not (DoesRegistryKeyPropertyExist -Path $global:PrinterPath -Name ([PrinterAndScanner]::LetWindowsManageDefaultPrinterProperty))) { + New-ItemProperty -Path $global:PrinterPath -Name ([PrinterAndScanner]::LetWindowsManageDefaultPrinterProperty) -Value $letWindowsManageDefaultPrinterValue -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:PrinterPath -Name ([PrinterAndScanner]::LetWindowsManageDefaultPrinterProperty) -Value $letWindowsManageDefaultPrinterValue + } + + if ($null -ne $this.DriverDownloadOverMeteredConnection) { + if (-not (DoesRegistryKeyPropertyExist -Path $global:PrinterPath -Name ([PrinterAndScanner]::DriverDownloadOverMeteredConnectionProperty))) { + New-ItemProperty -Path $global:PrinterPath -Name ([PrinterAndScanner]::DriverDownloadOverMeteredConnectionProperty) -Value ([int]$this.DriverDownloadOverMeteredConnection) -PropertyType DWord | Out-Null + } + Set-ItemProperty -Path $global:PrinterPath -Name ([PrinterAndScanner]::DriverDownloadOverMeteredConnectionProperty) -Value ([int]$this.DriverDownloadOverMeteredConnection) + } + } + } + + #region PrinterAndScanner helper functions + static [bool] GetLetWindowsManageDefaultPrinterStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:PrinterPath -Name ([PrinterAndScanner]::LetWindowsManageDefaultPrinterProperty))) { + return $true + } else { + $LetWindowsManageDefaultPrinterStatus = (Get-ItemProperty -Path $global:PrinterPath -Name ([PrinterAndScanner]::LetWindowsManageDefaultPrinterProperty)).LegacyDefaultPrinterModer + return ($LetWindowsManageDefaultPrinterStatus -eq 0) + } + } + + static [bool] GetDriverDownloadOverMeteredConnectionStatus() { + if (-not(DoesRegistryKeyPropertyExist -Path $global:PrinterPath -Name ([PrinterAndScanner]::DriverDownloadOverMeteredConnectionProperty))) { + return $false + } else { + $DriverDownloadOverMeteredConnectionStatus = (Get-ItemProperty -Path $global:PrinterPath -Name ([PrinterAndScanner]::DriverDownloadOverMeteredConnectionProperty)).CostedNetworkPolicy + return ($DriverDownloadOverMeteredConnectionStatus -eq 1) + } + } + #endregion PrinterAndScanner helper functions +} + # TODO: Does not work (yet). Check comments in Get-TouchpadSettings function. # [DscResource()] From c37e81349a9b2fe01b757aedcb269c1d6f54e0f0 Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Mon, 20 Jan 2025 15:05:58 +0100 Subject: [PATCH 19/21] Add synopsis --- .../PrinterAndScanner.md | 0 .../Microsoft.Windows.Setting.Bluetooth.psm1 | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 resources/Help/Microsoft.Windows.Setting.Bluetooth/PrinterAndScanner.md diff --git a/resources/Help/Microsoft.Windows.Setting.Bluetooth/PrinterAndScanner.md b/resources/Help/Microsoft.Windows.Setting.Bluetooth/PrinterAndScanner.md new file mode 100644 index 00000000..e69de29b diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 index 1fdf6d04..62f3d9c8 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psm1 @@ -1134,6 +1134,24 @@ class AutoPlay { #endregion AutoPlay helper functions } +<# +.SYNOPSIS + The `PrinterAndScanner` class is a DSC resource that allows you to manage the printer and scanner settings on your Windows device. + +.PARAMETER SID + The security identifier. This is a key property and should not be set manually. + +.PARAMETER LetWindowsManageDefaultPrinter + Let Windows manage the default printer. + +.PARAMETER DriverDownloadOverMeteredConnection + Download drivers over a metered connection. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name PrinterAndScanner -Method Set -Property @{ LetWindowsManageDefaultPrinter = $false } + + This example disables Windows from managing the default printer. +#> [DscResource()] class PrinterAndScanner { [DscProperty(Key)] From 7d0aadbc8eb70df41333eeb64ad80b96e5b7fba6 Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Mon, 20 Jan 2025 15:09:00 +0100 Subject: [PATCH 20/21] Add Pester test --- .../PrinterAndScanner.md | 45 +++++++++++++++++++ .../Microsoft.Windows.Setting.Bluetooth.psd1 | 6 ++- ...rosoft.Windows.Setting.Bluetooth.Tests.ps1 | 12 +++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/resources/Help/Microsoft.Windows.Setting.Bluetooth/PrinterAndScanner.md b/resources/Help/Microsoft.Windows.Setting.Bluetooth/PrinterAndScanner.md index e69de29b..26408e60 100644 --- a/resources/Help/Microsoft.Windows.Setting.Bluetooth/PrinterAndScanner.md +++ b/resources/Help/Microsoft.Windows.Setting.Bluetooth/PrinterAndScanner.md @@ -0,0 +1,45 @@ +--- +external help file: Microsoft.Windows.Setting.Bluetooth-Help.xml +Module Name: Microsoft.Windows.Setting.Bluetooth +ms.date: 01/19/2025 +online version: +schema: 2.0.0 +title: PrinterAndScanne +--- + +# PrinterAndScanne + +## SYNOPSIS + +The `PrinterAndScanner` class is a DSC resource that allows you to manage the printer and scanner settings on your Windows device. + +## DESCRIPTION + +The `PrinterAndScanner` class is a DSC resource that allows you to manage the printer and scanner settings on your Windows device. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| ------------------------------------- | ------------- | ------------ | ------------------------------------------------------------------------------- | ------------------ | +| `SID` | Key | String | The security identifier. This is a key property and should not be set manually. | N/A | +| `LetWindowsManageDefaultPrinter` | Optional | Boolean | Let Windows manage the default printer. | `$true`, `$false` | +| `DriverDownloadOverMeteredConnection` | Optional | Boolean | Download drivers over a metered connection. | `$true`, `$false` | + +.PARAMETER SID + The security identifier. This is a key property and should not be set manually. + +.PARAMETER LetWindowsManageDefaultPrinter + Let Windows manage the default printer. + +.PARAMETER DriverDownloadOverMeteredConnection + Download drivers over a metered connection. + +## EXAMPLES + +### EXAMPLE 1 - Disable Windows from managing the default printer + +```powershell +Invoke-DscResource -Name PrinterAndScanner -Method Set -Property @{ LetWindowsManageDefaultPrinter = $false } + +# This example disables Windows from managing the default printer. +``` diff --git a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 index 1d230768..3ea43647 100644 --- a/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 +++ b/resources/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.psd1 @@ -12,7 +12,8 @@ 'PenWindowsInk', 'Mouse', 'MobileDevice', - 'AutoPlay' + 'AutoPlay', + 'PrinterAndScanner' ) PrivateData = @{ PSData = @{ @@ -22,7 +23,8 @@ 'PSDscResource_PenWindowsInk', 'PSDscResource_Mouse', 'PSDscResource_MobileDevice', - 'PSDscResource_AutoPlay' + 'PSDscResource_AutoPlay', + 'PSDscResource_PrinterAndScanner' ) # Prerelease string of this module diff --git a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 index 32be9f6a..9200ded5 100644 --- a/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 +++ b/tests/Microsoft.Windows.Setting.Bluetooth/Microsoft.Windows.Setting.Bluetooth.Tests.ps1 @@ -258,3 +258,15 @@ Describe 'AutoPlay' { $finalState.AutoPlay | Should -Be $false } } + +Describe 'PrinterAndScanner' { + It 'Set the printer to not be managed by Windows' { + $desiredState = @{ + LetWindowsManageDefaultPrinter = $false + } + Invoke-DscResource -Name PrinterAndScanner -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name PrinterAndScanner -ModuleName Microsoft.Windows.Setting.Bluetooth -Method Get -Property @{} + $finalState.LetWindowsManageDefaultPrinter | Should -Be $false + } +} From b889a49a90f8e9b15ceae1166d48649fc2a4775b Mon Sep 17 00:00:00 2001 From: Gijs Reijn Date: Mon, 20 Jan 2025 16:47:46 +0100 Subject: [PATCH 21/21] Spelling --- .github/actions/spelling/allow.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index f057fa99..274d4bc4 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -77,4 +77,14 @@ touchpad Usb vparam WFingertip -WFingertip \ No newline at end of file +WFingertip +anner +desktopappxcontent +Devicetatus +dsd +eksajf +gypaqjh +jykhws +nyek +showpicturesonarrival +showshowpicturesonarrival