PowerShell: Dokumentations-Trigger pflegen
Verfasst: 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.
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.
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.
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\"
}