Public/Import-IntuneMobileApp.ps1

function Import-IntuneMobileApp {
    <#
    .SYNOPSIS
        Imports mobile apps from JSON templates
    .DESCRIPTION
        Reads JSON templates from Templates/MobileApps and creates mobile apps via Graph API.
    .PARAMETER TemplatePath
        Path to the mobile apps template directory (defaults to Templates/MobileApps)
    .PARAMETER RemoveExisting
        If specified, removes existing mobile apps that were created by Intune-Hydration-Kit
    .EXAMPLE
        Import-IntuneMobileApp
    .EXAMPLE
        Import-IntuneMobileApp -RemoveExisting
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter()]
        [string]$TemplatePath,

        [Parameter()]
        [switch]$RemoveExisting
    )

    if (-not $TemplatePath) {
        $TemplatePath = Join-Path -Path $script:TemplatesPath -ChildPath "MobileApps"
    }

    if (-not (Test-Path -Path $TemplatePath)) {
        Write-Warning "MobileApps template directory not found: $TemplatePath"
        return @()
    }

    $templateFiles = Get-HydrationTemplates -Path $TemplatePath -Recurse -ResourceType "mobile app template"

    if (-not $templateFiles -or $templateFiles.Count -eq 0) {
        Write-Warning "No mobile app templates found in: $TemplatePath"
        return @()
    }

    # Prefetch existing mobile apps (paged)
    $existingApps = @{}
    $listUri = "beta/deviceAppManagement/mobileApps"
    try {
        do {
            $existingResponse = Invoke-MgGraphRequest -Method GET -Uri $listUri -ErrorAction Stop
            foreach ($app in $existingResponse.value) {
                $appName = $app.displayName
                if ($appName -and -not $existingApps.ContainsKey($appName)) {
                    $existingApps[$appName] = @{
                        Id = $app.id
                        Notes = $app.notes
                    }
                }
            }
            $listUri = $existingResponse.'@odata.nextLink'
        } while ($listUri)
    }
    catch {
        Write-Warning "Failed to list existing mobile apps: $($_.Exception.Message)"
    }

    $results = @()

    # Remove existing apps if requested
    if ($RemoveExisting) {
        foreach ($appName in $existingApps.Keys) {
            $appInfo = $existingApps[$appName]

            # Safety check: Only delete if created by this kit (has hydration marker in notes)
            if (-not (Test-HydrationKitObject -Description $appInfo.Notes -ObjectName $appName)) {
                Write-Verbose "Skipping '$appName' - not created by Intune-Hydration-Kit"
                continue
            }

            $deleteEndpoint = "beta/deviceAppManagement/mobileApps/$($appInfo.Id)"

            if ($PSCmdlet.ShouldProcess($appName, "Delete mobile app")) {
                try {
                    Invoke-MgGraphRequest -Method DELETE -Uri $deleteEndpoint -ErrorAction Stop
                    Write-HydrationLog -Message " Deleted: $appName" -Level Info
                    $results += New-HydrationResult -Name $appName -Type 'MobileApp' -Action 'Deleted' -Status 'Success'
                }
                catch {
                    $errMessage = Get-GraphErrorMessage -ErrorRecord $_
                    Write-HydrationLog -Message " Failed: $appName - $errMessage" -Level Warning
                    $results += New-HydrationResult -Name $appName -Type 'MobileApp' -Action 'Failed' -Status "Delete failed: $errMessage"
                }
            }
            else {
                Write-HydrationLog -Message " WouldDelete: $appName" -Level Info
                $results += New-HydrationResult -Name $appName -Type 'MobileApp' -Action 'WouldDelete' -Status 'DryRun'
            }
        }

        return $results
    }

    foreach ($templateFile in $templateFiles) {
        try {
            $template = Get-Content -Path $templateFile.FullName -Raw -Encoding utf8 | ConvertFrom-Json
            $displayName = $template.displayName
            if (-not $displayName) {
                Write-Warning "Template missing displayName: $($templateFile.FullName)"
                $results += New-HydrationResult -Name $templateFile.Name -Path $templateFile.FullName -Type 'MobileApp' -Action 'Failed' -Status 'Missing displayName'
                continue
            }

            if ($existingApps.ContainsKey($displayName)) {
                Write-HydrationLog -Message " Skipped: $displayName" -Level Info
                $results += New-HydrationResult -Name $displayName -Path $templateFile.FullName -Type 'MobileApp' -Action 'Skipped' -Status 'Already exists'
                continue
            }

            $importBody = Copy-DeepObject -InputObject $template
            Remove-ReadOnlyGraphProperties -InputObject $importBody

            # Add hydration kit tag to notes field (mobile apps use notes instead of description for this)
            $existingNotes = if ($importBody.PSObject.Properties['notes']) { $importBody.notes } else { "" }
            $newNotes = if ($existingNotes) { "$existingNotes - Imported by Intune-Hydration-Kit" } else { "Imported by Intune-Hydration-Kit" }
            if ($importBody.PSObject.Properties['notes']) {
                $importBody.notes = $newNotes
            } else {
                $importBody | Add-Member -NotePropertyName 'notes' -NotePropertyValue $newNotes
            }

            $endpoint = "beta/deviceAppManagement/mobileApps"

            if ($PSCmdlet.ShouldProcess($displayName, "Create mobile app")) {
                $null = Invoke-MgGraphRequest -Method POST -Uri $endpoint -Body ($importBody | ConvertTo-Json -Depth 100) -ContentType 'application/json' -ErrorAction Stop
                Write-HydrationLog -Message " Created: $displayName" -Level Info
                $results += New-HydrationResult -Name $displayName -Path $templateFile.FullName -Type 'MobileApp' -Action 'Created' -Status 'Success'
            }
            else {
                Write-HydrationLog -Message " WouldCreate: $displayName" -Level Info
                $results += New-HydrationResult -Name $displayName -Path $templateFile.FullName -Type 'MobileApp' -Action 'WouldCreate' -Status 'DryRun'
            }
        }
        catch {
            $errMessage = Get-GraphErrorMessage -ErrorRecord $_
            Write-HydrationLog -Message " Failed: $($templateFile.Name) - $errMessage" -Level Warning
            $results += New-HydrationResult -Name $templateFile.Name -Path $templateFile.FullName -Type 'MobileApp' -Action 'Failed' -Status $errMessage
        }
    }

    return $results
}