CPolydorou.PuTTY.psm1

#region Download-Putty
function Download-Putty
{
    #region Parameters
    [cmdletBinding()]

    Param
    (
        [Parameter()]
        $Path
    )
    #endregion

    #region Destination Path
    # Set the path to download the file to
    if($Path)
    {
        if( (Test-Path -Path $Path) -ne $true)
        {
            Write-Error "Could not find directory $Path"
            return
        }
        else
        {
            $filePath = $Path + '\' + 'putty.exe'
        }
    }
    else
    {
        $filePath = (Get-Location).Path + '\' + 'putty.exe'
    }
    #endregion

    #region Download
    Write-Verbose "Downloading PuTTY.exe."
    try
    {
        Invoke-WebRequest -Uri 'http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe' -OutFile $filePath -ErrorAction Stop
        Write-Verbose "PuTTY.exe has been successfully downloaded to $filePath"
    }
    catch
    {
        Write-Error "Failed to download the file. $($_.Exception.Message)"
    }
    #endregion
}
#endregion

#region Download-PuttyGen
function Download-PuttyGen
{
    #region Parameters
    [cmdletBinding()]

    Param
    (
        [Parameter()]
        $Path
    )
    #endregion

    #region Destination Path
    # Set the path to download the file to
    if($Path)
    {
        if( (Test-Path -Path $Path) -ne $true)
        {
            Write-Error "Could not find directory $Path"
            return
        }
        else
        {
            $filePath = $Path + '\' + 'puttygen.exe'
        }
    }
    else
    {
        $filePath = (Get-Location).Path + '\' + 'puttygen.exe'
    }
    #endregion

    #region Download
    Write-Verbose "Downloading PuTTYGen.exe."
    try
    {
        Invoke-WebRequest -Uri 'http://the.earth.li/~sgtatham/putty/latest/x86/puttygen.exe' -OutFile $filePath -ErrorAction Stop
        Write-Verbose "PuTTYGen.exe has been successfully downloaded to $filePath"
    }
    catch
    {
        Write-Error "Failed to download the file. $($_.Exception.Message)"
    }
    #endregion
}
#endregion

#region Get-PuttySesssion
Function Get-PuttySession
{
    #region Parameters
    [cmdletBinding()]

    Param
    (
        [Parameter()]
        [string]
        $Name
    )
    #endregion

    # Set the registry base path
    $registryPath = "HKCU:\SOFTWARE\SimonTatham\PuTTY\Sessions\"

    # Get the session keys
    Write-Verbose "Getting sessions from registry."
    try
    {
        $sessions = Get-ChildItem $registryPath -ErrorAction Stop
    }
    catch
    {
        Write-Error "Failed to read the registry. $($_.Exception.Message)"
    }

    # Process each session
    Write-Verbose "Getting session details."
    foreach( $s in $sessions)
    {
        # Get the properties of the sessions
        $hostname = Get-ItemProperty -Path ("HKCU:\Software\SimonTatham\PuTTY\Sessions\" + $s.PSChildName) -Name Hostname
        $obj = New-Object PSObject
        $obj | Add-Member -MemberType NoteProperty -Name "Name" -Value $s.PSChildName
        $obj | Add-Member -MemberType NoteProperty -Name "Hostname" -Value $hostname.hostname

        # Check if a specific session was requested
        if($Name)
        {
            if($Name -eq $obj.Name)
            {
                $obj
            }
        }
        else
        {
            $obj
        }
    }
}
#endregion

#region Export-PuttySession
Function Export-PuttySession
{
    #region Parameters
    [CmdletBinding()]

    Param
    (
        [Parameter(Mandatory = $false,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true)]
        
        [string]
        $Name,

        [Parameter(Mandatory = $false)]
        [string]
        $Path = (Get-Location).Path
    )
    #endregion

    #region Begin
    Begin
    {
        # Test if path exists
        $sessionsDirectory = $Path + '\'
        if((Test-Path($sessionsDirectory)) -eq $false)
        {
            Write-Error "Target directory does not exist."
            return
        }

        # Get sessions from registry
        $registryPath = "HKCU:\SOFTWARE\SimonTatham\PuTTY\Sessions\"
        try
        {
            $sessions = Get-ChildItem $registryPath -ErrorAction Stop
        }
        catch
        {
            Throw "Failed to read the registry. $($_.Exception.Message)"
            
        }
    }
    #endregion

    #region Process
    Process
    {
        # Export sessions
        foreach( $s in $sessions)
        {
            # If a specific session is to be exported, skip the others
            if($Name)
            {
                if($s.PSChildName -ne $Name)
                {
                    continue
                }
            }

            # Create a directory for the session
            Write-Verbose "Creating a directory for the session files."
            if( (Test-Path -Path ($sessionsDirectory + $s.PSChildName)) -ne $true)
            {
                try
                {
                    New-Item -ItemType Directory -Path $sessionsDirectory -Name $s.PSChildName -ErrorAction Stop | Out-Null
                }
                catch
                {
                    Write-Error "Failed to create directory to save the session. $($_.Exception.Message)"
                    return
                }
            }

            # Export the session options
            Write-Verbose "Exporting the session."

            # Create the process start information
            $pinfo = New-Object System.Diagnostics.ProcessStartInfo
            $pinfo.FileName = $env:SystemRoot + "\System32\reg.exe"
            $pinfo.CreateNoWindow = $true
            $pinfo.UseShellExecute = $false
            $pinfo.WorkingDirectory = (Get-Location).Path
            $pinfo.Arguments = @("export", $s.Name, ($sessionsDirectory + $s.PSChildName + '\' + $s.PSChildName + ".reg"))
            
            # Create the process
            $p = New-Object System.Diagnostics.Process
            $p.StartInfo = $pinfo
            $p.Start() | Out-Null
            $p.WaitForExit()

            # Copy the private key
            $key = Get-ItemProperty -Path ("HKCU:\Software\SimonTatham\PuTTY\Sessions\" + $s.PSChildName) -Name PublicKeyFile
            if( $key.PublicKeyFile.Length -gt 0 )
            {
                Write-Verbose "Exporting the private key."
                try
                {
                    # Get the name of the file
                    $keyFileName = $key.PublicKeyFile.Substring($key.PublicKeyFile.LastIndexOf('\') + 1)

                    # Copy the file
                    Copy-Item -Path $key.PublicKeyFile -Destination ((resolve-path($sessionsDirectory)).Path + '\' + $s.PSChildName + '\' + $keyFileName) -ErrorAction Stop
                }
                catch
                {
                    Write-Error "Failed to copy the private key file. $($_.Exception.Message)"
                    continue
                }
            }
        }
    }
    #endregion

    #region End
    End{}
    #endregion
}
#endregion

#region Import-PuttySession
Function Import-PuttySession
{
    #region Parameters
    [CmdletBinding()]
    
    Param
    (
        [Parameter(Mandatory = $true)]
        [string]
        $Path,

        [Parameter(Mandatory = $false)]
        [string]
        $KeyFileDirectory
    )
    #endregion

    #region Begin
    Begin {}
    #endregion

    #region Process
    Process
    {
        # Test if path exists
        $sessionsDirectory = $Path
        if((Test-Path($sessionsDirectory)) -eq $false)
        {
            Write-Error "Source directory does not exist."
            return
        }

        # Find the reg file
        $sessionFile = @(Get-ChildItem -Path $sessionsDirectory | Where-Object {$_.Name.ToLower().EndsWith(".reg")})
        if($sessionFile.Count -ne 1)
        {
            Write-Error "No/Multiple session files found."
            return
        }

        # Find the key file
        $keyFile = @(Get-ChildItem -Path $sessionsDirectory | Where-Object {$_.Name.ToLower().EndsWith(".ppk")})

        # Set the session name
        $sessionName = $sessionFile.BaseName

        # Create the registry keys
        CreateRegistryKeys -SessionName $sessionName

        # Import the session
        Write-Verbose "Importing session $sessionName from file $($sessionFile.Fullname)."

        # Create the process start information
        $pinfo = New-Object System.Diagnostics.ProcessStartInfo
        $pinfo.FileName = $env:SystemRoot + "\System32\reg.exe"
        $pinfo.CreateNoWindow = $true
        $pinfo.UseShellExecute = $false
        $pinfo.WorkingDirectory = (Get-Location).Path
        $pinfo.Arguments = @("import", ('"' + $sessionFile.FullName +'"'))
        $pinfo.RedirectStandardError = $true
        $pinfo.RedirectStandardOutput = $true
            
        # Create the process
        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $pinfo
        $p.Start() | Out-Null
        $p.WaitForExit()

        # Write the output from the import
        $stdOut = $p.StandardOutput.ReadToEnd()
        if( -not ([System.String]::IsNullOrEmpty($stdOut)))
        {
            Write-Verbose $stdOut
        }

        $stdErr = $p.StandardError.ReadToEnd()
        if($p.ExitCode -ne 0)
        {
            Write-Error $stdErr
            return
        }


        # Copy the key file
            $key = Get-ItemProperty -Path ("HKCU:\Software\SimonTatham\PuTTY\Sessions\" + $sessionName) -Name PublicKeyFile -ErrorAction Stop
            if( $key.PublicKeyFile.Length -gt 0 )
            {
                # Check if a directory has been provided for the key file
                if($KeyFileDirectory)
                {
                    if( (Test-Path -Path $KeyFileDirectory) -ne $true)
                    {
                        Write-Error "Failed to access the directory for the key file."
                    }
                    else
                    {
                        $targetKeyFileDirectory = $KeyFileDirectory
                    }
                }
                else
                {
                    Write-Verbose "A directory to store the session key has not been provided, using profile directory."

                    # Check if a directory exists for the key files
                    if( (Test-Path -Path ($home+ '\PuTTYSessionKeys')) -ne $true)
                    {
                        try
                        {
                            New-Item -ItemType Directory -Path $home -Name "PuTTYSessionKeys" -Force -ErrorAction Stop | Out-Null
                            $targetKeyFileDirectory = $home +'\' + "PuTTYSessionKeys\"
                        }
                        catch
                        {
                            Write-Error "Failed to create directory to save the key file."
                            return
                        }
                    }
                    else
                    {
                        $targetKeyFileDirectory = $home + "\PuTTYSessionKeys"
                    }
                }

                # Create a subdirectory for the session
                try
                {
                    Write-Verbose "Creating a directory for the key."
                    New-Item -ItemType Directory -Path $targetKeyFileDirectory -Name $sessionName -Force -ErrorAction Stop | Out-Null
                    $subDirectory = $targetKeyFileDirectory + '\' + $sessionName
                }
                catch
                {
                    Write-Error "Failed to create a directory for the session key. $($_.Exception.Message)"
                    return
                }

                # Copy the key file
                try
                {
                    Write-Verbose "Copying key file."
                    Copy-Item -Path $keyFile.FullName -Destination $subDirectory -Force -ErrorAction Stop
                }
                catch
                {
                    Write-Error "Failed to copy key file to $($key.PublicKeyFile). $_.Exception.Message"
                    return
                }

                # Update the session with the new key
                try
                {
                    Write-Verbose "Updating session with new key file path."
                    Set-ItemProperty -Path ("HKCU:\Software\SimonTatham\PuTTY\Sessions\" + $sessionName) -Name PublicKeyFile -Value ($subDirectory + '\' + $keyFile.Name) -ErrorAction Stop
                }
                catch
                {
                    Write-Error "Failed to update the session with the new key file path."
                    return
                }

                Write-Verbose "The sesssion was successfully imported."
            }
        #>
    }
    #endregion

    #region End
    End {}
    #endregion
}
#endregion

#region Remove-PuttySession
Function Remove-PuttySession
{
    #region Parameters
    [cmdletBinding(SupportsShouldProcess=$true,
                   ConfirmImpact = 'Medium')]

    Param
    ( 
        [Parameter(Mandatory = $true, 
                   ValueFromPipeline = $true, 
                   ValueFromPipelineByPropertyName = $true)]
        [String[]]
        $Name
    ) 
    #endregion

    #region Begin
    Begin{}
    #endregion

    Process
    {
        # Process each session name
        foreach( $n in $Name)
        {
            # Check if a session exists
            Write-Verbose "Checking if a session named $n exists."
            if( Test-Path ("HKCU:\SOFTWARE\SimonTatham\PuTTY\Sessions\" + $n))
            {
                if ($pscmdlet.ShouldProcess($n, "Remove-PuTTYSession"))
                {
                    # Remove the session
                    Write-Verbose "Removing session $n."
                    try
                    {
                        Remove-Item -Path ("HKCU:\SOFTWARE\SimonTatham\PuTTY\Sessions\" + $n) -Recurse -Force -ErrorAction Stop
                        Write-Verbose "The session $n has been removed."
                    }
                    catch
                    {
                        Write-Error "Failed to remove session $n. $($_.Exception.Message)"
                        continue
                    }
                }
            }
            else
            {
                Write-Warning "Could not find a session named $n."
            }
        }
    }

    #region End
    End {}
    #endregion
}
#endregion

#region Helper Functions
function CreateRegistryKeys
{
    param
    (
        [string]$SessionName
    )

    if(-not (Test-Path -Path 'HKCU:\Software\SimonTatham'))
    {
        New-Item 'HKCU:\Software\SimonTatham' |
            Out-Null
    }

    if(-not (Test-Path -Path 'HKCU:\Software\SimonTatham\PuTTY'))
    {
        New-Item 'HKCU:\Software\SimonTatham\PuTTY' |
            Out-Null
    }

    if(-not (Test-Path -Path 'HKCU:\Software\SimonTatham\PuTTY\Sessions'))
    {
        New-Item 'HKCU:\Software\SimonTatham\PuTTY\Sessions' |
            Out-Null
    }

    $sessionPath = 'HKCU:\Software\SimonTatham\PuTTY\Sessions\' + $SessionName

    if(-not (Test-Path -Path $sessionPath))
    {
        New-Item $sessionPath |
            Out-Null
    }
}
#endregion