adding process files only

This commit is contained in:
Mariah Breakey
2016-12-14 20:22:16 -08:00
parent b00ca5233e
commit 4bab1eca63
16 changed files with 3166 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,18 @@
[ClassVersion("1.0.0"), FriendlyName("WindowsProcess")]
class MSFT_WindowsProcess : OMI_BaseResource
{
[Key, Description("The full path or file name to the process executable to start or stop.")] String Path;
[Key, Description("A string of arguments to pass to the process executable. Pass in an empty string if no arguments are needed.")] String Arguments;
[Write, EmbeddedInstance("MSFT_Credential"), Description("The credential to run the process under.")] String Credential;
[Write, ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}, Description("Indicates whether the process is present (running) or absent (not running).")] String Ensure;
[Write, Description("The path to write the standard output stream to.")] String StandardOutputPath;
[Write, Description("The path to write the standard error stream to.")] String StandardErrorPath;
[Write, Description("The path to receive standard input from.")] String StandardInputPath;
[Write, Description("The directory to run the processes under.")] String WorkingDirectory;
[Read, Description("The amount of paged memory, in bytes, allocated for the process.")] UInt64 PagedMemorySize;
[Read, Description("The amount of nonpaged memory, in bytes, allocated for the process.")] UInt64 NonPagedMemorySize;
[Read, Description("The amount of virtual memory, in bytes, allocated for the process.")] UInt64 VirtualMemorySize;
[Read, Description("The number of handles opened by the process.")] SInt32 HandleCount;
[Read, Description("The unique identifier of the process.")] SInt32 ProcessId;
[Read, Description("The number of instances of the given process that are currently running.")] SInt32 ProcessCount;
};
@@ -0,0 +1,36 @@
# Localized resources for MSFT_WindowsProcess
ConvertFrom-StringData @'
CouldNotCreateProcessError = Could not create process. Error code:
DuplicateTokenError = Duplicate token. Error code:
FileNotFound = File '{0}' not found in the environment path.
ErrorInvalidUserName = Invalid username: {0}. Username cannot contain multiple '@' or multiple '\'
ErrorParametersNotSupportedWithCredential = Can't specify StandardOutputPath, StandardInputPath or WorkingDirectory when trying to run a process under a local user.
ErrorRunAsCredentialParameterNotSupported = The PsDscRunAsCredential parameter is not supported by the Process resource. To start the process with user '{0}', add the Credential parameter.
ErrorStarting = Failure starting process matching path '{0}'. Message: {1}.
ErrorStopping = Failure stopping processes matching path '{0}' with IDs '({1})'. Message: {2}.
FailureWaitingForProcessesToStart = Failed to wait for processes to start.
FailureWaitingForProcessesToStop = Failed to wait for processes to stop.
GetTargetResourceStartMessage = Begin executing Get functionality for the process {0}.
GetTargetResourceEndMessage = End executing Get functionality for the process {0}.
OpenProcessTokenError = Error while opening process token. Error code:
ParameterShouldNotBeSpecified = Parameter {0} should not be specified.
PathShouldBeAbsolute = The path '{0}' should be absolute for argument '{1}'.
PathShouldExist = The path '{0}' should exist for argument '{1}'.
PrivilegeLookingUpError = Error while looking up privilege. Error code:
ProcessAlreadyStarted = Process matching path '{0}' found running. No action required.
ProcessAlreadyStopped = Process matching path '{0}' not found running. No action required.
ProcessesStarted = Processes matching path '{0}' started.
ProcessesStopped = Processes matching path '{0}' with IDs '({1})' stopped.
RetriveStatusError = Failed to retrieve status. Error code:
SetTargetResourceStartMessage = Begin executing Set functionality for the process {0}.
SetTargetResourceEndMessage = End executing Set functionality for the process {0}.
StartingProcessWhatif = Start-Process.
StoppingProcessWhatIf = Stop-Process.
TestTargetResourceStartMessage = Begin executing Test functionality for the process {0}.
TestTargetResourceEndMessage = End executing Test functionality for the process {0}.
TokenElevationError = Error while getting token elevation. Error code:
UserCouldNotBeLoggedError = User could not be logged. Error code:
WaitFailedError = Failed while waiting for process. Error code:
VerboseInProcessHandle = In process handle {0}.
'@
+25
View File
@@ -0,0 +1,25 @@
<#
.SYNOPSIS
Starts the gpresult process which generates a log about the group policy.
The path to the log is provided in 'Arguments'.
#>
Configuration Sample_WindowsProcess_Start
{
param
()
Import-DSCResource -ModuleName 'PSDscResources'
Node localhost
{
WindowsProcess GPresult
{
Path = 'C:\Windows\System32\gpresult.exe'
Arguments = '/h C:\gp2.htm'
Ensure = 'Present'
}
}
}
Sample_WindowsProcess_Start
@@ -0,0 +1,37 @@
<#
.SYNOPSIS
Starts the gpresult process under the given credential which generates a log
about the group policy. The path to the log is provided in 'Arguments'.
.PARAMETER Credential
Credential to start the process under.
#>
Configuration Sample_WindowsProcess_StartUnderUser
{
[CmdletBinding()]
param
(
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = (Get-Credential)
)
Import-DSCResource -ModuleName 'PSDscResources'
Node localhost
{
WindowsProcess GPresult
{
Path = 'C:\Windows\System32\gpresult.exe'
Arguments = '/h C:\gp2.htm'
Credential = $Credential
Ensure = 'Present'
}
}
}
<#
To use the sample(s) with credentials, see blog at:
http://blogs.msdn.com/b/powershell/archive/2014/01/31/want-to-secure-credentials-in-windows-powershell-desired-state-configuration.aspx
#>
+26
View File
@@ -0,0 +1,26 @@
<#
.SYNOPSIS
Stops the gpresult process if it is running.
Since the Arguments parameter isn't needed to stop the process,
an empty string is passed in.
#>
Configuration Sample_WindowsProcess_Stop
{
param
()
Import-DSCResource -ModuleName 'PSDscResources'
Node localhost
{
WindowsProcess GPresult
{
Path = 'C:\Windows\System32\gpresult.exe'
Arguments = ''
Ensure = 'Absent'
}
}
}
Sample_WindowsProcess_Stop
@@ -0,0 +1,39 @@
<#
.SYNOPSIS
Stops the gpresult process running under the given credential if it is running.
Since the Arguments parameter isn't needed to stop the process,
an empty string is passed in.
.PARAMETER Credential
Credential that the process is running under.
#>
Configuration Sample_WindowsProcess_StopUnderUser
{
[CmdletBinding()]
param
(
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = (Get-Credential)
)
Import-DSCResource -ModuleName 'PSDscResources'
Node localhost
{
WindowsProcess GPresult
{
Path = 'C:\Windows\System32\gpresult.exe'
Arguments = ''
Credential = $Credential
Ensure = 'Absent'
}
}
}
<#
To use the sample(s) with credentials, see blog at:
http://blogs.msdn.com/b/powershell/archive/2014/01/31/want-to-secure-credentials-in-windows-powershell-desired-state-configuration.aspx
#>
+36
View File
@@ -40,6 +40,7 @@ Please check out the common DSC Resources [contributing guidelines](https://gith
* [WindowsFeature](#windowsfeature): Provides a mechanism to install or uninstall windows roles or features on a target node.
* [WindowsOptionalFeature](#windowsoptionalfeature): Provides a mechanism to enable or disable optional features on a target node.
* [WindowsPackageCab](#windowspackagecab): Provides a mechanism to install or uninstall a package from a windows cabinet (cab) file on a target node.
* [WindowsProcess](#windowsprocess): Provides a mechanism to start and stop a Windows process.
### Resources that Work on Nano Server
@@ -221,6 +222,39 @@ None
* [Install a cab file with the given name from the given path](https://github.com/PowerShell/PSDesResources/blob/master/Examples/Sample_WindowsPackageCab.ps1)
### WindowsProcess
Provides a mechanism to start and stop a Windows process.
#### Requirements
None
#### Parameters
* **[String] Path** _(Key)_: The executable file of the process. This can be defined as either the full path to the file or as the name of the file if it is accessible through the environment path. Relative paths are not supported.
* **[String] Arguments** _(Key)_: A single string containing all the arguments to pass to the process. Pass in an empty string if no arguments are needed.
* **[PSCredential] Credential** _(Write)_: The credential of the user account to run the process under. If this user is from the local system, the StandardOutputPath, StandardInputPath, and WorkingDirectory parameters cannot be provided at the same time.
* **[String] Ensure** _(Write)_: Specifies whether or not the process should be running. To start the process, specify this property as Present. To stop the process, specify this property as Absent. { *Present* | Absent }.
* **[String] StandardOutputPath** _(Write)_: The file path to which to write the standard output from the process. Any existing file at this file path will be overwritten. This property cannot be specified at the same time as Credential when running the process as a local user.
* **[String] StandardErrorPath** _(Write)_: The file path to which to write the standard error output from the process. Any existing file at this file path will be overwritten.
* **[String] StandardInputPath** _(Write)_: The file path from which to receive standard input for the process. This property cannot be specified at the same time as Credential when running the process as a local user.
* **[String] WorkingDirectory** _(Write)_: The file path to the working directory under which to run the file. This property cannot be specified at the same time as Credential when running the process as a local user.
#### Read-Only Properties from Get-TargetResource
* **[UInt64] PagedMemorySize** _(Read)_: The amount of paged memory, in bytes, allocated for the process.
* **[UInt64] NonPagedMemorySize** _(Read)_: The amount of nonpaged memory, in bytes, allocated for the process.
* **[UInt64] VirtualMemorySize** _(Read)_: The amount of virtual memory, in bytes, allocated for the process.
* **[SInt32] HandleCount** _(Read)_: The number of handles opened by the process.
* **[SInt32] ProcessId** _(Read)_: The unique identifier of the process.
* **[SInt32] ProcessCount** _(Read)_: The number of instances of the given process that are currently running.
#### Examples
* [Start a process](https://github.com/PowerShell/PSDesResources/blob/master/Examples/Sample_WindowsProcess_Start.ps1)
* [Stop a process](https://github.com/PowerShell/PSDesResources/blob/master/Examples/Sample_WindowsProcess_Stop.ps1)
* [Start a process under a user](https://github.com/PowerShell/PSDesResources/blob/master/Examples/Sample_WindowsProcess_StartUnderUser.ps1)
* [Stop a process under a user](https://github.com/PowerShell/PSDesResources/blob/master/Examples/Sample_WindowsProcess_StopUnderUser.ps1)
## Versions
### Unreleased
@@ -228,6 +262,8 @@ None
* WindowsFeature:
* Added Catch to ignore RuntimeException when importing ServerManager module. This solves the issue described [here](https://social.technet.microsoft.com/Forums/en-US/9fc314e1-27bf-4f03-ab78-5e0f7a662b8f/importmodule-servermanager-some-or-all-identity-references-could-not-be-translated?forum=winserverpowershell).
* Updated unit tests.
* Added WindowsProcess
### 2.1.0.0
@@ -0,0 +1,26 @@
$errorActionPreference = 'Stop'
Set-StrictMode -Version 'Latest'
<#
.SYNOPSIS
Stops all instances of the process with the given name.
.PARAMETER ProcessName
The name of the process to stop.
#>
function Stop-ProcessByName
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[String]
$ProcessName
)
Stop-Process -Name $ProcessName -ErrorAction 'SilentlyContinue' -Force
Wait-ScriptBlockReturnTrue -ScriptBlock { return $null -eq (Get-Process -Name $ProcessName -ErrorAction 'SilentlyContinue') } `
-TimeoutSeconds 15
}
Export-ModuleMember -Function Stop-ProcessByName
@@ -0,0 +1,540 @@
<#
These tests should only be run in AppVeyor since the second half of the tests require
the AppVeyor administrator account credential to run.
Also please note that some of these tests depend on each other.
They must be run in the order given - if one test fails, subsequent tests may
also fail.
#>
$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 'Integration'
try
{
Describe 'WindowsProcess Integration Tests without Credential' {
$testProcessPath = Join-Path -Path $script:testHelpersPath -ChildPath 'WindowsProcessTestProcess.exe'
$logFilePath = Join-Path -Path $script:testHelpersPath -ChildPath 'processTestLog.txt'
$configFile = Join-Path -Path $PSScriptRoot -ChildPath 'MSFT_WindowsProcess.config.ps1'
Context 'Should stop any current instances of the testProcess running' {
$configurationName = 'MSFT_WindowsProcess_Setup'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Absent' `
-ErrorAction 'Stop' `
-OutputPath $configurationPath
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Absent'
}
It 'Should not create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $false
}
}
Context 'Should start a new testProcess instance as running' {
$configurationName = 'MSFT_WindowsProcess_StartProcess'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Present' `
-ErrorAction 'Stop' `
-OutputPath $configurationPath
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Present'
$currentConfig.ProcessCount | Should Be 1
}
It 'Should create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $true
}
}
Context 'Should not start a second new testProcess instance when one is already running' {
$configurationName = 'MSFT_WindowsProcess_StartSecondProcess'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Present' `
-ErrorAction 'Stop' `
-OutputPath $configurationPath
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Present'
$currentConfig.ProcessCount | Should Be 1
}
It 'Should not create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $false
}
}
Context 'Should stop the testProcess instance from running' {
$configurationName = 'MSFT_WindowsProcess_StopProcesses'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Absent' `
-ErrorAction 'Stop' `
-OutputPath $configurationPath
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Absent'
}
It 'Should not create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $false
}
}
Context 'Should return correct amount of processes running when more than 1 are running' {
$configurationName = 'MSFT_WindowsProcess_StartMultipleProcesses'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Present' `
-ErrorAction 'Stop' `
-OutputPath $configurationPath
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should start another process running' {
Start-Process -FilePath $testProcessPath -ArgumentList @($logFilePath)
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Present'
$currentConfig.ProcessCount | Should Be 2
}
It 'Should create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $true
}
}
Context 'Should stop all of the testProcess instances from running' {
$configurationName = 'MSFT_WindowsProcess_StopAllProcesses'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Absent' `
-ErrorAction 'Stop' `
-OutputPath $configurationPath
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Absent'
}
It 'Should not create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $false
}
}
}
Describe 'WindowsProcess Integration Tests with Credential' {
$ConfigData = @{
AllNodes = @(
@{
NodeName = '*'
PSDscAllowPlainTextPassword = $true
}
@{
NodeName = 'localhost'
}
)
}
$testCredential = Get-AppVeyorAdministratorCredential
$testProcessPath = Join-Path -Path $script:testHelpersPath -ChildPath 'WindowsProcessTestProcess.exe'
$logFilePath = Join-Path -Path $script:testHelpersPath -ChildPath 'processTestLog.txt'
$configFile = Join-Path -Path $PSScriptRoot -ChildPath 'MSFT_WindowsProcessWithCredential.config.ps1'
Context 'Should stop any current instances of the testProcess running' {
$configurationName = 'MSFT_WindowsProcess_SetupWithCredential'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Absent' `
-Credential $testCredential `
-ErrorAction 'Stop' `
-OutputPath $configurationPath `
-ConfigurationData $ConfigData
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Absent'
}
It 'Should not create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $false
}
}
Context 'Should start a new testProcess instance as running' {
$configurationName = 'MSFT_WindowsProcess_StartProcessWithCredential'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Present' `
-Credential $testCredential `
-ErrorAction 'Stop' `
-OutputPath $configurationPath `
-ConfigurationData $ConfigData
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Present'
$currentConfig.ProcessCount | Should Be 1
}
It 'Should create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $true
}
}
Context 'Should not start a second new testProcess instance when one is already running' {
$configurationName = 'MSFT_WindowsProcess_StartSecondProcessWithCredential'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Present' `
-Credential $testCredential `
-ErrorAction 'Stop' `
-OutputPath $configurationPath `
-ConfigurationData $ConfigData
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Present'
$currentConfig.ProcessCount | Should Be 1
}
It 'Should not create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $false
}
}
Context 'Should stop the testProcess instance from running' {
$configurationName = 'MSFT_WindowsProcess_StopProcessesWithCredential'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Absent' `
-Credential $testCredential `
-ErrorAction 'Stop' `
-OutputPath $configurationPath `
-ConfigurationData $ConfigData
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Absent'
}
It 'Should not create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $false
}
}
Context 'Should return correct amount of processes running when more than 1 are running' {
$configurationName = 'MSFT_WindowsProcess_StartMultipleProcessesWithCredential'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Present' `
-ErrorAction 'Stop' `
-Credential $testCredential `
-OutputPath $configurationPath `
-ConfigurationData $ConfigData
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should start another process running' {
Start-Process -FilePath $testProcessPath -ArgumentList @($logFilePath)
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Present'
$currentConfig.ProcessCount | Should Be 2
}
It 'Should create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $true
}
}
Context 'Should stop all of the testProcess instances from running' {
$configurationName = 'MSFT_WindowsProcess_StopAllProcessesWithCredential'
$configurationPath = Join-Path -Path $TestDrive -ChildPath $configurationName
It 'Should compile without throwing' {
{
if (Test-Path -Path $logFilePath)
{
Remove-Item -Path $logFilePath
}
.$configFile -ConfigurationName $configurationName
& $configurationName -Path $testProcessPath `
-Arguments $logFilePath `
-Ensure 'Absent' `
-Credential $testCredential `
-ErrorAction 'Stop' `
-OutputPath $configurationPath `
-ConfigurationData $ConfigData
Start-DscConfiguration -Path $configurationPath -ErrorAction 'Stop' -Wait -Force
} | Should Not Throw
}
It 'Should be able to call Get-DscConfiguration without throwing' {
{ Get-DscConfiguration -Verbose -ErrorAction 'Stop' } | Should Not Throw
}
It 'Should return the correct configuration' {
$currentConfig = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
$currentConfig.Path | Should Be $testProcessPath
$currentConfig.Arguments | Should Be $logFilePath
$currentConfig.Ensure | Should Be 'Absent'
}
It 'Should not create a logfile' {
$pathResult = Test-Path $logFilePath
$pathResult | Should Be $false
}
}
}
}
finally
{
Exit-DscResourceTestEnvironment -TestEnvironment $script:testEnvironment
}
@@ -0,0 +1,35 @@
param
(
[Parameter(Mandatory = $true)]
[String]
$ConfigurationName
)
Configuration $ConfigurationName
{
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Path,
[Parameter(Mandatory = $true)]
[AllowEmptyString()]
[String]
$Arguments,
[ValidateSet('Present', 'Absent')]
[String]
$Ensure = 'Present'
)
Import-DscResource -ModuleName 'PSDscResources'
WindowsProcess Process1
{
Path = $Path
Arguments = $Arguments
Ensure = $Ensure
}
}
@@ -0,0 +1,44 @@
param
(
[Parameter(Mandatory = $true)]
[String]
$ConfigurationName
)
Configuration $ConfigurationName
{
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Path,
[Parameter(Mandatory = $true)]
[AllowEmptyString()]
[String]
$Arguments,
[ValidateSet('Present', 'Absent')]
[String]
$Ensure = 'Present',
[Parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = (Get-Credential)
)
Import-DscResource -ModuleName 'PSDscResources'
Node $AllNodes.NodeName
{
WindowsProcess Process1
{
Path = $Path
Arguments = $Arguments
Credential = $Credential
Ensure = $Ensure
}
}
}
@@ -0,0 +1,37 @@
using System.IO;
using System.Threading;
// This is a test process used for testing configuring running and stopping a process on a machine
namespace WindowsProcessTestProcess
{
class Program
{
static void Main(string[] args)
{
string[] lines = { "Test line1", "Test line2", "Test line3" };
if (args.Length > 0)
{
// and that it is a path
// a second argument for infinite wait
string filePath = args[0];
using (StreamWriter outputFile = new StreamWriter(filePath))
{
// Write to a log file so that we can see if the process ran
foreach (var line in lines)
{
outputFile.WriteLine(line);
}
}
if (args.Length == 1 || args[1] != "Stop Running")
{
// Sleep so that the process stays running until it is killed
Thread.Sleep(Timeout.Infinite);
}
}
}
}
}
Binary file not shown.
+781
View File
@@ -0,0 +1,781 @@
[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
}