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 Path Path to a specific yml Deployment file .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 Tags Only invoke deployments that are tagged with all of the specified Tags (-and, not -or) .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 } } } } } |