Private/Add-Solution.ps1

function Invoke-SolutionAdder {

    $message = "Connecting to Power Platform"
    Write-Host $message
    do {
        $sel = Invoke-Menu -MenuTitle "---- Connecting to Power Platform ------" -MenuOptions "Continue", "Quit"
        
     } until ($sel -ge 0)

    if ($sel -eq 1) {
        exit
    }

    Install-XrmToolingPowerShell
    Install-XrmModule

    $message = "Connecting to Development Environment"
    Write-Host $message
    
    Write-Host ""
    Write-Host "---- Enter the Credentials for your Development Environment ------"
    if (!$Credentials) {
        Do {
            $Credentials = Get-Credential -Message "Enter Credentials to Connect to D365 / Power Platform"
        } Until (($Credentials.GetNetworkCredential().UserName -ne "") -and ($Credentials.GetNetworkCredential().Password -ne "")) 
    }
    if (!$username) {
        $username = $Credentials.GetNetworkCredential().UserName
        $password = $Credentials.GetNetworkCredential().Password
    }

    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
    $connDev = Get-CrmOrganizations -OnLineType OAuth -Credential $Credentials
    $options = $connDev | ForEach-Object {"$($_.FriendlyName) ($($_.WebApplicationUrl))"}
    
     do {
        $sel = Invoke-Menu -MenuTitle "---- Please Select your Development Environment ------" -MenuOptions $options
        $DevEnvironment = $connDev[$sel]
        $conn = Get-CrmConnection -OnlineType OAuth -Credential $Credentials -OrganizationName $DevEnvironment.UniqueName
     } until ($DevEnvironment -ne "")
     Write-Host $DevEnvironment.WebApplicationUrl

    $message = "Create a New Solution or Select existing"

    do {
        $sel = Invoke-Menu -MenuTitle "---- $message ------" -MenuOptions "Create New", "Select Existing"
        
     } until ($sel -ge 0)

    if ($sel -eq 0) {

        $message = "Creating Solution and Publisher"
        Write-Host $message

        $message = "Create or select a Solution Publisher"
        do {
            $sel = Invoke-Menu -MenuTitle "---- $message ------" -MenuOptions "Create New", "Select Existing"
            
         } until ($sel -ge 0)

        if ($sel -eq 0) {
       
            do {
                $PublisherName = Read-Host -Prompt "Enter a Name for your Solution Publisher"
            }until($PublisherName -ne "")

            do {
                $PublisherPrefix = Read-Host -Prompt "Enter a Publisher Prefix"
            }until($PublisherPrefix -ne "")

            $PublisherId = New-CrmRecord -EntityLogicalName publisher -Fields @{"uniquename" = $PublisherName.Replace(' ', ''); "friendlyname" = $PublisherName; "customizationprefix" = $PublisherPrefix.Replace(' ', '').ToLower() }
            $PubLookup = New-CrmEntityReference -EntityLogicalName publisher -Id $PublisherId.Guid
        }
        else {
            $publisherFetch = @"
    <fetch>
    <entity name='publisher' >
        <filter type='and' >
        <condition attribute='isreadonly' operator='eq' value='false' />
        </filter>
    </entity>
    </fetch>
"@


            $publishers = (Get-CrmRecordsByFetch -conn $conn -Fetch $publisherFetch).CrmRecords
            $options = $publishers | ForEach-Object {$($_.friendlyname)}  

            do {
                $choice = Invoke-Menu -MenuTitle "---- Select Publisher ------" -MenuOptions $options
                $chosenPublisher = $publishers[$choice].customizationprefix
             } until ($chosenPublisher -ne "")
                        if ($null -ne $chosenPublisher) {
                            $PublisherPrefix = $publishers[$choice].customizationprefix
                            $PubLookup = New-CrmEntityReference -EntityLogicalName publisher -Id $publishers[$choice].publisherid
                        }
                        else {
                            Write-Host "Invalid selection (index out of range)"
                        }
                   
                        do {
            $SolutionName = Read-Host -Prompt "Enter a Name for your Unmanaged Development Solution"    
        }until ($SolutionName -ne "")

        $SolutionId = New-CrmRecord -EntityLogicalName solution -Fields @{"uniquename" = $SolutionName.Replace(' ', ''); "friendlyname" = $SolutionName; "version" = "1.0.0.0"; "publisherid" = $PubLookup }
        $chosenSolution = $SolutionName.Replace(' ', '')
    }
}
    else {

        $solutionFetch = @"
    <fetch>
    <entity name='solution' >
        <filter type='and' >
        <condition attribute='ismanaged' operator='eq' value='0' />
        <condition attribute='isvisible' operator='eq' value='1' />
        </filter>
    </entity>
    </fetch>
"@


        $solutions = (Get-CrmRecordsByFetch -conn $conn -Fetch $solutionFetch).CrmRecords
        $options = $solutions | ForEach-Object { $($_.uniquename) }  
        do {
            $choice = Invoke-Menu -MenuTitle "---- Select Solution ------" -MenuOptions $options
            $chosenSolution = $solutions[$choice].uniquename
         } until ($chosenSolution -ne "")

                    if ($null -ne $chosenSolution) {
                        $PublisherPrefix = (Get-CrmRecord -conn $conn -EntityLogicalName publisher -Id $solutions[$choice].publisherid_Property.Value.Id -Fields customizationprefix).customizationprefix
                    }
                    else {
                        Write-Host "Invalid selection (index out of range)"
                    }
                }
    #update values in Solution files
    $TextInfo = (Get-Culture).TextInfo

    $message = "Copying Solution Template to New $chosenSolution Project"
    Write-Host $message

    Remove-Item -Path ".\SolutionTemplate\node_modules", ".\SolutionTemplate\.awcache", ".\SolutionTemplate\bin", ".\SolutionTemplate\dist", ".\SolutionTemplate\obj" -Recurse -Force -ErrorAction SilentlyContinue
    Copy-Item -Path .\SolutionTemplate\. -Destination $chosenSolution -Recurse 

    $message = "Setting Configurations in Source Code"
    Write-Host $message

    Write-Host "Updating config.json ..."
    (Get-Content -Path .\$chosenSolution\Scripts\config.json) -replace "https://AddServer.crm6.dynamics.com", $DevEnvironment.WebApplicationUrl | Set-Content -Path .\$chosenSolution\Scripts\config.json
    (Get-Content -Path .\$chosenSolution\Scripts\config.json) -replace "AddName", $chosenSolution | Set-Content -Path .\$chosenSolution\Scripts\config.json
    (Get-Content -Path .\$chosenSolution\Scripts\_GenerateTypes.ps1) -replace "ProjName", $chosenSolution | Set-Content -Path .\$chosenSolution\Scripts\_GenerateTypes.ps1
    (Get-Content -Path .\$chosenSolution\package.json) -replace "solutiontemplate", $chosenSolution | Set-Content -Path .\$chosenSolution\package.json

    Write-Host "Updating spkl.json ..."
    (Get-Content -Path .\$chosenSolution\spkl\spkl.json) -replace "AddName", $chosenSolution | Set-Content -Path .\$chosenSolution\spkl\spkl.json
    (Get-Content -Path .\$chosenSolution\spkl\spkl.json) -replace "prefix", $PublisherPrefix.Replace(' ', '').ToLower() | Set-Content -Path .\$chosenSolution\spkl\spkl.json

    Write-Host "Updating ImportConfig.xml ..."
    Move-Item .\$chosenSolution\Deployment\FeatureTemplate .\$chosenSolution\Deployment\$chosenSolution
    Move-Item .\$chosenSolution\Deployment\FeatureTemplatePackage.cs .\$chosenSolution\Deployment\$($chosenSolution)Package.cs  
    (Get-Content -Path .\$chosenSolution\Deployment\$chosenSolution\ImportConfig.xml) -replace "AddName", $chosenSolution | Set-Content -Path .\$chosenSolution\Deployment\$chosenSolution\ImportConfig.xml
    (Get-Content -Path .\$chosenSolution\Deployment\$($chosenSolution)Package.cs) -replace "AddName", $chosenSolution | Set-Content -Path .\$chosenSolution\Deployment\$($chosenSolution)Package.cs
    (Get-Content -Path .\$chosenSolution\Compile.bat) -replace "FeatureTemplate", $chosenSolution | Set-Content -Path .\$chosenSolution\Compile.bat
    (Get-Content -Path .\$chosenSolution\webpack.config.js) -replace "AddName", $chosenSolution.ToLower() | Set-Content -Path .\$chosenSolution\webpack.config.js -ErrorAction Ignore

    Write-Host "Updating XrmContext.exe.config ..."
    (Get-Content -Path .\$chosenSolution\XrmContext\XrmContext.exe.config) -replace "AddName", $chosenSolution | Set-Content -Path .\$chosenSolution\XrmContext\XrmContext.exe.config

    Write-Host "Updating XrmDefinitelyTyped.exe.config ..."
    (Get-Content -Path .\$chosenSolution\XrmDefinitelyTyped\XrmDefinitelyTyped.exe.config) -replace "AddName", $chosenSolution | Set-Content -Path .\$chosenSolution\XrmDefinitelyTyped\XrmDefinitelyTyped.exe.config

    Write-Host "Rename SolutionTemplate.csproj to $chosenSolution.csproj"
    Rename-Item -Path .\$chosenSolution\SolutionTemplate.csproj -NewName "$chosenSolution.csproj"

    Write-Host "Rename SolutionTemplate.snk to $chosenSolution.snk"
    Rename-Item -Path .\$chosenSolution\SolutionTemplate.snk -NewName "$chosenSolution.snk"

    Write-Host "Updating $chosenSolution.csproj ..."
    (Get-Content -Path .\$chosenSolution\$chosenSolution.csproj) -replace "FeatureTemplate", $chosenSolution | Set-Content -Path .\$chosenSolution\$chosenSolution.csproj
    (Get-Content -Path .\$chosenSolution\$chosenSolution.csproj) -replace "SolutionTemplate", $chosenSolution | Set-Content -Path .\$chosenSolution\$chosenSolution.csproj

    Write-Host "Update Sample Plugin NameSpace"
    (Get-Content -Path .\$chosenSolution\Plugins\Users\SamplePlugin.cs) -replace "AddName", $chosenSolution | Set-Content -Path .\$chosenSolution\\Plugins\Users\SamplePlugin.cs -ErrorAction Ignore

    (Get-Content -Path .\$chosenSolution\map.xml) -replace "PowerPlatformDevOpsPlugins", ($chosenSolution) | Set-Content -Path .\$chosenSolution\map.xml


    Write-Host "Adding Solution to packageDeploy.json"
    $packagesToDeploy = Get-Content .\deployPackages.json | ConvertFrom-Json
    $deployTo = @([ordered]@{EnvironmentName = "Deployment Staging"; DeploymentType = "Managed"; DeployData = "true"; PreAction = "false"; PostAction = "false" })
    if ($packagesToDeploy.Count -gt 0) {
        $packagesToDeploy += [ordered]@{DestinationFolder = $chosenSolution; PackageFolder = $chosenSolution; PackageName = "$($chosenSolution)Package.dll"; SolutionName = $chosenSolution; DeploymentSteps = ""; DeployTo = $deployTo }     
        ConvertTo-Json -Depth 3 $packagesToDeploy | Format-Json | Out-File .\deployPackages.json
    }
    else {
        ConvertTo-Json -Depth 3 @(@{DestinationFolder = $chosenSolution; PackageFolder = $chosenSolution; PackageName = "$($chosenSolution)Package.dll"; SolutionName = $chosenSolution; DeploymentSteps = ""; DeployTo = $deployTo }) | Format-Json | Out-File .\deployPackages.json
    }

    Set-Location -Path  .\$chosenSolution
    
    Write-Host "Adding $chosenSolution Project to Solution"
    Set-Location .\..
    $sln = Get-ChildItem *.sln
    dotnet sln $sln.Name add $chosenSolution\$chosenSolution.csproj
    dotnet sln $sln.Name remove SolutionTemplate\SolutionTemplate.csproj

    git add -A
    git commit -m "Added Solution $chosenSolution"

    $global:projectFile.CDSSolutions += [ordered]@{SolutionName = $chosenSolution; ID = $global:projectFile.CDSSolutions.Count }     

    $message = "Complete ... Enjoy !!!"
    Write-Host $message
    pause
}

function Invoke-AddSolution
{
    Param(
    [bool] [Parameter(Mandatory = $false)] $SkipPreReqs = $false
)

$logo = @"
____ ____ _ _ __ ____ ___
| _ \ _____ _____ _ __ | _ \| | __ _| |_ / _| ___ _ __ _ __ ___ | _ \ _____ __/ _ \ _ __ ___
| |_) / _ \ \ /\ / / _ \ '__| | |_) | |/ _` | __| |_ / _ \| '__| '_ ` _ \ | | | |/ _ \ \ / / | | | '_ \/ __|
| __/ (_) \ V V / __/ | | __/| | (_| | |_| _| (_) | | | | | | | | | |_| | __/\ V /| |_| | |_) \__ \
|_| \___/ \_/\_/ \___|_| |_| |_|\__,_|\__|_| \___/|_| |_| |_| |_| |____/ \___| \_/ \___/| .__/|___/
                                                                                                  |_|
 
"@


$solmessage = @"
 
Welcome to the Power Platform DevOps Solution Add script. This script will perform the following steps automatically :
 
- Connect to CDS to Get Solution
- Add Development Solution Project to your Visual Studio Solution
 
ver. $global:version
 
"@


if ($global:configfile.PreReqsComplete -eq "True") {
    $SkipPreReqs = $true
}

#$ProgressPreference = 'SilentlyContinue'
Clear-Host
Write-Host $logo -ForegroundColor Magenta
Write-Host $solmessage -ForegroundColor White

$quit = Read-Host -Prompt "Press Enter to Continue or [Q]uit"
if ($quit -eq "Q") {
    return
}

try {
    Invoke-SolutionAdder    
    $global:projectFile.SolutionAdded = "True"
    $global:projectFile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.Devops\$global:gitRepo\$global:gitRepo.json")

}
catch {
    $global:projectFile.SolutionAdded = "Error"
    $global:projectFile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.Devops\$global:gitRepo\$global:gitRepo.json")
    pause    
}
#$ProgressPreference = 'Continue'
}