PowerShell: Mergen von Versionslisten / Objektdatumsabgleich

30. Oktober 2014 10:14

Das Mergen von Versionslisten wird ja von dem Merge-Cmdlet nicht durchgeführt, man hat derzeit nur Optionen aus welchem Mergeordner die Versionsliste entnommen werden soll.

Um dem abzuhelfen, hat Morten Jensen von MS in diesem Artikel Merging Application Objects using Windows PowerShell in Microsoft Dynamics NAV 2015 in den Kommentaren vorgestern eine Beispielfunktion zum Mergen von Versionslisten veröffentlicht.
Da die dort recht tief verbuddelt ist, hier noch mal in besser lesbarer Form:
Code:
<#

   .SYNOPSIS

   Creates version list string based on the three inputs of a merge operation (original, modified, target).

   The returned version includes the "highest" version for each prefix and any other non-prefixed versions.

   This script does a 3-way merge and then updates the version list in the resulting objects.

   .EXAMPLE

      $mergeInfo = Merge-NAVApplicationObject ...

      $mergeInfo | Foreach-Object { Set-NAVApplicationObjectProperty $_.Result -VersionListProperty (New-NAVVersionList $_ ('MyTag', 'NAVDEU')) }

#>

function New-NAVVersionList($MergeInfo, [string[]]$VersionPrefix = 'NAVW1')

{

   $allVersions = @()

   if ( $mergeInfo.original.versionlist -ne $null )

       { $allVersions += $mergeInfo.original.versionlist.Split(',') }

   if ( $mergeInfo.modified.versionlist -ne $null )

       { $allVersions += $mergeInfo.modified.versionlist.Split(',') }

   if ( $mergeInfo.target.versionlist -ne $null )

       { $allVersions += $mergeInfo.target.versionlist.Split(',') }

   $mergedVersions = @()

   foreach ($prefix in $VersionPrefix)

   {

       # add the "highest" version that starts with the prefix

       $mergedVersions += $allVersions | where { $_.StartsWith($prefix) } | sort | select -last 1

       # remove all prefixed versions

       $allVersions = $allVersions.Where({ !$_.StartsWith($prefix) })

   }

   # return a ,-delimited string consisting of the "highest" prefixed versions and any other non-prefixed versions

   $mergedVersions += $allVersions

   $mergedVersions -join ','

}

$result = Merge-NAVApplicationObject -OriginalPath .\ORIGINAL -ModifiedPath .\MODIFIED -TargetPath .\TARGET -ResultPath .\RESULT -Force

$result |

   foreach { Set-NAVApplicationObjectProperty -Target $_.Result `

                      -VersionListProperty (New-NAVVersionList $_ ('NAVW1',’YOURTAG’)); `

             Get-NAVApplicationObjectProperty -Source $_.Result `

           }

Re: Mergen von Versionslisten mit PowerShell

30. Oktober 2014 10:48

Unterscheidet sich das von Waldos Version?
http://www.waldo.be/2014/10/28/powershe ... rsionlist/

Re: Mergen von Versionslisten mit PowerShell

30. Oktober 2014 11:29

Natalie hat geschrieben:Unterscheidet sich das von Waldos Version?

Ja, links die von Waldo, rechts Morten Jensen. Ich probiere beide mal aus, wenn die Zeit es erlaubt. Kamil Sacek hatte schon vor Wochen eine erstellt, aber damit hatte ich keinen Erfolg, und mit meinem eigenen Versuch in der Richtung auch noch nicht :wink: .
VersionListMergeFunc.png
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Re: Mergen von Versionslisten mit PowerShell

31. Oktober 2014 12:50

Ich habe meine eigene Funktion nun doch fertiggestellt, die macht wenigstens genau das, was ich brauche und auch nichts kaputt :wink: .
Szenario:
  • Im MODIFIED liegt die neue Basisversion, z.B. NAV 2015 RTM oder die aktuelle Cumulative Update Version
  • Im TARGET liegen die alten Addon-Objekte auf Grundlage der alten Basisversion, aber mit dem richtigen Addon-Versionstag in der Versionsliste. Im Beispiel ist dies das Addontag ",OPP" für OPplus, das muss je nach Bedarf angepasst werden.
  • Im RESULT liegen die gemergten Addon-Objekte, mit einer unbrauchbaren Versionsliste. Egal, von wo die beim Mergen versorgt wurde, die wird durch diese Funktion komplett ausgetauscht:
    Neue Versionsliste = Komplette Basisversionsliste aus dem MODIFIED-Ordner + Substring mit allem ab dem Addon-Tag in der Versionsliste in den TARGET-Objekten


In der Powershell wechselt man in das Verzeichnis, in dem die Mergeordner liegen (MODIFIED,TARGET,RESULT), gibt die Funktion ein und ruft danach ihren Namen auf:
VersionslistenMergeFunktion.png

Während die Funktion läuft, wird man über die aktualisierten Objekte im RESULT-Ordner auf dem Laufenden gehalten:

VersionListMerge.png


Code:
function MergeAddonToBaseVersionList
{
Get-ChildItem -Path .\RESULT\*.txt |
foreach `
   (
    {
    $AddonTargetTagPos = 0
   if (Test-Path (".\TARGET\" + $_.Name) -and Test-Path (".\MODIFIED\" + $_.Name))
    {
    # Addon-Objekte liegen im Target-Ordner
    $AddonTargetVersionList = (Get-NAVApplicationObjectProperty -Source (".\TARGET\" + $_.Name)).VersionList
    # Versionliste des alten Addonstands mit Addontag aus dem Target-Ordner, hier als Beispiel OPP für OPplus
    IF ($AddonTargetVersionList -eq "$_null") {$AddonTargetTagPos = 0} ELSE {$AddonTargetTagPos = $AddonTargetVersionList.IndexOf(",OPP")}
    # Versionsliste der neuen Basisversion aus dem Modified-Ordner, natürlich ohne die Addon-Tags
    $BaseVersionList = (Get-NAVApplicationObjectProperty -Source (".\MODIFIED\" + $_.Name)).VersionList
        # Aktuelle alte Versionsliste
    $CurrVersionList = (Get-NAVApplicationObjectProperty -Source $_.FullName).VersionList
    # Prüfen ob Addontag im Targetorder am Objekt vorhanden, das sollte immer der Fall sein wenn die Versionsliste dort gepflegt ist
    IF ($AddonTargetTagPos -gt 0)
    {
    # Alles ab der Addon-Tag-Position entnehmen
   
    $AddonVersionList = $AddonTargetVersionList.Substring($AddonTargetTagPos)
    $NewVersionList = $BaseVersionList + $AddonVersionList
    Write-host "Object: "$_.FullName "Old Version List:" $CurrVersionlist "-> New Version List:" $NewVersionList "Object: "$_.FullName
    Set-NAVApplicationObjectProperty -Target $_.FullName -VersionListProperty $NewVersionList
   
    }
    }
    }
   )
}
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Versionsmerge mit Datumsabgleich (neueres gewinnt)

31. Oktober 2014 17:55

Mit dieser erweiterten Funktion kann man zusätzlich das Datum (d.h. ein weiterer Teil der ObjectProperty innerhalb der Fob-Datei, nicht das der Dateieigenschaften im Explorer, das ist hier irrelevant) zwischen neuer Basisversion und den Addon-Objekten vergleichen. Je nachdem, wo die Objekte zuletzt geändert wurden, ist mal das Objekt aus dem MODIFIED-Ordner mit der neuen Basisversion, mal das aus dem TARGET-Ordner mit den AddOn-Objekten im Datum neuer. Das kann sich sich mit jedem monatlichen Cumulative Update neu darstellen, wenn gleichzeitig eine Weiterentwicklung der AddOn-Lösung stattfindet. Mit einem pauschalen Datum oder Optionen beim Mergen, aus welchem Ordner das Datum genommen wird (wie das Merge-Cmdlet es anbietet), kommt man da also nicht weiter.

In der Funktion werden die Objekte gleichen Dateinamens jeweils einzeln verglichen und dann das neuere Datum der beiden im RESULT-Objekt übernommen. Die Uhrzeit wird dabei pauschal auf 12:00:00 gesetzt, damit es auch da wieder sauber ausssieht, falls in den AddOn-Objekten die letzte Bearbeitungszeit stehengeblieben ist :wink: .

Das Datumsformat muss in der passenden Stringformatierung an das Cmdlet Set-NAVApplicationObjectProperty übergeben werden, da es sonst dort nicht verabeitet werden kann. In der Funktion wird das in DE übliche Format verwendet.

Eingabe der Funktion
DatumsvergleichVersionenFunktion.png


Ausgabe zur Laufzeit
DatumsvergleichVersionen.png

Code:
function SetNewerDateAndMergeAddonToBaseList
{
Get-ChildItem -Path .\RESULT\*.txt |
foreach `
   (
    {
    $AddonTargetTagPos = 0
    if ((Test-Path (".\TARGET\" + $_.Name)) -and (Test-Path (".\MODIFIED\" + $_.Name)))
      {
      # Addon-Objekte liegen im Target-Ordner
      $AddonTargetVersionList = (Get-NAVApplicationObjectProperty -Source (".\TARGET\" + $_.Name)).VersionList
      $AddonDateString = (Get-NAVApplicationObjectProperty -Source (".\TARGET\" + $_.Name)).Date
      $AddonDateTime = [datetime]::ParseExact($AddonDateString, "dd.MM.yy", $null)
      
      # Versionliste des alten Addonstands mit Addontag aus dem Target-Ordner
      IF ($AddonTargetVersionList -eq "$_null") {$AddonTargetTagPos = 0} ELSE {$AddonTargetTagPos = $AddonTargetVersionList.IndexOf(",OPP")}
      # Versionsliste der neuen Basisversion aus dem Modified-Ordner, natürlich ohne die Addon-Tags
      $BaseVersionList = (Get-NAVApplicationObjectProperty -Source (".\MODIFIED\" + $_.Name)).VersionList
       $BaseDateString = (Get-NAVApplicationObjectProperty -Source (".\MODIFIED\" + $_.Name)).Date
      #$BaseTime = (Get-NAVApplicationObjectProperty -Source (".\MODIFIED\" + $_.Name)).Time
      $BaseDateTime = [datetime]::ParseExact($BaseDateString, "dd.MM.yy", $null)
      
      # Datetimevariable in String umwandeln und fest auf 12:00 Uhr setzen
      $BaseDateTimeString = $BaseDateTime.ToString("dd.MM.yy 12:00:00")
      $AddonDateTimeString = $AddonDateTime.ToString("dd.MM.yy 12:00:00")
      
       # Aktuelle alte Versionsliste
      $CurrVersionList = (Get-NAVApplicationObjectProperty -Source $_.FullName).VersionList
      # Datum im RESULT setzen, je nachdem welches neuer ist
      if ($BaseDateTime -ge $AddonDateTime)
        {Set-NAVApplicationObjectProperty -Target $_.FullName -DateTimeProperty $BaseDateTimeString}
      else
        {Set-NAVApplicationObjectProperty -Target $_.FullName -DateTimeProperty $AddonDateTimeString}
      if ($BaseDateTime -ge $AddonDateTime)
        {Write-host "Base object has newer or same datetime," $BaseDateString "applied to" $_.Name}
      else
        {Write-host "AddOn object has newer datetime," $AddonDateString "applied to" $_.Name} 
      
      IF ($AddonTargetTagPos -gt 0)
      # Prüfen ob Addontag im Targetorder am Objekt vorhanden, das sollte immer der Fall sein wenn die Versionsliste dort gepflegt ist

     {
      # Alles ab der Addon-Tag-Position entnehmen
      $AddonVersionList = $AddonTargetVersionList.Substring($AddonTargetTagPos)
      $NewVersionList = $BaseVersionList + $AddonVersionList
      Write-host "Object: "$_.Name "Old Version List:" $CurrVersionlist " -> New Version List:" $NewVersionList 
      Set-NAVApplicationObjectProperty -Target $_.FullName -VersionListProperty $NewVersionList
    
    }
    }
    }
   )
}
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Basisversion mit 2 Add-ons und Datumsabgleich

7. November 2014 17:00

Hier eine Beispielfunktion zum Mergen von 2 Add-on-Versionslisten inklusive Datumsvergleich, welches Add-on dabei den neueren Zeitstempel hat.
Im ORIGINAL liegt die gemeinsame Basisversion (hier NAV 2015)
Im MODIFIED liegen die Objekte von AddOn 1 (im Beispiel mit mit ",OPP…" in der Versionsliste getaggt).
Im TARGET liegen die Objekte von AddOn 2 (im Beispiel mit ",DC…" getaggt)

Im RESULT wurden die Objekte automatisch gemergt, die in der Nachverarbeitung mit dieser Funktion eine zusammengesetzte Versionsliste und den jeweils neueren Zeitstempel erhalten.
FunktionMergeAddon1Addon2.png


Ausgabe zur Laufzeit, hier für ein Objekt:
MergeAddon1Addon2.png


Code:
function MergeVersionDateBaseAddOn1AddOn2
    {
    Get-ChildItem -Path .\RESULT\*.txt |
    foreach `
       (
        {
        Write-host "Checking Object:" $_.Name

      # Addon1-Objekte liegen im MODIFIED-Ordner
      # Addon2-Objekte liegen im TARGET-Ordner
      # Tags je nach Addon anpassen , hier OPP für OPplus und DC für Document Capture
      if (Test-Path (".\MODIFIED\" + $_.Name))
      {
      $Addon1FullVersionList = (Get-NAVApplicationObjectProperty -Source (".\MODIFIED\" + $_.Name)).VersionList
      # Position des AddOn1versiontags
      IF ($Addon1FullVersionList -eq "$_null") {$Addon1TagPos = 0} ELSE {$Addon1TagPos = $Addon1FullVersionList.IndexOf(",OPP")}
      IF ($Addon1TagPos -gt 0) {$ObjectTaggedByAddon1 = $true}
      }
      
      if (Test-Path (".\TARGET\" + $_.Name))
      {
      $Addon2FullVersionList = (Get-NAVApplicationObjectProperty -Source (".\TARGET\" + $_.Name)).VersionList
      # Position des AddOn2versiontags
      IF ($Addon2FullVersionList -eq "$_null") {$Addon2TagPos = 0} ELSE {$Addon2TagPos = $Addon2FullVersionList.IndexOf(",DC")}
      IF ($Addon2TagPos -gt 0) {$ObjectTaggedByAddon2 = $true}
      }
      
      # ORIGINAL-Ordner muss Objekt haben und mindestens ein AddonTag in MODIFIED oder TARGET haben
      $ObjectToMerge = $false
      $ObjectToMerge = (Test-Path (".\ORIGINAL\" + $_.Name)) -and (($ObjectTaggedByAddon1 -or $ObjectTaggedByAddon2))
      
      
      IF ($ObjectToMerge)
         {
          # Versionsliste der Basisversion aus dem ORIGINAL-Ordner
          $BaseFullVersionList = (Get-NAVApplicationObjectProperty -Source (".\ORIGINAL\" + $_.Name)).VersionList
          $BaseDateString = (Get-NAVApplicationObjectProperty -Source (".\ORIGINAL\" + $_.Name)).Date
          # $BaseTime = (Get-NAVApplicationObjectProperty -Source (".\ORIGINAL\" + $_.Name)).Time
          $BaseDateTime = [datetime]::ParseExact($BaseDateString, "dd.MM.yy", $null)
      
       # Versionsliste AddOn1
        IF ($ObjectTaggedByAddon1)
        {
        $Addon1FullVersionList = (Get-NAVApplicationObjectProperty -Source (".\MODIFIED\" + $_.Name)).VersionList
          $Addon1DateString = (Get-NAVApplicationObjectProperty -Source (".\MODIFIED\" + $_.Name)).Date
          $Addon1DateTime = [datetime]::ParseExact($Addon1DateString, "dd.MM.yy", $null)
          }
        # Versionsliste AddOn2
       
        IF ($ObjectTaggedByAddon2)
        {
        $Addon2FullVersionList = (Get-NAVApplicationObjectProperty -Source (".\TARGET\" + $_.Name)).VersionList
          $Addon2DateString = (Get-NAVApplicationObjectProperty -Source (".\TARGET\" + $_.Name)).Date
          $Addon2DateTime = [datetime]::ParseExact($Addon2DateString, "dd.MM.yy", $null)
        }

         
        # Datetimevariable in String umwandeln und fest auf 12:00 Uhr setzen
          $BaseDateTimeString = $BaseDateTime.ToString("dd.MM.yy 12:00:00")
          IF ($ObjectTaggedByAddon1)
          {$Addon1DateTimeString = $Addon1DateTime.ToString("dd.MM.yy 12:00:00")} ELSE {$Addon1DateTimeString = ""}
          IF ($ObjectTaggedByAddon2)
          {$Addon2DateTimeString = $Addon2DateTime.ToString("dd.MM.yy 12:00:00")} ELSE {$Addon1DateTimeString = ""}
         
       
        # Aktuelle alte Versionsliste
          $CurrVersionList = (Get-NAVApplicationObjectProperty -Source $_.FullName).VersionList
          # Datum im RESULT setzen, je nachdem welches neuer ist
          IF (($Addon1TagPos -gt 0) -and ($Addon2TagPos -gt 0))
        {if ($Addon1DateTime -ge $Addon2DateTime)
            {Set-NAVApplicationObjectProperty -Target $_.FullName -DateTimeProperty $Addon1DateTimeString}
          else
            {Set-NAVApplicationObjectProperty -Target $_.FullName -DateTimeProperty $Addon2DateTimeString}}
         
         
        IF (($Addon1TagPos -gt 0) -and ($Addon2TagPos -gt 0))
        {if ($Addon1DateTime -ge $Addon2DateTime)
            {Write-host "AddOn1 object has newer or same datetime," $Addon1DateString "applied to "$_.Name".Base date:"$BaseDateTimeString }
          else
            {Write-host "AddOn2 object has newer datetime," $Addon2DateString "applied to" $_.Name".Base date:"$BaseDateTimeString}}
       
        IF (($Addon1TagPos -gt 0) -and ($Addon2TagPos -eq 0))
         {Set-NAVApplicationObjectProperty -Target $_.FullName -DateTimeProperty $Addon1DateTimeString}
        IF (($Addon1TagPos -eq 0) -and ($Addon2TagPos -gt 0))
         {Set-NAVApplicationObjectProperty -Target $_.FullName -DateTimeProperty $Addon2DateTimeString}
        IF (($Addon1TagPos -eq 0) -and ($Addon2TagPos -eq 0))
         {Set-NAVApplicationObjectProperty -Target $_.FullName -DateTimeProperty $BaseDateTimeString}
       
        # Alles ab der Addon-Tag-Position entnehmen
          IF ($Addon1TagPos -gt 0 -and ($Addon1FullVersionList -ne "$_null"))
        {$Addon1VersionList = $Addon1FullVersionList.Substring($Addon1TagPos)}
          IF ($Addon2TagPos -gt 0 -and ($Addon2FullVersionList -ne "$_null"))
        {$Addon2VersionList = $Addon2FullVersionList.Substring($Addon2TagPos)}
       
        $NewVersionList = $BaseFullVersionList
        IF (($Addon1TagPos -gt 0) -and ($Addon2TagPos -eq 0))
         {$NewVersionList = $BaseFullVersionList + $Addon1VersionList}
        IF (($Addon1TagPos -eq 0) -and ($Addon2TagPos -gt 0))
         {$NewVersionList = $BaseFullVersionList + $Addon2VersionList}
        IF (($Addon1TagPos -gt 0) -and ($Addon2TagPos -gt 0))
         {$NewVersionList = $BaseFullVersionList + $Addon1VersionList + $Addon2VersionList}
        IF (($Addon1TagPos -gt 0) -and ($Addon2TagPos -gt 0))
        {Write-host "Object:"$_.Name $BaseFullVersionList "+" $Addon1VersionList "+" $Addon2VersionList "->" $NewVersionList}
          IF (($Addon1TagPos -gt 0) -and ($Addon2TagPos -eq 0))
        {Write-host "Object:"$_.Name $BaseFullVersionList "+" $Addon1VersionList "->" $NewVersionList}
        IF (($Addon1TagPos -eq 0) -and ($Addon2TagPos -gt 0))
        {Write-host "Object:"$_.Name $BaseFullVersionList "+" $Addon2VersionList "->" $NewVersionList}
       
        Set-NAVApplicationObjectProperty -Target $_.FullName -VersionListProperty $NewVersionList
          IF ($Addon1VersionList -ne "$_null") {Remove-Variable -name Addon1VersionList}
        IF ($Addon2VersionList -ne "$_null") {Remove-Variable -name Addon2VersionList}
        IF ($ObjectTaggedByAddon1 -ne "$_null") {Remove-Variable -name ObjectTaggedByAddon1}
        IF ($ObjectTaggedByAddon2 -ne "$_null") {Remove-Variable -name ObjectTaggedByAddon2}
      }
        }
       )
    }
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Re: Mergen von Versionslisten mit PowerShell

12. November 2014 10:48

Kowa hat geschrieben:Versionsmerge mit Datumsabgleich (neueres gewinnt)

Hier kann man das Ergebnis sehen, wie das Skript in der Praxis funktioniert.
Update 13 Build 38455 für NAV 2013 R2 hat als Datum 30.10, OPP 8.00 den 24.10, welches neuer ist als das von Build 37563 bzw. 38053. Je nach Kombination am Objekt übersteuert jeweils das neuere Datum.
VersionsUndDatumsabgleich.png
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Re: Mergen von Versionslisten mit PowerShell

22. Dezember 2014 10:58

Noch eine Variante, dieses Mal von Bas Graaf: Code Upgrade: Merging Version Lists
und außerdem Info zum den Detailinformationen, die dem Merge-NAVApplicationObject über
Get-Member -MemberType Properties entnommen werden können.

Edit 26.06.16: Aufbauend darauf eine Variante von Luc Van Vugt.
New-NavVersionList - A Useful Improvement

Merge-NAVApplicationObject

8. September 2015 09:11

Merge-NAVApplicationObject enthält in älteren Builds einen Fehler: You notice that the ConflictTarget folder is empty after Merge-NAVApplicationObject has reported documentation conflicts.
Korrigiert ab:

Ab NAV 2017

24. Oktober 2016 08:34

Weil die NAV-Versionskennung ab NAV 2017 ("10") ein Zeichen mehr als in der Vergangenheit hat, sind die Mergskripts, welche mit einem Stringvergleich gearbeitet haben, entsprechend auf integer umzustellen. Ein Vorschlag hierzu von Waldo: Merging NAV Versionlists to NAV 2017 – Updated PowerShell functions!

Re: Ab NAV 2017

24. Oktober 2016 09:23

Natalie hat geschrieben: sind die Mergskripts, welche mit einem Stringvergleich gearbeitet haben, entsprechend auf integer umzustellen.

Um Nachfragen vorzubeugen (ich hatte auch schon Partneranrufe, die mit den anderen Methoden jetzt Probleme bekamen): Meine Methode ist davon nicht betroffen, die obigen Skripte laufen unverändert auch mit NAV 2017.