UpgradeWizard/UpgradeWizard.ps1

function UpgradeWizard
{
    param(
        [Parameter(Mandatory=$true)]
        [ValidateSet('True','False')]
        [string]$SkipQuestions
    )
    [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
    $total = 10;
    $counter1 = 1;
    [string]$test = '';    
    [string]$inputStr ='';
    cls;
    Write-Progress -activity "Upgrade Wizard" -status "Step $counter1 of $total (CUSTOMER)" -PercentComplete (($counter1 / $total)  * 100);
    [string]$CustomerDB = UW-Get-TFSFolders -Desc 'Specify Customer Database (Source modified)' ;
    $counter1 += 1;
    $intAnswer = 99;
    try
    {
    $AppVersion = "$CustomerDB/COD1.TXT"
    $FileContent = Invoke-TFSAPIUW -Url ('_apis/tfvc/items/{0}' -f $AppVersion) -GetContents -NoRaw 'false'
    $FileContent = $FileContent|Select-String -Pattern "PROCEDURE ApplicationBuild" -Context 1,2
    $FileContent2 = $FileContent.Context.PostContext
    $FileContent3 = $FileContent2|Select-String -Pattern "EXIT"
    $FileContent4 = $FileContent3.Line
    $AppVersion = $FileContent4.Remove(0, $FileContent4.IndexOf('(''')+2)
    $AppVersion = $AppVersion.Remove($AppVersion.IndexOf(''')'))
    $AllBranches = Get-TFSBranches
    [string]$BaseSourceFound = $AllBranches -like "*$AppVersion*"
    $VersionMsg = $BaseSourceFound.Remove(0, 22)
    $popup = new-object -comobject wscript.shell 
    $intAnswer = $popup.popup("The script discovered that the Customer Database Version is $VersionMsg`nDo you want to use this version as a Base Source Version?", 0,"Customer Version Detection",4)
    }
    catch
    {}
    if ($intAnswer -ne 6){
    Write-Progress -activity "Upgrade Wizard" -status "Step $counter1 of $total (Current BASE)" -PercentComplete (($counter1 / $total)  * 100);
    [string]$BaseSource = UW-Get-TFSFolders -LevelPath '$/NAV - Base Versions' -Desc 'Specify CURRENT CUSTOMER BASE version (Source base)' ;
    }
    else
    {
    [string]$BaseSource = $BaseSourceFound
    }    
    $counter1 += 1;
    Write-Progress -activity "Upgrade Wizard" -status "Step $counter1 of $total (TARGET BASE)" -PercentComplete (($counter1 / $total)  * 100);
    [string]$BaseTarget = UW-Get-TFSFolders -LevelPath '$/NAV - Base Versions' -Desc 'Specify TARGET CUSTOMER BASE version (Target base)' ;
    $counter1 += 1;
    Write-Progress -activity "Upgrade Wizard" -status "Step $counter1 of $total (WORK FOLDER)" -PercentComplete (($counter1 / $total)  * 100);
    $WorkFolder = [Microsoft.VisualBasic.Interaction]::InputBox("Enter work folder path", "Work folder", "")
    if ($WorkFolder -eq '')
    {
        Write-Host 'Canceled by the user'
        breakl
    }
    $counter1 += 1;
    Write-Progress -activity "Upgrade Wizard" -status "Step $counter1 of $total (Creating folder structure)" -PercentComplete (($counter1 / $total)  * 100);
    $counter1 += 1;
    
    Try
    {        
        $BaseSourceF = UW-RemoveCharFromString -text $BaseSource;
        $BaseTargetF = UW-RemoveCharFromString -text $BaseTarget;
        $CustomerDBF = UW-RemoveCharFromString -text $CustomerDB;
    }
    Catch
    {
        Write-Host
        Write-Host
        Write-Host
        Write-Host
        Write-Host
        Write-Host
        Write-Host
        Write-Host
        Write-Host 'The TFS folder structure is sooo wrong - there is only one level of folder somewhere!'
        Write-Host 'Base Source: '$BaseSource
        Write-Host 'Base Target: '$BaseTarget
        Write-Host 'Customer database: '$customerDB;
        Write-Host
        Write-Host
        Write-Host
        for ($i = 0; $i -lt 3; $i ++) {
        [System.Console]::Beep(1000, 500)
        [System.Console]::Beep(1500, 500)
        }
        break
    }

    Try
    {
        UW-CreateDirectory -DirectoryPath $WorkFolder
        UW-CreateDirectory -DirectoryPath $WorkFolder\$BaseSourceF
        UW-CreateDirectory -DirectoryPath $WorkFolder\$BaseTargetF
        UW-CreateDirectory -DirectoryPath $WorkFolder\$CustomerDBF
        UW-CreateDirectory -DirectoryPath $WorkFolder\Result
    }
    Catch
    {
        Write-Host 'Error: '$_ 
        for ($i = 0; $i -lt 3; $i ++) {
        [System.Console]::Beep(1000, 500)
        [System.Console]::Beep(1500, 500)
        }
        break
    }

    $popup = new-object -comobject wscript.shell 
    Write-Progress -activity "Upgrade Wizard" -status "Step $counter1 of $total (Getting object differences between Customer DB and Base Source)" -PercentComplete (($counter1 / $total)  * 100);
    $counter1 += 1;
    $DiffArray1 = Invoke-TFFolderDiffUW -SourceFolder $CustomerDB -TargetFolder $BaseSource
    Write-Progress -activity "Upgrade Wizard" -status "Step $counter1 of $total (Getting object differences between Base Source and Base Target)" -PercentComplete (($counter1 / $total)  * 100);
    $counter1 += 1;
    $DiffArray2 = Invoke-TFFolderDiffUW -SourceFolder $BaseSource -TargetFolder $BaseTarget
    Write-Progress -activity "Upgrade Wizard" -status "Step $counter1 of $total (Preparing object list to download)" -PercentComplete (($counter1 / $total)  * 100);
    $counter1 += 1;
    $ObjToDownload = New-Object System.Collections.Generic.List[System.String]
    foreach($DiffItem in $DiffArray2)
    {
        $ObjToDownload.Add($DiffItem)
    }

    foreach ($DiffItem in $DiffArray1)
    {
        if(!$ObjToDownload.contains($DiffItem))
        {
            $ObjToDownload.Add($DiffItem);
        }
    }


    Try
    {
        if(($SkipQuestions -eq 'False') -or ($SkipQuestions -eq ''))
        {$intAnswer = $popup.popup("Do you want to download CURRENT Base objects?", 0,"Download objects",4)}
        else
        {$intAnswer = 6}
        If ($intAnswer -eq 6) 
        {
            $counter2 = 1
            foreach ($DItem in $ObjToDownload)
            {
                $total2 = $ObjToDownload.count;
                Write-Progress -activity "Base Source" -status "Files $counter2 of $total2" -PercentComplete (($counter2 / $total2)  * 100);
                Get-ObjectsFromTFSBranch -BranchPath "$BaseSource/$DItem" -DestinationPath $WorkFolder\$BaseSourceF\$DItem -Type File
                $counter2 += 1;
            }
        }

        if(($SkipQuestions -eq 'False') -or ($SkipQuestions -eq ''))
        {$intAnswer = $popup.popup("Do you want to download TARGET Base objects?", 0,"Download objects",4) }
        else
        {$intAnswer = 6}                
        If ($intAnswer -eq 6) 
        {
            $counter2 = 1
            foreach ($DItem in $ObjToDownload)
            {
                $total2 = $ObjToDownload.count;
                Write-Progress -activity "Base Source" -status "Files $counter2 of $total2" -PercentComplete (($counter2 / $total2)  * 100);
                Get-ObjectsFromTFSBranch -BranchPath "$BaseTarget/$DItem" -DestinationPath $WorkFolder\$BaseTargetF\$DItem -Type File
                $counter2 += 1;
            }
        }

        if(($SkipQuestions -eq 'False') -or ($SkipQuestions -eq ''))
        {$intAnswer = $popup.popup("Do you want to download Customer Database objects?", 0,"Download objects",4) }
        else
        {$intAnswer = 6}                
        If ($intAnswer -eq 6) 
        {
            $counter2 = 1
            foreach ($DItem in $ObjToDownload)
            {
                $total2 = $ObjToDownload.count;
                Write-Progress -activity "Base Source" -status "Files $counter2 of $total2" -PercentComplete (($counter2 / $total2)  * 100);
                Get-ObjectsFromTFSBranch -BranchPath "$CustomerDB/$DItem" -DestinationPath $WorkFolder\$CustomerDBF\$DItem -Type File
                $counter2 += 1;
            }
        }
               
    }
    Catch
    {
        Write-Host 'Error: '$_ 
        for ($i = 0; $i -lt 3; $i ++) {
        [System.Console]::Beep(1000, 500)
        [System.Console]::Beep(1500, 500)
        }
        break;
    }
    $counter1 += 1;
    $collection = @() 
    Write-Progress -activity "Upgrade Wizard" -status "Step $counter1 of $total (Upgrade)" -PercentComplete (($counter1 / $total)  * 100);    
    Try
    {
        if(($SkipQuestions -eq 'False') -or ($SkipQuestions -eq ''))
        {$intAnswer = $popup.popup("Do you want to do the upgrade process?", 0,"Upgrade",4) }
        else
        {$intAnswer = 6}                
        
        If ($intAnswer -eq 6) 
        {
            $collection = Merge-NAVObjectsWithPropertiesUW -workFolder $WorkFolder -sourceBaseFolder $BaseSourceF -sourceModFolder $CustomerDBF -targetBaseFolder $BaseTargetF -resultFolder Result
        }
       
    }
    Catch
    {
        Write-Host 'Error: '$_ 
        for ($i = 0; $i -lt 3; $i ++) {
        [System.Console]::Beep(1000, 500)
        [System.Console]::Beep(1500, 500)
        }
        break;
    }    

    $summary = @()   
    $path = "$WorkFolder\Result\"
    $TotalNoOfObj = 0
    $TotalNoOfConfObj = 0
    $TotalNoOfConf = 0
    $TotalTime = 0

    $FixTimes = @(("Codeunit", 5), ("XMLPort", 5), ("Query", 5), ("MenuSuite", 7), ("Page", 10), ("Report", 8), ("Table", 4))
    foreach ($obj in $collection) 
    {
        $short = $obj.ObjectName.Substring(0,3)              
        $ObjTotal = (dir $path"$short*.TXT" | measure).Count
        $ObjConflicted = (dir $path"$short*.CONFLICT" | measure).Count
        $minutes = 0
        foreach ($min in $FixTimes) {
            if ($min[0] -eq $obj.ObjectName)
            {
                $minutes = $min[1]
            }
        }
        $out = new-object psobject
        $out | add-member noteproperty "Object Name" $obj.ObjectName
        $out | add-member noteproperty "No of objects" $ObjTotal; 
        $out | add-member noteproperty "No of conflicted objects" $ObjConflicted; 
        $out | add-member noteproperty "No of conflicts" $obj.Total; 
        $out | add-member noteproperty "Minutes to fix 1 conflict" $minutes;
        [decimal]$linetime = $obj.Total
        $linetime = $linetime * $minutes;
        $out | add-member noteproperty "Total minutes" $linetime
        $summary += $out
        $TotalNoOfObj += $ObjTotal
        $TotalNoOfConfObj += $ObjConflicted
        $TotalNoOfConf += $obj.Total
        $TotalTime += $linetime
    }

        $out = new-object psobject
        $lineSep = '----------'
        $out | add-member noteproperty "Object Name" $lineSep
        $out | add-member noteproperty "No of objects" $lineSep
        $out | add-member noteproperty "No of conflicted objects" $lineSep
        $out | add-member noteproperty "No of conflicts" $lineSep
        $out | add-member noteproperty "Minutes to fix 1 conflict" $lineSep
        $out | add-member noteproperty "Total minutes" $lineSep
        $summary += $out

        $out = new-object psobject
        $out | add-member noteproperty "Object Name" ">> TOTAL <<"
        $out | add-member noteproperty "No of objects" $TotalNoOfObj
        $out | add-member noteproperty "No of conflicted objects" $TotalNoOfConfObj
        $out | add-member noteproperty "No of conflicts" $TotalNoOfConf
        $out | add-member noteproperty "Minutes to fix 1 conflict" "Minutes:"
        $out | add-member noteproperty "Total minutes" $TotalTime
        $summary += $out

        $out = new-object psobject
        $out | add-member noteproperty "Object Name" " "
        $out | add-member noteproperty "No of objects" " "
        $out | add-member noteproperty "No of conflicted objects" " "
        $out | add-member noteproperty "No of conflicts" " "
        $out | add-member noteproperty "Minutes to fix 1 conflict" "Hours:"
        $hours = [math]::Round($TotalTime/60, 1)
        $out | add-member noteproperty "Total minutes" $hours
        $summary += $out

        $out = new-object psobject
        $out | add-member noteproperty "Object Name" " "
        $out | add-member noteproperty "No of objects" " "
        $out | add-member noteproperty "No of conflicted objects" " "
        $out | add-member noteproperty "No of conflicts" " "
        $out | add-member noteproperty "Minutes to fix 1 conflict" "Days:"
        [decimal]$daypart = (($hours/7) % 1)
        [decimal]$daypart2 = 0
        if ($daypart -lt 0.5)
        {
            $daypart2 = 0.5
        }
        else
        {
            $daypart2 = 1
        }
        [decimal]$days2 = [math]::Floor($hours/7) + $daypart2

        $out | add-member noteproperty "Total minutes" $days2
        $summary += $out
    Write $summary |Out-GridView
    
}

function UW-Get-TFSFolders
(
    [Parameter(Mandatory=$false)]
    [string]$LevelPath,
    [Parameter(Mandatory=$false)]
    [string]$Desc,
    [Parameter(Mandatory=$false)]
    [int]$Level

)
{
    Add-Type -Assembly Microsoft.VisualBasic
  
   $ItemCollection = New-Object System.Collections.Generic.List[System.String]
   $ItemDictionary = New-Object "System.Collections.Generic.Dictionary``2[System.Int32, System.String]"
   [string] $URLString = '';
   if ($LevelPath -ne '') {
       $URLString = '_apis/tfvc/items?scopePath=' + $LevelPath + '&recursionLevel=OneLevel&isFolder=true'
   }
   else
   {
       $URLString = "_apis/tfvc/items?recursionLevel=OneLevel&isFolder=true"
   }
   
    $Folders = Invoke-TFSAPIUW -Url $URLString
    
    [int]$num = 1;
    [bool]$isFound = 0;
    [int]$Lines = 10;
    [int]$counter = 0;
    [int]$inputInt = 0;
    
    foreach ($Folder in $Folders.value)
    {   
        if (($Folder.IsFolder) -and ($Folder.path -ne $LevelPath)) {
            if (($Folder.path -notlike '*$/Addition*') -and ($Folder.path -notlike '*$/Mobile Apps*') -and ($Folder.path -notlike '*BuildProcessTemplates*') `
            -and ($Folder.path -notlike '$/')) {
                $ItemCollection.Add($Folder.path);
            }
        }      
    }

    $ItemCollection.Sort();
    
    foreach ($SItem in $ItemCollection)
    {
        $ItemDictionary.Add($num, $SItem);
        $num = $num + 1;
        $isFound = 1;
    }
$PickValue = $ItemDictionary| Out-GridView -Title $Desc -OutputMode Single
[string]$tmpVal = $PickValue.Key;
if ($tmpVal -eq '') 
{
    write-host 'Canceled by the user'
    break

}
else
{
$inputInt = [int]$tmpVal;
}

    $errInput = 0;
    while($errInput -eq 0)
    {
        IF ($isFound -ne 0)
        {
            if ($inputInt -eq '')
            {                                
                if ((-not [Microsoft.VisualBasic.Information]::IsNumeric($inputInt)) -or ($inputInt -eq ''))
                {
                    $inputInt = 0
                }
            }            
            if ($level -lt 1)
            {             
                                             
                if (([int]$inputInt -gt 0) -and ([int]$inputInt -le $ItemCollection.Count))
                {
                    $errInput = 1
                    $level = $Level + 1;
                    UW-Get-TFSFolders -LevelPath $ItemCollection[$inputInt-1] -Desc "details..." -Level $level
                }
                else
                {
                    $inputInt = 0
                }
            }
            else
            {                
                if (([int]$inputInt -gt 0) -and ([int]$inputInt -le $ItemCollection.Count))
                {
                    $errInput = 1 
                    #return $LevelPath
                    return $ItemCollection[$inputInt-1]                  
                }
                else
                {
                    $inputInt = 0                    
                }
            }
        }
        else
        {
            $errInput = 1;            
        }
        
    }                
}

function UW-RemoveCharFromString
(
    [Parameter(Mandatory=$true)]
    [string]$Text
)
{
    $Text = $Text.Replace('/', '').Replace('$','').Replace(' ', '').Replace('-', '')
    return $Text
}

Function UW-CreateDirectory
{
    Param(
        [Parameter(Mandatory=$true)]
        [string]$DirectoryPath
    )
    [IO.Directory]::CreateDirectory($DirectoryPath) | Out-Null
}

Export-ModuleMember -Function UpgradeWizard