Public/Invoke-PSDeployment.ps1
Function Invoke-PSDeployment { <# .SYNOPSIS Invoke a deployment .DESCRIPTION Invoke a deployment Takes output from Get-PSDeployment, or a deployment yml path. Runs deployment scripts depending on each deployment's type. If a deployment is not found, we continue processing other deployments. See Get-Help about_PSDeploy for more information. .PARAMETER Deployment Deployment object from Get-PSDeployment. .PARAMETER DeploymentFile Deployment file. We run Get-PSDeployment against it. .PARAMETER DeploymentParameters Hashtable of hashtables The first layer of keys are the deployment types These deployment types are assigned a hashtable of parameters So, pretend we have a FileSystemRemote deployement. Here's how we pass parameters: -DeploymentParameters @{ FilesystemRemote = @{ ComputerName = 'DeployFromThis' Credential = $CredentialForDeploy ConfigurationName = 'SomeSessionConfigToHit' } } In this case, any deployments of 'FilesystemRemote' type will use those parameters Why separate this out? What if I have a deployment that takes two sorts of parameters? What if I want to add a new deployment type without modifying this function? Okay, now what if we have two types, and want to fit it all on one line? - DeploymentParameters @{ FilesystemRemote=@{ComputerName = 'PC1'}; Filesystem=@{} } .PARAMETER PSDeployTypePath Specify a PSDeploy.yml file that maps DeploymentTypes to their scripts. This defaults to the PSDeploy.yml in the PSDeploy module folder .PARAMETER Force Force deployment, skipping prompts and confirmation .EXAMPLE Invoke-PSDeployment -Path C:\Git\Module1\Deployments.yml # Run deployments from a deployment yml. You will be prompted on whether to deploy .EXAMPLE Get-PSDeployment -Path C:\Git\Module1\Deployments.yml, C:\Git\Module2\Deployments.yml | Invoke-PSDeployment -Force # Get deployments from two yml files, invoke their deployment, no prompting .EXAMPLE Invoke-PSDeployment -Path C:\Git\Module1\Deployments.yml -PSDeployTypePath \\Path\To\Central\PSDeploy.yml # Run deployments from a deployment yml. Use deployment type definitions from a central config. .LINK about_PSDeploy .LINK https://github.com/RamblingCookieMonster/PSDeploy .LINK Get-PSDeployment .LINK Invoke-PSDeploy .LINK Get-PSDeploymentType .LINK Get-PSDeploymentScript #> [cmdletbinding( DefaultParameterSetName = 'Map', SupportsShouldProcess = $True, ConfirmImpact='High' )] Param( [parameter( ValueFromPipeline = $True, ParameterSetName='Map', Mandatory = $True)] [ValidateScript({ $_.PSObject.TypeNames[0] -eq 'PSDeploy.Deployment' })] [psobject]$Deployment, [validatescript({Test-Path -Path $_ -PathType Leaf -ErrorAction Stop})] [parameter( ParameterSetName='File', Mandatory = $True)] [string[]]$Path, [Hashtable]$DeploymentParameters, [validatescript({Test-Path -Path $_ -PathType Leaf -ErrorAction Stop})] [string]$PSDeployTypePath = $(Join-Path $ModulePath PSDeploy.yml), [string[]]$Tags, [switch]$Force ) Begin { # This script reads a deployment YML, deploys files or folders as defined Write-Verbose "Running Invoke-PSDeployment with ParameterSetName '$($PSCmdlet.ParameterSetName)' and params: $($PSBoundParameters | Out-String)" if($PSBoundParameters.ContainsKey('Path')) { # Create a map for deployments Try { #Resolve relative paths... Thanks Oisin! http://stackoverflow.com/a/3040982/3067642 $Path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path) # Debating whether to make this a terminating error. # Stop all deployments because one is misconfigured? # I'm going with Copy-Item precedent. # Not terminating, so try catch is superfluous. Feel free to make this strict... $Deployment = Get-PSDeployment -Path $Path If($PSBoundParameters.ContainsKey('Tags')) { $Deployment = Get-TaggedDeployment -Deployment $Deployment -Tags $Tags } } Catch { Throw "Error retrieving deployments from '$Path':`n$_" } } } Process { Write-Verbose "Deployments:`n$($Deployment | Out-String)" if( ($Force -and -not $WhatIf) -or $PSCmdlet.ShouldProcess( "Processed the deployment '$($Deployment.DeploymentName -join ", ")'", "Process the deployment '$($Deployment.DeploymentName -join ", ")'?", "Processing deployment" )) { #Get definitions, and deployments in this particular yml $DeploymentDefs = Get-PSDeploymentScript $TheseDeploymentTypes = @( $Deployment.DeploymentType | Sort -Unique ) #Build up hash, we call each deploymenttype script for applicable deployments $ToDeploy = @{} foreach($DeploymentType in $TheseDeploymentTypes) { $DeploymentScript = $DeploymentDefs.$DeploymentType if(-not $DeploymentScript) { Write-Error "DeploymentType $DeploymentType is not defined in PSDeploy.yml" continue } $TheseDeployments = @( $Deployment | Where-Object {$_.DeploymentType -eq $DeploymentType}) #Define params for the script #Each deployment type can have a hashtable to splat. if($PSBoundParameters.ContainsKey('DeploymentParameters') -and $DeploymentParameters.ContainsKey($DeploymentType)) { $splat = $DeploymentParameters.$DeploymentType } else { $splat = @{} } $splat.add('Deployment', $TheseDeployments) # PITA, but tasks can run two ways, each different than typical deployment scripts if($DeploymentType -eq 'Task') { foreach($Deployment in $TheseDeployments) { if($Deployment.Source -is [scriptblock]) { . $Deployment.Source } elseif($Deployment.Source) { . $DeploymentScript @splat } } } else { #Run the associated script, splat the parameters . $DeploymentScript @splat } } } } } |