5 ConvertFrom-StringData @'
6 InvalidChecksumArgsMessage=Specifying a Checksum without requesting content validation (the Validate parameter) is not meaningful
7 InvalidDestinationDirectory=The specified destination directory {0} does not exist or is not a directory
8 InvalidSourcePath=The specified source file {0} does not exist or is not a file
9 InvalidNetSourcePath=The specified source file {0} is not a valid net source path
10 ErrorOpeningExistingFile=An error occurred while opening the file {0} on disk. Please examine the inner exception for details
11 ErrorOpeningArchiveFile=An error occurred while opening the archive file {0}. Please examine the inner exception for details
12 ItemExistsButIsWrongType=The named item ({0}) exists but is not the expected type, and Force was not specified
13 ItemExistsButIsIncorrect=The destination file {0} has been determined not to match the source, but Force has not been specified. Cannot continue
14 ErrorCopyingToOutstream=An error was encountered while copying the archived file to {0}
15 PackageUninstalled=The archive at {0} was removed from destination {1}
16 PackageInstalled=The archive at {0} was unpacked to destination {1}
17 ConfigurationStarted=The configuration of MSFT_ArchiveResource is starting
18 ConfigurationFinished=The configuration of MSFT_ArchiveResource has completed
19 MakeDirectory=Make directory {0}
20 RemoveFileAndRecreateAsDirectory=Remove existing file {0} and replace it with a directory of the same name
21 RemoveFile=Remove file {0}
22 RemoveDirectory=Remove directory {0}
23 UnzipFile=Unzip archived file to {0}
24 DestMissingOrIncorrectTypeReason=The destination file {0} was missing or was not a file
25 DestHasIncorrectHashvalue=The destination file {0} exists but its checksum did not match the origin file
26 DestShouldNotBeThereReason=The destination file {0} exists but should not
27 UsingKeyToRetrieveHashValue = Using {0} to retrieve hash value
28 Nocachevaluefound = No cache value found
29 Cachevaluefoundreturning = Cache value found, returning {0}
30 CacheCorrupt = Cache found, but failed to loaded. Ignoring Cache.
31 Usingtmpkeytosavehashvalue = Using {0} {1} to save hash value
32 AbouttocachevalueInputObject = About to cache value {0}
33 InUpdateCache = In Update-Cache
34 AddingentryFullNameasacacheentry = Adding {0} as a cache entry
35 UpdatingCacheObject = Updating CacheObject
36 Placednewcacheentry = Placed new cache entry
37 NormalizeChecksumreturningChecksum = Normalize-Checksum returning {0}
38 PathPathisalreadyaccessiableNomountneeded. = Path {0} is already accessible. No mount needed.
39 Pathpathisnotavalidatenetpath = Path {0} is not a validate net path.
40 createpsdrivewithPathpath = create psdrive with Path {0}...
41 CannotaccessPathPathwithgivenCredential = Cannot access Path {0} with given Credential
42 Abouttovalidatestandardarguments = About to validate standard arguments
43 Goingforcacheentries = Going for cache entries
44 Thecachewasuptodateusingcachetosatisfyrequests = The cache was up to date, using cache to satisfy requests
45 Abouttoopenthezipfile = About to open the zip file
46 Cacheupdatedwithentries = Cache updated with {0} entries
47 Processing = Processing {0}
48 InTestTargetResourcedestexistsnotusingchecksumscontinuing = In Test-TargetResource: {0} exists, not using checksums, continuing
49 Notperformingchecksumthefileondiskhasthesamewritetimeasthelasttimeweverifieditscontents = Not performing checksum, the file on disk has the same write time as the last time we verified its contents
50 destexistsandthehashmatcheseven = {0} exists and the hash matches even though the LastModifiedTime did not. Updating cache
51 InTestTargetResourcedestexistsandtheselectedtimestampChecksummatched = In Test-TargetResource: {0} exists and the selected timestamp {1} matched
52 RemovePSDriveonRootpsdriveRoot = Remove PSDrive on Root {0}
53 RemovingDir = Removing {0}
54 Hashesofexistingandzipfilesmatchremoving = Hashes of existing and zip files match, removing
55 HashdidnotmatchfilehasbeenmodifiedsinceitwasextractedLeaving = Hash did not match, file has been modified since it was extracted. Leaving
56 InSetTargetResourceexistsselectedtimestampmatched = In Set-TargetResource: {0} exists and the selected timestamp {1} matched, removing
57 InSetTargetResourceexistsdtheselectedtimestampnotmatchg = In Set-TargetResource: {0} exists and the selected timestamp {1} did not match, leaving
58 existingappearstobeanemptydirectoryRemovingit = {0} appears to be an empty directory. Removing it
59 LastWriteTimemtcheswhatwehaverecordnotreexaminingchecksum = LastWriteTime of {0} matches what we have on record, not re-examining {1}
60 FoundfatdestwheregoingtoplaceoneandhashmatchedContinuing = Found a file at {0} where we were going to place one and hash matched. Continuing
61 FoundfileatdestwhereweweregoingtoplaceoneandhashdidntmatchItwillbeoverwritten = Found a file at $dest where we were going to place one and hash did not match. It will be overwritten
62 FoundfileatdestwhereweweregoingtoplaceoneanddoesnotmatchthesourcebutForcewasnotspecifiedErroring = Found a file at {0} where we were going to place one and does not match the source, but Force was not specified. Erroring
63 InSetTargetResourcedestexistsandtheselectedtimestamp$ChecksumdidnotmatchForcewasspecifiedwewilloverwrite = "In Set-TargetResource: {0} exists and the selected timestamp {1} did not match. Force was specified, we will overwrite
64 FoundafileatdestandtimestampChecksumdoesnotmatchthesourcebutForcewasnotspecifiedErroring = Found a file at {0} and timestamp {1} does not match the source, but Force was not specified. Erroring
65 FoundadirectoryatdestwhereafileshouldbeRemoving = Found a directory at {0} where a file should be. Removing
66 FounddirectoryatdestwhereafileshouldbeandForcewasnotspecifiedErroring = Found a directory at {0} where a file should be and Force was not specified. Erroring.
67 Writingtofiledest = Writing to file {0}
68 RemovePSDriveonRootdriveRoot = Remove PSDrive on Root {0}
69 Updatingcache = Updating cache
70 FolderDirdoesnotexist = Folder {0} does not exist
71 Examiningdirectorytoseeifitshouldberemoved = Examining {0} to see if it should be removed
72 InSetTargetResourcedestexistsandtheselectedtimestampChecksummatchedwillleaveit = In Set-TargetResource: {0} exists and the selected timestamp {1} matched, will leave it
76 Import-LocalizedData LocalizedData -filename ArchiveProvider.psd1
78 Import-Module "$PSScriptRoot\..\RunAsHelper.psm1"
81 Function Trace-Message
83 param([string] $Message)
87 Write-Verbose $Message
91 $CacheLocation = "$env:systemroot\system32\Configuration\BuiltinProvCache\MSFT_ArchiveResource"
93 Function DSCHashNameToPSHashName
100 # Since in-box powershell Get-FileHash cmdlet takes algorithm without hypen, we silently change the names
106 $psName = $dscToPsName[$Algorithm]
112 Function Get-CacheEntry
119 $key = ($path + $destination).GetHashCode()
120 Trace-Message ($LocalizedData.UsingKeyToRetrieveHashValue -f $Key)
121 $path = Join-Path $CacheLocation $key
122 if(-not (Test-Path $path))
124 Trace-Message ($LocalizedData.Nocachevaluefound)
129 # ErroAction seems to have no affect on this condition, (see: https://microsoft.visualstudio.com/web/wi.aspx?pcguid=cb55739e-4afe-46a3-970f-1b49d8ee7564&id=1185735)
130 # using a try/catch to work around the issue.
133 $tmp = Import-CliXml $path
134 Trace-Message ($LocalizedData.Cachevaluefoundreturning -f $tmp)
137 catch [System.Xml.XmlException]
139 Trace-Message ($LocalizedData.CacheCorrupt)
145 Function Set-CacheEntry
148 [object] $InputObject,
150 [string] $destination
152 $key = ($path + $destination).GetHashCode()
153 Trace-Message ($LocalizedData.Usingtmpkeytosavehashvalue -f $tmp, $key)
154 $path = Join-Path $CacheLocation $key
155 Trace-Message ($LocalizedData.AbouttocachevalueInputObject -f $InputObject)
156 if(-not (Test-Path $CacheLocation))
158 mkdir $CacheLocation | Out-Null
161 Export-CliXml -Path $path -InputObject $InputObject
164 Function Throw-InvalidArgumentException
171 $exception = new-object System.ArgumentException $Message,$ParamName
172 $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception,$ParamName,"InvalidArgument",$null
176 Function Throw-TerminatingError
180 [System.Management.Automation.ErrorRecord] $ErrorRecord,
181 [string] $ExceptionType
184 $exception = new-object "System.InvalidOperationException" $Message,$ErrorRecord.Exception
185 $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception,"MachineStateIncorrect","InvalidOperation",$null
189 Function Assert-ValidStandardArgs
193 [string] $Destination,
198 #mkdir and Test-Path can each fail with a useful error message
199 #We want to stop our execution if that happens
200 $ErrorActionPreference = "Stop"
202 if(-not (Test-Path -PathType Leaf $Path))
204 Throw-InvalidArgumentException ($LocalizedData.InvalidSourcePath -f $Path) "Path"
207 $item = Get-Item -EA Ignore $Destination
208 if($item -and $item.GetType() -eq [System.IO.FileInfo])
210 Throw-InvalidArgumentException ($LocalizedData.InvalidDestinationDirectory -f $Destination) "Destination"
213 if($Checksum -and -not $Validate)
215 Throw-InvalidArgumentException ($LocalizedData.InvalidChecksumArgsMessage -f $Checksum) "Checksum"
219 Function Compare-FileToEntry
227 $existingStream = $null
231 $existingStream = New-Object System.IO.FileStream $FileName, "Open"
232 $psAlgorithm = DSCHashNameToPSHashName -Algorithm $Algorithm
233 $hash1 = Get-FileHash -InputStream $existingStream -Algorithm $psAlgorithm
237 Throw-TerminatingError ($LocalizedData.ErrorOpeningExistingFile -f $FileName) $_
241 if($existingStream -ne $null)
243 $existingStream.Dispose()
247 $hash2 = $Entry.Checksum
248 return ($hash1.Algorithm -eq $hash2.Algorithm) -and ($hash1.Hash -eq $hash2.Hash)
251 Function Get-RelevantChecksumTimestamp
254 [System.IO.FileSystemInfo] $FileSystemObject,
258 if($Checksum.Equals("createddate"))
260 return $FileSystemObject.CreationTime
262 else #$Checksum.Equals("modifieddate")
264 return $FileSystemObject.LastWriteTime
268 Function Update-Cache
271 [Hashtable] $CacheObject,
272 [System.IO.Compression.ZipArchiveEntry[]] $Entries,
274 [string] $SourceLastWriteTime
277 Trace-Message ($LocalizedData.InUpdateCache)
278 $cacheEntries = new-object System.Collections.ArrayList
279 foreach($entry in $Entries)
282 if($Checksum.StartsWith("sha"))
287 $stream = $entry.Open()
288 $psAlgorithm = DSCHashNameToPSHashName -Algorithm $Checksum
289 $hash = Get-FileHash -InputStream $stream -Algorithm $psAlgorithm
300 Trace-Message ($LoalizedData.AddingentryFullNameasacacheentry -f $entry.FullName)
302 FullName = $entry.FullName
303 LastWriteTime = $entry.LastWriteTime
308 Trace-Message ($LocalizedData.UpdatingCacheObject)
309 $CacheObject["SourceLastWriteTime"] = $SourceLastWriteTime
310 $CacheObject["Entries"] = (@() + $cacheEntries)
311 Set-CacheEntry -InputObject $CacheObject -path $Path -destination $Destination
312 Trace-Message ($LocalizedData.Placednewcacheentry)
315 Function Normalize-Checksum
326 $Checksum = "SHA-256"
329 $Checksum = $Checksum.ToLower()
332 Trace-Message ($LocalizedData.NormalizeChecksumreturningChecksum -f $Checksum)
336 # create a psdrive to a net share with a given credential.
337 function Mount-NetworkPath
339 param ( [string] $path, [pscredential] $Credential)
341 # mount the drive only if not accessible
342 if (Test-Path $path -ErrorAction Ignore)
344 Trace-Message ($LocalizedData.PathPathisalreadyaccessiableNomountneeded -f $Path)
349 if (-not $path.EndsWith("\"))
351 $index = $Path.LastIndexOf("\");
354 Trace-Message ($LocalizedData.Pathpathisnotavalidatenetpath -f $path)
355 Throw-TerminatingError ($LocalizedData.InvalidNetSourcePath -f $Path)
359 $path = $path.Substring(0, $index)
363 $psdriveArgs = @{ Name=([guid]::NewGuid()); PSProvider="FileSystem"; Root=$Path; Scope="Script"; Credential=$Credential }
366 Trace-Message ($LocalizedData.createpsdrivewithPathpath -f $path)
367 $psdrive = New-PSDrive @psdriveArgs
371 Trace-Message ($LocalizedData.CannotaccessPathPathwithgivenCredential -f $Path)
372 Throw-TerminatingError ($LocalizedData.ErrorOpeningArchiveFile -f $Path) $_
379 # The Test-TargetResource cmdlet is used to test the status of item on the destination
380 function Test-TargetResource
384 [ValidateSet("Present", "Absent")]
385 [string] $Ensure = "Present",
387 [parameter(Mandatory = $true)]
388 [ValidateNotNullOrEmpty()]
391 [parameter(Mandatory = $true)]
392 [ValidateNotNullOrEmpty()]
393 [string] $Destination,
395 [boolean] $Validate = $false,
397 [ValidateSet("", "SHA-1", "SHA-256", "SHA-512", "CreatedDate", "ModifiedDate")]
400 [boolean] $Force = $false,
402 [pscredential] $Credential
407 $psdrive = Mount-NetworkPath -path $Path -Credential $Credential
412 $ErrorActionPreference = "Stop"
414 Trace-Message ($LocalizedData.Abouttovalidatestandardarguments)
415 Assert-ValidStandardArgs $Path $Destination $Validate $Checksum
416 $Checksum = Normalize-Checksum $Validate $Checksum
417 Trace-Message ($LocalizedData.Goingforcacheentries)
419 $cacheObj = Get-CacheEntry -path $Path -destination $Destination
420 $sourceLastWriteTime = (Get-Item $Path).LastWriteTime
421 $cacheUpToDate = $cacheObj -and $cacheObj.SourceLastWriteTime -and $cacheObj.SourceLastWriteTime -eq $sourceLastWriteTime
428 Trace-Message ($LocalizedData.Thecachewasuptodateusingcachetosatisfyrequests)
429 $entries = $cacheObj.Entries
433 Trace-Message ($LocalizedData.Abouttoopenthezipfile)
434 $entries, $null, $file = Open-ZipFile $Path
436 Trace-Message ($LocalizedData.Updatingcache)
437 Update-Cache $cacheObj $entries $Checksum $sourceLastWriteTime
438 $entries = $cacheObj.Entries
439 Trace-Message ($LocalizedData.Cacheupdatedwithentries -f $cacheObj.Entries.Length)
442 foreach($entry in $entries)
444 $individualResult = $true
445 Trace-Message ($LocalizedData.Processing -f $entry.FullName)
446 $dest = join-path $Destination $entry.FullName
447 if($dest.EndsWith('\')) #Directory
449 $dest = $dest.TrimEnd('\')
450 if(-not (Test-Path -PathType Container $dest))
452 Write-Verbose ($LocalizedData.DestMissingOrIncorrectTypeReason -f $dest)
453 $individualResult = $result = $false
458 $item = Get-Item $dest -EA Ignore
461 $individualResult = $result = $false
463 elseif($item.GetType() -ne [System.IO.FileInfo])
465 $individualResult = $result = $false
470 Trace-Message ($LocalizedData.InTestTargetResourcedestexistsnotusingchecksumscontinuing -f $dest)
471 if(-not $individualResult -and $Ensure -eq "Present")
473 Write-Verbose ($LocalizedData.DestMissingOrIncorrectTypeReason -f $dest)
475 elseif($individualResult -and $Ensure -eq "Absent")
477 Write-Verbose ($LocalizedData.DestShouldNotBeThereReason -f $dest)
482 #If the file is there we need to check if it could possibly fail in a different way
483 #Otherwise we skip all these checks - there's nothing to work with
484 if($individualResult)
486 $Checksum = $Checksum.ToLower()
487 if($Checksum.StartsWith("sha"))
489 if($item.LastWriteTime.Equals($entry.ExistingItemTimestamp))
491 Trace-Message ($LocalizedData.Notperformingchecksumthefileondiskhasthesamewritetimeasthelasttimeweverifieditscontents)
495 if(-not (Compare-FileToEntry $dest $entry $Checksum))
497 $individualResult = $result = $false
501 $entry.ExistingItemTimestamp = $item.LastWriteTime
502 Trace-Message ($LocalizedData.destexistsandthehashmatcheseven -f $dest)
508 $date = Get-RelevantChecksumTimestamp $item $Checksum
509 if(-not $date.Equals($entry.LastWriteTime.DateTime))
511 $individualResult = $result = $false
515 Trace-Message ($LocalizedData.InTestTargetResourcedestexistsandtheselectedtimestampChecksummatched -f $dest, $Checksum)
520 if(-not $individualResult -and $Ensure -eq "Present")
522 Write-Verbose ($LocalizedData.DestHasIncorrectHashvalue -f $dest)
524 elseif($individualResult -and $Ensure -eq "Absent")
526 Write-Verbose ($LocalizedData.DestShouldNotBeThereReason -f $dest)
540 Set-CacheEntry -InputObject $cacheObj -path $Path -destination $Destination
541 $result = $result -eq ("Present" -eq $Ensure)
547 $ErrorActionPreference = "SilentlyContinue"
548 Trace-Message ($LoalizedData.RemovePSDriveonRootpsdrive -f $($psdrive.Root))
549 Remove-PSDrive $psdrive -Force -ErrorAction SilentlyContinue
556 Function Ensure-Directory
559 $item = get-item $Dir -EA SilentlyContinue
562 Trace-Message ($LocalizedData.FolderDirdoesnotexist -f $Dir)
563 if($PSCmdlet.ShouldProcess(($LocalizedData.MakeDirectory -f $Dir), $null, $null))
565 mkdir $Dir | Out-Null
570 if($item.GetType() -ne [System.IO.DirectoryInfo])
572 if($Force -and $PSCmdlet.ShouldProcess(($LocalizedData.RemoveFileAndRecreateAsDirectory -f $Dir), $null, $null))
574 Trace-Message ($LocalizedData.RemovingDir -f $Dir)
576 mkdir $Dir | Out-Null #Note that we don't do access time translations onto directories since we are emulating the shell's behavior
580 Throw-TerminatingError ($LocalizedData.ItemExistsButIsWrongType -f $Path)
586 Function Open-ZipFile
591 add-type -assemblyname System.IO.Compression
595 add-type -assemblyname System.IO.Compression.FileSystem
600 $fileHandle = ([System.IO.Compression.ZipFile]::OpenRead($Path))
601 $entries = $fileHandle.Entries
605 Throw-TerminatingError ($LocalizedData.ErrorOpeningArchiveFile -f $Path) $_
608 $entries | %{$nameHash[$_.FullName] = $_}
609 return $entries, $nameHash, $fileHandle
612 # The Set-TargetResource cmdlet is used to unpack or remove a zip file to a particular directory
613 function Set-TargetResource
615 [CmdletBinding(SupportsShouldProcess=$true)]
618 [parameter(Mandatory = $true)]
619 [ValidateNotNullOrEmpty()]
622 [parameter(Mandatory = $true)]
623 [ValidateNotNullOrEmpty()]
624 [string] $Destination,
626 [ValidateSet("Present", "Absent")]
627 [string] $Ensure = "Present",
629 [boolean] $Validate = $false,
631 [ValidateSet("", "SHA-1", "SHA-256", "SHA-512", "CreatedDate", "ModifiedDate")]
634 [boolean] $Force = $false,
636 [pscredential] $Credential
641 $psdrive = Mount-NetworkPath -path $Path -Credential $Credential
646 $ErrorActionPreference = "Stop"
647 Assert-ValidStandardArgs $Path $Destination $Validate $Checksum
648 $Checksum = Normalize-Checksum $Validate $Checksum
649 Write-Verbose $LocalizedData.ConfigurationStarted
651 if(-not (Test-Path $Destination))
653 mkdir $Destination | Out-Null
656 $cacheObj = Get-CacheEntry -path $Path -destination $Destination
657 $sourceLastWriteTime = (Get-Item $Path).LastWriteTime
658 $cacheUpToDate = $cacheObj -and $cacheObj.SourceLastWriteTime -and $cacheObj.SourceLastWriteTime -eq $sourceLastWriteTime
664 # once cache is updated we need to dispose the handle
665 # if not, when the second time $file is updated with a
666 # new handle, the old one not being disposed will lead
667 # to archive resource having a lock on the file
668 if(-not $cacheUpToDate)
670 $entries, $nameToEntry, $file = Open-ZipFile $Path
671 Update-Cache $cacheObj $entries $Checksum $sourceLastWriteTime
687 $entries = $cacheObj.Entries
688 if($Ensure -eq "Absent")
690 $directories = new-object system.collections.generic.hashset[string]
691 foreach($entry in $entries)
694 if($entry.FullName.EndsWith("\"))
697 $directories.Add((Split-Path -Leaf $entry)) | Out-Null
700 $parent = $entry.FullName
701 while(($parent = (Split-Path $parent))) { $directories.Add($parent) | Out-Null }
705 #Directory removal is handled as its own pass, see note and code after this loop
709 $existing = Join-Path $Destination $entry.FullName
710 $item = Get-Item $existing -EA SilentlyContinue
716 #Possible for a folder to have been replaced by a directory of the same name, in which case we must leave it alone
717 $type = $item.GetType()
718 if($type -ne [System.IO.FileInfo])
723 if(-not $Checksum -and $PSCmdlet.ShouldProcess(($LocalizedData.RemoveFile -f $existing), $null, $null))
725 Trace-Message ($LocalizedData.RemovingDir -f $existing)
730 $Checksum = $Checksum.ToLower()
731 if($Checksum.StartsWith("sha"))
733 if((Compare-FileToEntry $existing $entry $Checksum) -and $PSCmdlet.ShouldProcess(($LocalizedData.RemoveFile -f $existing), $null, $null))
735 Trace-Message ($LocalizedData.Hashesofexistingandzipfilesmatchremoving)
740 Trace-Message ($LocalizedData.HashdidnotmatchfilehasbeenmodifiedsinceitwasextractedLeaving)
745 $date = Get-RelevantChecksumTimestamp $item $Checksum
746 if($date.Equals($entry.LastWriteTime.DateTime) -and $PSCmdlet.ShouldProcess(($LocalizedData.RemoveFile -f $existing), $null, $null))
748 Trace-Message ($LocalizedData.InSetTargetResourceexistsselectedtimestampmatched -f $existing, $Checksum)
753 Trace-Message ($LocalizedData.InSetTargetResourceexistsdtheselectedtimestampnotmatchg -f $existing, $Checksum)
758 #Hashset was useful for dropping dupes in an efficient manner, but it can mess with ordering
759 #Sort according to current culture (directory names can be localized, obviously)
760 #Reverse so we hit children before parents
761 $directories = [system.linq.enumerable]::ToList($directories)
762 $directories.Sort([System.StringComparer]::InvariantCultureIgnoreCase)
763 $directories.Reverse()
764 foreach($directory in $directories)
766 Trace-Message ($LocalizedData.Examiningdirectorytoseeifitshouldberemoved -f $directory)
767 $existing = Join-Path $Destination $directory
768 $item = Get-Item $existing -EA SilentlyContinue
769 if($item -and $item.GetType() -eq [System.IO.DirectoryInfo] -and $item.GetFiles().Count -eq 0 -and $item.GetDirectories().Count -eq 0 `
770 -and $PSCmdlet.ShouldProcess(($LocalizedData.RemoveDirectory -f $existing), $null, $null))
772 Trace-Message ($LocalizedData.existingappearstobeanemptydirectoryRemovingit -f $existing)
777 Write-Verbose ($LocalizedData.PackageUninstalled -f $Path,$Destination)
778 Write-Verbose $LocalizedData.ConfigurationFinished
782 Ensure-Directory $Destination
783 foreach($entry in $entries)
785 $dest = join-path $Destination $entry.FullName
786 if($dest.EndsWith('\')) #Directory
788 Ensure-Directory $dest.TrimEnd("\") #Some cmdlets have problems with trailing char
792 $item = Get-Item $dest -EA SilentlyContinue
795 if($item.GetType() -eq [System.IO.FileInfo])
799 #It exists. The user didn't specify -Validate, so that's good enough for us
803 if($Checksum.StartsWith("sha"))
805 if($item.LastWriteTime.Equals($entry.ExistingTimestamp))
807 Trace-Message ($LocalizedData.LastWriteTimemtcheswhatwehaverecordnotreexaminingchecksum -f $dest, $checksum)
811 $identical = Compare-FileToEntry $dest $entry $Checksum
815 Trace-Message ($LocalizedData.FoundfatdestwheregoingtoplaceoneandhashmatchedContinuing -f $dest)
816 $entry.ExistingItemTimestamp = $item.LastWriteTime
823 Trace-Message ($LocalizedData.FoundfileatdestwhereweweregoingtoplaceoneandhashdidntmatchItwillbeoverwritten -f $dest)
827 Trace-Message ($LocalizedData.FoundfileatdestwhereweweregoingtoplaceoneanddoesnotmatchthesourcebutForcewasnotspecifiedErroring -f $dest)
828 Throw-TerminatingError ($LocalizedData.ItemExistsButIsIncorrect -f $dest)
835 $date = Get-RelevantChecksumTimestamp $item $Checksum
836 if($date.Equals($entry.LastWriteTime.DateTime))
838 Trace-Message ($LocalizedData.InSetTargetResourcedestexistsandtheselectedtimestampChecksummatchedwillleaveit -f $dest, $Checksum)
845 Trace-Message ($LocalizedData.InSetTargetResourcedestexistsandtheselectedtimestamp -f $dest, $Checksum)
849 Trace-Message ($LocalizedData.FoundafileatdestandtimestampChecksumdoesnotmatchthesourcebutForcewasnotspecifiedErroring -f $dest, $Checksum)
850 Throw-TerminatingError ($LocalizedData.ItemExistsButIsIncorrect -f $dest)
859 Trace-Message ($LocalizedData.FoundadirectoryatdestwhereafileshouldbeRemoving -f $dest)
860 if($PSCmdlet.ShouldProcess(($LocalizedData.RemoveDirectory -f $dest), $null, $null))
862 rmdir -Recurse -Force $dest
867 Trace-Message ($LocalizedData.FounddirectoryatdestwhereafileshouldbeandForcewasnotspecifiedErroring -f $dest)
868 Throw-TerminatingError ($LocalizedData.ItemExistsButIsWrongType -f $dest)
873 $parent = Split-Path $dest
874 if(-not (Test-Path $parent) -and $PSCmdlet.ShouldProcess(($LocalizedData.MakeDirectory -f $parent), $null, $null))
876 #TODO: This is an edge case we need to revisit. We should be correctly handling wrong file types along
877 #the directory path if they occur within the archive, but they don't have to. Simple tests demonstrate that
878 #the Zip format allows you to have the file within a folder without explicitly having an entry for the folder
879 #This solution will fail in such a case IF anything along the path is of the wrong type (e.g. file in a place
880 #we expect a directory to be)
881 mkdir $parent | Out-Null
884 if($PSCmdlet.ShouldProcess(($LocalizedData.UnzipFile -f $dest), $null, $null))
886 #If we get here we can safely blow away anything we find.
887 $null, $nameToEntry, $file = Open-ZipFile $Path
892 Trace-Message ($LocalizedData.Writingtofiledest -f $dest)
893 $stream = $nameToEntry[$entry.FullName].Open()
894 $outStream = New-Object System.IO.FileStream $dest, "Create"
895 $stream.CopyTo($outStream)
899 Throw-TerminatingError ($LocalizedData.ErrorCopyingToOutstream -f $dest) $_
903 if($stream -ne $null)
908 if($outStream -ne $null)
914 $fileInfo = New-Object System.IO.FileInfo $dest
915 $entry.ExistingItemTimestamp = $fileInfo.LastWriteTime = $fileInfo.LastAccessTime = $fileInfo.CreationTime = $entry.LastWriteTime.DateTime
927 Set-CacheEntry -InputObject $cacheObj -path $Path -destination $Destination
928 Write-Verbose ($LocalizedData.PackageInstalled -f $Path,$Destination)
929 Write-Verbose $LocalizedData.ConfigurationFinished
935 $ErrorActionPreference = "SilentlyContinue"
936 Trace-Message ($LocalizedData.RemovePSDriveonRootdriveRoot -f ($($psdrive.Root)))
937 Remove-PSDrive $psdrive -Force -ErrorAction SilentlyContinue
942 # The Get-TargetResource cmdlet is used to fetch the object
943 function Get-TargetResource
947 [parameter(Mandatory = $true)]
948 [ValidateNotNullOrEmpty()]
951 [parameter(Mandatory = $true)]
952 [ValidateNotNullOrEmpty()]
953 [string] $Destination,
955 [boolean] $Validate = $false,
957 [ValidateSet("", "SHA-1", "SHA-256", "SHA-512", "CreatedDate", "ModifiedDate")]
960 [pscredential] $Credential
963 if ($null -eq $Credential)
965 $PSBoundParameters.Remove("Credential")
968 $exists = Test-TargetResource @PSBoundParameters
970 $stringResult = "Absent"
973 $stringResult = "Present"
977 Ensure = $stringResult;
979 Destination = $Destination;
983 Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource