Skip to content

Commit ee9292d

Browse files
committed
Add and expand Pester tests for scripts and modules
Added Install-Defaults.Module.Tests.ps1 for comprehensive module function testing. Expanded Install-Defaults.Tests.ps1 and Remove-AppxApps.Tests.ps1 with detailed integration, parameter, and scenario coverage, including OS/version detection, registry, logging, and feature update support. Improves reliability and coverage of script and module validation.
1 parent 3e714f6 commit ee9292d

3 files changed

Lines changed: 794 additions & 31 deletions

File tree

Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
<#
2+
.SYNOPSIS
3+
Pester tests for Install-Defaults.psm1 module functions
4+
#>
5+
[CmdletBinding()]
6+
param()
7+
8+
BeforeAll {
9+
# Import the module
10+
$ModulePath = Join-Path -Path $PSScriptRoot -ChildPath "..\src\Install-Defaults.psm1"
11+
Import-Module $ModulePath -Force
12+
13+
# Helper function to get OS version
14+
function Get-OSVersionInfo {
15+
$OS = Get-CimInstance -ClassName CIM_OperatingSystem
16+
$Build = [System.Environment]::OSVersion.Version.Build
17+
$IsServer = $OS.Caption -match 'Server'
18+
$IsWindows11 = $OS.Caption -match 'Windows 11' -or ($Build -ge 22000 -and -not $IsServer)
19+
$IsServer2025 = $OS.Caption -match 'Server 2025' -or ($Build -ge 26100 -and $IsServer)
20+
$IsServer2022 = $OS.Caption -match 'Server 2022'
21+
$SupportsLanguagePack = $IsWindows11 -or $IsServer2025
22+
23+
return @{
24+
Build = $Build
25+
IsServer = $IsServer
26+
IsClient = -not $IsServer
27+
IsWindows11 = $IsWindows11
28+
IsWindows10 = $OS.Caption -match 'Windows 10'
29+
IsServer2025 = $IsServer2025
30+
IsServer2022 = $IsServer2022
31+
SupportsLanguagePack = $SupportsLanguagePack
32+
Caption = $OS.Caption
33+
}
34+
}
35+
36+
$OSInfo = Get-OSVersionInfo
37+
$IsAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
38+
}
39+
40+
Describe 'Module Import' {
41+
It 'Should import the module successfully' {
42+
Get-Module -Name 'Install-Defaults' | Should -Not -BeNullOrEmpty
43+
}
44+
45+
It 'Should export expected functions' {
46+
$ExportedFunctions = @(
47+
'Get-Symbol', 'Write-Message', 'Write-LogFile',
48+
'Get-Platform', 'Get-OSName', 'Get-Model',
49+
'Get-SettingsContent', 'Set-RegistryOwner',
50+
'Set-Registry', 'Remove-RegistryPath', 'Set-DefaultUserProfile',
51+
'Copy-File', 'New-Directory', 'Remove-Path',
52+
'Remove-Feature', 'Remove-Capability', 'Remove-Package',
53+
'Get-CurrentUserSid', 'Restart-NamedService',
54+
'Start-NamedService', 'Stop-NamedService',
55+
'Install-SystemLanguage', 'Set-SystemLocale',
56+
'Set-TimeZoneUsingName', 'Test-IsOobeComplete', 'Copy-RegExe'
57+
)
58+
59+
$Module = Get-Module -Name 'Install-Defaults'
60+
foreach ($Function in $ExportedFunctions) {
61+
$Module.ExportedFunctions.Keys | Should -Contain $Function
62+
}
63+
}
64+
}
65+
66+
Describe 'Get-Symbol' {
67+
It 'Should return a tick symbol' {
68+
$Result = Get-Symbol -Symbol 'Tick'
69+
$Result | Should -Not -BeNullOrEmpty
70+
}
71+
72+
It 'Should return a cross symbol' {
73+
$Result = Get-Symbol -Symbol 'Cross'
74+
$Result | Should -Not -BeNullOrEmpty
75+
}
76+
77+
It 'Should return null for default when called without parameters' {
78+
$Result = Get-Symbol
79+
$Result | Should -Not -BeNullOrEmpty
80+
}
81+
}
82+
83+
Describe 'Write-Message' {
84+
It 'Should write message without throwing' {
85+
{ Write-Message -Message 'Test message' -LogLevel 1 } | Should -Not -Throw
86+
}
87+
88+
It 'Should handle long messages that exceed console width' {
89+
$LongMessage = 'A' * 200
90+
{ Write-Message -Message $LongMessage -LogLevel 1 } | Should -Not -Throw
91+
}
92+
93+
It 'Should handle different log levels' {
94+
{ Write-Message -Message 'Info' -LogLevel 1 } | Should -Not -Throw
95+
{ Write-Message -Message 'Warning' -LogLevel 2 } | Should -Not -Throw
96+
{ Write-Message -Message 'Error' -LogLevel 3 } | Should -Not -Throw
97+
}
98+
99+
It 'Should handle empty messages' {
100+
{ Write-Message -Message '' -LogLevel 1 } | Should -Not -Throw
101+
}
102+
}
103+
104+
Describe 'Write-LogFile' {
105+
It 'Should create log file' -Skip:(-not $IsAdmin) {
106+
{ Write-LogFile -Message 'Test log entry' } | Should -Not -Throw
107+
}
108+
109+
It 'Should handle multiple messages' -Skip:(-not $IsAdmin) {
110+
$Messages = @('Message 1', 'Message 2', 'Message 3')
111+
{ $Messages | Write-LogFile } | Should -Not -Throw
112+
}
113+
114+
It 'Should handle different log levels' -Skip:(-not $IsAdmin) {
115+
{ Write-LogFile -Message 'Info message' -LogLevel 1 } | Should -Not -Throw
116+
{ Write-LogFile -Message 'Warning message' -LogLevel 2 } | Should -Not -Throw
117+
{ Write-LogFile -Message 'Error message' -LogLevel 3 } | Should -Not -Throw
118+
}
119+
}
120+
121+
Describe 'Get-Platform' {
122+
It 'Should return a valid platform' {
123+
$Result = Get-Platform
124+
$Result | Should -BeIn @('Client', 'Server')
125+
}
126+
127+
It 'Should match OS type' {
128+
$Result = Get-Platform
129+
if ($OSInfo.IsServer) {
130+
$Result | Should -Be 'Server'
131+
} else {
132+
$Result | Should -Be 'Client'
133+
}
134+
}
135+
}
136+
137+
Describe 'Get-OSName' {
138+
It 'Should return a valid OS name' {
139+
$Result = Get-OSName
140+
$ValidNames = @('Windows2025', 'Windows2022', 'Windows2019', 'Windows2016', 'Windows11', 'Windows10', 'Unknown')
141+
$Result | Should -BeIn $ValidNames
142+
}
143+
144+
It 'Should match current OS' {
145+
$Result = Get-OSName
146+
if ($OSInfo.IsWindows11) {
147+
$Result | Should -Be 'Windows11'
148+
} elseif ($OSInfo.IsWindows10) {
149+
$Result | Should -Be 'Windows10'
150+
} elseif ($OSInfo.IsServer2025) {
151+
$Result | Should -Be 'Windows2025'
152+
} elseif ($OSInfo.IsServer2022) {
153+
$Result | Should -Be 'Windows2022'
154+
}
155+
}
156+
}
157+
158+
Describe 'Get-Model' {
159+
It 'Should return a valid model type' {
160+
$Result = Get-Model
161+
$Result | Should -BeIn @('Virtual', 'Physical')
162+
}
163+
}
164+
165+
Describe 'Get-SettingsContent' {
166+
BeforeAll {
167+
$TestJsonPath = "$env:TEMP\test-settings.json"
168+
$TestContent = @{
169+
MinimumBuild = '10.0.19041'
170+
MaximumBuild = '10.0.99999'
171+
Registry = @{
172+
Type = 'Direct'
173+
Set = @()
174+
}
175+
} | ConvertTo-Json
176+
Set-Content -Path $TestJsonPath -Value $TestContent
177+
}
178+
179+
It 'Should parse valid JSON file' {
180+
$Result = Get-SettingsContent -Path $TestJsonPath
181+
$Result | Should -Not -BeNullOrEmpty
182+
$Result.MinimumBuild | Should -Be '10.0.19041'
183+
}
184+
185+
It 'Should throw on invalid file path' {
186+
{ Get-SettingsContent -Path 'C:\NonExistent\file.json' } | Should -Throw
187+
}
188+
189+
AfterAll {
190+
if (Test-Path $TestJsonPath) {
191+
Remove-Item -Path $TestJsonPath -Force
192+
}
193+
}
194+
}
195+
196+
Describe 'Set-Registry' {
197+
BeforeAll {
198+
$TestRegPath = 'HKCU:\Software\PesterTest'
199+
}
200+
201+
It 'Should create registry key and set value' -Skip:(-not $IsAdmin) {
202+
$Setting = @(
203+
@{
204+
path = $TestRegPath
205+
name = 'TestValue'
206+
value = 'TestData'
207+
type = 'String'
208+
protected = $false
209+
}
210+
)
211+
212+
{ Set-Registry -Setting $Setting -Confirm:$false } | Should -Not -Throw
213+
214+
if (Test-Path $TestRegPath) {
215+
$Value = Get-ItemProperty -Path $TestRegPath -Name 'TestValue' -ErrorAction SilentlyContinue
216+
$Value.TestValue | Should -Be 'TestData'
217+
}
218+
}
219+
220+
AfterAll {
221+
if (Test-Path $TestRegPath) {
222+
Remove-Item -Path $TestRegPath -Recurse -Force -ErrorAction SilentlyContinue
223+
}
224+
}
225+
}
226+
227+
Describe 'New-Directory' {
228+
BeforeAll {
229+
$TestDirPath = "$env:TEMP\PesterTestDir"
230+
}
231+
232+
It 'Should create directory' {
233+
{ New-Directory -Path $TestDirPath -Confirm:$false } | Should -Not -Throw
234+
Test-Path -Path $TestDirPath | Should -Be $true
235+
}
236+
237+
It 'Should not error if directory exists' {
238+
{ New-Directory -Path $TestDirPath -Confirm:$false } | Should -Not -Throw
239+
}
240+
241+
AfterAll {
242+
if (Test-Path $TestDirPath) {
243+
Remove-Item -Path $TestDirPath -Recurse -Force
244+
}
245+
}
246+
}
247+
248+
Describe 'Remove-Path' {
249+
BeforeAll {
250+
$TestPath = "$env:TEMP\PesterTestRemove"
251+
New-Item -Path $TestPath -ItemType Directory -Force | Out-Null
252+
}
253+
254+
It 'Should remove path' -Skip:(-not $IsAdmin) {
255+
{ Remove-Path -Path @($TestPath) -Confirm:$false } | Should -Not -Throw
256+
Test-Path -Path $TestPath | Should -Be $false
257+
}
258+
}
259+
260+
Describe 'Install-SystemLanguage' {
261+
It 'Should only run on Windows 11 or Server 2025+' {
262+
if (-not $OSInfo.SupportsLanguagePack) {
263+
Set-ItResult -Skipped -Because "Install-SystemLanguage requires Windows 11 (Build 22000+) or Windows Server 2025 (Build 26100+). Current OS: $($OSInfo.Caption), Build: $($OSInfo.Build)"
264+
}
265+
}
266+
267+
It 'Should attempt to import LanguagePackManagement module on supported OS' -Skip:(-not $OSInfo.SupportsLanguagePack) {
268+
{ Install-SystemLanguage -Language 'en-US' -Confirm:$false -WhatIf } | Should -Not -Throw
269+
}
270+
271+
It 'Should handle missing module gracefully on unsupported OS' -Skip:($OSInfo.SupportsLanguagePack) {
272+
# On older OS, the function should handle the missing cmdlet gracefully
273+
{ Install-SystemLanguage -Language 'en-US' -Confirm:$false -WhatIf } | Should -Not -Throw
274+
}
275+
}
276+
277+
Describe 'Set-SystemLocale' {
278+
It 'Should set locale on all Windows versions' {
279+
$TestLanguage = [System.Globalization.CultureInfo]::GetCultureInfo('en-US')
280+
{ Set-SystemLocale -Language $TestLanguage -Confirm:$false -WhatIf } | Should -Not -Throw
281+
}
282+
283+
It 'Should use Set-SystemPreferredUILanguage on supported OS' -Skip:(-not $OSInfo.SupportsLanguagePack) {
284+
$TestLanguage = [System.Globalization.CultureInfo]::GetCultureInfo('en-US')
285+
Get-Command -Name 'Set-SystemPreferredUILanguage' -ErrorAction SilentlyContinue | Should -Not -BeNullOrEmpty
286+
}
287+
288+
It 'Should skip Set-SystemPreferredUILanguage on older OS' -Skip:($OSInfo.SupportsLanguagePack) {
289+
Get-Command -Name 'Set-SystemPreferredUILanguage' -ErrorAction SilentlyContinue | Should -BeNullOrEmpty
290+
}
291+
}
292+
293+
Describe 'Set-TimeZoneUsingName' {
294+
It 'Should set time zone with WhatIf' {
295+
{ Set-TimeZoneUsingName -TimeZone 'UTC' -Confirm:$false -WhatIf } | Should -Not -Throw
296+
}
297+
298+
It 'Should handle invalid time zone' {
299+
{ Set-TimeZoneUsingName -TimeZone 'InvalidTimeZone' -Confirm:$false -WhatIf } | Should -Throw
300+
}
301+
}
302+
303+
Describe 'Test-IsOobeComplete' {
304+
It 'Should return a boolean value' {
305+
$Result = Test-IsOobeComplete
306+
$Result | Should -BeOfType [System.Boolean]
307+
}
308+
309+
It 'Should return true on fully configured system' {
310+
$Result = Test-IsOobeComplete
311+
# On a running system where tests are executed, OOBE should be complete
312+
$Result | Should -Be $true
313+
}
314+
}
315+
316+
Describe 'Get-CurrentUserSid' {
317+
It 'Should return valid SID' {
318+
$Result = Get-CurrentUserSid
319+
$Result | Should -Match '^S-1-'
320+
}
321+
}
322+
323+
Describe 'Copy-RegExe' {
324+
It 'Should copy reg.exe to temp location' -Skip:(-not $IsAdmin) {
325+
$Result = Copy-RegExe
326+
$Result | Should -Not -BeNullOrEmpty
327+
Test-Path -Path $Result | Should -Be $true
328+
329+
# Cleanup
330+
if (Test-Path $Result) {
331+
Remove-Item -Path $Result -Force -ErrorAction SilentlyContinue
332+
}
333+
}
334+
}
335+
336+
Describe 'Service Management Functions' {
337+
BeforeAll {
338+
# Use a service that exists on all Windows versions
339+
$TestService = 'wuauserv' # Windows Update service
340+
}
341+
342+
It 'Should query service status' {
343+
$Service = Get-Service -Name $TestService -ErrorAction SilentlyContinue
344+
$Service | Should -Not -BeNullOrEmpty
345+
}
346+
347+
It 'Should handle Start-NamedService with WhatIf' {
348+
{ Start-NamedService -Service @($TestService) -Confirm:$false -WhatIf } | Should -Not -Throw
349+
}
350+
351+
It 'Should handle Stop-NamedService with WhatIf' {
352+
{ Stop-NamedService -Service @($TestService) -Confirm:$false -WhatIf } | Should -Not -Throw
353+
}
354+
355+
It 'Should handle Restart-NamedService with WhatIf' {
356+
{ Restart-NamedService -Service @($TestService) -Confirm:$false -WhatIf } | Should -Not -Throw
357+
}
358+
}
359+
360+
AfterAll {
361+
Remove-Module -Name 'Install-Defaults' -Force -ErrorAction SilentlyContinue
362+
}

0 commit comments

Comments
 (0)