PSDependScripts/FileSystem.ps1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
<# .SYNOPSIS EXPERIMENTAL: Use Robocopy or Copy-Item for folder and file dependencies, respectively. .DESCRIPTION EXPERIMENTAL: Use Robocopy or Copy-Item for folder and file dependencies, respectively. Runs in the current session (i.e. as the current user) Relevant Dependency metadata: DependencyName (Key): The key for this dependency is used as the URL. This can be overridden by 'Source' Name: Optional file name for the downloaded file. Defaults to parsing filename from the URL Target: The folder to copy the source to. If the source is a file, we adjust this in Robocopy to append the source folder name. Source: The source folder or file to copy .PARAMETER Dependency Dependency to run .PARAMETER PSDependAction Test, Install, or Import the module. Defaults to Install Test: Return true or false on whether the dependency is in place IMPORTANT: If a folder exists, return $True, whether the contents are the same or not If a file exists, we check the hash Install: Install the dependency Import: Import the dependency 'Target'. Override with ImportPath .PARAMETER ImportPath If specified with PSDependAction Import, we import this path, instead of the target (or target parent if target is a file) .PARAMETER Force If specified, and target is a folder, overwrite the target .PARAMETER Mirror If specified and the target is a folder, we effectively call robocopy /MIR (Can remove folders/files...) .EXAMPLE @{ 'notepad' = @{ DependencyType = 'FileSystem' Source = 'C:\windows\notepad.exe' Target = 'C:\PSDependPesterTest' } } # Copy C:\Windows\Notepad.exe to C:\PSDependPesterTest\notepad.exe .EXAMPLE @{ 'psams' = @{ DependencyType = 'FileSystem' Source = '\\FileServer\powershell\modules\psams' Target = 'C:\ProjectX' } } # Copy psams module to C:\ProjectX\psams #> [cmdletbinding()] param ( [PSTypeName('PSDepend.Dependency')] [psobject[]] $Dependency, [ValidateSet('Test', 'Install', 'Import')] [string[]]$PSDependAction = @('Install'), [string]$ImportPath ) # Extract data from Dependency $DependencyName = $Dependency.DependencyName $Name = $Dependency.Name $Target = $Dependency.Target $Sources = @($Dependency.Source) $TestOutput = @() foreach($Source in @($Sources)) { if(-not (Test-Path $Source)) { if(-not $PSDependAction -like 'Test') { Write-Error "Skipping $DependencyName, could not find source [$Sources] due to error:" } continue } $IsContainer = ( Get-Item $Source ).PSIsContainer # Resolve PSDrives. $Target = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Target) $Source = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Source) if($IsContainer) { $Folder = Split-Path $Source -Leaf $Target = Join-Path $Target $Folder if(-not $ImportPath) {$ImportPath = $Target} # We don't test equality for containers yet if(Test-Path $Target) { $TestOutput += $true } else { $TestOutput += $false } if($PSDependAction -like 'Install') { # TODO: Add non Windows equivalent... [string[]]$Arguments = "/XO" $Arguments += "/E" if($Dependency.Parameters.Mirror -eq $True -or $Mirror) { $Arguments += "/PURGE" } Write-Verbose "Invoking ROBOCOPY.exe $Source $Target $Arguments" ROBOCOPY.exe $Source $Target @Arguments } } else { $SourceFolderPath = Split-Path $Source -Parent $SourceFileName = Split-Path $Source -Leaf $TargetFile = Join-Path $Target $SourceFileName $SourceHash = ( Get-Hash $Source ).SHA256 $TargetHash = $null if(Test-Path $Target -PathType Leaf) { $TargetHash = ( Get-Hash $Target -ErrorAction SilentlyContinue -WarningAction SilentlyContinue ).SHA256 $TargetPath = $Target } elseif(Test-Path $TargetFile -PathType Leaf) { $TargetHash = ( Get-Hash $TargetFile -ErrorAction SilentlyContinue -WarningAction SilentlyContinue ).SHA256 $TargetPath = $TargetFile } Write-Verbose "Source [$Source] hash [$SourceHash]`n`tTarget [$TargetPath] hash [$TargetHash]" if($TargetHash -ne $SourceHash) { Write-Verbose "Hashes do not match" if($PSDependAction -like 'Install') { Write-Verbose "Copying file [$Source] to [$Target]" Copy-Item -Path $Source -Destination $Target -Force } if($PSDependAction -like 'Test' -and $PSDependAction.count -eq 1) { $TestOutput += $false } } else { Write-Verbose "Matching hash: [$Source] = [$TargetFile]" if($PSDependAction -like 'Test' -and $PSDependAction.count -eq 1) { $TestOutput += $True } } } } if($PSDependAction -like 'Test' -and $PSDependAction.count -eq 1) { if(@($TestOutput) -contains $false -or @($TestOutput) -notcontains $true) { return $false } else { return $True } } if($PSDependAction -like 'Import') { if(-not $ImportPath) { if(Test-Path $Target -PathType Leaf) { $ImportPath = Split-Path $Target -Parent } elseif(Test-Path $Target -PathType Container) { $ImportPath = $Target } else { Write-Error "Could not import target [$Target], path not found" return } } Import-PSDependModule $ImportPath } |