diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 1c720079..aad9360b 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 +immersivecontrolpanel diff --git a/.github/actions/spelling/expect/generic_terms.txt b/.github/actions/spelling/expect/generic_terms.txt index 870c3e87..57c5f635 100644 --- a/.github/actions/spelling/expect/generic_terms.txt +++ b/.github/actions/spelling/expect/generic_terms.txt @@ -19,4 +19,9 @@ ssh usr versioning VGpu +Ntp +Systray ADDLOCAL +dstoff +tzautoupdate +tzutil diff --git a/resources/Help/Microsoft.VSCode.Dsc/VSCodeExtension.md b/resources/Help/Microsoft.VSCode.Dsc/VSCodeExtension.md index 4f5e62b1..97cd085b 100644 --- a/resources/Help/Microsoft.VSCode.Dsc/VSCodeExtension.md +++ b/resources/Help/Microsoft.VSCode.Dsc/VSCodeExtension.md @@ -28,7 +28,7 @@ The `VSCodeExtension` DSC Resource allows you to install, update, and remove Vis ## EXAMPLES -### Example 1 +### EXAMPLE 1 ```powershell # Install the latest version of the Visual Studio Code extension 'ms-python.python' diff --git a/resources/Help/Microsoft.Windows.Setting.Time/Clock.md b/resources/Help/Microsoft.Windows.Setting.Time/Clock.md new file mode 100644 index 00000000..9923185b --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Time/Clock.md @@ -0,0 +1,44 @@ +--- +external help file: Microsoft.Windows.Setting.Time.psm1-Help.xml +Module Name: Microsoft.Windows.Setting.Time +ms.date: 05/11/2024 +online version: +schema: 2.0.0 +title: Clock +--- + +# Clock + +## SYNOPSIS + +The `Clock` DSC Resource allows you to manage the system tray date/time visibility settings on a Windows machine. + +## DESCRIPTION + +The `Clock` DSC Resource allows you to manage the system tray date/time visibility settings on a Windows machine. + +## 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 | +| `ShowSystemTrayClock` | Optional | Boolean | Whether to show the date and time in the system tray. The value should be a boolean. The default value is `$true`. | `$true`, `$false` | +| `NotifyClockChangeProperty` | Optional | Boolean | Whether to notify the user when the time changes. The value should be a boolean. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 - Get the current clock settings + +```powershell +C:\> Invoke-DscResource -Name Clock -Method Get -Property {} + +# This example gets the current clock settings on the machine. +``` + +### EXAMPLE 2 - Set system tray date and notify clock change + +```powershell +Invoke-DscResource -Name Clock -Method Set -Property @{ ShowSystemTrayDateTime = $true; NotifyClockChange = $true } + +# This example sets the system tray date/time visibility settings on the machine. +``` diff --git a/resources/Help/Microsoft.Windows.Setting.Time/TimeZone.md b/resources/Help/Microsoft.Windows.Setting.Time/TimeZone.md new file mode 100644 index 00000000..b05b8dd7 --- /dev/null +++ b/resources/Help/Microsoft.Windows.Setting.Time/TimeZone.md @@ -0,0 +1,45 @@ +--- +external help file: Microsoft.Windows.Setting.Time.psm1-Help.xml +Module Name: Microsoft.Windows.Setting.Time +ms.date: 05/11/2024 +online version: +schema: 2.0.0 +title: TimeZone +--- + +# Time + +## SYNOPSIS + +This `TimeZone` DSC Resource allows you to manage the time zone, automatic time zone update, and system tray date/time visibility settings on a Windows machine. + +## DESCRIPTION + +This `TimeZone` DSC Resource allows you to manage the time zone, automatic time zone update, and system tray date/time visibility settings on a Windows machine. + +## PARAMETERS + +| **Parameter** | **Attribute** | **DataType** | **Description** | **Allowed Values** | +| -------------------------- | ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- | +| `Id` | Key | String | Specifies the time zone to set on the machine. | Any valid time zone identifier from `Get-TimeZone -ListAvailable` | +| `SetTimeZoneAutomatically` | Optional | Boolean | Whether to set the time zone automatically. The value should be a boolean. You can find the setting in `Settings -> Time & Language -> Date & Time -> Set time zone automatically. | `$true`, `$false` | +| `SetTimeAutomatically` | Optional | Boolean | Whether to set the time automatically. The value should be a boolean. You can find the setting in `Settings -> Time & Language -> Date & Time -> Set time automatically. | `$true`, `$false` | +| `AdjustForDayLightSaving` | Optional | Boolean | Whether to adjust for daylight saving time. The value should be a boolean. You can find the setting in `Settings -> Time & Language -> Date & Time -> Adjust for daylight saving time automatically. | `$true`, `$false` | + +## EXAMPLES + +### EXAMPLE 1 - Set time zone to Pacific Standard Time + +```powershell +Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property @{ Id = "Pacific Standard Time"} + +# This example sets the time zone to Pacific Standard Time. +``` + +### EXAMPLE 2 - Get current time zone + +```powershell +Invoke-DscResource -Name Time -Method Get -Property {} + +# This example gets the current time settings on the machine. +``` diff --git a/resources/Microsoft.Windows.Setting.Time/Microsoft.Windows.Setting.Time.psd1 b/resources/Microsoft.Windows.Setting.Time/Microsoft.Windows.Setting.Time.psd1 new file mode 100644 index 00000000..211d1915 --- /dev/null +++ b/resources/Microsoft.Windows.Setting.Time/Microsoft.Windows.Setting.Time.psd1 @@ -0,0 +1,131 @@ +# +# Module manifest for module 'Microsoft.Windows.Setting.Time' +# +# Generated by: Microsoft Corporation +# +# Generated on: 05/11/2024 +# + +@{ + + # Script module or binary module file associated with this manifest. + RootModule = 'Microsoft.Windows.Setting.Time.psm1' + + # Version number of this module. + ModuleVersion = '0.1.0' + + # Supported PSEditions + # CompatiblePSEditions = @() + + # ID used to uniquely identify this module + GUID = '6a947f86-eb17-46a4-9b0d-9f757b19c29a' + + # Author of this module + Author = 'Microsoft Corporation' + + # Company or vendor of this module + CompanyName = 'Microsoft Corporation' + + # Copyright statement for this module + Copyright = '(c) Microsoft Corporation. All rights reserved.' + + # Description of the functionality provided by this module + Description = 'DSC Resource for Windows Time Settings' + + # Minimum version of the PowerShell engine required by this module + PowerShellVersion = '7.2' + + # Name of the PowerShell host required by this module + # PowerShellHostName = '' + + # Minimum version of the PowerShell host required by this module + # PowerShellHostVersion = '' + + # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # DotNetFrameworkVersion = '' + + # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # ClrVersion = '' + + # Processor architecture (None, X86, Amd64) required by this module + # ProcessorArchitecture = '' + + # Modules that must be imported into the global environment prior to importing this module + # RequiredModules = @() + + # Assemblies that must be loaded prior to importing this module + # RequiredAssemblies = @() + + # Script files (.ps1) that are run in the caller's environment prior to importing this module. + # ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + # TypesToProcess = @() + + # Format files (.ps1xml) to be loaded when importing this module + # FormatsToProcess = @() + + # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess + # NestedModules = @() + + # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. + # FunctionsToExport = '*' + + # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. + # CmdletsToExport = '*' + + # Variables to export from this module + # VariablesToExport = '*' + + # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. + # AliasesToExport = '*' + + # DSC resources to export from this module + DscResourcesToExport = @('TimeZone', 'Clock') + + # List of all modules packaged with this module + # ModuleList = @() + + # List of all files packaged with this module + # FileList = @() + + # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + Tags = @('PSDscResource_TimeZone', 'PSDscResource_Clock') + + # A URL to the license for this module. + LicenseUri = 'https://github.com/microsoft/winget-dsc/blob/main/LICENSE' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/microsoft/winget-dsc' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + Prerelease = 'alpha' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + + } # End of PrivateData hashtable + + # HelpInfo URI of this module + # HelpInfoURI = '' + + # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. + # DefaultCommandPrefix = '' +} + diff --git a/resources/Microsoft.Windows.Setting.Time/Microsoft.Windows.Setting.Time.psm1 b/resources/Microsoft.Windows.Setting.Time/Microsoft.Windows.Setting.Time.psm1 new file mode 100644 index 00000000..fdb71abf --- /dev/null +++ b/resources/Microsoft.Windows.Setting.Time/Microsoft.Windows.Setting.Time.psm1 @@ -0,0 +1,388 @@ +if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { + $global:tzAutoUpdatePath = 'HKLM:\System\CurrentControlSet\Services\tzautoupdate' + $global:w32TimePath = 'HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Parameters' + $global:timeZoneInformationPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\TimeZoneInformation' +} else { + $global:tzAutoUpdatePath = $global:timeZoneInformationPath = $env:TestRegistryPath +} + +#region Functions +function TryGetRegistryValue { + param ( + [Parameter(Mandatory = $true)] + [string]$Key, + + [Parameter(Mandatory = $true)] + [string]$Property + ) + + if (Test-Path -Path $Key) { + try { + return (Get-ItemProperty -Path $Key -Name $Property -ErrorAction SilentlyContinue | Select-Object -ExpandProperty $Property) + } catch { + Write-Verbose "Property `"$($Property)`" could not be found." + } + } else { + Write-Verbose 'Registry key does not exist.' + } +} +function Get-ValidTimeZone { + param ( + [Parameter(Mandatory = $true)] + [string] $TimeZone + ) + + try { + $timeZoneId = (Get-TimeZone -Id $TimeZone -ErrorAction Stop).Id + } catch { + throw [System.Configuration.ConfigurationException]::new("Executing 'Get-TimeZone' failed. Error: $($PSItem.Exception.Message)") + } + + return $timeZoneId +} + +function Test-LocationSettingPermission { + # On Windows 11, the HKLM is the location services, whereas HKCU is the Let apps access your location setting + $registryKeys = @('HKLM:\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\location', 'HKCU:\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\location', 'HKCU:\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\location\windows.immersivecontrolpanel*') + foreach ($key in $registryKeys) { + $res = Get-ItemProperty -Path $key -Name 'Value' -ErrorAction SilentlyContinue + if ($res.Value -ne 'Allow') { + # TODO: Or should we throw an error? + return $false + } + } + + return $true +} + +function Set-DaylightSavingTime { + param ( + [Parameter()] + [switch] $Enable, + + [Parameter(Mandatory = $true)] + [string] $Id + ) + + $command = $Enable.IsPresent ? ('tzutil /s "{0}"' -f $Id) : ('tzutil /s "{0}_dstoff"' -f $Id) + + Invoke-Expression -Command $command + + if ($LASTEXITCODE -ne 0) { + throw [System.Configuration.ConfigurationException]::new("Failed to set daylight saving time. Error: $LASTEXITCODE") + } +} +#endRegion Functions + +#region Classes +<# +.SYNOPSIS + This `TimeZone` DSC Resource allows you to manage the time zone, automatic time zone update, and system tray date/time visibility settings on a Windows machine. + +.DESCRIPTION + This `TimeZone` DSC Resource allows you to manage the time zone, automatic time zone update, and system tray date/time visibility settings on a Windows machine. + +.PARAMETER Id + The Id to set on the machine. The value should be a valid time zone ID from the list of time zones (Get-TimeZone -ListAvailable).Id. The default value is the current time zone. + +.PARAMETER SetTimeZoneAutomatically + Whether to set the time zone automatically. The value should be a boolean. You can find the setting in `Settings -> Time & Language -> Date & Time -> Set time zone automatically. + +.PARAMETER SetTimeAutomatically + Whether to set the time automatically. The value should be a boolean. You can find the setting in `Settings -> Time & Language -> Date & Time -> Set time automatically. + +.PARAMETER AdjustForDaylightSaving + Whether to adjust for daylight saving time. The value should be a boolean. You can find the setting in `Settings -> Time & Language -> Date & Time -> Adjust for daylight saving time automatically. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property @{ TimeZone = "Pacific Standard Time"} + + This example sets the time zone to Pacific Standard Time. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Get -Property {} + + This example gets the current time settings on the machine. +#> +[DscResource()] +class TimeZone { + [DscProperty(Key)] + [string] $Id + + [DscProperty()] + [nullable[bool]] $SetTimeZoneAutomatically + + [DscProperty()] + [nullable[bool]] $SetTimeAutomatically + + [DscProperty()] + [nullable[bool]] $AdjustForDaylightSaving + + [DscProperty(NotConfigurable)] + [bool] $SupportsDaylightSavingProperty + + static hidden [string] $SetTimeZoneAutomaticallyProperty = 'Start' + static hidden [string] $SetTimeAutomaticallyProperty = 'Type' + static hidden [string] $AdjustForDaylightSavingProperty = 'DynamicDaylightTimeDisabled' + static hidden [string] $NtpEnabled = 'NTP' + static hidden [string] $NtpDisabled = 'NoSync' + + TimeZone() { + $timeZone = Get-TimeZone + $this.Id = $timeZone.Id + + # We set the SupportsDaylightSavingProperty to the value that is supported by the current time zone + [TimeZone]::SupportsDaylightSavingProperty = $timeZone.SupportsDaylightSavingTime + } + + [TimeZone] Get() { + $currentState = [TimeZone]::new() + $currentState.SetTimeZoneAutomatically = [TimeZone]::GetTimeZoneAutomaticallyStatus() + $currentState.SetTimeAutomatically = [TimeZone]::GetTimeAutomaticallyStatus() + + if ($currentState::SupportsDaylightSavingProperty) { + $currentState.AdjustForDaylightSaving = [TimeZone]::GetDayLightSavingStatus() + } + + return $currentState + } + + [void] Set() { + if ($this.Test()) { + return + } + + $currentState = $this.Get() + + if ($currentState.Id -ne $this.Id) { + Set-TimeZone -Id (Get-ValidTimeZone -TimeZone $this.Id) + } + + if (($null -ne $this.SetTimeZoneAutomatically) -and ($this.SetTimeZoneAutomatically -ne $currentState.SetTimeZoneAutomatically)) { + $desiredState = $this.SetTimeZoneAutomatically ? 3 : 4 + + if (Test-LocationSettingPermission) { + Set-ItemProperty -Path $global:tzAutoUpdatePath -Name ([TimeZone]::SetTimeZoneAutomaticallyProperty) -Value $desiredState + } + } + + if (($null -ne $this.SetTimeAutomatically) -and ($this.SetTimeAutomatically -ne $currentState.SetTimeAutomatically)) { + $desiredState = $this.SetTimeAutomatically ? [TimeZone]::NtpEnabled : [TimeZone]::NtpDisabled + + Set-ItemProperty -Path $global:w32TimePath -Name ([TimeZone]::SetTimeAutomaticallyProperty) -Value $desiredState + } + + if ($currentState::SupportsDaylightSavingProperty -and ($null -ne $this.AdjustForDaylightSaving)) { + $desiredState = @{ + Id = $this.Id + Enable = $this.AdjustForDaylightSaving + } + + if ($this.AdjustForDaylightSaving -ne $currentState.AdjustForDaylightSaving) { + # Falling back on tzutil because the amount of registry keys to modify is too high, plus difficult to determine which one to modify + Set-DaylightSavingTime @desiredState + } + } + } + + [bool] Test() { + $currentState = $this.Get() + + if ($this.Id -ne $currentState.Id) { + return $false + } + + if (($null -ne $this.SetTimeZoneAutomatically) -and ($this.SetTimeZoneAutomatically -ne $currentState.SetTimeZoneAutomatically)) { + return $false + } + + if (($null -ne $this.SetTimeAutomatically) -and ($this.SetTimeAutomatically -ne $currentState.SetTimeAutomatically)) { + return $false + } + + if ($currentState::SupportsDaylightSavingProperty -and ($null -ne $this.AdjustForDaylightSaving)) { + if ($this.AdjustForDaylightSaving -ne $currentState.AdjustForDaylightSaving) { + return $false + } + } + + return $true + } + + #region TimeZone helper functions + static [bool] GetTimeZoneAutomaticallyStatus() { + $keyValue = TryGetRegistryValue -Key $global:tzAutoUpdatePath -Property ([TimeZone]::SetTimeZoneAutomaticallyProperty) + if ($null -eq $keyValue) { + return $true + } else { + return ($keyValue -eq 3) + } + } + + static [bool] GetTimeAutomaticallyStatus() { + $keyValue = TryGetRegistryValue -Key $global:w32TimePath -Property ([TimeZone]::SetTimeAutomaticallyProperty) + if ($null -eq $keyValue) { + return $true + } else { + return ($keyValue -eq 'NTP') + } + } + + static [bool] GetDayLightSavingStatus() { + $keyValue = TryGetRegistryValue -Key $global:timeZoneInformationPath -Property ([TimeZone]::AdjustForDaylightSavingProperty) + if ($null -eq $keyValue) { + return $true + } else { + return ($keyValue -eq 0) + } + } + + # helper function for Pester tests + [hashtable] ToHashTable() { + $parameters = @{} + foreach ($property in $this.PSObject.Properties) { + if (-not ([string]::IsNullOrEmpty($property.Value))) { + $parameters[$property.Name] = $property.Value + } + } + + return $parameters + } + #endRegion TimeZone helper functions +} + +if ([string]::IsNullOrEmpty($env:TestRegistryPath)) { + $global:SysTrayPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' + $global:AdditionalClockPath = 'HKCU:\Control Panel\TimeDate' +} else { + $global:SysTrayPath = $global:AdditionalClockPath = $env:TestRegistryPath +} + +<# +.SYNOPSIS + The 'Clock' DSC Resource allows you to manage the system tray date/time visibility settings on a Windows machine. + +.DESCRIPTION + The 'Clock' DSC Resource allows you to manage the system tray date/time visibility settings on a Windows machine. + +.PARAMETER ShowSystemTrayDateTime + Whether to show the date and time in the system tray. The value should be a boolean. The default value is `$true`. + +.PARAMETER NotifyClockChange + Whether to notify the user when the time changes. The value should be a boolean. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name Clock -Method Get -Property {} + + This example gets the current clock settings on the machine. + +.EXAMPLE + PS C:\> Invoke-DscResource -Name Clock -Method Set -Property @{ ShowSystemTrayDateTime = $true; NotifyClockChange = $true } + + This example sets the system tray date/time visibility settings on the machine. +#> +[DscResource()] +class Clock { + [DscProperty(Key)] + [string] $SID + + [DscProperty()] + [nullable[bool]] $ShowSystemTrayDateTime + + [DscProperty()] + [nullable[bool]] $NotifyClockChange + + static hidden [string] $ShowSystemTrayDateTimeProperty = 'ShowSystrayDateTimeValueName' + static hidden [string] $NtpEnabled = 'NTP' + static hidden [string] $NtpDisabled = 'NoSync' + static hidden [string] $NotifyClockChangeProperty = 'DstNotification' + + [Clock] Get() { + $currentState = [Clock]::New() + $currentState.ShowSystemTrayDateTime = [Clock]::GetShowSystemTrayDateTimeStatus() + $currentState.NotifyClockChange = [Clock]::GetNotifyClockChangeStatus() + + return $currentState + } + + [void] Set() { + if ($this.Test()) { + return + } + + $currentState = $this.Get() + + if (($null -ne $this.ShowSystemTrayDateTime) -and ($currentState.ShowSystemTrayDateTime -ne $this.ShowSystemTrayDateTime)) { + $desiredState = [int]$this.ShowSystemTrayDateTime + + if ([string]::IsNullOrEmpty((TryGetRegistryValue -Key $global:SysTrayPath -Property ([Clock]::ShowSystemTrayDateTimeProperty)))) { + New-ItemProperty -Path $global:SysTrayPath -Name ([Clock]::ShowSystemTrayDateTimeProperty) -Value $desiredState -PropertyType DWORD + return + } + + Set-ItemProperty -Path $global:SysTrayPath -Name ([Clock]::ShowSystemTrayDateTimeProperty) -Value $desiredState + } + + if (($null -ne $this.NotifyClockChange) -and ($currentState.NotifyClockChange -ne $this.NotifyClockChange)) { + $desiredState = [int]$this.NotifyClockChange + + if ([string]::IsNullOrEmpty((TryGetRegistryValue -Key $global:AdditionalClockPath -Property ([Clock]::NotifyClockChangeProperty)))) { + New-ItemProperty -Path $global:AdditionalClockPath -Name ([Clock]::NotifyClockChangeProperty) -Value $desiredState -PropertyType DWORD + return + } + + Set-ItemProperty -Path $global:AdditionalClockPath -Name ([Clock]::NotifyClockChangeProperty) -Value $desiredState + } + } + + [bool] Test() { + $currentState = $this.Get() + + if (($null -ne $this.ShowSystemTrayDateTime) -and ($this.ShowSystemTrayDateTime -ne $currentState.ShowSystemTrayDateTime)) { + return $false + } + + if (($null -ne $this.NotifyClockChange) -and ($this.NotifyClockChange -ne $currentState.NotifyClockChange)) { + return $false + } + + return $true + } + + #region Clock helper functions + static [bool] GetShowSystemTrayDateTimeStatus() { + $value = TryGetRegistryValue -Key $global:SysTrayPath -Property ([Clock]::ShowSystemTrayDateTimeProperty) + if (([string]::IsNullOrEmpty($value))) { + # if it is empty, we assume it is set to 1 + return $true + } else { + return ($value -eq 1) + } + } + + static [bool] GetNotifyClockChangeStatus() { + $value = TryGetRegistryValue -Key $global:AdditionalClockPath -Property ([Clock]::NotifyClockChangeProperty) + if (([string]::IsNullOrEmpty($value))) { + # if it is empty, we assume it is set to 1 + return $true + } else { + return ($value -eq 1) + } + } + + # helper function for Pester tests + [hashtable] ToHashTable() { + $parameters = @{} + foreach ($property in $this.PSObject.Properties) { + if (-not ([string]::IsNullOrEmpty($property.Value))) { + $parameters[$property.Name] = $property.Value + } + } + + return $parameters + } + #endRegion Clock helper functions + +} +#endRegion Classes + diff --git a/tests/Microsoft.Windows.Setting.Time/Microsoft.Windows.Setting.Time.Tests.ps1 b/tests/Microsoft.Windows.Setting.Time/Microsoft.Windows.Setting.Time.Tests.ps1 new file mode 100644 index 00000000..aadf5043 --- /dev/null +++ b/tests/Microsoft.Windows.Setting.Time/Microsoft.Windows.Setting.Time.Tests.ps1 @@ -0,0 +1,109 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +using module Microsoft.Windows.Setting.Time + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +<# +.Synopsis + Pester tests related to the Microsoft.Windows.Setting.Time PowerShell module. +#> + +BeforeAll { + if ($null -eq (Get-Module -ListAvailable -Name PSDesiredStateConfiguration)) { + Install-Module -Name PSDesiredStateConfiguration -Force -SkipPublisherCheck + } + + $timeZoneState = Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Get -Property @{} + $global:timeZoneParameters = $timeZoneState.ToHashTable() + + $clockState = Invoke-DscResource -Name Clock -ModuleName Microsoft.Windows.Setting.Time -Method Get -Property @{} + $global:clockStateParameters = $clockState.ToHashTable() +} + +Describe 'List available DSC resources' { + It 'Shows DSC Resources' { + $expectedDSCResources = 'TimeZone', 'Clock' + $availableDSCResources = (Get-DscResource -Module Microsoft.Windows.Setting.Time).Name + $availableDSCResources.Count | Should -Be 2 + $availableDSCResources | Where-Object { $expectedDSCResources -notcontains $_ } | Should -BeNullOrEmpty -ErrorAction Stop + } +} + +Describe 'TimeZone' { + It 'Set Time Zone only by Id' { + $desiredState = @{ Id = 'Pacific Standard Time' } + + Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Test -Property @{} + $finalState.InDesiredState | Should -Be $true + } + + It 'Set Time Zone automatically' { + $desiredState = @{ Id = 'W. Europe Standard Time'; SetTimeZoneAutomatically = $true } + + Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Test -Property @{} + $finalState.InDesiredState | Should -Be $true + } + + It 'Disable Time automatically' { + $desiredState = @{ Id = 'W. Europe Standard Time'; SetTimeAutomatically = $false } + + Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Test -Property @{} + $finalState.InDesiredState | Should -Be $true + } + + It 'Disable daylight saving' { + $desiredState = @{ + Id = (Get-TimeZone -ListAvailable | Where-Object { $_.SupportsDaylightSavingTime -eq $true } | Select-Object -First 1 -ExpandProperty Id) + SetTimeZoneAutomatically = $false + AdjustForDaylightSaving = $false + } + + Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Test -Property @{} + $finalState.InDesiredState | Should -Be $true + } +} + +Describe 'Clock' { + It 'Display System Tray' { + $desiredState = @{ ShowSystemTrayDateTime = $true } + + Invoke-DscResource -Name Clock -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Clock -ModuleName Microsoft.Windows.Setting.Time -Method Test -Property $desiredState + $finalState.InDesiredState | Should -Be $true + } + + It 'Hide System Tray' { + $desiredState = @{ ShowSystemTrayDateTime = $false } + + Invoke-DscResource -Name Clock -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Clock -ModuleName Microsoft.Windows.Setting.Time -Method Test -Property @{} + $finalState.InDesiredState | Should -Be $true + } + + It 'Disable clock notify change' { + $desiredState = @{ NotifyClockChange = $false } + + Invoke-DscResource -Name Clock -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property $desiredState + + $finalState = Invoke-DscResource -Name Clock -ModuleName Microsoft.Windows.Setting.Time -Method Test -Property @{} + $finalState.InDesiredState | Should -Be $true + } +} + +AfterAll { + # Restore the original state + Invoke-DscResource -Name TimeZone -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property $global:timeZoneParameters + Invoke-DscResource -Name Clock -ModuleName Microsoft.Windows.Setting.Time -Method Set -Property $global:clockStateParameters +}