diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3f27578..f69b1dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added wiki generation and publish to GitHub repository wiki.
- Added recommended VS Code extensions.
- Added settings for VS Code extension _Pester Test Adapter_.
+ - New File resource added to enable cross-platform file operations.
### Changed
diff --git a/source/Classes/002.FileSystemObject.ps1 b/source/Classes/002.FileSystemObject.ps1
new file mode 100644
index 0000000..ee13354
--- /dev/null
+++ b/source/Classes/002.FileSystemObject.ps1
@@ -0,0 +1,383 @@
+class FileSystemDscReason
+{
+ [DscProperty()]
+ [System.String]
+ $Code
+
+ [DscProperty()]
+ [System.String]
+ $Phrase
+}
+
+<#
+ .SYNOPSIS
+ The File resource enables file system operations on Linux and Windows.
+ With regards to parameters and globbing, it behaves like the Item and Content
+ cmdlets.
+
+ .PARAMETER DestinationPath
+ The path to create/copy to.
+
+ .PARAMETER SourcePath
+ If data should be copied, the source path to copy from.
+
+ .PARAMETER Ensure
+ Indicates if destination should be created or removed. Values: Absent, Present. Default: Present.
+
+ .PARAMETER Type
+ The type of the object to create. Values: file, directory, symboliclink. Default: directory
+
+ .PARAMETER Contents
+ The file contents. Unused if type is directory
+
+ .PARAMETER Checksum
+ The type of checksum to use for copy operations. Values: md5, CreationTime, LastModifiedTime. Default: md5
+
+ .PARAMETER Recurse
+ Indicates that recurse should be used if data is copied.
+
+ .PARAMETER Force
+ Indicates that folder structures should be created and existing files overwritten
+
+ .PARAMETER Links
+ Link behavior, currently not implemented. Values: follow, manage. Default: follow
+
+ .PARAMETER Group
+ Linux group name for chown, currently not implemented.
+
+ .PARAMETER Mode
+ Linux mode for chmod, currently not implemented.
+
+ .PARAMETER Owner
+ Linux owner name for chown, currently not implemented.
+
+ .PARAMETER Encoding
+ File encoding, used with Contents. Values: ASCII, Latin1, UTF7, UTF8, UTF32, BigEndianUnicode, Default, Unicode. Default: Default
+
+ .PARAMETER IgnoreTrailingWhitespace
+ Indicates that trailing whitespace should be ignored when comparing file contents.
+#>
+[DscResource()]
+class FileSystemObject
+{
+ [DscProperty(Key)]
+ [System.String]
+ $DestinationPath
+
+ [DscProperty()]
+ [System.String]
+ $SourcePath
+
+ [DscProperty()]
+ [Ensure]
+ $Ensure = [Ensure]::Present
+
+ [DscProperty()]
+ [ObjectType]
+ $Type = [ObjectType]::Directory
+
+ [DscProperty()]
+ [System.String]
+ $Contents
+
+ [DscProperty()]
+ [ChecksumType]
+ $Checksum = [ChecksumType]::MD5
+
+ [DscProperty()]
+ [System.Boolean]
+ $Recurse = $false
+
+ [DscProperty()]
+ [System.Boolean]
+ $Force = $false
+
+ [DscProperty()]
+ [LinkBehavior]
+ $Links = [LinkBehavior]::Follow
+
+ [DscProperty()]
+ [System.String]
+ $Group
+
+ [DscProperty()]
+ [System.String]
+ $Mode
+
+ [DscProperty()]
+ [System.String]
+ $Owner
+
+ [DscProperty(NotConfigurable)]
+ [System.DateTime]
+ $CreatedDate
+
+ [DscProperty(NotConfigurable)]
+ [System.DateTime]
+ $ModifiedDate
+
+ [DscProperty()]
+ [Encoding]
+ $Encoding = 'Default'
+
+ [DscProperty()]
+ [System.Boolean]
+ $IgnoreTrailingWhitespace
+
+ [DscProperty(NotConfigurable)]
+ [FileSystemDscReason[]]
+ $Reasons
+
+ [FileSystemObject] Get ()
+ {
+ $returnable = @{
+ DestinationPath = $this.DestinationPath
+ SourcePath = $this.SourcePath
+ Ensure = $this.Ensure
+ Type = $this.Type
+ Contents = ''
+ Checksum = $this.Checksum
+ Recurse = $this.Recurse
+ Force = $this.Force
+ Links = $this.Links
+ Encoding = $this.Encoding
+ Group = ''
+ Mode = ''
+ Owner = ''
+ IgnoreTrailingWhitespace = $this.IgnoreTrailingWhitespace
+ CreatedDate = [datetime]::new(0)
+ ModifiedDate = [datetime]::new(0)
+ Reasons = @()
+ }
+
+ if ($this.Type -eq [objectType]::directory -and -not [string]::IsNullOrWhiteSpace($this.Contents))
+ {
+ Write-Verbose -Message "Type is directory, yet parameter Contents was used."
+ $returnable.Reasons += @{
+ Code = "File:File:ParameterMismatch"
+ Phrase = "Type is directory, yet parameter Contents was used."
+ }
+ return [FileSystemObject]$returnable
+ }
+
+ $object = Get-Item -ErrorAction SilentlyContinue -Path $this.DestinationPath -Force
+ if ($null -eq $object -and $this.Ensure -eq [ensure]::present)
+ {
+ Write-Verbose -Message "Object $($this.DestinationPath) does not exist, but Ensure is set to 'Present'"
+ $returnable.Reasons += @{
+ Code = "File:File:ObjectMissingWhenItShouldExist"
+ Phrase = "Object $($this.DestinationPath) does not exist, but Ensure is set to 'Present'"
+ }
+ return [FileSystemObject]$returnable
+ }
+
+ if ($null -ne $object -and $this.Ensure -eq [ensure]::absent)
+ {
+ Write-Verbose -Message "Object $($this.DestinationPath) exists, but Ensure is set to 'Absent'"
+ $returnable.Reasons += @{
+ Code = "File:File:ObjectExistsWhenItShouldNot"
+ Phrase = "Object $($this.DestinationPath) exists, but Ensure is set to 'Absent'"
+ }
+ return [FileSystemObject]$returnable
+ }
+
+ if ($object.Count -eq 1 -and ($object.Attributes -band 'ReparsePoint') -eq 'ReparsePoint')
+ {
+ $returnable.Type = 'SymbolicLink'
+ }
+ elseif ($object.Count -eq 1 -and ($object.Attributes -band 'Directory') -eq 'Directory')
+ {
+ $returnable.Type = 'Directory'
+ }
+ elseif ($object.Count -eq 1)
+ {
+ $returnable.Type = 'File'
+ }
+
+ if ($returnable.Type -ne $this.Type)
+ {
+ $returnable.Reasons += @{
+ Code = "File:File:TypeMismatch"
+ Phrase = "Type of $($object.FullName) has type '$($returnable.Type)', should be '$($this.Type)'"
+ }
+ }
+
+ $returnable.DestinationPath = $object.FullName
+ if ([string]::IsNullOrWhiteSpace($this.SourcePath) -and $object -and $this.Type -eq [objectType]::file)
+ {
+ $returnable.Contents = Get-Content -Raw -Path $object.FullName -Encoding $this.Encoding.ToString()
+ }
+
+ if (-not $this.Ensure -eq 'Absent' -and -not [string]::IsNullOrWhiteSpace($returnable.Contents) -and $this.IgnoreTrailingWhitespace)
+ {
+ $returnable.Contents = $returnable.Contents.Trim()
+ }
+
+ if (-not [string]::IsNullOrWhiteSpace($this.Contents) -and $returnable.Contents -ne $this.Contents)
+ {
+ $returnable.Reasons += @{
+ Code = "File:File:ContentMismatch"
+ Phrase = "Content of $($object.FullName) different from parameter Contents"
+ }
+ }
+
+ if ($object.Count -eq 1)
+ {
+ $returnable.CreatedDate = $object.CreationTime
+ $returnable.ModifiedDate = $object.LastWriteTime
+ $returnable.Owner = $object.User
+ $returnable.Mode = $object.Mode
+ $returnable.Group = $object.Group
+ }
+
+ if (-not [string]::IsNullOrWhiteSpace($this.SourcePath))
+ {
+ if (-not $this.Recurse -and $this.Type -eq [objectType]::directory)
+ {
+ Write-Verbose -Message "Directory is copied without Recurse parameter. Skipping file checksum"
+ return [FileSystemObject]$returnable
+ }
+
+ $destination = if (-not $this.Recurse -and $this.SourcePath -notmatch '\*\?\[\]')
+ {
+ Join-Path $this.DestinationPath (Split-Path $this.SourcePath -Leaf)
+ }
+ else
+ {
+ $this.DestinationPath
+ }
+
+ $currHash = $this.CompareHash($destination, $this.SourcePath, $this.Checksum, $this.Recurse)
+
+ if ($currHash.Count -gt 0)
+ {
+ Write-Verbose -Message "Hashes of files in $($this.DestinationPath) (comparison path used: $destination) different from hashes in $($this.SourcePath)"
+ $returnable.Reasons += @{
+ Code = "File:File:HashMismatch"
+ Phrase = "Hashes of files in $($this.DestinationPath) different from hashes in $($this.SourcePath)"
+ }
+ }
+ }
+ return [FileSystemObject]$returnable
+ }
+
+ [void] Set()
+ {
+ if ($this.Ensure -eq 'Absent')
+ {
+ Write-Verbose -Message "Removing $($this.DestinationPath) with Recurse and Force"
+ Remove-Item -Recurse -Force -Path $this.DestinationPath
+ return
+ }
+
+ if ($this.Type -in [objectType]::file, [objectType]::directory -and [string]::IsNullOrWhiteSpace($this.SourcePath))
+ {
+ Write-Verbose -Message "Creating new $($this.Type) $($this.DestinationPath), Force"
+ $param = @{
+ ItemType = $this.Type
+ Path = $this.DestinationPath
+ }
+ if ($this.Force)
+ {
+ $param['Force'] = $true
+ }
+ $null = New-Item @param
+ }
+
+ if ($this.Type -eq [objectType]::SymbolicLink)
+ {
+ Write-Verbose -Message "Creating new symbolic link $($this.DestinationPath) --> $($this.SourcePath)"
+ New-Item -ItemType SymbolicLink -Path $this.DestinationPath -Value $this.SourcePath
+ return
+ }
+
+ if ($this.Contents)
+ {
+ Write-Verbose -Message "Setting content of $($this.DestinationPath) using $($this.Encoding)"
+ $this.Contents | Set-Content -Path $this.DestinationPath -Force -Encoding $this.Encoding.ToString() -NoNewline
+ }
+
+ if ($this.SourcePath -and ($this.SourcePath -match '\*|\?\[\]') -and -not (Test-Path -Path $this.DestinationPath))
+ {
+ Write-Verbose -Message "Creating destination directory for wildcard copy $($this.DestinationPath)"
+ $null = New-Item -ItemType Directory -Path $this.DestinationPath
+ }
+
+ if ($this.SourcePath)
+ {
+ Write-Verbose -Message "Copying from $($this.SourcePath) to $($This.DestinationPath), Recurse is $($this.Recurse), Using the Force: $($this.Force)"
+ $copyParam = @{
+ Path = $this.SourcePath
+ Destination = $this.DestinationPath
+ }
+ if ($this.Recurse)
+ {
+ $copyParam['Recurse'] = $this.Recurse
+ }
+ if ($this.Force)
+ {
+ $copyParam['Force'] = $this.Force
+ }
+ Copy-Item @copyParam
+ }
+ }
+
+ [bool] Test()
+ {
+ $currentState = $this.Get()
+
+ return ($currentState.Reasons.Count -eq 0)
+ }
+
+ [System.IO.FileInfo[]] CompareHash([string]$Path, [string]$ReferencePath, [checksumType]$Type = 'md5', [bool]$Recurse)
+ {
+ [object[]]$sourceHashes = $this.GetHash($ReferencePath, $Type, $Recurse)
+ [object[]]$hashes = $this.GetHash($Path, $Type, $Recurse)
+
+ if ($hashes.Count -eq 0)
+ {
+ return [System.IO.FileInfo[]]$sourceHashes.Path
+ }
+
+ $comparison = Compare-Object -ReferenceObject $sourceHashes -DifferenceObject $hashes -Property Hash -PassThru | Where-Object SideIndicator -eq '<='
+ return [System.IO.FileInfo[]]$comparison.Path
+ }
+
+ # Return type unclear and either Microsoft.PowerShell.Commands.FileHashInfo or PSCustomObject
+ # Might be better to create a custom class for this
+ [object[]] GetHash([string]$Path, [checksumType]$Type, [bool]$Recurse)
+ {
+ $hashStrings = if ($Type -eq 'md5')
+ {
+ Get-ChildItem -Recurse:$Recurse -Path $Path -Force -File | Get-FileHash -Algorithm md5
+ }
+ else
+ {
+ $propz = @(
+ @{
+ Name = 'Path'
+ Expression = { $_.FullName }
+ }
+ @{
+ Name = 'Algorithm'
+ Expression = { $Type }
+ }
+ @{
+ Name = 'Hash'
+ Expression = { if ($Type -eq 'CreationTime')
+ {
+ $_.CreationTime
+ }
+ else
+ {
+ $_.LastWriteTime
+ }
+ }
+ }
+ )
+ Get-ChildItem -Recurse:$Recurse -Path $Path -Force -File | Select-Object -Property $propz
+ }
+
+ return $hashStrings
+ }
+}
diff --git a/source/Enum/ChecksumType.ps1 b/source/Enum/ChecksumType.ps1
new file mode 100644
index 0000000..990cf2d
--- /dev/null
+++ b/source/Enum/ChecksumType.ps1
@@ -0,0 +1,6 @@
+enum ChecksumType
+{
+ MD5
+ LastModifiedTime
+ CreationTime
+}
diff --git a/source/Enum/Encoding.ps1 b/source/Enum/Encoding.ps1
new file mode 100644
index 0000000..514ef72
--- /dev/null
+++ b/source/Enum/Encoding.ps1
@@ -0,0 +1,11 @@
+enum Encoding
+{
+ ASCII
+ Latin1
+ UTF7
+ UTF8
+ UTF32
+ BigEndianUnicode
+ Default
+ Unicode
+}
diff --git a/source/Enum/Ensure.ps1 b/source/Enum/Ensure.ps1
new file mode 100644
index 0000000..ac64f85
--- /dev/null
+++ b/source/Enum/Ensure.ps1
@@ -0,0 +1,6 @@
+enum Ensure
+{
+ Present
+ Absent
+}
+
diff --git a/source/Enum/LinkBehavior.ps1 b/source/Enum/LinkBehavior.ps1
new file mode 100644
index 0000000..ccb32f5
--- /dev/null
+++ b/source/Enum/LinkBehavior.ps1
@@ -0,0 +1,5 @@
+enum LinkBehavior
+{
+ Follow
+ Manage
+}
diff --git a/source/Enum/ObjectType.ps1 b/source/Enum/ObjectType.ps1
new file mode 100644
index 0000000..b60952d
--- /dev/null
+++ b/source/Enum/ObjectType.ps1
@@ -0,0 +1,6 @@
+enum ObjectType
+{
+ File
+ Directory
+ Symboliclink
+}
diff --git a/source/Examples/Resources/FileSystemObject/1-FileSystemObject_CreateFileWithContent_Config.ps1 b/source/Examples/Resources/FileSystemObject/1-FileSystemObject_CreateFileWithContent_Config.ps1
new file mode 100644
index 0000000..04d39fb
--- /dev/null
+++ b/source/Examples/Resources/FileSystemObject/1-FileSystemObject_CreateFileWithContent_Config.ps1
@@ -0,0 +1,37 @@
+<#PSScriptInfo
+.VERSION 1.0.0
+.GUID e479ea7f-abcd-40a5-96ab-17215511b05f
+.AUTHOR DSC Community
+.COMPANYNAME DSC Community
+.COPYRIGHT DSC Community contributors. All rights reserved.
+.TAGS DSCConfiguration
+.LICENSEURI https://github.com/dsccommunity/FileSystemDsc/blob/main/LICENSE
+.PROJECTURI https://github.com/dsccommunity/FileSystemDsc
+.ICONURI https://dsccommunity.org/images/DSC_Logo_300p.png
+.RELEASENOTES
+First release.
+#>
+
+#Requires -Module FileSystemDsc
+
+<#
+
+.DESCRIPTION
+ Sample to create a file with contents.
+
+#>
+Configuration FileSystemObject_CreateFileWithContent_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject MyFile
+ {
+ DestinationPath = 'C:\inetpub\wwwroot\index.html'
+ Contents = '
My PageDSC is the best'
+ Type = 'file'
+ Ensure = 'present'
+ }
+ }
+}
diff --git a/source/FileSystemDsc.psd1 b/source/FileSystemDsc.psd1
index 1f9884e..d8c788d 100644
--- a/source/FileSystemDsc.psd1
+++ b/source/FileSystemDsc.psd1
@@ -1,48 +1,41 @@
@{
+ RootModule = 'FileSystemDsc.psm1'
+
# Version number of this module.
- moduleVersion = '0.0.1'
+ ModuleVersion = '0.0.1'
# ID used to uniquely identify this module
- GUID = '86a20a80-3bcd-477e-9b90-ec8d52fbe415'
+ GUID = '86a20a80-3bcd-477e-9b90-ec8d52fbe415'
+
+ CompatiblePSEditions = @('Core', 'Desktop')
# Author of this module
- Author = 'DSC Community'
+ Author = 'DSC Community'
# Company or vendor of this module
- CompanyName = 'DSC Community'
+ CompanyName = 'DSC Community'
# Copyright statement for this module
- Copyright = 'Copyright the DSC Community contributors. All rights reserved.'
+ Copyright = 'Copyright the DSC Community contributors. All rights reserved.'
# Description of the functionality provided by this module
- Description = 'This module contains DSC resources for managing file systems.'
+ Description = 'This module contains DSC resources for managing file systems.'
# Minimum version of the Windows PowerShell engine required by this module
- PowerShellVersion = '5.1'
+ PowerShellVersion = '5.1'
# Minimum version of the common language runtime (CLR) required by this module
- CLRVersion = '4.0'
-
- # Functions to export from this module
- FunctionsToExport = @()
-
- # Cmdlets to export from this module
- CmdletsToExport = @()
-
- # Variables to export from this module
- VariablesToExport = @()
-
- # Aliases to export from this module
- AliasesToExport = @()
+ CLRVersion = '4.0'
DscResourcesToExport = @(
'FileSystemAccessRule'
+ 'File'
)
- RequiredAssemblies = @()
+ RequiredAssemblies = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
- PrivateData = @{
+ PrivateData = @{
PSData = @{
# Set to a prerelease string value if the release should be a prerelease.
Prerelease = ''
diff --git a/source/en-US/FileSystemDsc.strings.psd1 b/source/en-US/FileSystemDsc.strings.psd1
new file mode 100644
index 0000000..b0c4547
--- /dev/null
+++ b/source/en-US/FileSystemDsc.strings.psd1
@@ -0,0 +1,9 @@
+<#
+ .SYNOPSIS
+ The localized resource strings in English (en-US) for the
+ resource FileSystemDsc module. This file should only contain
+ localized strings for private and public functions.
+#>
+
+ConvertFrom-StringData @'
+'@
diff --git a/tests/Integration/DSC_FileSystemObject.Integration.Tests.ps1 b/tests/Integration/DSC_FileSystemObject.Integration.Tests.ps1
new file mode 100644
index 0000000..7730ff6
--- /dev/null
+++ b/tests/Integration/DSC_FileSystemObject.Integration.Tests.ps1
@@ -0,0 +1,628 @@
+BeforeDiscovery {
+ try
+ {
+ Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
+ }
+ catch [System.IO.FileNotFoundException]
+ {
+ throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.'
+ }
+
+ <#
+ Need to define that variables here to be used in the Pester Discover to
+ build the ForEach-blocks.
+ #>
+ $script:dscResourceFriendlyName = 'FileSystemObject'
+ $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)"
+ $script:temproot = Join-Path -Path ([io.Path]::GetTempPath()) -ChildPath DscFileIntTest
+ $script:tempdir = Join-Path -Path $temproot -ChildPath Source
+ $script:tempDirDestination = Join-Path -Path $temproot -ChildPath Destination
+}
+
+BeforeAll {
+ # Need to define the variables here which will be used in Pester Run.
+ $script:dscModuleName = 'FileSystemDsc'
+ $script:dscResourceFriendlyName = 'FileSystemObject'
+ $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)"
+ $script:temproot = Join-Path -Path ([io.Path]::GetTempPath()) -ChildPath DscFileIntTest
+ $script:tempdir = Join-Path -Path $temproot -ChildPath Source
+ $script:tempDirDestination = Join-Path -Path $temproot -ChildPath Destination
+
+ $script:testEnvironment = Initialize-TestEnvironment `
+ -DSCModuleName $script:dscModuleName `
+ -DSCResourceName $script:dscResourceName `
+ -ResourceType 'Mof' `
+ -TestType 'Integration'
+
+ # This helper function should be removed when it is merged into DscResource.Test
+ function Wait-ForIdleLcm
+ {
+ [CmdletBinding()]
+ param ()
+
+ while ((Get-DscLocalConfigurationManager).LCMState -ne 'Idle')
+ {
+ Write-Verbose -Message 'Waiting for the LCM to become idle'
+
+ Start-Sleep -Seconds 2
+ }
+ }
+
+ $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1"
+ . $configFile
+}
+
+AfterAll {
+ Restore-TestEnvironment -TestEnvironment $script:testEnvironment
+}
+
+Describe "_Integration" {
+ BeforeAll {
+ $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test"
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_EmptyDir_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It "Should be able to find $($script:tempdir )" {
+ Test-Path -Path $script:tempdir -PathType Container | Should -BeTrue
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_EmptyFile_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should find the newly created file' {
+ Test-Path -Path (Join-Path -Path $script:tempdir -ChildPath emptyfile) -PathType Leaf | Should -BeTrue
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_CreateFile_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should find the newly created file and validate its contents' {
+ Test-Path -Path (Join-Path -Path $script:tempdir -ChildPath contentfile) -PathType Leaf | Should -BeTrue
+ Get-Content -Path (Join-Path -Path $script:tempdir -ChildPath contentfile) | Should -Be 'It works'
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_CopyFile_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should have copied a single file' {
+ Test-Path -Path (Join-Path -Path $script:tempDirDestination -ChildPath copiedfile) -PathType Leaf | Should -BeTrue
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_CopyFileWildcard_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should have copied multiple files' {
+ (Get-ChildItem -Path (Join-Path -Path $script:tempDirDestination -ChildPath "copydestfilewc")).Count | Should -Be 2
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_CopyDir_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should have copied single dir' {
+ Test-Path -Path (Join-Path -Path $tempDirDestination -ChildPath "copydestfilewc") | Should -BeTrue
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_CopyDirWildcard_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should have copied single dir with wildcard pattern' {
+ Test-Path -Path (Join-Path -Path $tempDirDestination -ChildPath "copydestfilewc\contentfile") | Should -BeTrue
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_CopyDirRecurse_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should have copied single dir recursive' {
+ Test-Path -Path (Join-Path -Path $tempDirDestination -ChildPath 'this\is\recursive') | Should -BeTrue
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_CopyDirRecurseWildcard_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should have copied single dir recursive wildcard' {
+ Test-Path -Path (Join-Path -Path $tempDirDestination -ChildPath "copydestdirrec\recursive\thing") | Should -BeTrue
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_RemoveFile_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should have removed single file' {
+ Test-Path -Path (Join-Path -Path $tempdir -ChildPath "emptyfile") | Should -BeFalse
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_RemoveFileWildcard_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should have removed single file' {
+ (Get-ChildItem -Path (Join-Path -Path $tempdir -ChildPath "copydestfilewc")).Count | Should -Be 0
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+
+ Context ('When using configuration <_>') -ForEach @(
+ "$($script:dscResourceName)_RemoveDirRecurse_Config"
+ ) {
+ BeforeAll {
+ $configurationName = $_
+ }
+
+ AfterAll {
+ Wait-ForIdleLcm
+ }
+
+ It 'Should compile and apply the MOF without throwing' {
+ {
+ $configurationParameters = @{
+ OutputPath = $TestDrive
+ }
+
+ & $configurationName @configurationParameters
+
+ $startDscConfigurationParameters = @{
+ Path = $TestDrive
+ ComputerName = 'localhost'
+ Wait = $true
+ Verbose = $true
+ Force = $true
+ ErrorAction = 'Stop'
+ }
+
+ Start-DscConfiguration @startDscConfigurationParameters
+ } | Should -Not -Throw
+ }
+
+ It 'Should be able to call Get-DscConfiguration without throwing' {
+ {
+ $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop
+ } | Should -Not -Throw
+ }
+
+ It 'Should have removed single folder' {
+ Test-Path -Path $tempdir | Should -BeFalse
+ }
+
+ It 'Should return $true when Test-DscConfiguration is run' {
+ Test-DscConfiguration -Verbose | Should -Be 'True'
+ }
+ }
+}
diff --git a/tests/Integration/DSC_FileSystemObject.config.ps1 b/tests/Integration/DSC_FileSystemObject.config.ps1
new file mode 100644
index 0000000..b9d190e
--- /dev/null
+++ b/tests/Integration/DSC_FileSystemObject.config.ps1
@@ -0,0 +1,300 @@
+$temproot = Join-Path -Path ([io.Path]::GetTempPath()) -ChildPath DscFileIntTest
+$tempdir = Join-Path -Path $temproot -ChildPath Source
+$tempDirDestination = Join-Path -Path $temproot -ChildPath Destination
+$null = New-Item -ItemType Directory -Path $tempDirDestination -ErrorAction SilentlyContinue
+
+<#
+ .SYNOPSIS
+ Create empty directory
+#>
+configuration DSC_FileSystemObject_EmptyDir_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject EmptyDir
+ {
+ DestinationPath = $tempdir
+ Type = 'directory'
+ Ensure = 'present'
+ Force = $true
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Create an empty file
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+#>
+configuration DSC_FileSystemObject_EmptyFile_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject EmptyFile
+ {
+ DestinationPath = Join-Path -Path $tempdir -ChildPath "emptyfile"
+ Type = 'file'
+ Ensure = 'present'
+ Force = $true
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Create a file with content and encoding utf8
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+#>
+configuration DSC_FileSystemObject_CreateFile_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject FileContent
+ {
+ DestinationPath = Join-Path -Path $tempdir -ChildPath "contentfile"
+ Type = 'file'
+ Ensure = 'present'
+ Contents = 'It works'
+ Encoding = 'utf8'
+ Force = $true
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Copy single file
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+#>
+configuration DSC_FileSystemObject_CopyFile_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject CopyFile
+ {
+ DestinationPath = Join-Path -Path $tempDirDestination -ChildPath "copiedfile"
+ SourcePath = Join-Path -Path $tempdir -ChildPath "contentfile"
+ Type = 'file'
+ Ensure = 'present'
+ Force = $true
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Copy several files with wildcard
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+ and that files were created in previous tests
+#>
+configuration DSC_FileSystemObject_CopyFileWildcard_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject CopyFile
+ {
+ DestinationPath = Join-Path -Path $tempDirDestination -ChildPath "copydestfilewc"
+ SourcePath = Join-Path -Path $tempdir -ChildPath "*file"
+ Type = 'file'
+ Ensure = 'present'
+ Force = $true
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Copy single directory
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+ and files were created in previous tests
+#>
+configuration DSC_FileSystemObject_CopyDir_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject CopyDir
+ {
+ DestinationPath = $tempDirDestination
+ SourcePath = $tempdir
+ Type = 'directory'
+ Ensure = 'present'
+ Force = $true
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Copy directories using a wildcard pattern
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+#>
+configuration DSC_FileSystemObject_CopyDirWildcard_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject CopyDirWc
+ {
+ DestinationPath = $tempDirDestination
+ SourcePath = Join-Path -Path $tempdir -ChildPath "*"
+ Type = 'directory'
+ Ensure = 'present'
+ Force = $true
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Copy single directory recursively
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+#>
+configuration DSC_FileSystemObject_CopyDirRecurse_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject CopyDirRec
+ {
+ DestinationPath = $tempDirDestination
+ SourcePath = $tempdir
+ Type = 'directory'
+ Ensure = 'present'
+ Recurse = $true
+ Force = $true
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Copy directory recursive using wildcard pattern
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+#>
+configuration DSC_FileSystemObject_CopyDirRecurseWildcard_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject SourceObject
+ {
+ DestinationPath = Join-Path -Path $tempDir -ChildPath 'this\is\recursive'
+ Type = 'file'
+ Ensure = 'present'
+ Recurse = $true
+ Force = $true
+ }
+
+ FileSystemObject CopyDirRecWc
+ {
+ DestinationPath = $tempDirDestination
+ SourcePath = Join-Path -Path $tempdir -ChildPath "*"
+ Type = 'directory'
+ Ensure = 'present'
+ Recurse = $true
+ Force = $true
+ DependsOn = '[FileSystemObject]SourceObject'
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Remove a single file
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+#>
+configuration DSC_FileSystemObject_RemoveFile_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject EmptyFile
+ {
+ DestinationPath = Join-Path -Path $tempdir -ChildPath "emptyfile"
+ Type = 'file'
+ Ensure = 'absent'
+ Force = $true
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Remove files using a wildcard pattern
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+#>
+configuration DSC_FileSystemObject_RemoveFileWildcard_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject RemoveFileWc
+ {
+ DestinationPath = Join-Path -Path $tempdir -ChildPath "copydestfilewc\*"
+ Type = 'file'
+ Force = $true
+ Ensure = 'absent'
+ }
+ }
+}
+
+<#
+ .SYNOPSIS
+ Remove the temporary directory, thereby cleaning up all test files
+
+ .NOTES
+ This requires that the temporary dir was created in the very first test
+#>
+configuration DSC_FileSystemObject_RemoveDirRecurse_Config
+{
+ Import-DscResource -ModuleName FileSystemDsc
+
+ node localhost
+ {
+ FileSystemObject RemoveDirRecurse
+ {
+ DestinationPath = $tempRoot
+ Type = 'file'
+ Ensure = 'absent'
+ Force = $true
+ Recurse = $true
+ }
+ }
+}
diff --git a/tests/Unit/DSC_FileSystemObject.Tests.ps1 b/tests/Unit/DSC_FileSystemObject.Tests.ps1
new file mode 100644
index 0000000..9bb8964
--- /dev/null
+++ b/tests/Unit/DSC_FileSystemObject.Tests.ps1
@@ -0,0 +1,166 @@
+<#
+ .SYNOPSIS
+ Unit test for DSC_FileSystemObject DSC resource.
+#>
+
+# Suppressing this rule because Script Analyzer does not understand Pester's syntax.
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
+param ()
+
+BeforeDiscovery {
+ try
+ {
+ if (-not (Get-Module -Name 'DscResource.Test'))
+ {
+ # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task.
+ if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
+ {
+ # Redirect all streams to $null, except the error stream (stream 2)
+ & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null
+ }
+
+ # If the dependencies has not been resolved, this will throw an error.
+ Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
+ }
+ }
+ catch [System.IO.FileNotFoundException]
+ {
+ throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.'
+ }
+}
+
+BeforeAll {
+ $script:dscModuleName = 'FileSystemDsc'
+
+ Import-Module -Name $script:dscModuleName
+
+ $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName
+ $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscModuleName
+ $PSDefaultParameterValues['Should:ModuleName'] = $script:dscModuleName
+}
+
+AfterAll {
+ $PSDefaultParameterValues.Remove('InModuleScope:ModuleName')
+ $PSDefaultParameterValues.Remove('Mock:ModuleName')
+ $PSDefaultParameterValues.Remove('Should:ModuleName')
+
+ # Unload the module being tested so that it doesn't impact any other tests.
+ Get-Module -Name $script:dscModuleName -All | Remove-Module -Force
+
+ # Remove module common test helper.
+ Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force
+}
+
+Describe 'FileSystemObject' {
+ Context 'When class is instantiated' {
+ It 'Should not throw an exception' {
+ InModuleScope -ScriptBlock {
+ { [FileSystemObject]::new() } | Should -Not -Throw
+ }
+ }
+
+ It 'Should have a default or empty constructor' {
+ InModuleScope -ScriptBlock {
+ $instance = [FileSystemObject]::new()
+ $instance | Should -Not -BeNullOrEmpty
+ }
+ }
+
+ It 'Should be the correct type' {
+ InModuleScope -ScriptBlock {
+ $instance = [FileSystemObject]::new()
+ $instance.GetType().Name | Should -Be 'FileSystemObject'
+ }
+ }
+ }
+}
+
+Describe 'FileSystemObject\Get()' -Tag 'Get' {
+ Context 'When the system is in the desired state'-Skip {
+
+ BeforeAll {
+ InModuleScope -ScriptBlock {
+ $script:mockFileSystemObjectInstanceDir = [FileSystemObject] @{
+ Ensure = 'present'
+ Type = 'directory'
+ DestinationPath = 'C:\MadeUpDir'
+ }
+ $script:mockFileSystemObjectInstanceDirCopyRecurse = [FileSystemObject] @{
+ Ensure = 'present'
+ Type = 'directory'
+ DestinationPath = 'C:\MadeUpDir'
+ SourcePath = 'D:\MadeUpSource'
+ Recurse = $true
+ Force = $true
+ }
+ $script:mockFileSystemObjectInstanceDirCopyRecurseWildcard = [FileSystemObject] @{
+ Ensure = 'present'
+ Type = 'directory'
+ DestinationPath = 'C:\MadeUpDir'
+ SourcePath = 'D:\MadeUpSource\*'
+ }
+ $script:mockFileSystemObjectInstanceFile = [FileSystemObject] @{
+ Ensure = 'present'
+ Type = 'file'
+ DestinationPath = 'C:\MadeUpDir\madeupfile'
+ }
+ $script:mockFileSystemObjectInstanceFileContent = [FileSystemObject] @{
+ Ensure = 'present'
+ Type = 'file'
+ Contents = 'Ladies and Gentlemen: The Content!'
+ DestinationPath = 'C:\MadeUpDir\madeupfile'
+ }
+ $script:mockFileSystemObjectInstanceFileCopyDefault = [FileSystemObject] @{
+ Ensure = 'present'
+ Type = 'file'
+ DestinationPath = 'C:\MadeUpDir'
+ SourcePath = 'D:\MadeUpSource\madeupfile'
+ }
+ $script:mockFileSystemObjectInstanceFileCopyCreation = [FileSystemObject] @{
+ Ensure = 'present'
+ Type = 'file'
+ DestinationPath = 'C:\MadeUpDir'
+ SourcePath = 'D:\MadeUpSource\madeupfile'
+ Checksum = 'CreationTime'
+ }
+ $script:mockFileSystemObjectInstanceFileCopyModified = [FileSystemObject] @{
+ Ensure = 'present'
+ Type = 'file'
+ DestinationPath = 'C:\MadeUpDir'
+ SourcePath = 'D:\MadeUpSource\madeupfile'
+ Checksum = 'LastModifiedTime'
+ }
+ $script:mockFileSystemObjectInstanceFileCopyWildcard = [FileSystemObject] @{
+ Ensure = 'present'
+ Type = 'file'
+ DestinationPath = 'C:\MadeUpDir'
+ SourcePath = 'D:\MadeUpSource\*file*'
+ }
+
+ # Empty hash function results, since system is in desired state
+ # GetHash should not be called at any rate, as CompareHash is "mocked"
+ foreach ($variable in (Get-Variable -Scope Script -Name mockFileSystemObjectInstance*))
+ {
+ $variable.Value | Add-Member -Force -MemberType 'ScriptMethod' -Name 'GetHash' -Value { return }
+ $variable.Value | Add-Member -Force -MemberType 'ScriptMethod' -Name 'CompareHash' -Value { return }
+ }
+ }
+ }
+ }
+}
+
+Describe 'FileSystemObject\Set()' -Tag 'Set' -Skip {
+
+}
+
+Describe 'FileSystemObject\Test()' -Tag 'Test' -Skip {
+
+}
+
+Describe 'FileSystemObject\GetHash()' -Tag 'GetHash' -Skip {
+
+}
+
+Describe 'FileSystemObject\CompareHash()' -Tag 'CompareHash' -Skip {
+
+}