GhCloudOps.psm1
<# .SYNOPSIS Converts tokenized bicepparam, HCL, json or psd1 files to expanded files using a token map. .DESCRIPTION Converts tokenized bicepparam, HCL, json or psd1 files to expanded files using a token map. The token map is a hashtable where the key is the token and the value is the replacement value. The token is in the format '{{ token }}'. The function reads the input file line by line and replaces the tokens with the corresponding values. The expanded content is written to the output file. The function also checks for unmatched tokens and unused tokens. .PARAMETER InputFile The path to the input file. .PARAMETER OutputFile The path to the output file. .PARAMETER TokenMap The hashtable containing the token map. .EXAMPLE $tokenParams = @{ InputFile = 'C:\input.txt' OutputFile = 'C:\output.txt' TokenMap = @{ string = 'string' int = 1 bool = $true null = $null } } Convert-Token @tokenParams Converts the input file 'C:\input.txt' to the output file 'C:\output.txt' using the token map. The token map is a hashtable where '{{ string }}' is replaced with 'string', '{{ int }}' is replaced with 1, '{{ bool }}' is replaced with true, '{{ null }}' is replaced with null. #> function Convert-Token { [CmdletBinding()] param ( [Parameter(Mandatory)] [ValidateScript({ Test-Path -Path $_ })] [string] $InputFile, [Parameter(Mandatory)] [string] $OutputFile, [Parameter(Mandatory)] [ValidateScript({ $_.Count -gt 0 })] [hashtable] $TokenMap ) $item = Get-Item -LiteralPath $InputFile if (($item.Extension -eq '.bicepparam') -or ($item.Extension -eq '.psd1')) { $quotedString = "'{0}'" } elseif (($item.Extension -eq '.json') -or ($item.Extension -eq '.tfvars')) { $quotedString = '"{0}"' } else { throw 'Unsupported file type: {0}' -f $item.Extension } $content = Get-Content -Path $InputFile $temporaryFile = New-TemporaryFile $usedTokens = New-Object -TypeName System.Collections.ArrayList foreach ($line in $content) { foreach ($key in $TokenMap.Keys) { $token = "{{ $key }}" if ($line -match $token) { $value = $TokenMap[$key] if ($null -eq $value) { if ($item.Extension -eq '.psd1') { $line = $line.Replace(($quotedString -f $token), '$null') } else { $line = $line.Replace(($quotedString -f $token), ('null'.Replace("'", ''))) } } elseif ($value.GetType() -eq [string]) { $line = $line.Replace($token, $value) } elseif ($value.GetType() -eq [int]) { $line = $line.Replace(($quotedString -f $token), $value) } elseif ($value.GetType() -eq [bool]) { if ($item.Extension -eq '.psd1') { $line = $line.Replace(($quotedString -f $token), ('$' + $value.ToString().ToLower())) } else { $line = $line.Replace(($quotedString -f $token), $value.ToString().ToLower()) } } $null = $usedTokens.Add($key) } } Out-File -InputObject $line -FilePath $temporaryFile -Append } $pattern = '\{\{[^\}]+\}\}' $unmatchedTokens = Select-String -Path $temporaryFile -Pattern $pattern -AllMatches if ($unmatchedTokens) { Write-Error -Message 'Unmatched tokens found' -ErrorAction 'Continue' throw $unmatchedTokens } $unusedTokens = New-Object -TypeName System.Collections.ArrayList foreach ($key in $TokenMap.Keys) { if (-not $usedTokens.Contains($key)) { $null = $unusedTokens.Add($key) } } if ($unusedTokens.Count -gt 0) { Write-Warning -Message ('Unused tokens: {0}' -f ($unusedTokens -join ', ')) } if (Test-Path -Path $OutputFile) { Clear-Content -Path $OutputFile } else { $null = New-Item -Path $OutputFile -ItemType File } Set-Content -Path $OutputFile -Value (Get-Content -Path $temporaryFile) Write-Host -Object ("Converted tokens in '{0}' to '{1}'" -f $InputFile, $OutputFile) } <# .SYNOPSIS Get the version from the latest tag or the tag specified in the parameter. .DESCRIPTION Get the version from the latest tag or the tag specified in the parameter. .PARAMETER Ref The tag reference to get the version from. .PARAMETER DefaultVersion The default version to return if no tag is found. Default is 'v1.0.0-beta'. .EXAMPLE Get-Version.ps1 -Ref refs/tags/v1.0.0 Returns 'v1.0.0'. .EXAMPLE Get-Version.ps1 -Ref refs/heads/main Returns 'v1.0.1', if it's the latest git tag. .EXAMPLE Get-Version.ps1 -Ref refs/heads/main -DefaultVersion 'v0.0.1' Returns 'v0.0.1', if no tags are found. #> function Get-TagVersion { [OutputType([string])] param ( [Parameter(Mandatory)] [string] $Ref, [Parameter()] [string] $DefaultVersion = 'v1.0.0-beta' ) $latestTagCommitHash = & git rev-list --tags --max-count=1 if ($null -ne $latestTagCommitHash) { Write-Host -Object ("The latest tag commit hash is '{0}'." -f $latestTagCommitHash) $latestTagVersion = & git describe --tags $latestTagCommitHash Write-Host -Object ("The latest tag is '{0}'." -f $latestTagVersion) } if ($Ref -like 'refs/tags/v*.*.*') { $tag = $Ref.Split('/')[-1] $version = $tag Write-Host -Object ("Version '{0}' is being set by ref '{1}'." -f $version, $Ref) } elseif ($Ref -like 'refs/tags/*') { throw "The tag '{0}' is not a version tag. Please, use a version tag in the format 'v*.*.*'." -f $Ref } elseif ($null -ne $latestTagVersion) { $version = $latestTagVersion Write-Host -Object ("Version '{0}' is being set by the latest tag." -f $version , $latestTagVersion) } else { $version = $DefaultVersion Write-Host -Object ("Version '{0}' is being set by the default value." -f $version, $DefaultVersion) } return $version } <# .SYNOPSIS Generates a random secure string. .DESCRIPTION Generates a random secure string of a given length. .PARAMETER Length The length of the random string to be generated. .EXAMPLE New-RandomSecret -Length 16 Creates a random secure string that's 16 characters long. #> function New-RandomSecret { [Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] [OutputType([System.Security.SecureString])] [CmdletBinding()] param ( [Parameter(Mandatory)] [int] $Length ) $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-+=<>?[]{}|;:,.`~' $secretValueParams = @{ String = -join (1..$Length | ForEach-Object { $chars[(Get-Random -Minimum 0 -Maximum $chars.Length)] }) AsPlainText = $true Force = $true } $secretValue = ConvertTo-SecureString @secretValueParams return $secretValue } <# .SYNOPSIS Sets a GitHub Actions environment variable. .DESCRIPTION Sets a GitHub Actions environment variable by appending the variable to the GITHUB_ENV file. The function takes the name and value of the variable as parameters and writes them to the file in the format 'NAME=VALUE'. .PARAMETER Name The name of the environment variable. .PARAMETER Value The value of the environment variable. .PARAMETER IsOutput Indicates whether the variable should be set in the GITHUB_OUTPUT file instead of the GITHUB_ENV file. .PARAMETER IsSecret Indicates whether the variable should be treated as a secret. .EXAMPLE Set-GhVariable -Name 'MY_VAR' -Value 'my_value' Sets the environment variable 'MY_VAR' to 'my_value' in the GITHUB_ENV file. .EXAMPLE Set-GhVariable -Name 'MY_SECRET_VAR' -Value 'my_secret_value' -IsSecret Sets the secret environment variable. The value is masked in the log output. .EXAMPLE Set-GhVariable -Name 'MY_OUTPUT_VAR' -Value 'output_value' -IsOutput Sets the output variable 'MY_OUTPUT_VAR' to 'output_value' in the GITHUB_OUTPUT file. .NOTES For security reasons, secret variables cannot be accessed from outside of the job that defines them. #> function Set-GhVariable { [Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Name, [Parameter(Mandatory)] [string] $Value, [Parameter()] [switch] $IsOutput, [Parameter()] [switch] $IsSecret ) if ($IsSecret) { Write-Host -Object ('::add-mask::{0}' -f $Value) } $setVariableParams = @{ InputObject = '{0}={1}' -f $Name, $Value FilePath = $IsOutput ? $env:GITHUB_OUTPUT : $env:GITHUB_ENV Append = $true } Out-File @setVariableParams } |