PowerShell: Dokumentations-Trigger pflegen

18. Januar 2018 18:15

Mit diesem Skript kann man ein Objektpaket zerlegen (Bedienung und Arbeitsweise wie im Objektspitter, das hiesige Skript schreibt dabei den Ordner SPLITNAVOBJCPYRT statt SPLITNAVOBJ) und zusätzlich dabei für alle Objekte oben im Documentation-Trigger einen beliebigen Eintrag vornehmen, bspw. für die üblichen Copyrightzeilen. Falls oben und unten benötigt wird siehe nächster Beitrag.
Für Objekte, die bislang keinen Eintrag im Documentationtrigger hatten, wird dabei einer angelegt, das ist im Skript separat pflegbar.

Die Umarbeitung erfolgt in 2 Schritten.
1. Die Objekte werden gespittet und nicht vorhandene Trigger dabei gleich mit angelegt. Für Objekte mit bereits vorhandenem Trigger wird die Startzeile für jedes Objekt getrennt ermittelt und in eine Hashtabelle geschrieben (deren Inhalt wird ausgegeben, das kann man ggf. abschalten, dazu diese Zeile$FilesWithDocTrigger.GetEnumerator() | Sort-Object Name) auskommentieren
2. Alle in der Hashtabelle aufgeführten Objektdateien werden erneut gelesen und geschrieben und erhalten an der ermittelten Startposition des Triggers den gewünschten Zeileneinschub.
DocuTrigger2.png

DocuTrigger1.png


Versehentlich eingefügte (und eindeutig erkennbare) Zeilen kann man hiermit wieder entfernen.
Für das Zusammenstellen zum neuen Objektpaket kann man für aktuelle Objekte dieses Skript verwenden. Für Forms und Dataports funktioniert das Join-Cmdlet von Microsoft leider nicht mehr, dann und auch sonst hilft dieses Tool weiter.

Code:
function Split-NAVObjectFileWithDocuTrigger
{
    $ErrorActionPreference = "Stop"
    $PSDefaultParameterValues['*:ErrorAction']='Stop'


 
    Function Get-FileName($initialDirectory)
    {
        [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
   
        $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
        $OpenFileDialog.initialDirectory = $initialDirectory
        $OpenFileDialog.filter = "NAV Object Files (*.txt)|*.txt"
        $OpenFileDialog.ShowDialog() | Out-Null
        $OpenFileDialog.filename
    }
       
    $inputfile = Get-FileName "C:\temp" # This is the default path in OpenFile window.
    if ($inputfile -eq "") {throw 'Please select a file'}
     
    [decimal]$filesize = ((Get-Item $inputfile).length/1MB)
    $filesize =[math]::round($filesize,2)
    $TotalLineCnt = $inputfile.count
   
    $inputfile = resolve-path $inputfile
    $WorkingFolder = Split-Path -Parent $inputfile
   

   
    if (Test-path "$WorkingFolder\SPLITNAVOBJCPYRT\")
    {Remove-Item -path "$WorkingFolder\SPLITNAVOBJCPYRT\" -Recurse -Force}

    Write-Host "Splitting NAV objects from $inputfile (Size: $filesize MB) to $WorkingFolder\SPLITNAVOBJCPYRT\, this may take a while..." -ForegroundColor Yellow
    $startime = date
   
   
    $fs= New-Object System.IO.FileStream($inputfile,"OpenOrCreate", "Read", "ReadWrite",8,"None")
    $Sr = new-object System.IO.StreamReader($fs,[system.text.encoding]::GetEncoding(850))

    [int]$ObjCnt = 0
    [int]$TabCnt = 0
    [int]$PagCnt = 0
    [int]$RepCnt = 0
    [int]$CodCnt = 0
    [int]$XmlCnt = 0
    [int]$ForCnt = 0
    [int]$DatCnt = 0
    [int]$QueCnt = 0
    [int]$MenCnt = 0
    [int]$PosCnt = 0

    $LastLine = ''
    $FilesWithDocTrigger = @{'File' = 'FilePos'}
    while (-not $Sr.EndOfStream)
    {
        $Currline = $sr.ReadLine()
        $fsr = $sr.BaseStream
        $posCnt++



        if ($Currline.StartsWith('OBJECT'))
        {
            $HasDocuTrigger  = $false   
            [String]$ObjectChar = $Currline.Substring(7,1)
            $ObjectLine = $currline.Split(' ')
            $ObjCnt++
            [int]$ObjposCnt = 0


            Switch ($ObjectChar)
            {
                'T' {$TabCnt++}
                'P' {$PagCnt++}
                'R' {$RepCnt++}
                'C' {$CodCnt++}
                'X' {$XmlCnt++}
                'F' {$ForCnt++}
                'D' {$DatCnt++}
                'Q' {$QueCnt++}
                'M' {$MenCnt++}
       
            }

            $ObjectFileName = $ObjectLine[1].Substring(0,3).ToUpper() + $ObjectLine[2] + ".TXT"
            $Objectfile = New-Item -path "$WorkingFolder\SPLITNAVOBJCPYRT\$ObjectFileName" -type file -force
            IF (Test-Path $ObjectFile) {Remove-Item $ObjectFile}
           
            $sw = new-object System.IO.Streamwriter($Objectfile,$false,[system.text.encoding]::GetEncoding(850))
        }
        $ObjposCnt++   
        if ($CurrLine -eq '    BEGIN')
        {
            $LastBeginPosInObj = $ObjposCnt
           
        }
        if (($Currline -eq '    END.') -and ($LastLine -eq '    BEGIN'))
        {   
            $sw.writeline('    {')
         
            $sw.writeline("      (c) Global Software Enterprises, all rights reserved" )
            $sw.writeline("      ------------------------------------------------")
            $sw.writeline()
            $sw.writeline('    }')
            $sw.writeline('    END.')
            $LastLine = $CurrLine
        }
         
        #
        elseif (($Currline -eq '    END.') -and ($LastLine -ne '    BEGIN'))
        {
            $sw.writeline($Currline)
            $Lastline = $CurrLine
            $HasDocuTrigger = $true

            [int]$SplitFileAtLine = $LastBeginPosinObj
 
        }
        elseif (-not $Currline.StartsWith('}'))
        {
            # normal line
 
           
            $sw.writeline($Currline)
            $Lastline = $CurrLine
 
        }
        else
        {
            # final line
            $sw.writeline($Currline)
            $Lastline = $CurrLine
            $sw.writeline()
           
            $sw.Flush()
           
            # End of splitted object file
            if ($HasDocuTrigger)
            {
                $FilesWithDocTrigger.Add($Objectfilename,$SplitFileAtLine)
                $ObjposCnt = 0
            }
   
        }

           


    }
           
   
    $endtime = date
    $time = $endtime - $startime
    Write-Host "$ObjCnt NAV objects splitted to $WorkingFolder\SPLITNAVOBJCPYRT\ in $($time.Minutes)m:$($time.Seconds)s:$($time.Milliseconds)ms" -ForegroundColor Yellow
    Write-Host "Tables: $TabCnt" -ForegroundColor Yellow
    Write-Host "Pages: $PagCnt" -ForegroundColor Yellow
    Write-Host "Reports: $RepCnt" -ForegroundColor Yellow
    Write-Host "Codeunits: $CodCnt" -ForegroundColor Yellow
    Write-Host "XMLPorts: $XMLCnt" -ForegroundColor Yellow
    Write-Host "MenuSuites: $MenCnt" -ForegroundColor Yellow
    if ($ForCnt -gt 0)
    {Write-Host "Forms: $ForCnt" -ForegroundColor Yellow}
    if ($DatCnt -gt 0)
    {Write-Host "Dataports: $DatCnt" -ForegroundColor Yellow}   
    $sr.Close()
    $sr.Dispose()
    $sw.close()
    $sw.Dispose()
    Write-Host "Files with existing documentation triggers  +++ Line number at top of trigger section" -ForegroundColor DarkYellow
    $FilesWithDocTrigger.GetEnumerator() | Sort-Object Name
    Start-Sleep -Seconds 2

    foreach($FilesWithDocTr in $FilesWithDocTrigger.Keys)
    {
        if (${FilesWithDocTr} -ne 'File')
        {
            #Write-Host "${FilesWithDocTr}: $($FilesWithDocTrigger.Item($FilesWithDocTr))"
            Write-Host "Adding new section to existing documentation trigger in ${FilesWithDocTr}" -ForegroundColor Yellow
            $sr2 = new-object System.IO.StreamReader("$WorkingFolder\SPLITNAVOBJCPYRT\$FilesWithDocTr",[system.text.encoding]::GetEncoding(850))
            $ObjectFileName2 = $FilesWithDocTr + ".tmp"
            $Objectfile2 = New-Item -path "$WorkingFolder\SPLITNAVOBJCPYRT\$ObjectFileName2"  -type file -force
            IF (Test-Path $ObjectFile2) {Remove-Item $ObjectFile2 -Force}
            $posCnt2 = 0       
            $sw2 = new-object System.IO.Streamwriter($Objectfile2,$false,[system.text.encoding]::GetEncoding(850))
            while (-not $Sr2.EndOfStream)
            {
                [int]$DocPosLine = $FilesWithDocTrigger.get_item($FilesWithDocTr)
                $Currline2 = $sr2.ReadLine()
                $posCnt2++
                if ($posCnt2 -ne ($DocPosLine + 2))
                {$sw2.writeline($Currline2)}
                else
                {
                    $sw2.writeline("      (c) Global Software Enterprises, all rights reserved")
                    $sw2.writeline("      ------------------------------------------------")
                    $sw2.writeline()
                    $sw2.writeline($Currline2)
                }
            }
            $sw2.close()
            $sw2.Dispose()
            $sr2.Close()
            $sr2.Dispose()
            Start-Sleep -Milliseconds 10
            IF (Test-Path "$WorkingFolder\SPLITNAVOBJCPYRT\$FilesWithDocTr") {Remove-Item "$WorkingFolder\SPLITNAVOBJCPYRT\$FilesWithDocTr" -Force}
            Start-Sleep -Milliseconds 10
            IF (Test-Path $ObjectFile2) {Rename-Item $ObjectFile2 -NewName "$WorkingFolder\SPLITNAVOBJCPYRT\$FilesWithDocTr" -Force}
            Start-Sleep -Milliseconds 10
        }
    }
    if ($sw2.BaseStream)
    {
        $sw2.close()
        $sw2.Dispose()
    }
    if ($sr2.BaseStream)
    {
        $sr2.Close()
        $sr2.Dispose()
    }
    Invoke-item "$WorkingFolder\SPLITNAVOBJCPYRT\"
   
}
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Dokumentations-Trigger oben und unten pflegen

20. Januar 2018 01:04

Mit dieser Variante kann man sowohl oben als auch unten in einem vorhandenen Trigger einen Einschub vornehmen.
DocuTrigger2Sections.png

Mit der Variante $AddBottomSection oben im Skript kann man den unteren bei Bedarf auch abschalten. Das Skript arbeitet dann wie das obige, das ich zu Vergleichszwecken aber trotzdem dort stehen lasse.
Code:
$AddBottomSection = $false

Der Ausgabetext passt sich dabei jeweils an, die Pluraloption kommt nur, wenn beide erzeugt werden.
DocuTrigger3.png

Code:
function Split-NAVObjectFileWithDocuTrigger2
{
    $ErrorActionPreference = "Stop"
    $PSDefaultParameterValues['*:ErrorAction']='Stop'

    $AddBottomSection = $true
 
    Function Get-FileName($initialDirectory)
    {
        [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
   
        $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
        $OpenFileDialog.initialDirectory = $initialDirectory
        $OpenFileDialog.filter = "NAV Object Files (*.txt)|*.txt"
        $OpenFileDialog.ShowDialog() | Out-Null
        $OpenFileDialog.filename
    }
       
    $inputfile = Get-FileName "C:\temp" # This is the default path in OpenFile window.
    if ($inputfile -eq "") {throw 'Please select a file'}
     
    [decimal]$filesize = ((Get-Item $inputfile).length/1MB)
    $filesize =[math]::round($filesize,2)
    #$TotalLineCnt = $inputfile.count
   
    $inputfile = resolve-path $inputfile
    $WorkingFolder = Split-Path -Parent $inputfile

    if (Test-path "$WorkingFolder\SPLITNAVOBJCPYRT\")
    {Remove-Item -path "$WorkingFolder\SPLITNAVOBJCPYRT\" -Recurse -Force}

    Write-Host "Splitting NAV objects from $inputfile (Size: $filesize MB) to $WorkingFolder\SPLITNAVOBJCPYRT\, this may take a while..." -ForegroundColor Yellow
    $startime = date
   
    $fs= New-Object System.IO.FileStream($inputfile,"OpenOrCreate", "Read", "ReadWrite",8,"None")
    $Sr = new-object System.IO.StreamReader($fs,[system.text.encoding]::GetEncoding(850))

    [int]$ObjCnt = 0
    [int]$TabCnt = 0
    [int]$PagCnt = 0
    [int]$RepCnt = 0
    [int]$CodCnt = 0
    [int]$XmlCnt = 0
    [int]$ForCnt = 0
    [int]$DatCnt = 0
    [int]$QueCnt = 0
    [int]$MenCnt = 0
    [int]$PosCnt = 0

    $LastLine = ''
    $FilesWithDocTrigger = @{}
    $FilesWithDocTriggerPeriodEnd = @{}
    while (-not $Sr.EndOfStream)
    {
        $Currline = $sr.ReadLine()
        #$fsr = $sr.BaseStream
        $posCnt++

        if ($Currline.StartsWith('OBJECT'))
        {
            $HasDocuTrigger  = $false   
            [String]$ObjectChar = $Currline.Substring(7,1)
            $ObjectLine = $currline.Split(' ')
            $ObjCnt++
            [int]$ObjposCnt = 0

            Switch ($ObjectChar)
            {
                'T' {$TabCnt++}
                'P' {$PagCnt++}
                'R' {$RepCnt++}
                'C' {$CodCnt++}
                'X' {$XmlCnt++}
                'F' {$ForCnt++}
                'D' {$DatCnt++}
                'Q' {$QueCnt++}
                'M' {$MenCnt++}
            }

            $ObjectFileName = $ObjectLine[1].Substring(0,3).ToUpper() + $ObjectLine[2] + ".TXT"
            $Objectfile = New-Item -path "$WorkingFolder\SPLITNAVOBJCPYRT\$ObjectFileName" -type file -force
            IF (Test-Path $ObjectFile) {Remove-Item $ObjectFile}
           
            $sw = new-object System.IO.Streamwriter($Objectfile,$false,[system.text.encoding]::GetEncoding(850))
        }
        $ObjposCnt++   
        if ($CurrLine -eq '    BEGIN')
        {
            $LastBeginPosInObj = $ObjposCnt
           
        }
        if ($CurrLine -eq '    END.')
        {
            $EndPeriodPosInObj = $ObjposCnt
           
        }
        if (($Currline -eq '    END.') -and ($LastLine -eq '    BEGIN'))
        {   
            # create new trigger
            $sw.writeline('    {')
            $sw.writeline("      (c) Global Software Enterprises, all rights reserved" )
            $sw.writeline("      ----------------------------------------------------")
            $sw.writeline()
            $sw.writeline('    }')
            $sw.writeline('    END.')
            $LastLine = $CurrLine
        }
         
        #
        elseif (($Currline -eq '    END.') -and ($LastLine -ne '    BEGIN'))
        {
            # existing trigger
            $sw.writeline($Currline)
            $Lastline = $CurrLine
            $HasDocuTrigger = $true

            [int]$SplitFileAtLine = $LastBeginPosinObj
 
        }
        elseif (-not $Currline.StartsWith('}'))
        {
            # normal line
            $sw.writeline($Currline)
            $Lastline = $CurrLine
        }
        else
        {
            # final line
            $sw.writeline($Currline)
            $Lastline = $CurrLine
            $sw.writeline()
           
            $sw.Flush()
           
            # End of splitted object file
            if ($HasDocuTrigger)
            {
                $FilesWithDocTrigger.Add($Objectfilename,$SplitFileAtLine)
                $FilesWithDocTriggerPeriodEnd.Add($Objectfilename,$EndPeriodPosInObj)
                $ObjposCnt = 0
            }
        }
    }
    $endtime = date
    $time = $endtime - $startime
    Write-Host "$ObjCnt NAV objects splitted to $WorkingFolder\SPLITNAVOBJCPYRT\ in $($time.Minutes)m:$($time.Seconds)s:$($time.Milliseconds)ms" -ForegroundColor Yellow
    Write-Host "Tables: $TabCnt" -ForegroundColor Yellow
    Write-Host "Pages: $PagCnt" -ForegroundColor Yellow
    Write-Host "Reports: $RepCnt" -ForegroundColor Yellow
    Write-Host "Codeunits: $CodCnt" -ForegroundColor Yellow
    Write-Host "XMLPorts: $XMLCnt" -ForegroundColor Yellow
    Write-Host "MenuSuites: $MenCnt" -ForegroundColor Yellow
    if ($ForCnt -gt 0)
    {Write-Host "Forms: $ForCnt" -ForegroundColor Yellow}
    if ($DatCnt -gt 0)
    {Write-Host "Dataports: $DatCnt" -ForegroundColor Yellow}   
    $sr.Close()
    $sr.Dispose()
    $sw.close()
    $sw.Dispose()
    Write-Host "Files with existing documentation triggers + Line number at top of trigger section" -ForegroundColor DarkYellow
    $FilesWithDocTrigger.GetEnumerator() | Sort-Object Name
    Start-Sleep -Seconds 3

    foreach($FilesWithDocTr in $FilesWithDocTrigger.Keys)
    {

 
        #Write-Host "${FilesWithDocTr}: $($FilesWithDocTrigger.Item($FilesWithDocTr))"
        if ($AddBottomSection) {$Plural = '(s)'}
        Write-Host "Adding new section$Plural to existing documentation trigger in ${FilesWithDocTr}" -ForegroundColor Yellow
        $sr2 = new-object System.IO.StreamReader("$WorkingFolder\SPLITNAVOBJCPYRT\$FilesWithDocTr",[system.text.encoding]::GetEncoding(850))
        $ObjectFileName2 = $FilesWithDocTr + ".tmp"
        $Objectfile2 = New-Item -path "$WorkingFolder\SPLITNAVOBJCPYRT\$ObjectFileName2"  -type file -force
        IF (Test-Path $ObjectFile2) {Remove-Item $ObjectFile2 -Force}
        $posCnt2 = 0       
        $sw2 = new-object System.IO.Streamwriter($Objectfile2,$false,[system.text.encoding]::GetEncoding(850))
        while (-not $sr2.EndOfStream)
        {
            [int]$DocPosLine = $FilesWithDocTrigger.get_item($FilesWithDocTr)
            [int]$DocPosEndLine = $FilesWithDocTriggerPeriodEnd.get_item($FilesWithDocTr)
            $Currline2 = $sr2.ReadLine()
            $posCnt2++
            if (($AddBottomSection) -and ($posCnt2 -eq ($DocPosEndLine -2)))
            {
                # bottom section
                $sw2.writeline($Currline2)
                $sw2.writeline("      ---------GLOBAL SOFTWARE ENTERPRISES---------")
                $sw2.writeline("      ---------ADDON MODULE VERSION----------------")
                $sw2.writeline("               XYZ   ABC    1.2.3")
               
            }
               
            elseif ($posCnt2 -ne ($DocPosLine + 2))
            {$sw2.writeline($Currline2)}
            else
            {
                # top section
                $sw2.writeline("      (c) Global Software Enterprises, all rights reserved")
                $sw2.writeline("      ------------------------------------------------")
                $sw2.writeline()
                $sw2.writeline($Currline2)

            }
        }
        $sw2.close()
        $sw2.Dispose()
        $sr2.Close()
        $sr2.Dispose()
        Start-Sleep -Milliseconds 10
        IF (Test-Path "$WorkingFolder\SPLITNAVOBJCPYRT\$FilesWithDocTr") {Remove-Item "$WorkingFolder\SPLITNAVOBJCPYRT\$FilesWithDocTr" -Force}
        Start-Sleep -Milliseconds 10
        IF (Test-Path $ObjectFile2) {Rename-Item $ObjectFile2 -NewName "$WorkingFolder\SPLITNAVOBJCPYRT\$FilesWithDocTr" -Force}
        Start-Sleep -Milliseconds 10
    }
    if ($sw2.BaseStream)
    {
        $sw2.close()
        $sw2.Dispose()
    }
    if ($sr2.BaseStream)
    {
        $sr2.Close()
        $sr2.Dispose()
    }
    Invoke-item "$WorkingFolder\SPLITNAVOBJCPYRT\"
   
}
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.