diff --git a/DSCResources/MSFT_xWindowsPackageCab/MSFT_xWindowsPackageCab.psm1 b/DSCResources/MSFT_xWindowsPackageCab/MSFT_xWindowsPackageCab.psm1 new file mode 100644 index 000000000..25fe7adc0 --- /dev/null +++ b/DSCResources/MSFT_xWindowsPackageCab/MSFT_xWindowsPackageCab.psm1 @@ -0,0 +1,225 @@ +Import-Module -Name (Join-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -ChildPath 'CommonResourceHelper.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_xWindowsPackageCab' + +Import-Module -Name 'Dism' + +<# + .SYNOPSIS + Retrieves the current state of a package from a windows cabinet (cab) file. + + .PARAMETER Name + The name of the package to retrieve the state of. + + .PARAMETER Ensure + Not used in Get-TargetResource. + Provided here to follow DSC design convention of including all mandatory parameters + in Get, Set, and Test. + + .PARAMETER SourcePath + The path to the cab file the package should be installed or uninstalled from. + Returned from Get-TargetResource as it is passed in. + + .PARAMETER LogPath + The path to a file to log this operation to. + There is no default value, but if not set, the log will appear at %WINDIR%\Logs\Dism\dism.log. +#> +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [Parameter(Mandatory = $true)] + [ValidateSet('Present', 'Absent')] + [String] + $Ensure, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $SourcePath, + + [ValidateNotNullOrEmpty()] + [String] + $LogPath + ) + + $windowsPackageCab = @{ + Name = $Name + Ensure = 'Present' + SourcePath = $SourcePath + LogPath = $LogPath + } + + $getWindowsPackageParams = @{ + PackageName = $Name + Online = $true + } + + if ($PSBoundParameters.ContainsKey('LogPath')) + { + $getWindowsPackageParams['LogPath'] = $LogPath + } + + Write-Verbose -Message ($script:localizedData.RetrievingPackage -f $Name) + + try + { + $windowsPackageInfo = Dism\Get-WindowsPackage @getWindowsPackageParams + } + catch + { + $windowsPackageInfo = $null + } + + if ($null -eq $windowsPackageInfo -or -not ($windowsPackageInfo.PackageState -in @( 'Installed', 'InstallPending' ))) + { + $windowsPackageCab.Ensure = 'Absent' + } + + Write-Verbose -Message ($script:localizedData.PackageEnsureState -f $Name, $windowsPackageCab.Ensure) + + return $windowsPackageCab +} + +<# + .SYNOPSIS + Installs or uninstalls a package from a windows cabinet (cab) file. + + .PARAMETER Name + The name of the package to install or uninstall. + + .PARAMETER Ensure + Specifies whether the package should be installed or uninstalled. + To install the package, set this property to Present. + To uninstall the package, set the property to Absent. + + .PARAMETER SourcePath + The path to the cab file to install or uninstall the package from. + + .PARAMETER LogPath + The path to a file to log this operation to. + There is no default value, but if not set, the log will appear at %WINDIR%\Logs\Dism\dism.log. +#> +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [Parameter(Mandatory = $true)] + [ValidateSet('Present', 'Absent')] + [String] + $Ensure, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $SourcePath, + + [ValidateNotNullOrEmpty()] + [String] + $LogPath + ) + + Write-Verbose -Message ($script:localizedData.SetTargetResourceStarting -f $Name) + + if (-not (Test-Path -Path $SourcePath)) + { + New-InvalidArgumentException -ArgumentName 'SourcePath' -Message ($script:localizedData.SourcePathDoesNotExist -f $SourcePath) + } + + if ($Ensure -ieq 'Present') + { + Write-Verbose -Message ($script:localizedData.AddingPackage -f $SourcePath) + Dism\Add-WindowsPackage -PackagePath $SourcePath -LogPath $LogPath -Online + } + else + { + Write-Verbose -Message ($script:localizedData.RemovingPackage -f $SourcePath) + Dism\Remove-WindowsPackage -PackagePath $SourcePath -LogPath $LogPath -Online + } + + Write-Verbose -Message ($script:localizedData.SetTargetResourceFinished -f $Name) +} + +<# + .SYNOPSIS + Tests whether a package in a windows cabinet (cab) file is installed or uninstalled. + + .PARAMETER Name + The name of the cab package to test for installation. + + .PARAMETER Ensure + Specifies whether to test if the package is installed or uninstalled. + To test if the package is installed, set this property to Present. + To test if the package is uninstalled, set the property to Absent. + + .PARAMETER SourcePath + Not used in Test-TargetResource. + + .PARAMETER LogPath + The path to a file to log this operation to. + There is no default value, but if not set, the log will appear at %WINDIR%\Logs\Dism\dism.log. +#> +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [Parameter(Mandatory = $true)] + [ValidateSet('Present', 'Absent')] + [String] + $Ensure, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $SourcePath, + + [ValidateNotNullOrEmpty()] + [String] + $LogPath + ) + + $getTargetResourceParams = @{ + Name = $Name + Ensure = $Ensure + SourcePath = $SourcePath + } + + if ($PSBoundParameters.ContainsKey('LogPath')) + { + $getTargetResourceParams['LogPath'] = $LogPath + } + + $windowsPackageCab = Get-TargetResource @getTargetResourceParams + + if ($windowsPackageCab.Ensure -ieq $Ensure) + { + Write-Verbose -Message ($script:localizedData.EnsureStatesMatch -f $Name) + return $true + } + else + { + Write-Verbose -Message ($script:localizedData.EnsureStatesDoNotMatch -f $Name) + return $false + } +} + +Export-ModuleMember -Function '*-TargetResource' diff --git a/DSCResources/MSFT_xWindowsPackageCab/MSFT_xWindowsPackageCab.schema.mof b/DSCResources/MSFT_xWindowsPackageCab/MSFT_xWindowsPackageCab.schema.mof new file mode 100644 index 000000000..cd7783029 --- /dev/null +++ b/DSCResources/MSFT_xWindowsPackageCab/MSFT_xWindowsPackageCab.schema.mof @@ -0,0 +1,9 @@ + +[ClassVersion("1.0.0.0"), FriendlyName("xWindowsPackageCab")] +class MSFT_xWindowsPackageCab : OMI_BaseResource +{ + [Key, Description("The name of the package to install or uninstall.")] String Name; + [Required, Description("Specifies whether the package should be installed or uninstalled. To install the package, set this property to Present. To uninstall the package, set the property to Absent."), ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}] String Ensure; + [Required, Description("The path to the cab file to install or uninstall the package from.")] String SourcePath; + [Write, Description("The path to a file to log the operation to.")] String LogPath; +}; diff --git a/DSCResources/MSFT_xWindowsPackageCab/en-US/MSFT_xWindowsPackageCab.schema.mfl b/DSCResources/MSFT_xWindowsPackageCab/en-US/MSFT_xWindowsPackageCab.schema.mfl new file mode 100644 index 000000000..553df0283 --- /dev/null +++ b/DSCResources/MSFT_xWindowsPackageCab/en-US/MSFT_xWindowsPackageCab.schema.mfl @@ -0,0 +1,8 @@ +[Description("This resource is used to install or uninstall a package from a windows cabinet (cab) file.") : Amended,AMENDMENT, LOCALE("MS_409")] +class MSFT_xWindowsPackageCab : OMI_BaseResource +{ + [Key, Description("The name of the package to install or uninstall.") : Amended] String Name; + [Description("Specifies whether the package should be installed or uninstalled. To install the package, set this property to Present. To uninstall the package, set the property to Absent.") : Amended] String Ensure; + [Description("The path to the cab file to install or uninstall the package from.") : Amended] String SourcePath; + [Description("The path to a file to log the operation to.") : Amended] String LogPath; +}; diff --git a/DSCResources/MSFT_xWindowsPackageCab/en-US/MSFT_xWindowsPackageCab.strings.psd1 b/DSCResources/MSFT_xWindowsPackageCab/en-US/MSFT_xWindowsPackageCab.strings.psd1 new file mode 100644 index 000000000..5b9faf70d --- /dev/null +++ b/DSCResources/MSFT_xWindowsPackageCab/en-US/MSFT_xWindowsPackageCab.strings.psd1 @@ -0,0 +1,13 @@ +# Localized resources for xWindowsPackageCab + +ConvertFrom-StringData @' + RetrievingPackage = Retrieving information for the package {0} + PackageEnsureState = The package {0} is currently {1} + SourcePathDoesNotExist = Could not find the source file at path {0} + SetTargetResourceStarting = Starting configuration of the WindowsPackageCab resource {0} + SetTargetResourceFinished = Finished configuration of WindowsPackageCab resource {0} + AddingPackage = Adding a package from the source at path {0} + RemovingPackage = Removing package from the source at path {0} + EnsureStatesMatch = Ensure states match for package {0} + EnsureStatesDoNotMatch = Ensure states do not match for package {0} +'@ diff --git a/Examples/Sample_xWindowsPackageCab.ps1 b/Examples/Sample_xWindowsPackageCab.ps1 new file mode 100644 index 000000000..5f7469860 --- /dev/null +++ b/Examples/Sample_xWindowsPackageCab.ps1 @@ -0,0 +1,49 @@ +<# + .SYNOPSIS + Installs a package from the cab file with the specified name from the specified source path + and outputs a log to the specified log path. + + .PARAMETER Name + The name of the package to install. + + .PARAMETER SourcePath + The path to the cab file to install the package from. + + .PARAMETER LogPath + The path to a file to log the install operation to. + + .NOTES + The DISM PowerShell module must be available on the target machine. +#> +Configuration Sample_xWindowsPackageCab +{ + param + ( + [Parameter (Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [Parameter (Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $SourcePath, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $LogPath + ) + + Import-DscResource -ModuleName 'xPSDesiredStateConfiguration' + + xWindowsPackageCab WindowsPackageCab1 + { + Name = $Name + Ensure = 'Present' + SourcePath = $SourcePath + LogPath = $LogPath + } +} + +Sample_xWindowsPackageCab diff --git a/README.md b/README.md index 3898f3db3..4b2113506 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,13 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **xWindowsFeatureSet** allows installation and uninstallation of a group of Windows features and their subfeatures. * **xWindowsOptionalFeature** provides a mechanism to enable or disable optional features on a target node. * **xWindowsOptionalFeatureSet** allows installation and uninstallation of a group of optional Windows features. +* **xWindowsPackageCab** provides a mechanism to install or uninstall a package from a windows cabinet (cab) file on a target node. Resources that work on Nano Server: -* xWindowsOptionalFeature * xUser +* xWindowsOptionalFeature +* xWindowsPackageCab ### xArchive @@ -360,6 +362,30 @@ These parameters will be the same for each Windows optional feature in the set. - Suported values: ErrorsOnly, ErrorsAndWarning, ErrorsAndWarningAndInformation. - Default value: ErrorsOnly. +### xWindowsPackageCab +Provides a mechanism to install or uninstall a package from a windows cabinet (cab) file on a target node. +This resource works on Nano Server. + +#### Requirements + +* Target machine must have access to the DISM PowerShell module + +#### Parameters + +* **[String] Name** _(Key)_: The name of the package to install or uninstall. +* **[String] Ensure** _(Required)_: Specifies whether the package should be installed or uninstalled. To install the package, set this property to Present. To uninstall the package, set the property to Absent. { *Present* | Absent }. +* **[String] SourcePath** _(Required)_: The path to the cab file to install or uninstall the package from. +* **[String] LogPath** _(Write)_: The path to a file to log the operation to. There is no default value, but if not set, the log will appear at %WINDIR%\Logs\Dism\dism.log. + +#### Read-Only Properties from Get-TargetResource + +None + +#### Examples + +* [Install a cab file with the given name from the given path](https://github.com/PowerShell/xPSDesiredStateConfiguration/blob/dev/Examples/Sample_xWindowsPackageCab.ps1) + + ## Functions ### Publish-ModuleToPullServer @@ -383,6 +409,7 @@ These parameters will be the same for each Windows optional feature in the set. * xUser: * Fixed PSSA/Style violations * Added/Updated Tests and Examples +* Added xWindowsPackageCab ### 4.0.0.0 diff --git a/Tests/Integration/MSFT_xWindowsPackageCab.Integration.Tests.ps1 b/Tests/Integration/MSFT_xWindowsPackageCab.Integration.Tests.ps1 new file mode 100644 index 000000000..1bedb0737 --- /dev/null +++ b/Tests/Integration/MSFT_xWindowsPackageCab.Integration.Tests.ps1 @@ -0,0 +1,134 @@ +Import-Module -Name (Join-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -ChildPath 'CommonTestHelper.psm1') + +$script:testEnvironment = Enter-DscResourceTestEnvironment ` + -DscResourceModuleName 'xPSDesiredStateConfiguration' ` + -DscResourceName 'MSFT_xWindowsPackageCab' ` + -TestType 'Integration' + +try +{ + Describe 'xWindowsPackageCab Integration Tests' { + BeforeAll { + Import-Module -Name 'Dism' + + $script:installedStates = @( 'Installed', 'InstallPending' ) + $script:confgurationFilePath = Join-Path -Path $PSScriptRoot -ChildPath 'MSFT_xWindowsPackageCab.config.ps1' + + $script:testPackageName = '' + $script:testSourcePath = Join-Path -Path $PSScriptRoot -ChildPath '' + + $script:cabPackageNotProvided = $script:testPackageName -eq [String]::Empty + + try + { + $originalPackage = Dism\Get-WindowsPackage -PackageName $script:testPackageName -Online + if ($null -ne $originalPackage -and $originalPackage.PackageState -in $script:installedStates) + { + $script:packageOriginallyInstalled = $true + } + else + { + $script:packageOriginallyInstalled = $false + } + } + catch + { + $script:packageOriginallyInstalled = $false + } + + if ($script:packageOriginallyInstalled) + { + throw "Package $script:testPackageName is currently installed on this machine. These tests may destroy this package. Aborting." + } + } + + AfterEach { + if (-not $script:packageOriginallyInstalled) + { + try + { + $windowsPackage = Dism\Get-WindowsPackage -PackageName $script:testPackageName -Online + if ($null -ne $windowsPackage -and $windowsPackage.PackageState -in $script:installedStates) + { + Dism\Remove-WindowsPackage -PackageName $script:testPackageName.Name -Online -NoRestart + } + } + catch + { + Write-Verbose -Message "No test cleanup needed. Package $script:testPackageName not found." + } + } + } + + It 'Should install a Windows package through a cab file' -Skip:$script:cabPackageNotProvided { + $configurationName = 'InstallWindowsPackageCab' + + $resourceParameters = @{ + Name = $script:testPackageName + SourcePath = $script:testSourcePath + Ensure = 'Present' + } + + { + . $script:confgurationFilePath -ConfigurationName $configurationName + & $configurationName -OutputPath $TestDrive @resourceParameters + Start-DscConfiguration -Path $TestDrive -ErrorAction 'Stop' -Wait -Force + } | Should Not Throw + + { $windowsPackage = Dism\Get-WindowsPackage -PackageName $resourceParameters.Name -Online } | Should Not Throw + + $windowsPackage = Dism\Get-WindowsPackage -PackageName $resourceParameters.Name -Online + $windowsPackage | Should Not Be $null + $windowsPackage.PackageState -in $script:installedStates | Should Be $true + } + + It 'Should uninstall a Windows package through a cab file' -Skip:$script:cabPackageNotProvided { + $configurationName = 'UninstallWindowsPackageCab' + + $resourceParameters = @{ + Name = $script:testPackageName + SourcePath = $script:testSourcePath + Ensure = 'Absent' + } + + Dism\Add-WindowsPackage -PackagePath $resourceParameters.SourcePath -Online -NoRestart + + { $windowsPackage = Dism\Get-WindowsPackage -PackageName $resourceParameters.Name -Online } | Should Not Throw + + { + . $script:confgurationFilePath -ConfigurationName $configurationName + & $configurationName -OutputPath $TestDrive @resourceParameters + Start-DscConfiguration -Path $TestDrive -ErrorAction 'Stop' -Wait -Force + } | Should Not Throw + + { $windowsPackage = Dism\Get-WindowsPackage -PackageName $resourceParameters.Name -Online } | Should Throw + } + + It 'Should not install an invalid Windows package through a cab file' { + $configurationName = 'InstallInvalidWindowsPackageCab' + + $resourceParameters = @{ + Name = 'NonExistentWindowsPackageCab' + SourcePath = (Join-Path -Path $TestDrive -ChildPath 'FakePath.cab') + Ensure = 'Present' + LogPath = (Join-Path -Path $TestDrive -ChildPath 'InvalidWindowsPackageCab.log') + } + + { Dism\Get-WindowsPackage -PackageName $resourceParameters.Name -Online } | Should Throw + + { + . $script:confgurationFilePath -ConfigurationName $configurationName + & $configurationName -OutputPath $TestDrive @resourceParameters + Start-DscConfiguration -Path $TestDrive -ErrorAction 'Stop' -Wait -Force + } | Should Throw + + Test-Path -Path $resourceParameters.LogPath | Should Be $true + + { Dism\Get-WindowsPackage -PackageName $resourceParameters.Name -Online } | Should Throw + } + } +} +finally +{ + Exit-DscResourceTestEnvironment -TestEnvironment $script:testEnvironment +} diff --git a/Tests/Integration/MSFT_xWindowsPackageCab.config.ps1 b/Tests/Integration/MSFT_xWindowsPackageCab.config.ps1 new file mode 100644 index 000000000..8f0e78ed5 --- /dev/null +++ b/Tests/Integration/MSFT_xWindowsPackageCab.config.ps1 @@ -0,0 +1,41 @@ +param +( + [Parameter(Mandatory = $true)] + [String] + $ConfigurationName +) + +Configuration $ConfigurationName +{ + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + [Parameter(Mandatory = $true)] + [ValidateSet('Present', 'Absent')] + [String] + $Ensure, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String] + $SourcePath, + + [ValidateNotNullOrEmpty()] + [String] + $LogPath = (Join-Path -Path (Get-Location) -ChildPath 'WindowsPackageCabTestLog.txt') + ) + + Import-DscResource -ModuleName 'xPSDesiredStateConfiguration' + + xWindowsPackageCab WindowsPackageCab1 + { + Name = $Name + Ensure = $Ensure + SourcePath = $SourcePath + LogPath = $LogPath + } +} diff --git a/Tests/Unit/MSFT_xWindowsPackageCab.Tests.ps1 b/Tests/Unit/MSFT_xWindowsPackageCab.Tests.ps1 new file mode 100644 index 000000000..31e526c38 --- /dev/null +++ b/Tests/Unit/MSFT_xWindowsPackageCab.Tests.ps1 @@ -0,0 +1,137 @@ +Import-Module -Name (Join-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -ChildPath 'CommonTestHelper.psm1') + +$script:testEnvironment = Enter-DscResourceTestEnvironment ` + -DscResourceModuleName 'xPSDesiredStateConfiguration' ` + -DscResourceName 'MSFT_xWindowsPackageCab' ` + -TestType 'Unit' + +try +{ + InModuleScope 'MSFT_xWindowsPackageCab' { + Describe 'xWindowsPackageCab Unit Tests' { + BeforeAll { + Import-Module -Name 'Dism' + + $script:testPackageName = 'TestPackage' + $script:testSourcePath = Join-Path -Path $TestDrive -ChildPath 'FakeCabFile.cab' + $script:testLogPath = Join-Path -Path $TestDrive -ChildPath 'WindowsPackageCabTestLog.log' + + New-Item -Path $script:testSourcePath -ItemType 'File' + } + + Context 'Get-TargetResource' { + Mock -CommandName 'Dism\Get-WindowsPackage' -MockWith { } + + $getTargetResourceCommonParams = @{ + SourcePath = $script:testSourcePath + Ensure = 'Present' + } + + It 'Should return Ensure as Absent when package is not installed' { + $getTargetResourceResult = Get-TargetResource -Name $script:testPackageName @getTargetResourceCommonParams + $getTargetResourceResult.Ensure | Should Be 'Absent' + + Assert-MockCalled -CommandName 'Dism\Get-WindowsPackage' + } + + It 'Should return Ensure as Absent when package is on machine but not installed' { + Mock -CommandName 'Dism\Get-WindowsPackage' -MockWith { return @{ PackageState = 'NotPresent' } } + + $getTargetResourceResult = Get-TargetResource -Name $script:testPackageName @getTargetResourceCommonParams + $getTargetResourceResult.Ensure | Should Be 'Absent' + + Assert-MockCalled -CommandName 'Dism\Get-WindowsPackage' + } + + It 'Should return Ensure as Present when package is installed' { + Mock -CommandName 'Dism\Get-WindowsPackage' -MockWith { return @{ PackageState = 'Installed' } } + + $getTargetResourceResult = Get-TargetResource -Name $script:testPackageName @getTargetResourceCommonParams + $getTargetResourceResult.Ensure | Should Be 'Present' + + Assert-MockCalled -CommandName 'Dism\Get-WindowsPackage' + } + + It 'Should return Ensure as Present when package install is pending' { + Mock -CommandName 'Dism\Get-WindowsPackage' -MockWith { return @{ PackageState = 'InstallPending' } } + + $getTargetResourceResult = Get-TargetResource -Name $script:testPackageName @getTargetResourceCommonParams + $getTargetResourceResult.Ensure | Should Be 'Present' + + Assert-MockCalled -CommandName 'Dism\Get-WindowsPackage' + } + + It 'Should pass specified log path to Get-WindowsPackage' { + $null = Get-TargetResource -Name $script:testPackageName -LogPath $script:testLogPath @getTargetResourceCommonParams + Assert-MockCalled -CommandName 'Dism\Get-WindowsPackage' -ParameterFilter { $LogPath -eq $script:testLogPath } + } + } + + Context 'Set-TargetResource' { + Mock -CommandName 'Dism\Add-WindowsPackage' -MockWith { } + Mock -CommandName 'Dism\Remove-WindowsPackage' -MockWith { } + + It 'Should throw when SourcePath is invalid' { + $invalidSourcePath = (Join-Path -Path $TestDrive -ChildPath 'DoesNotExist') + { Set-TargetResource -Name 'Name' -SourcePath $invalidSourcePath -Ensure 'Absent' } | + Should Throw ($script:localizedData.SourcePathDoesNotExist -f $invalidSourcePath) + } + + It 'Should call Add-WindowsPackage when Ensure is Present' { + Set-TargetResource -Name $script:testPackageName -SourcePath $script:testSourcePath -Ensure 'Present' + Assert-MockCalled -CommandName 'Dism\Add-WindowsPackage' + } + + It 'Should call Remove-WindowsPackage when Ensure is Absent' { + Set-TargetResource -Name $script:testPackageName -SourcePath $script:testSourcePath -Ensure 'Absent' + Assert-MockCalled -CommandName 'Dism\Remove-WindowsPackage' + } + + It 'Should pass specified log path to Add-WindowsPackage' { + Set-TargetResource -Name $script:testPackageName -SourcePath $script:testSourcePath -Ensure 'Present' -LogPath $script:testLogPath + Assert-MockCalled -CommandName 'Dism\Add-WindowsPackage' -ParameterFilter { $LogPath -eq $script:testLogPath } + } + + It 'Should pass specified log path to Remove-WindowsPackage' { + Set-TargetResource -Name $script:testPackageName -SourcePath $script:testSourcePath -Ensure 'Absent' -LogPath $script:testLogPath + Assert-MockCalled -CommandName 'Dism\Remove-WindowsPackage' -ParameterFilter { $LogPath -eq $script:testLogPath } + } + } + + Context 'Test-TargetResource' { + Mock -CommandName 'Get-TargetResource' -MockWith { return @{ Ensure = 'Absent' } } + + It 'Should return true when Get-TargetResource returns Ensure Absent and Ensure is set to Absent' { + Test-TargetResource -Name $script:testPackageName -SourcePath $script:testSourcePath -Ensure 'Absent' | Should Be $true + Assert-MockCalled -CommandName 'Get-TargetResource' + } + + It 'Should return false when Get-TargetResource returns Ensure Absent and Ensure is set to Present' { + Test-TargetResource -Name $script:testPackageName -SourcePath $script:testSourcePath -Ensure 'Present' | Should Be $false + Assert-MockCalled -CommandName 'Get-TargetResource' + } + + Mock -CommandName 'Get-TargetResource' -MockWith { return @{ Ensure = 'Present' } } + + It 'Should return true when Get-TargetResource returns Ensure Present and Ensure is set to Present' { + Test-TargetResource -Name $script:testPackageName -SourcePath $script:testSourcePath -Ensure 'Present' | Should Be $true + Assert-MockCalled -CommandName 'Get-TargetResource' + } + + It 'Should return false when Get-TargetResource returns Ensure Present and Ensure is set to Absent' { + Test-TargetResource -Name $script:testPackageName -SourcePath $script:testSourcePath -Ensure 'Absent' | Should Be $false + Assert-MockCalled -CommandName 'Get-TargetResource' + } + + It 'Should pass specified log path to Get-TargetResource' { + $null = Test-TargetResource -Name $script:testPackageName -SourcePath $script:testSourcePath -Ensure 'Absent' -LogPath $script:testLogPath + Assert-MockCalled -CommandName 'Get-TargetResource' -ParameterFilter { $LogPath -eq $script:testLogPath } + } + } + } + } +} +finally +{ + Exit-DscResourceTestEnvironment -TestEnvironment $script:testEnvironment +}