Containers.psm1

#region Functions
#region Get-DockerContainer
function Get-DockerContainer
{
    [CmdletBinding()]
    param (
        [Parameter()]
        [String]
        $Name,

        [Parameter()]
        [switch]
        $ShowAll
    )

    Begin
    {
        # Check if docker is installed and running
        try {
            Check-Docker
        }
        catch {
            throw "Could not find docker."
        }
    }

    Process
    {
        #region Get the running containers

        # Form the arguments
        $arguments = @("ps", "--format", '"{{json .}}"')

        if($ShowAll -or $Name)
        {
            $arguments += "--all"
        }

        $pinfo = New-Object System.Diagnostics.ProcessStartInfo
        $pinfo.FileName = "docker"
        $pinfo.RedirectStandardError = $true
        $pinfo.RedirectStandardOutput = $true
        $pinfo.CreateNoWindow = $true
        $pinfo.UseShellExecute = $false
        $pinfo.Arguments = $arguments
        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $pinfo
        $p.Start() | Out-Null

        [string]$stdout = "";
        [string]$stderr = "";
        while ( !$p.HasExited ) {
            $stdout += $p.StandardOutput.ReadToEnd();
            $stdout += $p.StandardError.ReadToEnd();
        }

        #Write-Verbose $stdout
        #endregion

        # Check if there were any errors
        if($p.ExitCode -ne 0)
        {
            Write-Error $stderr
            return
        }

        # Convert the output to objects
        $data = "[" + $stdout.Replace("}`n{", "}, {") + "]" | ConvertFrom-Json

        #region Filter out any unwanted containers
        if($Name)
        {
            foreach($d in $data)
            {
                if($Name -eq $d.Names)
                {
                    Write-Output $d
                }
            }
        }
        else
        {
            Write-Output $data    
        }
        #endregion
    }

    End {}
}
#endregion

#region New-DockerContainer
function New-DockerContainer
{
    [CmdletBinding()]
    param (
        [Parameter()]
        [String]
        $Name,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Image,

        [Parameter()]
        [String]
        $Command,

        [Parameter()]
        [Switch]
        $TTY,

        [Parameter()]
        [String]
        $MountVolumeName,

        [Parameter()]
        [String]
        $MountVolumePath
    )

    Begin
    {
        # Check if docker is installed and running
        try {
            Check-Docker
        }
        catch {
            throw "Could not find docker."
        }
    }

    Process
    {
        #region Create the container

        # Form the arguments
        $arguments = @("create")

        # Check if a TTY has to be attached
        if($TTY)
        {
            $arguments += "-t"
        }

        # Add any volumes
        if( (-not [string]::IsNullOrEmpty($MountVolumeName)) -and (-not [string]::IsNullOrEmpty($MountVolumePath)))
        {
            $arguments += @("--mount", "source=$MountVolumeName,target=$MountVolumePath")
        }


        # Check if a name has been specified
        if(-not [string]::IsNullOrEmpty($Name))
        {
            $arguments += "--name"
            $arguments += $Name
        }

        # Configure the image
        if(-not [string]::IsNullOrEmpty($Image))
        {
            $arguments += $Image
        }

        # Check if a command should be set
        if(-not [string]::IsNullOrEmpty($Command))
        {
            $arguments += $Command
        }

        # Display the command to be executed
        Write-Verbose ("Executing: " + ($arguments -join " "))

        # Run the command
        $pinfo = New-Object System.Diagnostics.ProcessStartInfo
        $pinfo.FileName = "docker"
        $pinfo.RedirectStandardError = $true
        $pinfo.RedirectStandardOutput = $true
        $pinfo.CreateNoWindow = $true
        $pinfo.UseShellExecute = $false
        $pinfo.Arguments = $arguments
        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $pinfo
        $p.Start() | Out-Null

        <#
        $p.WaitForExit()
        $stdout = $p.StandardOutput.ReadToEnd()
        $stderr = $p.StandardError.ReadToEnd()
        #>


        [string]$stdout = "";
        [string]$sterr = "";
        while ( !$p.HasExited ) {
            $stdout += $p.StandardOutput.ReadToEnd();
            $stderr += $p.StandardError.ReadToEnd();
        }        

        # Write command output as verbose
        Write-Verbose $stdout
        #endregion

        # Check if there were any errors
        if($p.ExitCode -ne 0)
        {
            Write-Error $stderr
            return
        }

        # Convert the output to objects
        #$data = "[" + $stdout.Replace("}`n{", "}, {") + "]" | ConvertFrom-Json
        Write-Output $data

        #region Filter out any unwanted containers
        if($Name)
        {
            foreach($d in $data)
            {
                if($Name -eq $d.Names)
                {
                    Write-Output $d
                }
            }
        }
        else
        {
            Write-Output $data    
        }
        #endregion
    }

    End {}
}
#endregion

#region Stop-DockerContainer
function Stop-DockerContainer
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias("Names")]
        [String]
        $Name
    )

    Begin
    {
        # Check if docker is installed and running
        try {
            Check-Docker
        }
        catch {
            throw "Could not find docker."
        }
    }

    Process
    {
        foreach($n in $name)
        {
            #region Stop the container

            # Form the arguments
            Write-Verbose "Stopping container $n"
            $arguments = @("stop", $n)
            Write-Verbose ("Executing: " + ($arguments -join " "))

            $pinfo = New-Object System.Diagnostics.ProcessStartInfo
            $pinfo.FileName = "docker"
            $pinfo.RedirectStandardError = $true
            $pinfo.RedirectStandardOutput = $true
            $pinfo.CreateNoWindow = $true
            $pinfo.UseShellExecute = $false
            $pinfo.Arguments = $arguments
            $p = New-Object System.Diagnostics.Process
            $p.StartInfo = $pinfo
            $p.Start() | Out-Null

            # Get the output
            [string]$stdout = "";
            [string]$stderr = "";
            while ( !$p.HasExited ) {
                $stdout += $p.StandardOutput.ReadToEnd();
                $stderr += $p.StandardError.ReadToEnd();
            }

            #Write-Verbose $stdout
            #endregion

            # Check if there were any errors
            if($p.ExitCode -ne 0)
            {
                Write-Error $stderr
                return
            }
            else
            {
                Write-Verbose "Container $n stopped."    
            }
        }
    }

    End {}
}
#endregion

#region Start-DockerContainer
function Start-DockerContainer
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias("Names")]
        [String]
        $Name
    )

    Begin
    {
        # Check if docker is installed and running
        try {
            Check-Docker
        }
        catch {
            throw "Could not find docker."
        }
    }

    Process
    {
        foreach($n in $Name)
        {
            #region Start the container

            # Form the arguments
            Write-Verbose "Starting container $n"
            $arguments = @("start", $n)

            Write-Verbose ("Executing: " + ($arguments -join " "))

            $pinfo = New-Object System.Diagnostics.ProcessStartInfo
            $pinfo.FileName = "docker"
            $pinfo.RedirectStandardError = $true
            $pinfo.RedirectStandardOutput = $true
            $pinfo.CreateNoWindow = $true
            $pinfo.UseShellExecute = $false
            $pinfo.Arguments = $arguments
            $p = New-Object System.Diagnostics.Process
            $p.StartInfo = $pinfo
            $p.Start() | Out-Null

            # Get the output
            [string]$stdout = "";
            [string]$stderr = "";
            while ( !$p.HasExited ) {
                $stdout += $p.StandardOutput.ReadToEnd();
                $stderr += $p.StandardError.ReadToEnd();
            }

            #Write-Verbose $stdout
            #endregion

            # Check if there were any errors
            if($p.ExitCode -ne 0)
            {
                Write-Error $stderr
                return
            }
            else
            {
                Write-Verbose "Container $n started."    
            }
        }
    }

    End {}
}
#endregion

#region Connect-DockerContainer
function Connect-DockerContainer
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias("Names")]
        [String]
        $Name
    )

    Begin
    {
        # Check if docker is installed and running
        try {
            Check-Docker
        }
        catch {
            throw "Could not find docker."
        }
    }

    Process
    {
        #Check if the container exists
        $container = Get-DockerContainer -Name $Name

        if($container -eq $null)
        {
            Write-Error "Could not find a container named $Name."
            return
        }

        # Set default shell to bash
        $shell = "bash"

        #region Start the process
        Start-Process -FilePath "docker.exe" -ArgumentList @("exec", "-it", $Name, $shell)
        #endregion
    }

    End {}
}
#endregion

#region Remove-DockerContainer
function Remove-DockerContainer
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias("Names")]
        [String]
        $Name,

        [Parameter()]
        [Switch]
        $Force
    )

    Begin
    {
        # Check if docker is installed and running
        try {
            Check-Docker
        }
        catch {
            throw "Could not find docker."
        }
    }

    Process
    {
        #Check if the container exists
        $container = Get-DockerContainer -Name $Name

        if($container -eq $null)
        {
            Write-Error "Could not find a container named $Name."
            return
        }

        # Create the arguments array
        $arguments = @("rm")

        # Check if force is selected
        if($Force)
        {
            $arguments += "-f"
        }

        # Add the name of the container to remove
        $arguments += $Name

        # Write the command to be executed
        Write-Verbose ("Executing: " + ($arguments -join " "))

        #region Start the process
        $pinfo = New-Object System.Diagnostics.ProcessStartInfo
        $pinfo.FileName = "docker"
        $pinfo.RedirectStandardError = $true
        $pinfo.RedirectStandardOutput = $true
        $pinfo.CreateNoWindow = $true
        $pinfo.UseShellExecute = $false
        $pinfo.Arguments = $arguments
        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $pinfo
        $p.Start() | Out-Null

        [string]$stdout = "";
        while ( !$p.HasExited ) {
            $stdout += $p.StandardOutput.ReadToEnd();
        }
        #endregion






    }

    End {}
}
#endregion

#region Helper Functions
function Check-Docker
{
    try {
        $pinfo = New-Object System.Diagnostics.ProcessStartInfo
        $pinfo.FileName = "docker.exe"
        $pinfo.RedirectStandardError = $true
        $pinfo.RedirectStandardOutput = $true
        $pinfo.CreateNoWindow = $true
        $pinfo.UseShellExecute = $false
        $pinfo.Arguments = @("--version")
        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $pinfo
        $p.Start() | Out-Null

        <#
        $p.WaitForExit()
        $stdout = $p.StandardOutput.ReadToEnd()
        $stderr = $p.StandardError.ReadToEnd()
        #>


        [string]$stdout = "";
        while ( !$p.HasExited ) {
            $stdout += $p.StandardOutput.ReadToEnd();
        }

        [string]$stderr = "";
        while ( !$p.HasExited ) {
            $stderr += $p.StandardError.ReadToEnd();
        }

    }
    catch {
        throw "Could not find docker."
    }
}
#endregion
#endregion

#region Exports
Export-ModuleMember -Function "Get-DockerContainer"
Export-ModuleMember -Function "New-DockerContainer"
Export-ModuleMember -Function "Stop-DockerContainer"
Export-ModuleMember -Function "Start-DockerContainer"
Export-ModuleMember -Function "Connect-DockerContainer"
Export-ModuleMember -Function "Remove-DockerContainer"
#endregion