Private/_MainFunctions.ps1

function Set-ColourOption(
    [string]$value
) {
    if ($value -eq "False") { 
        return "White" 
    } 
    elseif ($value -eq "Error") {
        return "Red"
    }
    elseif ($value -eq "Optional") {
        return "Magenta"
    }
    else { return "Green" }
}

function Install-XrmModule {
    $moduleName = "Microsoft.Xrm.Data.Powershell"
    $moduleVersion = "2.8.8"
    $module = Get-Module -ListAvailable -Name $moduleName
    if (!($module.Version -ge $moduleVersion )) {
        Write-host "Module $moduleName version $moduleVersion or higher not found, installing now"
        Install-Module -Name $moduleName -MinimumVersion $moduleVersion -Force -AllowClobber
    }
    else {
        Write-host "Module $moduleName Found"
        Import-Module -Name $moduleName -MinimumVersion $moduleVersion -Force 
    }
}

function Install-PowerAppsAdmin {
    $moduleName = "Microsoft.PowerApps.Administration.PowerShell"
    $moduleVersion = "2.0.66"
    $module = Get-Module -ListAvailable -Name $moduleName
    if (!($module.Version -ge $moduleVersion )) {
        Write-host "Module $moduleName version $moduleVersion or higher not found, installing now"
        Install-Module -Name $moduleName -MinimumVersion $moduleVersion -Force -AllowClobber
    }
    else {
        Write-host "Module $moduleName version $moduleVersion or higher Found"
        Import-Module -Name $moduleName -MinimumVersion $moduleVersion -Force 
    }
}

function Install-PowerAppsPowerShell {
    $moduleName = "Microsoft.PowerApps.PowerShell"
    $moduleVersion = "1.0.13"
    $module = Get-Module -ListAvailable -Name $moduleName
    if (!($module.Version -ge $moduleVersion )) {
        Write-host "Module $moduleName version $moduleVersion or higher not found, installing now"
        Install-Module -Name $moduleName -MinimumVersion $moduleVersion -Force -AllowClobber
    }
    else {
        Write-host "Module $moduleName Found"
        Import-Module -Name $moduleName -MinimumVersion $moduleVersion -Force 
    }
}

function Install-XrmToolingPowerShell {
    $moduleName = "Microsoft.Xrm.Tooling.CrmConnector.PowerShell"
    $moduleVersion = "3.3.0.899"
    $module = Get-Module -ListAvailable -Name $moduleName
    if (!($module.Version -ge $moduleVersion )) {
        Write-host "Module $moduleName version $moduleVersion or higher not found, installing now"
        Install-Module -Name $moduleName -MinimumVersion $moduleVersion -Force -AllowClobber
    }
    else {
        Write-host "Module $moduleName Found"
        Import-Module -Name $moduleName -MinimumVersion $moduleVersion -Force 
    }
}

function Format-Json {
    <#
  .SYNOPSIS
      Prettifies JSON output.
  .DESCRIPTION
      Reformats a JSON string so the output looks better than what ConvertTo-Json outputs.
  .PARAMETER Json
      Required: [string] The JSON text to prettify.
  .PARAMETER Minify
      Optional: Returns the json string compressed.
  .PARAMETER Indentation
      Optional: The number of spaces (1..1024) to use for indentation. Defaults to 4.
  .PARAMETER AsArray
      Optional: If set, the output will be in the form of a string array, otherwise a single string is output.
  .EXAMPLE
      $json | ConvertTo-Json | Format-Json -Indentation 2
  #>

    [CmdletBinding(DefaultParameterSetName = 'Prettify')]
    Param(
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
        [string]$Json,

        [Parameter(ParameterSetName = 'Minify')]
        [switch]$Minify,

        [Parameter(ParameterSetName = 'Prettify')]
        [ValidateRange(1, 1024)]
        [int]$Indentation = 4,

        [Parameter(ParameterSetName = 'Prettify')]
        [switch]$AsArray
    )

    if ($PSCmdlet.ParameterSetName -eq 'Minify') {
        return ($Json | ConvertFrom-Json) | ConvertTo-Json -Depth 100 -Compress
    }

    # If the input JSON text has been created with ConvertTo-Json -Compress
    # then we first need to reconvert it without compression
    if ($Json -notmatch '\r?\n') {
        $Json = ($Json | ConvertFrom-Json) | ConvertTo-Json -Depth 100
    }

    $indent = 0
    $regexUnlessQuoted = '(?=([^"]*"[^"]*")*[^"]*$)'

    $result = $Json -split '\r?\n' |
    ForEach-Object {
        # If the line contains a ] or } character,
        # we need to decrement the indentation level unless it is inside quotes.
        if ($_ -match "[}\]]$regexUnlessQuoted") {
            $indent = [Math]::Max($indent - $Indentation, 0)
        }

        # Replace all colon-space combinations by ": " unless it is inside quotes.
        $line = (' ' * $indent) + ($_.TrimStart() -replace ":\s+$regexUnlessQuoted", ': ')

        # If the line contains a [ or { character,
        # we need to increment the indentation level unless it is inside quotes.
        if ($_ -match "[\{\[]$regexUnlessQuoted") {
            $indent += $Indentation
        }

        $line
    }

    if ($AsArray) { return $result }
    return $result -Join [Environment]::NewLine
}

Function Invoke-Menu() {    
    Param(
        [Parameter(Mandatory = $True)][String]$MenuTitle,
        [Parameter(Mandatory = $True)][array]$MenuOptions
    )
    $MaxValue = $MenuOptions.count - 1
    $Selection = 0
    $EnterPressed = $False
    
    Clear-Host

    While ($EnterPressed -eq $False) { 
        Write-Host "$MenuTitle"
        For ($i = 0; $i -le $MaxValue; $i++) {            
            If ($i -eq $Selection) {
                Write-Host -BackgroundColor Cyan -ForegroundColor Black "[ $($MenuOptions[$i]) ]"
            }
            Else {
                Write-Host " $($MenuOptions[$i]) "
            }
        }
        $KeyInput = $host.ui.rawui.readkey("NoEcho,IncludeKeyDown").virtualkeycode
        Switch ($KeyInput) {
            13 {
                $EnterPressed = $True
                Return $Selection
                Clear-Host
                break
            }
            38 {
                If ($Selection -eq 0) {
                    $Selection = $MaxValue
                }
                Else {
                    $Selection -= 1
                }
                Clear-Host
                break
            }
            40 {
                If ($Selection -eq $MaxValue) {
                    $Selection = 0
                }
                Else {
                    $Selection += 1
                }
                Clear-Host
                break
            }
            Default {
                Clear-Host
            }
        }
    }
}

function Copy-GitRepoFromTemplate {
    Write-Host "Select a folder to create a new git Repository for your Power Platform Project"
    try {
        $application = New-Object -ComObject Shell.Application
        $path = ($application.BrowseForFolder(0, 'Select a folder', 0)).Self.Path
        $global:projectLocation = "$path\$global:gitRepo"
    
        if (!(Test-Path -Path "$global:projectLocation") -and !($null -eq $path)) {
            Write-Host "Creating Project Folder"
            New-Item -Path $path -Name $global:gitRepo -ItemType Directory
            Copy-Item -Path (Join-Path $PSScriptRoot emptyProject.json) -Destination $global:projectLocation\$global:gitRepo.json
            $newProject = @([ordered]@{ID = $global:configfile.Projects.Count; Name = $global:gitRepo; ProjectLocation = "$global:projectLocation" })
            $global:configfile.Projects += $newProject
            $global:configfile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json")
            $global:projectFile = Get-Content ("$global:projectLocation\$global:gitRepo.json") | ConvertFrom-Json
            Set-Location -Path "$global:projectLocation" 
              
    
            $message = "Setting up PowerPlatformCICD locally"
            Write-Host $message
    
            Remove-Item -Path (Join-Path $PSScriptRoot ..\FrameworkTemplate\node_modules) -Recurse -Force -ErrorAction Ignore  
            Copy-Item -Path (Join-Path $PSScriptRoot ..\FrameworkTemplate\*) -Destination $global:projectLocation\ -Recurse -Force
        
            $message = "Confirming Git User Details"
            Write-Host $message
    
            $GitUser = git config --global user.name
            $GitEmail = git config --global user.email
    
            If ($null -eq $GitUser) {
                $GitUser = Read-Host "Enter your name (to use when committing changes to Git)"
                git config --global user.name $GitUser
            }
    
            If ($null -eq $GitEmail) {
                $GitEmail = Read-Host "Enter your email address (to use when committing changes to Git)"
                git config --global user.email $GitEmail
            }  
    
            Remove-Item .git -Recurse -Force -ErrorAction SilentlyContinue
    
            git init

            Write-Host "Updating Build.yaml ..."
            (Get-Content -Path $global:projectLocation\build.yaml) -replace "replaceRepo", $global:gitRepo | Set-Content -Path $global:projectLocation\build.yaml

            Write-Host "Rename PowerPlatformDevOps.sln to $global:gitRepo.sln"
            Rename-Item -Path $global:projectLocation\PowerPlatformDevOps.sln -NewName "$global:gitRepo.sln"
            $global:projectFile.gitRepo = $global:gitRepo
            $global:projectFile | ConvertTo-Json | Set-Content ("$global:projectLocation\$global:gitRepo.json") 
    
        }
        else {
            Write-Warning "The Path $global:projectLocation already exists, please select a different path or project name"
            $continue = Read-Host -Prompt "Press [Enter] to Continue or [Q] to Quit"
            if (!$continue -eq 'Q') {
            }
        } 
    }
    catch {
    
    }
}
function Add-GitRepo {
    do {
        $global:gitRepo = Read-Host -Prompt "Please enter a Name for the Git Repository you wish to Create"
    }until ($global:gitRepo -ne "")
  
    if (!(Test-Path $env:APPDATA\Microsoft.PowerPlatform.DevOps)) {
        New-Item -Path $env:APPDATA\Microsoft.PowerPlatform.Devops -ItemType Directory
    }
    if (!($global:configfile.PSobject.Properties.Project -contains "Name") -or !($global:configfile.Projects.Name.Contains($global:gitRepo))) {
        Copy-GitRepoFromTemplate
        pause
    }
    else {
        Write-Host "You already have a repo called $global:gitRepo, please select a different name"
        $global:gitRepo = ""
        Add-GitRepo
    }
}

function Select-GitRepo {
    if ($global:configfile.Projects.Count -gt 0) {
        $options = $global:configfile.Projects | ForEach-Object { "$($_.Name)" }

        do {
            $sel = Invoke-Menu -MenuTitle "---- Please Select your Project ------" -MenuOptions $options
            $selectedRepo = $global:configfile.Projects[$sel].Name
        } until ($selectedRepo -ne "")
        if (($global:configfile.Projects[$sel].PSobject.Properties.Name -contains "ProjectLocation")) {
            $global:projectFile = Get-Content ("$($global:configfile.Projects[$sel].ProjectLocation)\$selectedRepo.json") | ConvertFrom-Json 
            $global:projectLocation = $global:configfile.Projects[$sel].ProjectLocation
        }
        else {
            $global:projectFile = Get-Content ("$env:APPDATA\Microsoft.PowerPlatform.Devops\$selectedRepo\$selectedRepo.json") | ConvertFrom-Json
            $global:projectLocation = $global:projectFile.ProjectLocation
            if (! (Test-Path -Path "$global:projectLocation\$selectedRepo.json")) {
                Copy-Item -Path "$env:APPDATA\Microsoft.PowerPlatform.Devops\$selectedRepo\$selectedRepo.json" -Destination " $global:projectLocation\"            
            }
            $updatedProject = [ordered]@{ID = $global:configfile.Projects[$sel].ID; Name = $global:configfile.Projects[$sel].Name; ProjectLocation = $global:projectLocation }
            $global:configfile.Projects[$sel] = $updatedProject
            $global:configfile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json")
            $global:projectFile = Get-Content ("$global:projectLocation\$selectedRepo.json") | ConvertFrom-Json
        }
         
        Set-Location  $global:projectLocation
        $global:projectTitle = $global:projectFile.gitRepo
        $global:gitRepo = $global:projectFile.gitRepo
            
    }
    else {
        Write-Host "You don't have any Projects set up, please Add a new one or Clone an existing Repo"
        pause
    }

}

function Clone-GitRepo {
    $regEx = '(http[s]?|[s]?ftp[s]?)(:\/\/)([^\s,]+)'

    do {
        $repoURL = Read-Host "Please enter the git clone URL"
    } until ($repoURL -ne "" -and $repoURL -match $regEx)  
    
    $application = New-Object -ComObject Shell.Application
    $path = ($application.BrowseForFolder(0, "Select a folder to Clone your $selectedRepo Repo to", 0)).Self.Path

    $repoFinder = $repoURL -split "/"
    $selectedRepo = $repoFinder[$repoFinder.Count - 1].Replace('.git', '')
    $global:gitRepo = $selectedRepo
    Write-Host $selectedRepo

    Write-host $path
    Write-Host $repoURL

    . git clone $repoURL $path\$global:gitRepo
    $global:projectLocation = "$path\$selectedRepo"

    if (!(Test-Path -Path "$global:projectLocation\$selectedRepo.json")) {
        Copy-Item -Path (Join-Path $PSScriptRoot emptyProject.json) -Destination $global:projectLocation\$selectedRepo.json
        $global:projectFile = Get-Content ("$global:projectLocation\$selectedRepo.json") | ConvertFrom-Json
        $global:projectFile.gitRepo = $global:gitRepo
        $global:projectFile | ConvertTo-Json | Set-Content ("$global:projectLocation\$global:gitRepo.json")            
    }
    $newProject = [ordered]@{ID = $global:configfile.Projects.Count; Name = $selectedRepo; ProjectLocation = $global:projectLocation }
    $global:configfile.Projects += $newProject
    $global:configfile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json")
    $global:projectFile = Get-Content ("$global:projectLocation\$global:gitRepo.json") | ConvertFrom-Json
     
    Set-Location  $global:projectLocation
    $global:projectTitle = $global:projectFile.gitRepo

    pause
}

function Get-GitRepo {
    if (!(Test-Path $env:APPDATA\Microsoft.PowerPlatform.DevOps)) {
        New-Item -Path $env:APPDATA\Microsoft.PowerPlatform.Devops -ItemType Directory
    }

    $application = New-Object -ComObject Shell.Application
    $path = ($application.BrowseForFolder(0, "Select the location of your Existing Project", 0)).Self.Path

    $repoFinder = $path -split "\\"
    $selectedRepo = $repoFinder[$repoFinder.Count - 1]
    Write-Host $selectedRepo
    Write-Host $path\$selectedRepo.json
    
    if ((Test-Path -Path "$path\$selectedRepo.json"))
    {
        $global:projectLocation = "$path"

        $global:projectFile = Get-Content ("$path\$selectedRepo.json") | ConvertFrom-Json
        $newProject = [ordered]@{ID = $global:configfile.Projects.Count; Name = $selectedRepo; ProjectLocation = $global:projectLocation }
        $global:configfile.Projects += $newProject
        $global:configfile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json")
        $global:gitRepo = $global:projectFile.gitRepo
        Set-Location  $global:projectLocation
    }
    else {
        Write-Host "$path is not a valid Project Location, please Add a new one or Clone an existing Repo"
    }

}