Function/Update-ContainersWithDefinitionFile.Function.psm1

## Namespaces.
using namespace System.Text.Json;
using namespace System.Text.Json.Serialization;

## Update-Containers Function.
function Update-ContainersWithDefinitionFile
{
    <#
    .NAME
        Update-ContainersWithDefinitionFile

    .SYNOPSIS
        Docker and Podman Container Management Script.

    .SYNTAX
        .\Update-Containers.ps1 `
            [-DefinitionFile <String>] `
            [-DryRun] `
            [-NoStart] `
            [-Only <csv|json|String[]>] `
            [-PrintCommands] `
            [-PurgeImages] `
            [-Replacements <json|kvp-csv|HashTable>];

    .DESCRIPTION
        This script manages Docker and Podman containers based on a JSON definition file.

    .PARAMETERS
        -DefinitionFile
            Optional path to the JSON definition file, if not provided,
            the script searches for a default file in standard locations.

            Required? false
            Default $null

        -DryRun
            If specified, the script will output the commands it would execute without actually running them.

            Required? false
            Default $false

        -NoStart
            If specified, the script will not start the containers after creation.

            Required? false
            Default $false

        -Only
            Optional CSV string, JSON array or PowerShell array of container names to limit the operation to specific containers.

            Required? false
            Default @()

        -PrintCommands
            If specified, the script will print each command before executing it.

            Required? false
            Default $false

        -PurgeImages
            If specified, the script will remove all images before pulling new ones.

            Required? false
            Default $false

        -Replacements
            Optional JSON object, CSV of key=value pairs, or PowerShell hashtable of string replacements to apply to paths in the definition file.
            [NOTE: Replacement values here will override any replacement values in the definition file.]

            Required? false
            Default @{}

    .EXAMPLE
        .\Update-ContainersWithDefinitionFile.ps1 `
            [-DefinitionFile "C:\path\to\definition.json"] `
            [-DryRun] `
            [-NoStart] `
            [-Only @("container1", "container2")] `
            [-PrintCommands] `
            [-PurgeImages] `
            [-Replacements @{
                "VAR1" = "Value1";
                "VAR2" = "Value2";
            }];
    #>


    param (
        ## Definition File Parameter.
        [Parameter(Mandatory = $false, Position = 0)]
        [String] $DefinitionFile = $null,

        ## Dry-Run Parameter.
        [Parameter(Mandatory = $false)]
        [Switch] $DryRun = $false,

        ## NoStart Parameter.
        [Parameter(Mandatory = $false)]
        [Switch] $NoStart = $false,

        ## Only Parameter.
        [Parameter(Mandatory = $false)]
        [PSObject] $Only = @(),

        ## PrintCommands Parameter.
        [Parameter(Mandatory = $false)]
        [Switch] $PrintCommands = $false,

        ## Purge Images Parameter.
        [Parameter(Mandatory = $false)]
        [Switch] $PurgeImages = $false,

        ## Replacements Parameter.
        [Parameter(Mandatory = $false)]
        [PSObject] $Replacements = @{}
    );

    ## Localize the container definition file.
    [String] $containerDefinitionFile = (Get-ContainerDefinitionFilePath -File "${DefinitionFile}");

    ## Read the container definition file.
    [String] $containerDefinitionJson = (Get-Content -Path "$(Resolve-Path -Path "${containerDefinitionFile}")" -Raw);

    ## Deserialize our definition file.
    [UpdateContainersDefinition] $definition = [JsonSerializer]::Deserialize("${containerDefinitionJson}",
            [UpdateContainersDefinition], $(Get-ContainerDefinitionJsonSerializerOptions));

    ## Check the $Only parameter's type for a string.
    if ($Only -is [string])
    {
        ## Check for a JSON array.
        if ($Only -contains '[' -and $Only -contains ']')
        {
            ## Convert JSON array to PowerShell array.
            $Only = (JsonSerializer]::Deserialize($Only.Trim(), [String[]], (Get-ContainerDefinitionJsonSerializerOptions)));
        }

        ## We've got a CSV string.
        else
        {
            ## Split CSV string into PowerShell array.
            $Only = ($Only -split ',') -as [String[]];
        }
    }

    ## Check the $Replacements parameter's type for a string.
    if ($Replacements -is [string])
    {
        ## Check for a JSON object.
        if ($Replacements -contains '{' -and $Replacements -contains '}')
        {
            ## Convert JSON object to PowerShell hashtable.
            $Replacements = (JsonSerializer]::Deserialize($Replacements.Trim(), [Dictionary[String,String]],
                (Get-ContainerDefinitionJsonSerializerOptions))) -as [HashTable];
        }

        ## We've got a CSV of key=value pairs.
        else
        {
            ## Localize the replacements CSV string.
            [String] $csv = $Replacements.Trim();

            ## Reset the replacements to a hashtable.
            $Replacements = @{};

            ## Split the CSV into its pairs and iterate over them.
            foreach ($kvp in $csv -split ',')
            {
                ## Split each pair into its key and value.
                $key, $value = $kvp -split '=';

                ## Trim whitespace and add the key-value pair to the replacements hashtable.
                $Replacements[$key.Trim()] = $value.Trim();
            }
        }
    }

    ## Run the definition.
    $definition.Run($DryRun.ToBool(), $NoStart, $Only -as [String[]], $PrintCommands.ToBool(),
            $PurgeImages.ToBool(), $Replacements -as [HashTable]);
};