Tests/Unit/MSFT_WindowsProcess.Tests.ps1
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] param () $errorActionPreference = 'Stop' Set-StrictMode -Version 'Latest' $script:moduleRootPath = Split-Path -Path $PSScriptRoot -Parent $script:testHelpersPath = Join-Path -Path $script:moduleRootPath -ChildPath 'TestHelpers' Import-Module -Name (Join-Path -Path $script:testHelpersPath -ChildPath 'CommonTestHelper.psm1') $script:testEnvironment = Enter-DscResourceTestEnvironment ` -DscResourceModuleName 'PSDscResources' ` -DscResourceName 'MSFT_WindowsProcess' ` -TestType 'Unit' try { InModuleScope 'MSFT_WindowsProcess' { # Mock objects $script:validPath1 = 'ValidPath1' $script:validPath2 = 'ValidPath2' $script:validPath3 = 'ValidPath3' $script:invalidPath = 'InvalidPath' $script:testUserName = 'TestUserName12345' $testPassword = 'StrongOne7.' $testSecurePassword = ConvertTo-SecureString -String $testPassword -AsPlainText -Force $script:testCredential = New-Object PSCredential ($script:testUserName, $testSecurePassword) $script:exceptionMessage = 'Test Invalid Operation Exception' $script:mockProcess1 = @{ Path = $script:validPath1 CommandLine = 'C:\temp\test.exe argument1 argument2 argument3' Arguments = 'argument1 argument2 argument3' ProcessId = 12345 Id = 12345 PagedMemorySize64 = 1048 NonpagedSystemMemorySize64 = 16 VirtualMemorySize64 = 256 HandleCount = 50 } $script:mockProcess2 = @{ Path = $script:validPath2 CommandLine = '' Arguments = '' ProcessId = 54321 Id = 54321 PagedMemorySize64 = 2096 NonpagedSystemMemorySize64 = 8 VirtualMemorySize64 = 512 HandleCount = 5 } $script:mockProcess3 = @{ Path = $script:validPath1 CommandLine = 'C:\test.exe arg6' Arguments = 'arg6' ProcessId = 1111101 Id = 1111101 PagedMemorySize64 = 512 NonpagedSystemMemorySize64 = 32 VirtualMemorySize64 = 64 HandleCount = 0 } $script:mockProcess4 = @{ Path = $script:validPath1 CommandLine = 'C:\test.exe arg6' Arguments = 'arg6' ProcessId = 1111101 Id = 1111101 PagedMemorySize64 = 510 NonpagedSystemMemorySize64 = 16 VirtualMemorySize64 = 8 HandleCount = 8 } $script:errorProcess = @{ Path = $script:validPath3 CommandLine = '' Arguments = '' ProcessId = 77777 Id = 77777 PagedMemorySize64 = 0 NonpagedSystemMemorySize64 = 0 VirtualMemorySize64 = 0 HandleCount = 0 } Describe 'WindowsProcess\Get-TargetResource' { Mock -CommandName Expand-Path -MockWith { return $Path } Mock -CommandName Get-ProcessCimInstance -MockWith { if ($Path -eq $script:validPath1) { return @($script:mockProcess1, $script:mockProcess3) } elseif ($Path -eq $script:validPath2) { return @($script:mockProcess2) } elseif ($Path -eq $script:validPath3) { return @($script:errorProcess) } else { return @() } } Mock -CommandName Get-Process -MockWith { if ($ID -eq $script:mockProcess1.Id) { return $script:mockProcess1 } elseif ($script:mockProcess2.Id) { return $script:mockProcess2 } elseif ($script:mockProcess3.Id) { return $script:mockProcess3 } else { return $script:errorProcess } } Mock -CommandName New-InvalidOperationException -MockWith { Throw $script:exceptionMessage } Mock -CommandName New-InvalidArgumentException -MockWith { Throw $script:exceptionMessage } It 'Should return the correct properties for a process that is Absent' { $processArguments = 'TestGetProperties' $getTargetResourceResult = Get-TargetResource -Path $invalidPath ` -Arguments $processArguments $getTargetResourceResult.Arguments | Should Be $processArguments $getTargetResourceResult.Ensure | Should Be 'Absent' $getTargetResourceResult.Path | Should Be $invalidPath Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It } It 'Should return the correct properties for one process with a credential' { $getTargetResourceResult = Get-TargetResource -Path $script:validPath2 ` -Arguments $script:mockProcess2.Arguments ` -Credential $script:testCredential $getTargetResourceResult.VirtualMemorySize | Should Be $script:mockProcess2.VirtualMemorySize64 $getTargetResourceResult.Arguments | Should Be $script:mockProcess2.Arguments $getTargetResourceResult.Ensure | Should Be 'Present' $getTargetResourceResult.PagedMemorySize | Should Be $script:mockProcess2.PagedMemorySize64 $getTargetResourceResult.Path | Should Be $script:mockProcess2.Path $getTargetResourceResult.NonPagedMemorySize | Should Be $script:mockProcess2.NonpagedSystemMemorySize64 $getTargetResourceResult.HandleCount | Should Be $script:mockProcess2.HandleCount $getTargetResourceResult.ProcessId | Should Be $script:mockProcess2.ProcessId Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-Process -Exactly 1 -Scope It } It 'Should return the correct properties when there are multiple processes' { $getTargetResourceResult = Get-TargetResource -Path $script:validPath1 ` -Arguments $script:mockProcess1.Arguments $getTargetResourceResult.VirtualMemorySize | Should Be $script:mockProcess1.VirtualMemorySize64 $getTargetResourceResult.Arguments | Should Be $script:mockProcess1.Arguments $getTargetResourceResult.Ensure | Should Be 'Present' $getTargetResourceResult.PagedMemorySize | Should Be $script:mockProcess1.PagedMemorySize64 $getTargetResourceResult.Path | Should Be $script:mockProcess1.Path $getTargetResourceResult.NonPagedMemorySize | Should Be $script:mockProcess1.NonpagedSystemMemorySize64 $getTargetResourceResult.HandleCount | Should Be $script:mockProcess1.HandleCount $getTargetResourceResult.ProcessId | Should Be $script:mockProcess1.ProcessId Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-Process -Exactly 1 -Scope It } } Describe 'WindowsProcess\Set-TargetResource' { Mock -CommandName Expand-Path -MockWith { return $Path } Mock -CommandName Get-ProcessCimInstance -MockWith { if ($Path -eq $script:validPath1) { return @($script:mockProcess1, $script:mockProcess3) } elseif ($Path -eq $script:validPath2) { return @($script:mockProcess2) } elseif ($Path -eq $script:validPath3) { return @($script:errorProcess) } else { return @() } } Mock -CommandName New-InvalidOperationException -MockWith { Throw $script:exceptionMessage } Mock -CommandName New-InvalidArgumentException -MockWith { Throw $script:exceptionMessage } Mock -CommandName Stop-Process -MockWith { return $null } ` -ParameterFilter { ($Id -contains $script:mockProcess1.ProcessId) -or ` ($Id -contains $script:mockProcess2.ProcessId) -or ` ($Id -contains $script:mockProcess3.ProcessId) } Mock -CommandName Stop-Process -MockWith { return 'error' } ` -ParameterFilter { $Id -contains $script:errorProcess.ProcessId} Mock -CommandName Test-IsRunFromLocalSystemUser -MockWith { return $true } Mock -CommandName Wait-ProcessCount -MockWith { return $true } It 'Should not throw when Ensure set to Absent and processes are running' { { Set-TargetResource -Path $script:validPath1 ` -Arguments $script:mockProcess1.Arguments ` -Credential $script:testCredential ` -Ensure 'Absent' } | Should Not Throw Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Stop-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 1 -Scope It } It 'Should not throw when Ensure set to Absent and processes are not running' { { Set-TargetResource -Path $script:invalidPath ` -Arguments '' ` -Ensure 'Absent' } | Should Not Throw Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Stop-Process -Exactly 0 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 0 -Scope It } It 'Should throw an invalid operation exception when Stop-Process throws an error' { { Set-TargetResource -Path $script:errorProcess.Path ` -Arguments '' ` -Ensure 'Absent' } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Stop-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName New-InvalidOperationException -Exactly 1 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 0 -Scope It } Mock -CommandName Wait-ProcessCount -MockWith { return $false } It 'Should throw an invalid operation exception when there is a problem waiting for the processes' { { Set-TargetResource -Path $script:validPath1 ` -Arguments $script:mockProcess1.Arguments ` -Ensure 'Absent' } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Stop-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 1 -Scope It Assert-MockCalled -CommandName New-InvalidOperationException -Exactly 1 -Scope It } Mock -CommandName Wait-ProcessCount -MockWith { return $true } Mock -CommandName Start-ProcessAsLocalSystemUser -MockWith {} It 'Should not throw when Ensure set to Present and processes are not running and credential passed in' { { Set-TargetResource -Path $script:invalidPath ` -Arguments $script:mockProcess1.Arguments ` -Credential $script:testCredential ` -Ensure 'Present' } | Should Not Throw Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Test-IsRunFromLocalSystemUser -Exactly 1 -Scope It Assert-MockCalled -CommandName Start-ProcessAsLocalSystemUser -Exactly 1 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 1 -Scope It } Mock -CommandName Start-ProcessAsLocalSystemUser -MockWith {} Mock -CommandName Assert-PathArgumentRooted -MockWith {} Mock -CommandName Assert-PathArgumentValid -MockWith {} It 'Should throw when Ensure set to Present, processes not running and credential and WorkingDirectory passed' { { Set-TargetResource -Path $script:invalidPath ` -Arguments $script:mockProcess1.Arguments ` -Credential $script:testCredential ` -WorkingDirectory 'test working directory' ` -Ensure 'Present' } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Test-IsRunFromLocalSystemUser -Exactly 1 -Scope It Assert-MockCalled -CommandName Start-ProcessAsLocalSystemUser -Exactly 0 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 0 -Scope It Assert-MockCalled -CommandName Assert-PathArgumentRooted -Exactly 1 -Scope It Assert-MockCalled -CommandName Assert-PathArgumentValid -Exactly 1 -Scope It Assert-MockCalled -CommandName New-InvalidArgumentException -Exactly 1 -Scope It } $testErrorRecord = 'test Start-ProcessAsLocalSystemUser error record' Mock -CommandName Start-ProcessAsLocalSystemUser -MockWith { Throw $testErrorRecord } It 'Should throw when Ensure set to Present and Start-processAsLocalSystemUser fails' { { Set-TargetResource -Path $script:invalidPath ` -Arguments $script:mockProcess1.Arguments ` -Credential $script:testCredential ` -Ensure 'Present' } | Should Throw $testErrorRecord Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Test-IsRunFromLocalSystemUser -Exactly 1 -Scope It Assert-MockCalled -CommandName Start-ProcessAsLocalSystemUser -Exactly 1 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 0 -Scope It } Mock -CommandName Start-Process -MockWith {} It 'Should not throw when Ensure set to Present and processes are not running and no credential passed' { { Set-TargetResource -Path $script:invalidPath ` -Arguments $script:mockProcess1.Arguments ` -Ensure 'Present' } | Should Not Throw Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Start-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 1 -Scope It } $mockStartProcessException = New-Object -TypeName 'InvalidOperationException' ` -ArgumentList @('Start-Process test exception') Mock -CommandName Start-Process -MockWith { Throw $mockStartProcessException } It 'Should throw when Ensure set to Present and Start-Process fails' { { Set-TargetResource -Path $script:invalidPath ` -Arguments $script:mockProcess1.Arguments ` -Ensure 'Present' } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Start-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 0 -Scope It Assert-MockCalled -CommandName New-InvalidOperationException -Exactly 1 -Scope It } Mock -CommandName Wait-ProcessCount -MockWith { return $false } Mock -CommandName Start-Process -MockWith {} It 'Should throw when there is a failure waiting for the process to start' { { Set-TargetResource -Path $script:invalidPath ` -Arguments $script:mockProcess1.Arguments ` -Ensure 'Present' } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Start-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 1 -Scope It } Mock -CommandName Wait-ProcessCount -MockWith { return $true } It 'Should not throw when Ensure set to Present and processes are already running' { { Set-TargetResource -Path $script:validPath1 ` -Arguments $script:mockProcess1.Arguments ` -Ensure 'Present' } | Should Not Throw Assert-MockCalled -CommandName Expand-Path -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessCimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Start-Process -Exactly 0 -Scope It Assert-MockCalled -CommandName Wait-ProcessCount -Exactly 0 -Scope It } } Describe 'WindowsProcess\Test-TargetResource' { Mock -CommandName Expand-Path -MockWith { return $Path } Mock -CommandName Get-ProcessCimInstance -MockWith { if ($Path -eq $script:validPath1) { return @($script:mockProcess1, $script:mockProcess3) } elseif ($Path -eq $script:validPath2) { return @($script:mockProcess2) } elseif ($Path -eq $script:validPath3) { return @($script:errorProcess) } else { return @() } } It 'Should return true when Ensure set to Present and process is running' { $testTargetResourceResult = Test-TargetResource -Path $script:validPath1 ` -Arguments $script:mockProcess1.Arguments ` -Ensure 'Present' $testTargetResourceResult | Should Be $true } It 'Should return false when Ensure set to Present and process is not running' { $testTargetResourceResult = Test-TargetResource -Path $script:invalidPath ` -Arguments $script:mockProcess1.Arguments ` -Ensure 'Present' $testTargetResourceResult | Should Be $false } It 'Should return true when Ensure set to Absent and process is not running and Credential passed' { $testTargetResourceResult = Test-TargetResource -Path $script:invalidPath ` -Arguments $script:mockProcess1.Arguments ` -Credential $script:testCredential ` -Ensure 'Absent' $testTargetResourceResult | Should Be $true } It 'Should return false when Ensure set to Absent and process is running' { $testTargetResourceResult = Test-TargetResource -Path $script:validPath1 ` -Arguments $script:mockProcess1.Arguments ` -Ensure 'Absent' $testTargetResourceResult | Should Be $false } } Describe 'WindowsProcess\Expand-Path' { Mock -CommandName New-InvalidArgumentException -MockWith { Throw $script:exceptionMessage } Mock -CommandName Test-Path -MockWith { return $true } It 'Should return the original path when path is rooted' { $rootedPath = 'C:\testProcess.exe' $expandPathResult = Expand-Path -Path $rootedPath $expandPathResult | Should Be $rootedPath } Mock -CommandName Test-Path -MockWith { return $false } It 'Should throw an invalid argument exception when Path is rooted and does not exist' { $rootedPath = 'C:\invalidProcess.exe' { Expand-Path -Path $rootedPath} | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName New-InvalidArgumentException -Exactly 1 -Scope It } It 'Should throw an invalid argument exception when Path is unrooted and does not exist' { $unrootedPath = 'invalidfile.txt' { Expand-Path -Path $unrootedPath} | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName New-InvalidArgumentException -Exactly 1 -Scope It } } Describe 'WindowsProcess\Get-ProcessCimInstance' { Mock -CommandName Get-Process -MockWith { return @($script:mockProcess2) } Mock -CommandName Get-CimInstance -MockWith { return $script:mockProcess2 } It 'Should return the correct process when it exists and no arguments passed' { $resultProcess = Get-ProcessCimInstance -Path $script:mockProcess2.Path $resultProcess | Should Be @($script:mockProcess2) Assert-MockCalled -CommandName Get-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-CimInstance -Exactly 1 -Scope It } Mock -CommandName Get-Process -MockWith { return @($script:mockProcess1) } Mock -CommandName Get-CimInstance -MockWith { return $script:mockProcess1 } It 'Should return the correct process when it exists and arguments are passed' { $resultProcess = Get-ProcessCimInstance -Path $script:mockProcess1.Path ` -Arguments $script:mockProcess1.Arguments $resultProcess | Should Be @($script:mockProcess1) Assert-MockCalled -CommandName Get-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-CimInstance -Exactly 1 -Scope It } Mock -CommandName Get-Process -MockWith { return @($script:mockProcess1, $script:mockProcess1, $script:mockProcess1) } Mock -CommandName Get-CimInstance -MockWith { return @($script:mockProcess1, $script:mockProcess1, $script:mockProcess1) } It 'Should return the correct processes when multiple exist' { $resultProcess = Get-ProcessCimInstance -Path $script:mockProcess1.Path ` -Arguments $script:mockProcess1.Arguments $resultProcess | Should Be @($script:mockProcess1, $script:mockProcess1, $script:mockProcess1) Assert-MockCalled -CommandName Get-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-CimInstance -Exactly 3 -Scope It } Mock -CommandName Get-Process -MockWith { return @($script:mockProcess2, $script:mockProcess2) } Mock -CommandName Get-CimInstance -MockWith { return @($script:mockProcess2, $script:mockProcess2) } It 'Should return the correct processes when they exists and cim instance threshold is lower than number of processes found' { $resultProcess = Get-ProcessCimInstance -Path $script:mockProcess2.Path ` -Arguments $script:mockProcess2.Arguments ` -UseGetCimInstanceThreshold 1 $resultProcess | Should Be @($script:mockProcess2, $script:mockProcess2) Assert-MockCalled -CommandName Get-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-CimInstance -Exactly 1 -Scope It } Mock -CommandName Get-Process -MockWith { return @($script:mockProcess2) } Mock -CommandName Get-CimInstance -MockWith { return $script:mockProcess2 } Mock -CommandName Get-ProcessOwner -MockWith { return ($env:computerName + '\' + $script:testUsername) } ` -ParameterFilter { ($Process -eq $script:mockProcess2) } It 'Should return the correct process when it exists and Credential is passed in' { $resultProcess = Get-ProcessCimInstance -Path $script:mockProcess2.Path ` -Credential $script:testCredential $resultProcess | Should Be @($script:mockProcess2) Assert-MockCalled -CommandName Get-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-CimInstance -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-ProcessOwner -Exactly 1 -Scope It } Mock -CommandName Get-Process -MockWith { return @($script:mockProcess3, $script:mockProcess3, $script:mockProcess4, $script:mockProcess2) } Mock -CommandName Get-CimInstance -MockWith { return @($script:mockProcess3, $script:mockProcess3, $script:mockProcess4, $script:mockProcess2) } Mock -CommandName Get-ProcessOwner -MockWith { return ($env:computerName + '\' + $script:testUsername) } ` -ParameterFilter { ($Process -eq $script:mockProcess3) } Mock -CommandName Get-ProcessOwner -MockWith { return ('wrongDomain' + '\' + $script:testUsername) } ` -ParameterFilter { ($Process -eq $script:mockProcess4) -or ($Process -eq $script:mockProcess2) } It 'Should return only processes that match Credential' { $resultProcess = Get-ProcessCimInstance -Path $script:mockProcess3.Path ` -Credential $script:testCredential ` -Arguments $script:mockProcess3.Arguments ` -UseGetCimInstanceThreshold 1 $resultProcess | Should Be @($script:mockProcess3, $script:mockProcess3) Assert-MockCalled -CommandName Get-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-CimInstance -Exactly 1 -Scope It } Mock -CommandName Get-ProcessOwner -MockWith { return ($env:computerName + '\' + $script:testUsername) } ` -ParameterFilter { ($Process -eq $script:mockProcess3) -or ($Process -eq $script:mockProcess2) } Mock -CommandName Get-ProcessOwner -MockWith { return ('wrongDomain' + '\' + $script:testUsername) } ` -ParameterFilter { ($Process -eq $script:mockProcess4) } It 'Should return only processes that match Credential and Arguments' { $resultProcess = Get-ProcessCimInstance -Path $script:mockProcess3.Path ` -Credential $script:testCredential ` -Arguments $script:mockProcess3.Arguments ` -UseGetCimInstanceThreshold 1 $resultProcess | Should Be @($script:mockProcess3, $script:mockProcess3) Assert-MockCalled -CommandName Get-Process -Exactly 1 -Scope It Assert-MockCalled -CommandName Get-CimInstance -Exactly 1 -Scope It } } Describe 'WindowsProcess\ConvertTo-EscapedStringForWqlFilter' { It 'Should return the same string when there are no escaped characters' { $inputString = 'testString%$.@123' $convertedString = ConvertTo-EscapedStringForWqlFilter -FilterString $inputString $convertedString | Should Be $inputString } It 'Should return a string with escaped characters: ("\)' { $inputString = '\test"string"\123' $expectedString = '\\test\"string\"\\123' $convertedString = ConvertTo-EscapedStringForWqlFilter -FilterString $inputString $convertedString | Should Be $expectedString } It "Should return a string with escaped characters: ('\)" { $inputString = "\test'string'\123" $expectedString = "\\test\'string\'\\123" $convertedString = ConvertTo-EscapedStringForWqlFilter -FilterString $inputString $convertedString | Should Be $expectedString } } Describe 'WindowsProcess\Get-ProcessOwner' { $mockOwner = @{ Domain = 'Mock Domain' User = 'Mock User' } Mock -CommandName Get-ProcessOwnerCimInstance -MockWith { return $mockOwner } It 'Should return the correct string with domain\user' { $owner = Get-ProcessOwner -Process $script:mockProcess1 $owner | Should Be ($mockOwner.Domain + '\' + $mockOwner.User) } It 'Should return the correct string with default-domain\user when domain is not there' { $mockOwner.Domain = $null $owner = Get-ProcessOwner -Process $script:mockProcess1 $owner | Should Be ($env:computerName + '\' + $mockOwner.User) } } Describe 'WindowsProcess\Get-ArgumentsFromCommandLineInput' { It 'Should return the correct arguments when single quotes are used' { $inputString = 'test.txt a b c' $argumentsReturned = Get-ArgumentsFromCommandLineInput -CommandLineInput $inputString $argumentsReturned | Should Be 'a b c' } It 'Should return the correct arguments when double quotes are used' { $inputString = '"test file test" a b c' $argumentsReturned = Get-ArgumentsFromCommandLineInput -CommandLineInput $inputString $argumentsReturned | Should Be 'a b c' } It 'Should return an empty string when an empty string is passed in' { $inputString = $null $resultString = [String]::Empty $argumentsReturned = Get-ArgumentsFromCommandLineInput -CommandLineInput $inputString $argumentsReturned | Should Be $resultString } It 'Should return an empty string when there are no arguments' { $inputString = 'test.txt' $resultString = [String]::Empty $argumentsReturned = Get-ArgumentsFromCommandLineInput -CommandLineInput $inputString $argumentsReturned | Should Be $resultString } } Describe 'WindowsProcess\Assert-HashtableDoesNotContainKey' { $mockHashtable = @{ Key1 = 'test key1' Key2 = 'test key2' Key3 = 'test key3' } Mock -CommandName New-InvalidArgumentException -MockWith { Throw $script:exceptionMessage } It 'Should not throw an exception if the hashtable does not contain a key' { $mockKey = @('k1', 'k2', 'k3', 'k4', 'k5') { Assert-HashTableDoesNotContainKey -Hashtable $mockHashtable -Key $mockKey } | Should Not Throw } It 'Should throw an exception if the hashtable contains a key' { $mockKey = @('k1', 'k2', 'Key3', 'k4', 'k5') { Assert-HashTableDoesNotContainKey -Hashtable $mockHashtable -Key $mockKey } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName New-InvalidArgumentException -Exactly 1 -Scope It } } Describe 'WindowsProcess\Wait-ProcessCount' { $mockProcessSettings = @{ Path = 'mockPath' Arguments = 'mockArguments' } Mock -CommandName Get-ProcessCimInstance -MockWith { return @($script:mockProcess1, $script:mockProcess3) } It 'Should return true when all processes are returned' { $processCountResult = Wait-ProcessCount -ProcessSettings $mockProcessSettings -ProcessCount 2 $processCountResult | Should Be $true } It 'Should return false when not all processes are returned' { $processCountResult = Wait-ProcessCount -ProcessSettings $mockProcessSettings ` -ProcessCount 3 ` -WaitTime 10 $processCountResult | Should Be $false } } Describe 'WindowsProcess\Assert-PathArgumentRooted' { Mock -CommandName New-InvalidArgumentException -MockWith { Throw $script:exceptionMessage } It 'Should not throw when path is rooted' { $rootedPath = 'C:\testProcess.exe' { Assert-PathArgumentRooted -PathArgumentName 'mock test name' ` -PathArgument $rootedPath } | Should Not Throw } It 'Should throw an invalid argument exception when Path is unrooted' { $unrootedPath = 'invalidfile.txt' { Assert-PathArgumentRooted -PathArgumentName 'mock test name' ` -PathArgument $unrootedPath } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName New-InvalidArgumentException -Exactly 1 -Scope It } } Describe 'WindowsProcess\Assert-PathArgumentValid' { Mock -CommandName New-InvalidArgumentException -MockWith { Throw $script:exceptionMessage } It 'Should not throw when path is valid' { Mock -CommandName Test-Path -MockWith { return $true } { Assert-PathArgumentValid -PathArgumentName 'test name' ` -PathArgument 'validPath' } | Should Not Throw } It 'Should throw an invalid argument exception when Path is not valid' { Mock -CommandName Test-Path -MockWith { return $false } { Assert-PathArgumentValid -PathArgumentName 'test name' ` -PathArgument 'invalidPath' } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName New-InvalidArgumentException -Exactly 1 -Scope It } } Describe 'WindowsProcess\Split-Credential' { Mock -CommandName New-InvalidArgumentException -MockWith { Throw $script:exceptionMessage } It 'Should return correct domain and username with @ seperator' { $testUsername = 'user@domain' $testPassword = ConvertTo-SecureString -String 'dummy' -AsPlainText -Force $testCredential = New-Object -TypeName 'PSCredential' -ArgumentList @($testUsername, $testPassword) $splitCredentialResult = Split-Credential -Credential $testCredential $splitCredentialResult.Domain | Should Be 'domain' $splitCredentialResult.Username | Should Be 'user' } It 'Should return correct domain and username with \ seperator' { $testUsername = 'domain\user' $testPassword = ConvertTo-SecureString -String 'dummy' -AsPlainText -Force $testCredential = New-Object -TypeName 'PSCredential' -ArgumentList @($testUsername, $testPassword) $splitCredentialResult = Split-Credential -Credential $testCredential $splitCredentialResult.Domain | Should Be 'domain' $splitCredentialResult.Username | Should Be 'user' } It 'Should return correct domain and username with a local user' { $testUsername = 'localuser' $testPassword = ConvertTo-SecureString -String 'dummy' -AsPlainText -Force $testCredential = New-Object -TypeName 'PSCredential' -ArgumentList @($testUsername, $testPassword) $splitCredentialResult = Split-Credential -Credential $testCredential $splitCredentialResult.Domain | Should Be $env:computerName $splitCredentialResult.Username | Should Be 'localuser' } It 'Should throw an invalid argument exception when more than one \ in username' { $testUsername = 'user\domain\foo' $testPassword = ConvertTo-SecureString -String 'dummy' -AsPlainText -Force $testCredential = New-Object -TypeName 'PSCredential' -ArgumentList @($testUsername, $testPassword) { $splitCredentialResult = Split-Credential -Credential $testCredential } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName New-InvalidArgumentException -Exactly 1 -Scope It } It 'Should throw an invalid argument exception when more than one @ in username' { $testUsername = 'user@domain@foo' $testPassword = ConvertTo-SecureString -String 'dummy' -AsPlainText -Force $testCredential = New-Object -TypeName 'PSCredential' -ArgumentList @($testUsername, $testPassword) { $splitCredentialResult = Split-Credential -Credential $testCredential } | Should Throw $script:exceptionMessage Assert-MockCalled -CommandName New-InvalidArgumentException -Exactly 1 -Scope It } } } } finally { Exit-DscResourceTestEnvironment -TestEnvironment $script:testEnvironment } |