ITGSerialTerminalTools.psm1

Function Invoke-RemoteCommand
{

    <#
    .Synopsis
        Выполняет в удалённой консоли команду и возвращает результат.
        Генерирует исключение в случае таймаута.
    .Description
        Выполняет в удалённой консоли команду Command и возвращает результат.
        Генерирует исключение в случае таймаута.
        Следует использовать для подачи команды на удалённую консоль.
        С ключом PassThru возвращает в качестве результата вывод удалённой консоли
        до строки, соответствующей PromptPattern.
    #>


    [CmdletBinding()]

    Param(
        # Шаблон строки, ожидаемой в выводе удалённой консоли
        [Parameter(
            Mandatory = $true,
            ValueFromPipeLine = $true,
            Position = 0
        )]
        [AllowEmptyString()]
        [String] $Command,

        # Шаблон строки, ожидаемой в выводе удалённой консоли
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string] $PromptPattern = '\[.+?\] >',

        # Читатель потока удалённой консоли
        [Parameter(
            Mandatory = $true
        )]
        [ValidateNotNull()]
        [System.IO.TextReader] $ConsoleStreamReader,

        # Писатель потока удалённой консоли
        [Parameter(
            Mandatory = $true
        )]
        [ValidateNotNull()]
        [System.IO.TextWriter] $ConsoleStreamWriter,

        # Ключ, определяющий необходимость возврата вывода удалённой консоли
        [Switch] $PassThru,

        # Таймаут
        [Parameter()]
        [System.TimeSpan] $Timeout = 0
    )

    try
    {

        $ConsoleStreamWriter.WriteLine( $Command );
        Write-Verbose ">>>> $Command";

        $EscapedCommand = [System.Text.RegularExpressions.Regex]::Escape( $Command );
        Wait-ExpectedMessage `
            -ConsoleStreamReader $ConsoleStreamReader `
            -PromptPattern "$PromptPattern\s*$EscapedCommand" `
            -Timeout $Timeout `
            -ErrorAction 'Stop';
        Wait-ExpectedMessage `
            -ConsoleStreamReader $ConsoleStreamReader `
            -PromptPattern "$PromptPattern\s*$EscapedCommand" `
            -Timeout $Timeout `
            -ErrorAction 'Stop';

        return Wait-ExpectedMessage `
            -ConsoleStreamReader $ConsoleStreamReader `
            -PromptPattern $PromptPattern `
            -PassThru:$PassThru `
            -Timeout $Timeout `
            -ErrorAction 'Stop';

    }
    catch
    {
        Write-Error -ErrorRecord $_;
    };

}


Function Wait-ExpectedMessage
{

    <#
    .Synopsis
        Ожидает появления в потоке строки, соответствующей шаблону PromptPattern.
        Генерирует исключение в случае таймаута.
    .Description
        Ожидает появления в потоке строки, соответствующей шаблону PromptPattern.
        Генерирует исключение в случае таймаута.
        Следует использовать до подачи команды на удалённую консоль, чтобы убедиться,
        что консоль готова принимать команды.
        С ключом PassThru возвращает в качестве результата вывод удалённой консоли
        до строки, соответствующей PromptPattern.
    #>


    [CmdletBinding()]

    Param(
        # Шаблон строки, ожидаемой в выводе удалённой консоли
        [Parameter(
            Position = 0
        )]
        [ValidateNotNullOrEmpty()]
        [string] $PromptPattern = '\[.+?\] >',

        # Читатель потока удалённой консоли
        [Parameter(
            Mandatory = $true
        )]
        [ValidateNotNull()]
        [System.IO.TextReader] $ConsoleStreamReader,

        # Ключ, определяющий необходимость возврата вывода удалённой консоли
        [Switch] $PassThru,

        # Таймаут
        [Parameter()]
        [System.TimeSpan] $Timeout = 0
    )

    try
    {

        $Buffer = '';
        $VerboseBuffer = '';

        $Timer = New-Object Diagnostics.StopWatch;
        if ( $Timeout -ne 0 )
        {
            $Timer.Start();
        };

        $RegExp = New-Object System.Text.RegularExpressions.Regex( $PromptPattern );

        do
        {
            $StreamData = $ConsoleStreamReader.Read();
            while ( ( $StreamData -eq -1 ) -and ( $Timer.Elapsed -le $Timeout ) )
            {
                Start-Sleep -Milliseconds 50;
                $StreamData = $ConsoleStreamReader.Read();
            };
            if ( $Timer.Elapsed -gt $Timeout )
            {
                throw ( New-Object System.TimeoutException );
            };
            switch ( [char]$StreamData )
            {
                "`r"
                {
                    if ( $VerboseBuffer )
                    {
                        Write-Verbose $VerboseBuffer;
                        $VerboseBuffer = "";
                    };
                }
                "`n"
                {
                }
                Default
                {
                    $VerboseBuffer += [char] $StreamData;
                }
            }
            $Buffer += [char] $StreamData;
            $SearchResults = $RegExp.Match( $Buffer );
        } while ( -not $SearchResults.Success );

        if ( $VerboseBuffer )
        {
            Write-Verbose $VerboseBuffer;
            $VerboseBuffer = "";
        };

        $Result = $Buffer.Substring( 0, $SearchResults.Index );
        $Buffer = $Buffer.Remove( 0, $SearchResults.Index + $SearchResults.Length );
        if ( $PassThru )
        {
            return $Result;
        };

    }
    catch
    {
        Write-Error -ErrorRecord $_;
    };

}


Export-ModuleMember -Function Invoke-RemoteCommand, Wait-ExpectedMessage