CmdMode.psm1

function Enter-CmdMode
{
    $script:oldPSConsoleHostReadline = $function:global:PSConsoleHostReadline
    $script:oldTabExpansion2 = $function:global:TabExpansion2
    if(Get-Module PSReadline)
    {
        $script:oldPSReadlineOptions = Get-PSReadlineOptionsHashtable
        Set-PSReadlineOptionsForCmd
    }

    $function:global:PSConsoleHostReadline = 
        {
            $line = & $script:oldPSConsoleHostReadline
            switch($line)
            {
                "psmode" { "Enter-PSMode" }
                default  { Get-CmdWrappedCommand $line }
            }
        }
        
    $function:global:TabExpansion2 = 
        {
            [CmdletBinding(DefaultParameterSetName = 'ScriptInputSet')]
            Param(
                [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 0)]
                [string] $inputScript,

                [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 1)]
                [int] $cursorColumn,

                [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 0)]
                [System.Management.Automation.Language.Ast] $ast,

                [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 1)]
                [System.Management.Automation.Language.Token[]] $tokens,

                [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 2)]
                [System.Management.Automation.Language.IScriptPosition] $positionOfCursor,

                [Parameter(ParameterSetName = 'ScriptInputSet', Position = 2)]
                [Parameter(ParameterSetName = 'AstInputSet', Position = 3)]
                [Hashtable] $options = $null
            )

            $results = & $script:oldTabExpansion2 @PSBoundParameters
            [System.Management.Automation.CompletionResult[]]$realMatches = @()
            foreach($result in $results.CompletionMatches)
            {
                $isRealMatch = $false;
                if($result.ResultType -eq [System.Management.Automation.CompletionResultType]::Command)
                {
                    if((Test-Path $result.ToolTip))
                    {
                        $isRealMatch = $true;
                    }
                }
                elseif($result.ResultType -eq [System.Management.Automation.CompletionResultType]::ProviderItem -or 
                    $result.ResultType -eq [System.Management.Automation.CompletionResultType]::ProviderContainer)
                {
                    try
                    {
                        $item = (Get-Item $result.ToolTip -Force -ErrorAction SilentlyContinue)
                        if($item.PSProvider.Name -eq "FileSystem")
                        {
                            $isRealMatch = $true
                        }
                    }
                    catch { }
                }

                if($isRealMatch)
                {
                    if($result.CompletionText.Substring(0,2) -eq "& ")
                    {
                        $result = New-Object System.Management.Automation.CompletionResult $result.CompletionText.Substring(2), $result.ListItemText, $result.ResultType, $result.ToolTip
                    }

                    if($result.CompletionText[0] -eq "'" -and $result.CompletionText[($result.CompletionText.Length)-1] -eq "'")
                    {
                        [string]$newCompletionText = $result.CompletionText.SubString(1,($result.CompletionText.Length)-2)
                        [string]$newCompletionText = Get-EscapedString $newCompletionText
                        [string]$newCompletionText = "`"$newCompletionText`""
                        $result = New-Object System.Management.Automation.CompletionResult $newCompletionText, $result.ListItemText, $result.ResultType, $result.ToolTip
                    }

                    $realMatches += $result
                }
            }

            if($realMatches.Count -eq 0)
            {
                $null
                return
            }

            $results.CompletionMatches = $realMatches
            $results
        }
}
Set-Alias cmdmode Enter-CmdMode

function Get-PSReadlineOptionsHashtable
{
    param(
        [Parameter(Mandatory=$false, Position=0)]
        [Microsoft.PowerShell.PSConsoleReadlineOptions]$psreadlineOptions = (Get-PSReadlineOption)
    )

    $psreadlineOptionsHash = @{}
    foreach($prop in $psreadlineOptions.psobject.Properties)
    {
        $psreadlineOptionsHash[$prop.Name] = $prop.Value
    }

    $psreadlineOptionsHash
}

function Set-PSReadlineOptionsForPS
{
    foreach($tk in "Comment","Keyword","Operator","Variable","Member")
    {
        Set-PSReadlineOption -TokenKind $tk -ForegroundColor $script:oldPSReadlineOptions["$($tk)ForegroundColor"].ToString()
        Set-PSReadlineOption -TokenKind $tk -BackgroundColor $script:oldPSReadlineOptions["$($tk)BackgroundColor"].ToString()
    }
}

function Set-PSReadlineOptionsForCmd
{
    $psreadlineOptions = Get-PSReadlineOption
    $defaultTokenForegroundColor = $psreadlineOptions.DefaultTokenForegroundColor.ToString()
    $defaultTokenBackgroundColor = $psreadlineOptions.DefaultTokenBackgroundColor.ToString()
    foreach($tk in "Comment","Keyword","Operator","Variable","Member")
    {
        Set-PSReadlineOption -TokenKind $tk -ForegroundColor $defaultTokenForegroundColor
        Set-PSReadlineOption -TokenKind $tk -BackgroundColor $defaultTokenBackgroundColor
    }
}

function Enter-PSMode
{
    $function:global:PSConsoleHostReadline = $script:oldPSConsoleHostReadline
    $function:global:TabExpansion2 = $script:oldTabExpansion2
    if(Get-Module PSReadline)
    {
        Set-PSReadlineOptionsForPS
    }
}

function Get-EscapedString
{
    param(
        [string]$str
    )

    #Note: Backtick must be first in this list
    [string[]]$specialChars = '`','"','$','@','[',']'

    foreach($specialChar in $specialChars)
    {
        [string]$str = $str -replace "\$specialChar","``$specialChar"
    }

    $str
}

function Get-CmdWrappedCommand
{
    param(
        [string]$line
    )

    [string]$line = $line -replace "`n"," "

    if([string]::IsNullOrWhiteSpace($line))
    {
        ""
        return
    }

    [string]$line = Get-EscapedString $line

    $wrappedCommand += "cmd /s /c `" $line & set > $($script:setOutTmpFile.FullName) & cd > $($script:cdOutTmpFile.FullName) `";"
    $wrappedCommand += "foreach(`$line in (Get-Content `"$($script:setOutTmpFile.FullName)`")){ `$spl = (`$line -split `"=`"); Set-Item -Path `"env:`$(`$spl[0])`" -Value `$spl[1] };"
    $wrappedCommand += "try{ Set-Location (Get-Content `"$($script:cdOutTmpFile.FullName)`") }catch{};"
    $wrappedCommand
}

$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
    Remove-Item $script:setOutTmpFile
    Remove-Item $script:cdOutTmpFile
}

$script:oldPSConsoleHostReadline = $function:global:PSConsoleHostReadline
$script:oldTabExpansion2 = $function:global:TabExpansion2
$script:setOutTmpFile = New-TemporaryFile
$script:cdOutTmpFile = New-TemporaryFile

Export-ModuleMember -Function @("Enter-CmdMode","Enter-PSMode") -Alias @("cmdmode")