ProfileFever.psm1


<#
    .SYNOPSIS
    Import the profile configuration file.
#>

function Import-ProfileConfig
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $Path
    )

    $configs = Get-Content -Path $Path | ConvertFrom-Json

    # Update configurations
    if ($configs.Name -contains "$Env:ComputerName\$Env:Username")
    {
        $config = $configs.Where({$_.Name -eq "$Env:ComputerName\$Env:Username"})[0]
    }
    else
    {
        $config = $configs.Where({$_.Name -eq 'Default'})[0]
    }

    Write-Output $config
}


<#
    .SYNOPSIS
    Show the headline with information about the local system and current user.
#>

function Show-HostHeadline
{
    # Get Windows version from registry. Update the object for non Windows 10 or
    # Windows Server 2016 systems to match the same keys.
    $osVersion = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
    if ($null -eq $osVersion.ReleaseId)
    {
        $osVersion | Add-Member -MemberType NoteProperty -Name 'ReleaseId' -Value $osVersion.CurrentVersion
    }
    if ($null -eq $osVersion.UBR)
    {
        $osVersion | Add-Member -MemberType NoteProperty -Name 'UBR' -Value '0'
    }

    # Rename the ConsoleHost string to a nice understandable string
    $profileHost = $Host.Name.Replace('ConsoleHost', 'Windows PowerShell Console Host')

    # Get the PowerShell version depending on the edition
    if ($PSVersionTable.PSEdition -eq 'Core')
    {
        $psVersion = 'Version {0}' -f $PSVersionTable.PSVersion
    }
    else
    {
        $psVersion = 'Version {0}.{1} (Build {2}.{3})' -f $PSVersionTable.PSVersion.Major, $PSVersionTable.PSVersion.Minor, $PSVersionTable.PSVersion.Build, $PSVersionTable.PSVersion.Revision
    }

    $Host.UI.WriteLine(('{0}, Version {1} (Build {2}.{3})' -f $osVersion.ProductName, $osVersion.ReleaseId, $osVersion.CurrentBuildNumber, $osVersion.UBR))
    $Host.UI.WriteLine(('{0}, {1}' -f $profileHost, $psVersion))
    $Host.UI.WriteLine()
    $Host.UI.WriteLine(('{0}\{1} on {2}, Uptime {3:%d} day(s) {3:hh\:mm\:ss}' -f $Env:USERDOMAIN, $Env:USERNAME, $Env:COMPUTERNAME.ToUpper(), [System.TimeSpan]::FromMilliseconds([System.Environment]::TickCount)))
    $Host.UI.WriteLine()
}


<#
    .SYNOPSIS
    Play the fun tool of Rick Astley.
#>

function Start-RickAstley
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')]
    param ()

    Start-Process -FilePath 'powershell.exe' -ArgumentList '-noprofile -noexit -command iex (New-Object Net.WebClient).DownloadString(''http://bit.ly/e0Mw9w'')'
}


<#
    .SYNOPSIS
    Disable the custom prompt and restore the default prompt.
#>

function Disable-Prompt
{
    [CmdletBinding()]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalFunctions', '')]
    param ()

    function Global:Prompt
    {
        "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "
        # .Link
        # http://go.microsoft.com/fwlink/?LinkID=225750
        # .ExternalHelp System.Management.Automation.dll-help.xml
    }
}


<#
    .SYNOPSIS
    Disable the prompt alias recommendation output after each command.
#>

function Disable-PromptAlias
{
    [CmdletBinding()]
    [Alias('dalias')]
    param ()

    Remove-Variable -Scope Script -Name PromptAlias -ErrorAction SilentlyContinue -Force
    New-Variable -Scope Script -Option ReadOnly -Name PromptAlias -Value $false -Force
}



<#
    .SYNOPSIS
    Disable the git repository status in the prompt.
#>

function Disable-PromptGit
{
    [CmdletBinding()]
    [Alias('dgit')]
    param ()

    Remove-Variable -Scope Script -Name PromptGit -ErrorAction SilentlyContinue -Force
    New-Variable -Scope Script -Option ReadOnly -Name PromptGit -Value $false -Force
}


function Disable-PromptTimeSpan
{
    [CmdletBinding()]
    [Alias('dtimespan')]
    param ()

    Remove-Variable -Scope Script -Name PromptTimeSpan -ErrorAction SilentlyContinue -Force
    New-Variable -Scope Script -Option ReadOnly -Name PromptTimeSpan -Value $false -Force
}


<#
    .SYNOPSIS
    Enable the custom prompt by replacing the default prompt.
#>

function Enable-Prompt
{
    [CmdletBinding()]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalFunctions', '')]
    param ()

    function Global:Prompt
    {
        if ($Script:PromptHistory -ne $MyInvocation.HistoryId)
        {
            $Script:PromptHistory = $MyInvocation.HistoryId

            if ($Script:PromptAlias) { Show-PromptAliasSuggestion }
            if ($Script:PromptTimeSpan) { Show-PromptLastCommandDuration }
        }

        $Host.UI.Write($Script:PromptColor, $Host.UI.RawUI.BackgroundColor, '[{0:dd MMM HH:mm}]' -f [DateTime]::Now)
        $Host.UI.Write(" $($ExecutionContext.SessionState.Path.CurrentLocation)")
        if ($Script:PromptGit) { Write-VcsStatus }
        return "`n$($MyInvocation.HistoryId.ToString().PadLeft(3, '0'))$('>' * ($NestedPromptLevel + 1)) "
    }
}


<#
    .SYNOPSIS
    Enable the prompt alias recommendation output after each command.
#>

function Enable-PromptAlias
{
    [CmdletBinding()]
    [Alias('ealias')]
    param ()

    Remove-Variable -Scope Script -Name PromptAlias -ErrorAction SilentlyContinue -Force
    New-Variable -Scope Script -Option ReadOnly -Name PromptAlias -Value $true -Force
}

<#
    .SYNOPSIS
    Enable the git repository status in the prompt.
#>

function Enable-PromptGit
{
    [CmdletBinding()]
    [Alias('egit')]
    param ()

    if ($null -eq (Get-Module -Name posh-git))
    {
        Import-Module -Name posh-git -Force
    }

    Remove-Variable -Scope Script -Name PromptGit -ErrorAction SilentlyContinue -Force
    New-Variable -Scope Script -Option ReadOnly -Name PromptGit -Value $true -Force
}


function Enable-PromptTimeSpan
{
    [CmdletBinding()]
    [Alias('etimespan')]
    param ()

    Remove-Variable -Scope Script -Name PromptTimeSpan -ErrorAction SilentlyContinue -Force
    New-Variable -Scope Script -Option ReadOnly -Name PromptTimeSpan -Value $true -Force
}


<#
    .SYNOPSIS
    Show the alias suggestion for the latest command.
#>

function Show-PromptAliasSuggestion
{
    [CmdletBinding()]
    param ()

    if ($MyInvocation.HistoryId -gt 1)
    {
        $history = Get-History -Id ($MyInvocation.HistoryId - 1)
        $reports = @()
        foreach ($alias in (Get-Alias))
        {
            if ($history.CommandLine.IndexOf($alias.ResolvedCommandName) -ne -1)
            {
                $reports += $alias
            }
        }
        if ($reports.Count -gt 0)
        {
            $report = $reports | Group-Object -Property 'ResolvedCommandName' | ForEach-Object { ' ' + $_.Name + ' => ' + ($_.Group -join ', ') }
            $Host.UI.WriteLine('Magenta', $Host.UI.RawUI.BackgroundColor, "Alias suggestions:`n" + ($report -join "`n"))
        }
    }
}


<#
    .SYNOPSIS
    Show the during of the last executed command.
#>

function Show-PromptLastCommandDuration
{
    [CmdletBinding()]
    param ()

    if ($MyInvocation.HistoryId -gt 1 -and $Host.UI.RawUI.CursorPosition.Y -gt 0)
    {
        $history  = Get-History -Id ($MyInvocation.HistoryId - 1)
        $duration = ($history.EndExecutionTime - $history.StartExecutionTime).ToString('\ \ \ h\:mm\:ss\.ffff')

        # Move cursor one up and to the right to show the execution time.
        $position = $Host.UI.RawUI.CursorPosition
        $position.Y = $position.Y - 1
        $position.X = $Host.UI.RawUI.WindowSize.Width - $duration.Length
        $Host.UI.RawUI.CursorPosition = $position

        $Host.UI.Write('Gray', $Host.UI.RawUI.BackgroundColor, $duration)
    }
}


<#
    .SYNOPSIS
    Disable the information output stream for the global shell.
#>

function Disable-Information
{
    [CmdletBinding()]
    [Alias('di')]
    param ()

    Set-Variable -Scope Global -Name InformationPreference -Value 'SilentlyContinue'
}


<#
    .SYNOPSIS
    Disable the verbose output stream for the global shell.
#>

function Disable-Verbose
{
    [CmdletBinding()]
    [Alias('dv')]
    param ()

    Set-Variable -Scope Global -Name VerbosePreference -Value 'SilentlyContinue'
}

<#
    .SYNOPSIS
    Enable the information output stream for the global shell.
#>

function Enable-Information
{
    [CmdletBinding()]
    [Alias('ei')]
    param ()

    Set-Variable -Scope Global -Name InformationPreference -Value 'Continue'
}


<#
    .SYNOPSIS
    Enable the verbose output stream for the global shell.
#>

function Enable-Verbose
{
    [CmdletBinding()]
    [Alias('ev')]
    param ()

    Set-Variable -Scope Global -Name VerbosePreference -Value 'Continue'
}


# Script-wide profile configuration variables
$Script:PromptHistory  = 0
$Script:PromptAdmin    = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
$Script:PromptColor    = $(if($Script:PromptAdmin) { 'Red' } else { 'DarkCyan' })
$Script:PromptAlias    = $false
$Script:PromptTimeSpan = $false
$Script:PromptGit      = $false