Module/HelperFunctions/CommonFunctions.ps1

$script:gConfig = '';

Function RunAsAdministrator ($myInvocationDefinition) {
    #Elevate to Administrator if necesarry.
    $myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $myWindowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
    $adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator

    if (!$myWindowsPrincipal.IsInRole($adminRole)) {
        $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
        $newProcess.Arguments = $myInvocationDefinition;
        $newProcess.Verb = "runas";
        [System.Diagnostics.Process]::Start($newProcess);
        exit
    }
}
function CheckNavContainerHelper() {
    if (Get-Module -ListAvailable -Name navcontainerhelper) {
        $returned = ConfirmYesNo -message "Would you like to check for NAVContainerHelper update?" -defaultchoice 1;
        if ($returned -eq $true) {
            Write-Output "Checking for updated NAVContainerHelper"
            Update-module navcontainerhelper
        }
    }
    else {
        Write-Output "Installing NAVContainerHelper"
        install-module navcontainerhelper -Force
    }
}

Function pause ($message) {
    # Check if running Powershell ISE
    if ($psISE) {
        Add-Type -AssemblyName System.Windows.Forms
        [System.Windows.Forms.MessageBox]::Show("$message")
    }
    else {
        Write-Output "$message"
        $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    }
}

function ConfirmYesNo() {
    Param
    (
        [Parameter(Mandatory = $true, Position = 0)]
        [string] $message,
        [Parameter(Mandatory = $true, Position = 1)]
        [int32] $defaultchoice
    )
    $choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes'))
    $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No'))

    $decision = $Host.UI.PromptForChoice($message, "Are you sure you want to proceed?", $choices, $defaultchoice)
    if ($decision -eq 0) {
        return $true;
    }
    else {
        return $false;
    }
}

function GetConfigFilePath {
    Param
    (
        [string] $ConfigFilePath
    )

    IF ([string]::IsNullOrEmpty($ConfigFilePath)) {
        $CurrentLocation = Get-Location;
        return Join-Path $CurrentLocation "config.json";
    }
    else {
        return $ConfigFilePath;
    }
}

function GetConfig {
    Param
    (
        [string] $ConfigFilePath
    )

    IF ([string]::IsNullOrEmpty($ConfigFilePath)) {
        $CurrentLocation = Get-Location;
        $ConfigFilePath = Join-Path $CurrentLocation "config.json";
    }

    return Get-Content $ConfigFilePath | ConvertFrom-Json;
}

function NAVContainerExist() {
    $ContainerName = $script:gConfig.ContainerName;

    $listResult = docker ps -a --filter "name=^/$ContainerName`$" | Measure-Object  
    if ($listResult.Count -eq 2) {
        return $true 
    } 
    else {
        return $false
    } 
}

function NAVContainerIsRunning {
    $ContainerName = $script:gConfig.ContainerName;

    $listResult = docker ps -a --filter status=running --filter "name=^/$ContainerName`$" | Measure-Object

    if ($listResult.Count -eq 2) {
        return $true 
    } 
    else {
        return $false
    } 

    #PARSE DOCKER PS INTO JSON
    #docker container ps --filter status=running --filter "name=^/$script:gContainerName`$" -a --no-trunc --format "{{json .}}" |
    # convertfrom-json |
    # Select-Object ID,@{Name="Name";Expression = {$_.names}},Image, @{Name="Created";Expression = {($_.createdat -split "\s[-+]\d{4}.*")[0] -as [datetime]}}, Networks,Mounts
    
}

function getPathToClientFolder($ContainerName) {
    # Find location of exe
    $exeLocation = Join-Path -Path "C:\ProgramData\NavContainerHelper\Extensions\" -ChildPath $ContainerName
    $exeLocation = Join-Path -Path $exeLocation  -ChildPath "Program Files"

    if (Test-Path $ExeLocation) {
        [string]$navVersion = Get-ChildItem -Name -Path $exeLocation
    }
    
    $exeLocation = Join-Path -Path $exeLocation -ChildPath $navVersion
    $exeLocation = Join-Path -Path $exeLocation -ChildPath "RoleTailored Client"
    return $exeLocation
}

function Update-LaunchJsonFile($ContainerName) {
    Set-Location $Script:gConfig.LocalProjectFolder;
    $Workspace = Get-Content .\EksjohusCustomizations.code-workspace | ConvertFrom-Json
    
    foreach ($folder in $Workspace.folders) {
        $JsonFilePath = ("{0}\.vscode\launch.json" -f $folder.path);
    
        $LaunchJson = Get-Content $JsonFilePath | ConvertFrom-Json;
        $LaunchJson.configurations[0].name = $ContainerName;
        $LaunchJson.configurations[0].server = ("http://{0}" -f $ContainerName);
        $LaunchJson = $LaunchJson | ConvertTo-Json
        Out-File -FilePath $JsonFilePath -InputObject $LaunchJson -Encoding default
    }
}

function Join-SourceCode($DestinationPath) {
    $header = @("commit", "author", "commiter", "Msg") 
    [string] $prettyGitLogDump = (git log --since=4.weeks --pretty=format:'%h|%an|%cn|%s;') 
    
    $gldata = foreach ($commit in $prettyGitLogDump.Replace("; ", ';') -split ";", 0, "multiline") {
        $prop = $commit -split "\|"
        $hash = [ordered]@{}
         
        for ($i = 0; $i -lt $header.count; $i++) {
            $hash.add($header[$i], $prop[$i]) 
        } 
            
        [pscustomobject]$hash
    }
    
    $commits = $gldata[0..($gldata.Length - 2)]
    Write-Host ("Importing files from {0} commits" -f $commits.Count) -ForegroundColor Green;

    $diffarr = @{};
    
    foreach ($commit in $commits) {
        $diffs = git diff --no-commit-id --name-only -r $commit.commit
    
        $diffshort = $diff.Replace("SourceCode/", "");

        foreach ($diff in $diffs) {
            if (-Not $diffarr.ContainsKey($diffshort)) {
                if (Test-Path $diff) {
                    Write-Host (">> {0}" -f $diff);
                    $diffarr.Add($diffshort, $diff);
                }
            }
        }
    }
    
    $diffarr.Values | Join-NAVApplicationObjectFile -Destination $DestinationPath   
}

function GetVersionFromArtifactURL($ArtifactURI) {
    $ArtifactURL = ("{0}{1}" -f $ArtifactURI.Authority, $ArtifactURI.AbsolutePath);
    
    $URISplit = $ArtifactURL.Split("/");
    
    $version = $URISplit[2];
    
    return $version
}

function Create-TemporaryPath {
    [string] $parent = [System.IO.Path]::GetTempPath()
    [string] $name = [System.Guid]::NewGuid()
    #New-Item -ItemType "directory" -Path (Join-Path $parent $name)

    $path = ("{0}\{1}" -f $parent, $name);

    return ($path)
}

function Import-BCModule {
    $serviceValues = Get-CimInstance win32_service | Where-Object{$_.Name -like "*${serverInstance}"} | Select-Object Name, PathName
    $nstPath = Convert-Path $serviceValues.PathName.Split('"')[1]
    $nstPath = [System.IO.DirectoryInfo]$nstPath

    Import-Module (Join-Path $nstPath.Parent.FullName 'Microsoft.Dynamics.Nav.Management.dll') -NoClobber
    Import-Module (Join-Path $nstPath.Parent.FullName 'Microsoft.Dynamics.Nav.Apps.Management.dll') -NoClobber
}

function Convert-ToFormattedDateTime {
    param (
        [Parameter(Mandatory=$true)]
        [string]$dateString
    )

    $culture = [System.Globalization.CultureInfo]::InvariantCulture
    $styles = [System.Globalization.DateTimeStyles]::AssumeLocal

    $inputFormats = @(
        "yyyy-MM-ddTHH:mm:ss.fffffffZ",
        "yyyy-MM-ddTHH:mm:ss.ffffffZ",
        "yyyy-MM-ddTHH:mm:ss.fffffZ",
        "yyyy-MM-ddTHH:mm:ss.ffffZ",
        "yyyy-MM-ddTHH:mm:ss.fffZ",
        "yyyy-MM-ddTHH:mm:ss.ffZ",
        "yyyy-MM-ddTHH:mm:ss.fZ",
        "yyyy-MM-ddTHH:mm:ssZ"
    )

    foreach ($format in $inputFormats) {
        try {
            $dateTime = [DateTime]::ParseExact($dateString, $format, $culture, $styles)
            return "{0:yyyy-MM-dd HH:mm:ss}" -f $dateTime
        }
        catch {
            # If parsing fails, try the next format
        }
    }
}