PSDeployScripts/FilesystemRemote.ps1
<#
.SYNOPSIS Uses PSRemoting and deploys with Robocopy or Copy-Item for folder and file deployments, respectively. .DESCRIPTION Uses PSRemoting and deploys with Robocopy or Copy-Item for folder and file deployments, respectively. Runs in the specified remoting endpoint. Keep in mind this uses kerberos by default. Some kerberos double hop workarounds: - Use a delegated endpoint - CredSSP authentication Deployment Options: If Mirror is 'True' and the source is a folder, we effectively call robocopy /MIR (Can remove folders/files...) .PARAMETER Deployment Deployment to run .PARAMETER Mirror If specified and the source is a folder, we effectively call robocopy /MIR (Can remove folders/files...) .PARAMETER ComputerName Computername passed to Invoke-Command for remote deployment .PARAMETER Deployment Deployment passed to Invoke-Command for remote deployment .PARAMETER Authentication Authentication passed to Invoke-Command for remote deployment .PARAMETER ConfigurationName ConfigurationName passed to Invoke-Command for remote deployment #> [cmdletbinding()] param ( [switch]$Mirror, [string]$ComputerName, [pscredential]$Credential, [System.Management.Automation.Runspaces.AuthenticationMechanism]$Authentication, [string]$ConfigurationName, [ValidateScript({ $_.PSObject.TypeNames[0] -eq 'PSDeploy.Deployment' })] [psobject[]]$Deployment ) Write-Verbose "Starting remote deployment on $ComputerName with $($Deployment.count) sources" [void]$PSBoundParameters.Remove('Deployment') Try { $SourceComputer = [System.Net.Dns]::GetHostEntry([string]$env:computername).HostName } Catch { Write-Error $_ Throw "Could not determine remote source for $($Map.Source), skipping" } # Set up module functions that need to be injected into the remote session. $FunctionsToInject = @( 'Get-Hash' ) $InjectedFunctions = @() foreach ($FunctionName in $FunctionsToInject) { $FunctionObject = Get-Command -Name $FunctionName -Module 'PSDeploy' -ErrorAction SilentlyContinue if ($FunctionObject) { $InjectedFunctions += "Function $FunctionName { $($FunctionObject.Definition) }" } else { Write-Warning -Message "Unable to prepare function $FunctionName for remote injection" } } #Remote deployment Invoke-Command @PSBoundParameters -ScriptBlock { # Inject required functions from local variable foreach ($FunctionDefinition in $Using:InjectedFunctions) { Invoke-Expression -Command $FunctionDefinition } foreach($Map in $Using:Deployment) { if($Map.SourceExists) { $RemoteSource = $null $RemoteSource = $Map.Source -replace '^(.):', "\\$Using:SourceComputer\`$1$" $Targets = $Map.Targets foreach($Target in $Targets) { if($Map.SourceType -eq 'Directory') { [string[]]$Arguments = "/XO" $Arguments += "/E" if($Map.DeploymentOptions.mirror -eq 'True' -or $Using:Mirror) { $Arguments += "/PURGE" } # Resolve PSDrives. $Target = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Target) Write-Verbose "Invoking ROBOCOPY.exe $RemoteSource $Target $Arguments" ROBOCOPY.exe $RemoteSource $Target @Arguments } else { $SourceHash = Get-Hash $RemoteSource $TargetHash = Get-Hash $Target -ErrorAction SilentlyContinue -WarningAction SilentlyContinue if($SourceHash -ne $TargetHash) { Write-Verbose "Deploying file '$RemoteSource' to '$Target'" Copy-Item -Path $RemoteSource -Destination $Target -Force } else { Write-Verbose "Skipping deployment with matching hash: '$RemoteSource' = '$Target')" } } } } } } |