public/Add-OSDWorkspaceSubmodule.ps1

function Add-OSDWorkspaceSubmodule {
    <#
    .SYNOPSIS
        Adds a GitHub repository as a submodule to the OSDWorkspace\submodules directory.
 
    .DESCRIPTION
        The Add-OSDWorkspaceSubmodule function adds a GitHub repository as a submodule to the OSDWorkspace submodules directory
        (typically located at C:\OSDWorkspace\submodules).
         
        This function performs the following operations:
        1. Validates administrator privileges
        2. Checks if the URL is a valid GitHub repository with .git extension
        3. Creates the submodules directory if it doesn't exist
        4. Executes 'git submodule add' operation to add the repository
        5. Commits the changes to the OSDWorkspace parent repository
         
        The submodule is added with the repository name extracted from the URL. The destination path will be
        submodules/[RepositoryName] within the OSDWorkspace root directory.
         
        If you need to update an existing submodule, use the Update-OSDWorkspaceSubmodule function instead.
 
    .PARAMETER Url
        The HTTPS URL of the GitHub repository to add as a submodule.
        Must be in the format https://github.com/RepositoryOwner/RepositoryName.git
         
        This parameter is mandatory and is validated to ensure it follows the correct GitHub URL pattern.
        This parameter also supports the aliases 'OriginUrl' and 'CloneUrl'.
 
    .EXAMPLE
        Add-OSDWorkspaceSubmodule -Url 'https://github.com/OSDeploy/osdws-gallery.git'
         
        Adds the OSDWorkspace Gallery as a submodule to the OSDWorkspace submodules directory.
 
    .EXAMPLE
        Add-OSDWorkspaceSubmodule -Url 'https://github.com/OSDeploy/OSDCloud.git' -Verbose
         
        Adds the OSDCloud repository as a submodule with verbose output showing each step of the process.
 
    .OUTPUTS
        None. This function does not generate any output objects.
 
    .NOTES
        Author: David Segura
        Version: 1.0
        Date: April 2025
         
        Prerequisites:
            - Git for Windows must be installed and available in the system's PATH. (https://gitforwindows.org/)
            - PowerShell 7.5 or higher is recommended.
            - The script must be run with administrator privileges.
            - The target OSDWorkspace repository (typically C:\OSDWorkspace) must be initialized as a Git repository.
         
        This function modifies the parent Git repository by adding a submodule and creating a commit.
        After adding the submodule, you may need to initialize and update it using:
        git submodule update --init --recursive
         
        For more information about Git submodules, see:
            https://git-scm.com/docs/git-submodule
            https://git-scm.com/book/en/v2/Git-Tools-Submodules
    #>



    [CmdletBinding()]
    param (
        # GitHub Origin HTTPS URL in the format https://github.com/RepositoryOwner/RepositoryName.git
        [Parameter(Mandatory = $true)]
        [ValidatePattern('^https:\/\/github\.com\/[\w\-]+\/[\w\-]+\.git$')]
        [Alias('OriginUrl', 'CloneUrl')]
        [System.Uri]
        $Url
    )
    #=================================================
    $Error.Clear()
    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Start"
    Initialize-OSDWorkspace
    #=================================================
    # Requires Run as Administrator
    $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
    if (-not $IsAdmin ) {
        Write-Warning "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] This function must be Run as Administrator"
        return
    }
    #=================================================
    # Url must have a .git extension
    if ($Url -notlike '*.git') {
        Write-Warning "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Url must have a .git extension"
        return
    }
    #=================================================
    # Url must be a GitHub hosted repository
    if ($Url.Authority -ne 'github.com') {
        Write-Warning "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Url must be a GitHub hosted repository"
        return
    }
    #=================================================
    # Get Paths
    $OSDWorkspaceRoot = $OSDWorkspace.path
    $LibrarySubmodulePath = $OSDWorkspace.paths.library_submodule
    #=================================================
    # Create submodules
    if (-not (Test-Path $LibrarySubmodulePath -ErrorAction SilentlyContinue)) {
        New-Item -Path $LibrarySubmodulePath -ItemType Directory -Force | Out-Null
    }
    #=================================================
    # Region Build the paths
    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] LibrarySubmodulePath: $LibrarySubmodulePath"

    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Repository Url to Add: $Url"
    
    $RepositoryName = (Split-Path $Url -Leaf).Replace('.git', '')
    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Repository Name to Add: $RepositoryName"

    $Destination = "submodules/$RepositoryName"
    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Repository Destination: $Destination"

    <#
    if (Test-Path -Path "$Destination\.git") {
        Write-Warning "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Destination repository already exists"
        Write-Warning "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Use the Update-OSDWorkspaceSubmodule cmdlet to update this repository"
        return
    }
    #>

    #endregion
    #=================================================
    # Region Git Submodule Add
    # https://git-scm.com/docs/git-submodule
    # https://git-scm.com/book/en/v2/Git-Tools-Submodules
    # git submodule add <URL> <path>

    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Push-Location $OSDWorkspaceRoot"
    Push-Location $OSDWorkspaceRoot

    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] git submodule add $Url submodules/$RepositoryName"
    git submodule add $Url submodules/$RepositoryName

    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] git commit -m `"Add submodule $RepositoryName`""
    git commit -m "Add submodule $RepositoryName"

    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Pop-Location"
    Pop-Location
    #endregion
    #=================================================
    # Region Git Clone
    <#
    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] git clone --verbose --progress --single-branch --depth 1 `"$Source`" `"$Destination`""
    git clone --verbose --progress --single-branch --depth 1 "$Source" "$Destination"
 
    if (Test-Path "$Destination\.git") {
        Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Push-Location `"$Destination`""
        Push-Location "$Destination"
 
        Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] git fetch --verbose --progress --depth 1 origin"
        git fetch --verbose --progress --depth 1 origin
 
        # Can leave this out since this is the first clone
        # Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] git reset --hard origin"
        # git reset --hard origin
 
        Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] git clean -d --force"
        git clean -d --force
 
        Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Pop-Location"
        Pop-Location
    }
    else {
        Write-Warning "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] Failed to clone repository"
    }
    #>

    #endregion
    #=================================================
    Write-Verbose "[$(Get-Date -format G)] [$($MyInvocation.MyCommand.Name)] End"
    #=================================================
}