usr/lib/Get-Strings.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using namespace System.IO
using namespace System.Text

Set-Alias -Name strings -Value Get-Strings
function Get-Strings {
  [CmdletBinding(DefaultParameterSetName='Path')]
  param(
    [Parameter(Mandatory,
               ParameterSetName='Path',
               Position=0,
               ValueFromPipeline,
               ValueFromPipelineByPropertyName)]
    [ValidateNotNullOrEmpty()]
    [SupportsWildcards()]
    [String]$Path,

    [Parameter(Mandatory,
               ParameterSetName='LiteralPath',
               Position=0,
               ValueFromPipelineByPropertyName)]
    [ValidateNotNullOrEmpty()]
    [Alias('PSPath')]
    [String]$LiteralPath,

    [Parameter()][Alias('b')][UInt32]$BytesToProcess = 0,
    [Parameter()][Alias('f')][UInt32]$BytesOffset    = 0,
    [Parameter()][Alias('n')][Byte]  $StringLength   = 3,
    [Parameter()][Alias('o')][Switch]$StringOffset,
    [Parameter()][Alias('u')][Switch]$Unicode
  )

  begin {
    if ($PSCmdlet.ParameterSetName -eq 'Path') {
      $PipelineInput = !$PSBoundParameters.ContainsKey('Path')
    }

    function private:Find-Strings([FileInfo]$File) {
      process {
        try {
          $fs = [File]::OpenRead($File.FullName)
          # unable to read beyond file length
          if ($BytesToProcess -ge $fs.Length -or $BytesOffset -ge $fs.Length) {
            throw [InvalidOperationException]::new('Out of stream.')
          }
          # offset has been defined
          if ($BytesOffset -gt 0) {[void]$fs.Seek($BytesOffset, [SeekOrigin]::Begin)}
          # bytes to process
          $buf = [Byte[]]::new(($BytesToProcess -gt 0 ? $BytesToProcess : $fs.Length))
          [void]$fs.Read($buf, 0, $buf.Length)
          # show printable strings
          ([Regex]"[\x20-\x7E]{$StringLength,}").Matches(
            [Encoding]::"U$($Unicode.IsPresent ? 'nicode' : 'TF7')".GetString($buf)
          ).ForEach{
            $StringOffset ? '{0}:{1}' -f $_.Index, $_.Value : $_.Value
          }
        }
        catch {Write-Verbose $_}
        finally {
          if ($fs) {$fs.Dispose()}
        }
      }
    }
  }
  process {}
  end {
    $PSCmdlet.ParameterSetName -eq 'Path' ? (
      Find-Strings ($PipelineInput ? $Path : (Get-Item $Path -ErrorAction 0))
    ) : (Find-Strings (Get-Item -LiteralPath $LiteralPath))
  }
}

Export-ModuleMember -Alias strings -Function Get-Strings