VaporShell.Attributes.ps1
using namespace System using namespace System.Collections using namespace System.Collections.Generic using namespace System.IO using namespace System.Management.Automation [CmdletBinding()] Param() Write-Verbose "Importing class 'VSError'" class VSError : ErrorRecord { hidden static [VSError] InsertError([VSError] $vsErrorRecord) { if ($null -eq $global:VSError) { $global:VSError = [List[VSError]]::new() } $global:VSError.Insert(0, $vsErrorRecord) return $vsErrorRecord } static [VSError] InvalidType([object] $inputObject, [type[]] $validTypes) { $record = [VSError]::new( [ArgumentException]::new("$($inputObject.GetType().FullName) is an invalid type for this property. Valid types include: $(($validTypes.FullName | Sort-Object -Unique) -join ', ')"), 'InvalidType', [ErrorCategory]::InvalidArgument, $inputObject ) return [VSError]::InsertError($record) } static [VSError] InvalidMap([object] $inputObject, [object] $key, [object] $value) { $record = [VSError]::new( [ArgumentException]::new("The values of the Map property must be IDictionarys themselves. Map key '$($key)' has a value of type '$($value.GetType())' assigned to it."), 'InvalidMap', [ErrorCategory]::InvalidArgument, $inputObject ) return [VSError]::InsertError($record) } static [VSError] InvalidLogicalId([string] $inputObject) { $record = [VSError]::new( [ArgumentException]::new("The LogicalId must be alphanumeric (a-z, A-Z, 0-9) and unique within the template. Value provided: '$inputObject'"), 'InvalidLogicalId', [ErrorCategory]::InvalidArgument, $inputObject ) return [VSError]::InsertError($record) } static [VSError] InvalidArgument([object] $inputObject, [string] $message) { $record = [VSError]::new( [ArgumentException]::new($message), 'InvalidArgument', [ErrorCategory]::InvalidArgument, $inputObject ) return [VSError]::InsertError($record) } static [VSError] MissingLogicalId([object] $inputObject, [string] $section) { $record = [VSError]::new( [ArgumentException]::new("This $($inputObject.GetType()) is missing a LogicalId! Unable to add to $section"), 'MissingLogicalId', [ErrorCategory]::InvalidArgument, $inputObject ) return [VSError]::InsertError($record) } static [VSError] DuplicateLogicalId([object] $inputObject, [string] $section) { $record = [VSError]::new( [ArgumentException]::new("The Template already contains a $section with a LogicalId of '$($inputObject.LogicalId)'. LogicalIds must be unique within the Template."), 'DuplicateLogicalId', [ErrorCategory]::InvalidArgument, $inputObject ) return [VSError]::InsertError($record) } static [VSError] InvalidJsonInput([string] $jsonStringOrFilePath) { $record = [VSError]::new( [ArgumentException]::new("Unable to convert input data from JSON to PSObject! Please use a JSON string OR provide a valid path to a JSON file!"), 'InvalidJsonInput', [ErrorCategory]::InvalidArgument, $jsonStringOrFilePath ) return [VSError]::InsertError($record) } static [VSError] InvalidYamlInput([string] $yamlStringOrFilePath) { $record = [VSError]::new( [ArgumentException]::new("Unable to convert input data from YAML to PSObject! Please use a YAML string OR provide a valid path to a YAML file!"), 'InvalidYamlInput', [ErrorCategory]::InvalidArgument, $yamlStringOrFilePath ) return [VSError]::InsertError($record) } VSError() {} VSError([ErrorRecord] $errorRecord) { foreach ($prop in $errorRecord.PSObject.Properties.Name) { if ($null -ne $errorRecord.$prop) { $this.$prop = $errorRecord.$prop } } } VSError([Exception] $exception, [string] $errorId, [ErrorCategory] $errorCategory, [object] $targetObject) : base($exception, $errorId, $errorCategory, $targetObject) {} } Write-Verbose "Importing class 'TransformDeletionPolicy'" class TransformDeletionPolicy : ArgumentTransformationAttribute { hidden [EngineIntrinsics] $engineIntrinsics hidden [object] TransformData([object] $inputData) { if ($inputData.ToString() -in @('Delete','Retain','Snapshot')) { return (Get-Culture).TextInfo.ToTitleCase(($inputData.ToString()).ToLower()) } return $inputData } [object] Transform([EngineIntrinsics] $engineIntrinsics, [object] $inputData) { $this.engineIntrinsics = $engineIntrinsics return $this.TransformData($inputData) } } Write-Verbose "Importing class 'TransformTag'" class TransformTag : ArgumentTransformationAttribute { hidden [EngineIntrinsics] $engineIntrinsics hidden [hashtable] ConvertToTag([object] $key, [object] $value) { $tag = @{ Key = $key.ToString() Value = $value } return $tag } hidden [IEnumerable[IDictionary]] TransformHashtable([IDictionary] $inputData) { $final = [List[IDictionary]]::new() if (($inputData['key'] -or $inputData.Key) -and ($inputData['value'] -or $inputData.Value)) { $final.Add($inputData) } else { $inputData.GetEnumerator() | ForEach-Object { $final.Add(@{ Key = $_.Key Value = $_.Value }) } } return $final } hidden [IEnumerable[IDictionary]] TransformPSObject([PSObject] $inputData) { $final = [List[IDictionary]]::new() if ($inputData.Properties.Name -contains "Key" -and $inputData.Properties.Name -contains "Value") { $final.Add(@{ Key = $inputData.Key Value = $inputData.Value }) } else { foreach ($property in $inputData.Properties) { $final.Add(@{ Key = $_.Name Value = $_.Value }) } } return $final } hidden [IEnumerable[IDictionary]] TransformSingle([object] $inputData) { $final = [List[IDictionary]]::new() if ($inputData -is [IDictionary]) { foreach ($tag in $this.TransformHashtable($inputData -as [IDictionary])) { $final.Add($tag) } } elseif ($inputData -is [PSObject]) { foreach ($tag in $this.TransformPSObject($inputData)) { $final.Add($tag) } } return $final } hidden [IEnumerable[IDictionary]] TransformData([object] $inputData) { $final = [List[IDictionary]]::new() if ($inputData -is [Array]) { foreach ($item in ($inputData -as [Array])) { foreach ($tag in $this.TransformSingle($item)) { $final.Add($tag) } } } else { foreach ($tag in $this.TransformSingle($inputData)) { $final.Add($tag) } } return $final } [object] Transform([EngineIntrinsics] $engineIntrinsics, [object] $inputData) { $this.engineIntrinsics = $engineIntrinsics return $this.TransformData($inputData) } } Write-Verbose "Importing class 'TransformUserData'" class TransformUserData : ArgumentTransformationAttribute { hidden [EngineIntrinsics] $engineIntrinsics hidden [object] TransformData([object] $inputData) { Write-Debug "Transforming UserData" if ( $inputData.GetType().FullName -match ('^(UserData|Fn(Base64|Join)|Con(Ref|And|Equals|If|Not|Or))$') -or $inputData.GetType() -in @([IDictionary],[psobject]) ) { return $inputData } else { $list = if ($inputData -is [array]) { $inputData } else { @($inputData) } $final = @() $tag = $null foreach ($item in $list) { if ($item -is [string] -and (Test-Path $item)) { $obj = Get-Item $item $tag = switch -RegEx ($obj.Extension) { '^\.ps1$' { "powershell" } '^\.(bat|cmd)$' { "script" } default { $null } } [File]::ReadAllLines($obj.FullName) | ForEach-Object { $final += $_ } } else { $final += $item } } if ($null -ne $tag -and ($final -join [Environment]::NewLine) -notmatch "<$tag>") { $final.Insert(0,"<$($tag)>") | Out-Null $final += "</$($tag)>" } return @{ 'Fn::Base64' = @{ 'Fn::Join' = @( [Environment]::NewLine, @($final) ) } } } } [object] Transform([EngineIntrinsics] $engineIntrinsics, [object] $inputData) { $this.engineIntrinsics = $engineIntrinsics return $this.TransformData($inputData) } } Write-Verbose "Importing class 'ValidateLogicalId'" class ValidateLogicalId : ValidateArgumentsAttribute { hidden [EngineIntrinsics] $engineIntrinsics [Void] ValidateLogicalIdString( [object] $logicalId ) { if ($logicalId.ToString() -notmatch '^(\w+|AWS::CloudFormation::.*|Fn::Transform)$') { throw [VSError]::InvalidLogicalId($logicalId) } } [Void] Validate([object] $arguments, [EngineIntrinsics] $engineIntrinsics) { $this.engineIntrinsics = $engineIntrinsics $this.ValidateLogicalIdString($arguments) } } Write-Verbose "Importing class 'ValidateType'" class ValidateType : ValidateEnumeratedArgumentsAttribute { hidden [Type[]] $_validTypes ValidateType([Type] $validType) { $this._validTypes = @($validType) } ValidateType([Type[]] $validTypes) { $this._validTypes = $validTypes } [Void] ValidateElement( [Object]$element ) { if ($element.GetType().FullName -in $this._validTypes.FullName) { Write-Debug "[$element] Validated current Type as acceptable -- matched against type: $($element.GetType().FullName)" } elseif ($element.GetType().BaseType.FullName -in $this._validTypes.FullName) { Write-Debug "[$element] Validated BaseType as acceptable -- matched against type: $($element.GetType().BaseType.FullName)" } elseif ($validMatch = $this._validTypes | Where-Object {$element -is $_}) { Write-Debug "[$element] Validated MatchedType(s) as acceptable -- matched against type: $($validMatch.FullName)" } else { throw [VSError]::InvalidType($element, $this._validTypes) } } } |