Viscalyx.Common.psm1

#Region '.\prefix.ps1' -1

$script:dscResourceCommonModulePath = Join-Path -Path $PSScriptRoot -ChildPath 'Modules/DscResource.Common'
Import-Module -Name $script:dscResourceCommonModulePath

$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US'
#EndRegion '.\prefix.ps1' 5
#Region '.\Public\Out-Diff.ps1' -1

<#
    .SYNOPSIS
        This output two text blocks side-by-side in hex to easily
        compare the diff.
 
    .DESCRIPTION
        This output two text blocks side-by-side in hex to easily
        compare the diff. It is main intended use is as a helper for unit test
        when comparing large text mass which can have small normally invisible
        difference like an extra pch missing LF.
 
    .PARAMETER ActualString
        A text string that should be compared against the text string that is passed
        in parameter 'Expected'.
 
    .PARAMETER ExpectedString
        A text string that should be compared against the text string that is passed
        in parameter 'Actual'.
 
    .EXAMPLE
        Out-Diff `
            -ExpectedString 'This is a longer text string that was expected to be shown' `
            -ActualString 'This is the actual text string'
 
    .NOTES
        This outputs the lines in verbose statements because it is the easiest way
        to show output when running tests in Pester. The output is wide, 185 characters,
        to get the best side-by-side comparison.
#>

function Out-Diff
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String[]]
        $ActualString,

        [Parameter(Mandatory = $true)]
        [System.String[]]
        $ExpectedString
    )

    # TODO: This should support output to the console as well using ANSI sequences to indicate the diff

    $expectedHex = $ExpectedString | Format-Hex
    $actualHex = $ActualString | Format-Hex

    $maxLength = @($expectedHex.length, $actualHex.length) |
        Measure-Object -Maximum |
        Select-Object -ExpandProperty 'Maximum'

    $column1Width = ($expectedHex[0] -replace '\r?\n').Length

    Write-Verbose -Message ("Expected:{0}But was:" -f ''.PadRight($column1Width - 1)) -Verbose

    # Remove one since we start at 0.
    $maxLength -= 1

    0..$maxLength | ForEach-Object -Process {
        $expectedRow = $expectedHex[$_] -replace '\r?\n'
        $actualRow = $actualHex[$_] -replace '\r?\n'

        # Handle if expected is shorter than actual
        if (-not $expectedRow)
        {
            $expectedRow = ''.PadRight($column1Width)
        }

        $diffIndicator = ' '

        if ($expectedRow -ne $actualRow)
        {
            $diffIndicator = '!='
        }

        Write-Verbose -Message ("{0} {1} {2}" -f $expectedRow, $diffIndicator, $actualRow) -Verbose
    }
}
#EndRegion '.\Public\Out-Diff.ps1' 80
#Region '.\Public\Remove-History.ps1' -1

<#
    .SYNOPSIS
        Removes command history entries that match a specified pattern.
 
    .DESCRIPTION
        The Remove-History function removes command history entries that match a
        specified pattern. It removes both the history entries stored by the
        PSReadLine module and the history entries stored by the PowerShell session.
 
    .PARAMETER Pattern
        Specifies the pattern to match against the command history entries. Only
        the entries that match the pattern will be removed.
 
    .PARAMETER EscapeRegularExpression
        Indicates that the pattern should be treated as a literal string. If this
        switch parameter is specified, the pattern will not be treated as a regular
        expression.
 
    .INPUTS
        None. You cannot pipe input to this function.
 
    .OUTPUTS
        None. The function does not generate any output.
 
    .EXAMPLE
        Remove-History -Pattern ".*\.txt"
 
        This example removes all command history entries that end with the ".txt"
        extension, using a regular expression pattern.
 
    .EXAMPLE
        Remove-History -Pattern './build.ps1' -EscapeRegularExpression
 
        This example removes all command history entries that contain the string
        "./build.ps1".
#>

function Remove-History
{
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '', Justification = 'Because ShouldProcess is handled in the commands it calls')]
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param
    (
        [Parameter(Mandatory = $true, Position = 0)]
        [System.String]
        $Pattern,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $EscapeRegularExpression
    )

    Remove-PSReadLineHistory @PSBoundParameters
    Remove-PSHistory @PSBoundParameters
}
#EndRegion '.\Public\Remove-History.ps1' 55
#Region '.\Public\Remove-PSHistory.ps1' -1

<#
    .SYNOPSIS
        Removes PowerShell history content matching a specified pattern.
 
    .DESCRIPTION
        The Remove-PSHistory function removes PowerShell history content that matches
        a specified pattern.
 
    .PARAMETER Pattern
        Specifies the pattern to match against the command history entries. Only
        the entries that match the pattern will be removed.
 
    .PARAMETER EscapeRegularExpression
        Indicates that the pattern should be treated as a literal string. If this
        switch parameter is specified, the pattern will not be treated as a regular
        expression.
 
    .EXAMPLE
        Remove-PSHistory -Pattern ".*\.txt"
 
        This example removes all command history entries that end with the ".txt"
        extension, using a regular expression pattern.
 
    .EXAMPLE
        Remove-PSHistory -Pattern './build.ps1' -EscapeRegularExpression
 
        This example removes all command history entries that contain the string
        "./build.ps1".
 
    .INPUTS
        None. You cannot pipe input to this function.
 
    .OUTPUTS
        None. The function does not generate any output.
#>

function Remove-PSHistory
{
    [CmdletBinding(SupportsShouldProcess = $true , ConfirmImpact = 'High')]
    param
    (
        [Parameter(Mandatory = $true, Position = 0)]
        [System.String]
        $Pattern,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $EscapeRegularExpression
    )

    if ($EscapeRegularExpression.IsPresent)
    {
        $Pattern = [System.Text.RegularExpressions.Regex]::Escape($Pattern)
    }

    $historyContent = Get-History

    $matchingLines = $historyContent |
        Where-Object -FilterScript {
            $_.CommandLine -match $Pattern
        }

    if ($matchingLines)
    {
        $matchingLines | Write-Verbose -Verbose

        $shouldProcessVerboseDescription = 'Removing content matching the pattern ''{0}''.' -f $Pattern
        $shouldProcessVerboseWarning = 'Are you sure you want to remove the content matching the pattern ''{0}'' from PowerShell history?' -f $Pattern
        # This string shall not end with full stop (.) since it is used as a title of ShouldProcess messages.
        $shouldProcessCaption = 'Remove content matching the pattern from PowerShell history'

        if ($PSCmdlet.ShouldProcess($shouldProcessVerboseDescription, $shouldProcessVerboseWarning, $shouldProcessCaption))
        {
            $matchingLines |
                ForEach-Object -Process {
                    Clear-History -Id $_.Id
                }

            Write-Information -MessageData 'Removed PowerShell history content matching the pattern.' -InformationAction Continue
        }
    }
    else
    {
        Write-Information -MessageData 'No PowerShell history content matching the pattern.' -InformationAction Continue
    }
}
#EndRegion '.\Public\Remove-PSHistory.ps1' 86
#Region '.\Public\Remove-PSReadLineHistory.ps1' -1

<#
    .SYNOPSIS
        Removes content from the PSReadLine history that matches a specified pattern.
 
    .DESCRIPTION
        The Remove-PSReadLineHistory function removes content from the PSReadLine
        history that matches a specified pattern.
 
    .PARAMETER Pattern
        Specifies the pattern to match against the command history entries. Only
        the entries that match the pattern will be removed.
 
    .PARAMETER EscapeRegularExpression
        Indicates that the pattern should be treated as a literal string. If this
        switch parameter is specified, the pattern will not be treated as a regular
        expression.
 
    .NOTES
        - This command requires the PSReadLine module to be installed.
        - The PSReadLine history is stored in a file specified by the HistorySavePath
          property of the PSReadLineOption object.
 
    .EXAMPLE
        Remove-PSReadLineHistory -Pattern ".*\.txt"
 
        This example removes all command history entries that end with the ".txt"
        extension, using a regular expression pattern.
 
    .EXAMPLE
        Remove-PSReadLineHistory -Pattern './build.ps1' -EscapeRegularExpression
 
        This example removes all command history entries that contain the string
        "./build.ps1".
 
    .INPUTS
        None. You cannot pipe input to this function.
 
    .OUTPUTS
        None. The function does not generate any output.
#>


function Remove-PSReadLineHistory
{
    [CmdletBinding(SupportsShouldProcess = $true , ConfirmImpact = 'High')]
    param
    (
        [Parameter(Mandatory = $true, Position = 0)]
        [System.String]
        $Pattern,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        $EscapeRegularExpression
    )

    if ($EscapeRegularExpression.IsPresent)
    {
        $Pattern = [System.Text.RegularExpressions.Regex]::Escape($Pattern)
    }

    $historyPath = (Get-PSReadLineOption).HistorySavePath

    $historyContent = Get-Content -Path $historyPath

    # Do not match the last line as it is the line that called the function.
    $matchingContent = $historyContent |
        Select-Object -SkipLast 1 |
        Select-String -Pattern $Pattern

    if ($matchingContent)
    {
        $matchingContent | Write-Verbose -Verbose

        $shouldProcessVerboseDescription = 'Removing content matching the pattern ''{0}''.' -f $Pattern
        $shouldProcessVerboseWarning = 'Are you sure you want to remove the content matching the pattern ''{0}'' from PSReadLine history?' -f $Pattern
        # This string shall not end with full stop (.) since it is used as a title of ShouldProcess messages.
        $shouldProcessCaption = 'Remove content matching the pattern from PSReadLine history'

        if ($PSCmdlet.ShouldProcess($shouldProcessVerboseDescription, $shouldProcessVerboseWarning, $shouldProcessCaption))
        {
            Set-Content -Path $historyPath -Value (
                $historyContent |
                    Select-String -NotMatch $Pattern
            ).Line

            Write-Information -MessageData 'Removed PSReadLine history content matching the pattern.' -InformationAction Continue
        }
    }
    else
    {
        Write-Information -MessageData 'No PSReadLine history content matching the pattern.' -InformationAction Continue
    }
}
#EndRegion '.\Public\Remove-PSReadLineHistory.ps1' 94