# encoding: ascii
# api: powershell
# title: Scan VB6 Code
# description: This functions work together to read the code of a Visual Basic Project into a PowerShell Object, which can be easyly scanned for patterns, returning filename, function/subroutine  name und the matching line. Great tool you got unmaintained VB6 projects to understand for fixing or migrating (perhaps into PowerShell ;-))
# version: 0.1
# type: function
# license: CC0
# function: Get-VBProject
# x-poshcode-id: 970
# x-archived: 2009-03-27T18:09:47
#
# For examples look at the comments at the end of the code.
#
#requires -version 2

# some PowerShell Functions to scan VB 6 Projects for patterns
# e.g. some SQL calls
 
# by Bernd Kriszio http://pauerschell.blogspot.com/

function Get-VBProject ($file)
{
    # this is developed for use with Visual Basic 6
    # to extract the files the contain VB Code
    pushd (Split-path $file)
    foreach ($line in (gc $file))
    {
        if ($line -match "Class=\S+;\s+(\S+.cls)")
        {
            gi $matches[1]
        }
        elseif ($line -match "Form=(\S+.frm)")
        {
            gi $matches[1]
        }
        elseif ($line -match "Module=\S+;\s*(\S+.BAS)")
        {
            gi $matches[1]
        }
    }
    popd

}

function Get-VBLines ($file)
{
    # VB 6 uses _ at end of line as line continuation character
    # we build logical VB lines, especially to get complete signatures of functions and subroutines
    $oFile = gi $file
    $SourceLineNumber = 0
    foreach ($line in (gc $file))
    {
        $SourceLineNumber++
        if ($continue)
        {
            $buffer += "`r`n" + $line 
            if ($line -notmatch '_$') 
            { 
                $continue = $False
                $o = New-Object object
		        Add-Member -InputObject $o -MemberType NoteProperty -Name LineNumber -Value $LineNumber
		        Add-Member -InputObject $o -MemberType NoteProperty -Name VBLine     -Value $buffer
		        Add-Member -InputObject $o -MemberType NoteProperty -Name file       -Value $oFile.Name
		        Add-Member -InputObject $o -MemberType NoteProperty -Name filepath   -Value $oFile.FullName
                $o
            }
        }
        else
        {
            $buffer = $line 
            $LineNumber = $SourceLineNumber 
            if ($line -match '_$') 
            { 
                $continue = $True
            }
            else
            {
                $o = New-Object object
		        Add-Member -InputObject $o -MemberType NoteProperty -Name LineNumber -Value $LineNumber
		        Add-Member -InputObject $o -MemberType NoteProperty -Name VBLine     -Value $buffer
		        Add-Member -InputObject $o -MemberType NoteProperty -Name file       -Value $oFile.Name
		        Add-Member -InputObject $o -MemberType NoteProperty -Name filepath   -Value $oFile.FullName
                $o
            }
        }
        
    }
}
 
function Get-VB_CodeObject ()
{
    param (     
        [Parameter(Position = 0, Mandatory=$true, ValueFromPipeline=$True)]
        $file    
    )     
    PROCESS
    {
        $inObject = $False
        $lines = @()
        $comments = @()
        $inDeclareations = $True
        #write-Host "--- $file ----"
        Get-VBLines $file  | %  {
            if ($inObject)
            {
                if ($_.VBLine -match "^End $end")
                {
                    $lines += $_.VBLine
                    $inObject = $False
                    if ($inDeclareations){
                        $o = New-Object object
        		        Add-Member -InputObject $o -MemberType NoteProperty -Name LineNumber -Value 1
        		        Add-Member -InputObject $o -MemberType NoteProperty -Name Code       -Value $comments
        		        Add-Member -InputObject $o -MemberType NoteProperty -Name Comments   -Value ''

        		        Add-Member -InputObject $o -MemberType NoteProperty -Name file       -Value $_.file
        		        Add-Member -InputObject $o -MemberType NoteProperty -Name filepath   -Value $_.filepath

        		        Add-Member -InputObject $o -MemberType NoteProperty -Name acces      -Value ''
        		        Add-Member -InputObject $o -MemberType NoteProperty -Name typ        -Value ''
        		        Add-Member -InputObject $o -MemberType NoteProperty -Name name       -Value 'Declarations'
                        $inDeclareations = $false
                        $o
                        $comments = @()
                    }

                    $o = New-Object object
    		        Add-Member -InputObject $o -MemberType NoteProperty -Name LineNumber -Value $LineNumber
    		        Add-Member -InputObject $o -MemberType NoteProperty -Name Code       -Value $lines
       		        Add-Member -InputObject $o -MemberType NoteProperty -Name Comments   -Value $comments
                  
                    
    		        Add-Member -InputObject $o -MemberType NoteProperty -Name file       -Value $_.file
    		        Add-Member -InputObject $o -MemberType NoteProperty -Name filepath   -Value $_.filepath

    		        Add-Member -InputObject $o -MemberType NoteProperty -Name acces      -Value $acces
    		        Add-Member -InputObject $o -MemberType NoteProperty -Name typ        -Value $typ
    		        Add-Member -InputObject $o -MemberType NoteProperty -Name name       -Value $name
                    $o
                    $lines = @()
                }
                else
                { # collect lines
                    $lines += $_.VBLine
                }
            }
            else
            {     
                if ($_.VBLine -match "^(Public|Private)?\s*Property\s+(Get|Set)\s+([^\s\(]+)")
                {
                    $acces = $matches[1]
                    $typ = 'Property ' + $matches[2]
                    $name = $matches[3]
                    $end =  'Property'
                    $inObject = $True
                    #$acces + " " +  $typ + " " + $name
                    $comments = $lines
                    $lines = (, $_.VBLine)
                    $LineNumber = $_.LineNumber
                    
                }
                elseif ($_.VBLine -match "^(Public|Private)?\s*(Function|Sub)\s+([^\s\(]+)")
                {
                    $acces = $matches[1]
                    $typ = $matches[2]
                    $name = $matches[3]
                    $end = $matches[2]
                    $inObject = $True
                    #$acces + " " +  $typ + " " + $name
                    $comments = $lines
                    $lines = (, $_.VBLine)
                    $LineNumber = $_.LineNumber
                }
                else
                {
                    $lines += $_.VBLine
                }
            }
        }
    }
}


filter Select-VBCode_String ($pattern)
{
    $o = New-Object object
    Add-Member -InputObject $o -MemberType NoteProperty -Name LineNumber -Value $_.LineNumber
   	Add-Member -InputObject $o -MemberType NoteProperty -Name Comments   -Value $_.comments
    
    Add-Member -InputObject $o -MemberType NoteProperty -Name file       -Value $_.file
    Add-Member -InputObject $o -MemberType NoteProperty -Name filepath   -Value $_.filepath

	Add-Member -InputObject $o -MemberType NoteProperty -Name acces      -Value $_.acces
    Add-Member -InputObject $o -MemberType NoteProperty -Name typ        -Value $_.typ
	Add-Member -InputObject $o -MemberType NoteProperty -Name name       -Value $_.name

    $patternFound = $False
    $lines = @() 
    foreach ($l in $_.Code)
    {
        if ($l -match $pattern)
        {
            $lines += $l
            $patternFound = $True
        }
    }
    if ( $patternFound)
    {
        Add-Member -InputObject $o -MemberType NoteProperty -Name Code       -Value $lines
        $o
    }

}


<#
    $myVBProject = 'myDirtyVb6Project.vbp'
    
    
    $vbp = Get-VBProject $myVBProject | Get-VB_CodeObject 

    # Now you search your VB Project for patterns
    
    # look for sql SELECT-Statements
    $vbp | Select-VBCode_String('"select') |% { $_.code }

    # or the location of Vb EXIT Statments
    $vbp| Select-VBCode_String('EXIT') | fl

    $vbp| select file, acces, typ, name

#>
