Public/New-IntuneApplication.ps1

function New-IntuneApplication {
    [CmdletBinding()]
    [OutputType([PSObject])]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$ApplicationName,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string[]]$SourceFiles,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$MainInstallerFileName,

        [string]$OutputFolder = $($PWD.Path),

        [ValidateNotNullOrEmpty()]
        [string]$Description = "# $ApplicationName`nPublisher: $Publisher`nVersion: $Version`nDeveloper: $Developer`n`n$notes",

        [ValidateNotNullOrEmpty()]
        [string]$Publisher = $Env:USERNAME,

        [string]$Version = "1.0",

        [string]$Developer = $Env:USERNAME,

        [string]$owner = "",

        [string]$notes = "",

        [ValidateScript({
                if (Test-Path -Path $_) {
                    if ($(Get-Item -Path $_).Extension -notin @('.png', '.jpg', '.jpeg')) {
                        throw "The LogoPath must be a PNG or JPG file."
                    }
                    else {
                        $true
                    }
                }
                else {
                    throw "The LogoPath path does not exist."
                }
                $true
            })]
        [string]$LogoPath,
        
        [ValidateSet("User", "System")]
        [string]$InstallFor = "System",

        [ValidateSet("basedOnReturnCode", "allow", "suppress", "force")]
        [string]$RestartBehavior = "basedOnReturnCode",

        [bool]$isFeatured = $false,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$InstallCommand,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$UninstallCommand,

        [hashtable]$RequirementRuleConfig,
        
        [Parameter(Mandatory = $true)]
        [hashtable]$DetectionRuleConfig,

        [Parameter(Mandatory = $true)]
        [ValidateSet('User-Group', 'Device-Group', 'All-Users', 'All-Devices')]
        [string]$AssignmentType,

        [string]$AssignmentGroup,

        [ValidateSet('Include', 'Exclude')]
        [string]$FilterRuleType,

        [string]$FilterRule,

        [switch]$Publish,

        [ValidateNotNullOrEmpty()]
        [string]$IntuneToolsPath = ".\IntuneWinAppUtil.exe",

        [switch]$Overwrite,

        [switch]$NoJson,

        [switch]$NoIntuneWin,

        [switch]$NoCleanUp
    )
    
    begin {
        #region PathValidation
        # Start by validating any paths passed to the function
        # Requirements Rule Script
        if ($RequirementRuleType -eq 'Script') {
            if (-not (Test-Path -Path $RequirementRuleScript)) {
                Write-Error "The RequirementRuleScript path '$RequirementRuleScript' does not exist."
                return
            }
        }
        # Detection Rule Script
        if ($DetectionRuleType -eq 'Script') {
            if (-not (Test-Path -Path $DetectionRuleScript)) {
                Write-Error "The DetectionRuleScript path '$DetectionRuleScript' does not exist."
                return
            }
        }
        # Image Path
        if ($LogoPath) {
            try {
                Test-IntuneLogoImage -Path $LogoPath -ErrorAction Stop
            }
            catch {
                Write-Error $_.Exception.Message
                return
            }
        }
        foreach ($File in $SourceFiles) {
            if (-not (Test-Path -Path $File)) {
                Write-Error "The Source File path '$File' does not exist."
                return
            }
        }
        if (-not (Test-Path -Path $OutputFolder)) {
            Write-Error "The Output Folder path '$OutputFolder' does not exist."
            return
        }
        #endregion PathValidation
        #region SourceFilesValidation
        # Validate the MainInstallerFileName is in the list of SourceFiles
        if ($SourceFiles.count -eq 1 -and (Test-Path -Path $SourceFiles[0] -PathType Container) -eq $false ) {
            if (Test-Path -Path $MainInstallerFileName -PathType Leaf) {
                $local:MainInstallerFilePath = Split-Path -Path $MainInstallerFileName -Parent
                $local:MainInstallerFileName = Split-Path -Path $MainInstallerFileName -Leaf
            }
            if ($(Split-Path -Path $SourceFiles[0] -Leaf) -ne $MainInstallerFileName) {
                Write-Error "The MainInstallerFileName '$MainInstallerFileName' does not exist in the SourceFiles list."
                return
            }
        }
        elseif ($SourceFiles.count -eq 1) {
            $MainInstallerFileNameFound = $false
            foreach ($File in $(Get-ChildItem -Path $SourceFiles[0] -Recurse -File | Select-Object -ExpandProperty FullName)) {
                if ($(Split-Path -Path $File -Leaf) -eq $MainInstallerFileName) {
                    $MainInstallerFileNameFound = $true
                    $local:MainInstallerFilePath = Split-Path -Path $File -Parent
                    break
                }
            }
        }

        foreach ($File in $SourceFiles) {
            if ($(Split-Path -Path $File -Leaf) -eq $MainInstallerFileName) {
                $MainInstallerFileNameFound = $true
                $local:MainInstallerFilePath = Split-Path -Path $File -Parent
                break
            }
        }
        if ($MainInstallerFileNameFound -eq $false) {
            Write-Error "The MainInstallerFileName '$MainInstallerFileName' does not exist in the SourceFiles list."
            break
        }
        #endregion SourceFilesValidation
        #region IntuneWinAppUtilValidation
        # Now test if the IntuneWinAppUtil.exe tool is available
        if ((Test-Path -Path $IntuneToolsPath) -eq $false) {
            # If not found, download the tool from the internet
            # Amend this to pull latest version from GitHub - remove -DownloadTag
            try {
                # Pinning to v1.8.6 as a know stable release
                Get-IntunePackagingTool -Path ".\" -Force -DownloadTag "v1.8.6" -ErrorAction Stop
            }
            catch {
                Write-Error $_.Exception.Message
                return
            }
        }
        #endregion IntuneWinAppUtilValidation
        #region ParameterSplat
        # Using the parameters passed to the function, create a splat.
        $ParameterSplat = @{}
        foreach ($P in $PSBoundParameters.Keys) {
            $ParameterSplat.Add($P, $PSBoundParameters[$P])
        }
        # Removing Verbose, Debug, and ErrorAction parameters
        $ParameterSplat.Remove('Verbose')
        $ParameterSplat.Remove('Debug')
        $ParameterSplat.Remove('ErrorAction')
        # Manually adding the paremeters that have default values
        $ParameterSplat.Add('Publisher', $Publisher)
        $ParameterSplat.Add('Version', $Version)
        $ParameterSplat.Add('Developer', $Developer)
        $ParameterSplat.Add('InstallFor', $InstallFor)
        $ParameterSplat.Add('RestartBehavior', $RestartBehavior)
        $ParameterSplat.Add('isFeatured', $isFeatured)
        $ParameterSplat.Add('OutputFolder', $OutputFolder)
        $ParamVerbose = "$($($ParameterSplat.GetEnumerator() | ForEach-Object { "$($_.Key): $($_.Value)" }) -join "`n")"
        Write-Verbose "`n$ParamVerbose"
        #endregion ParameterSplat
    }
    process {
        #region CreateJSON
        # Create JSON file
        if ($NoJson -eq $false) {
            Write-Verbose "Creating JSON file for $ApplicationName"
            $JSONOutputPath = "$OutputFolder\$ApplicationName.$Version.json"
            if ($Overwrite -eq $true -and (Test-Path -Path $JSONOutputPath) -eq $true) {
                Write-Verbose "Overwriting existing JSON file"
                Remove-Item -Path $JSONOutputPath -Force -Confirm:$false
            }
            elseif ((Test-Path -Path $JSONOutputPath) -eq $true) {
                Write-Error "The JSON file already exists, use -Overwrite to replace it."
                break
            }
            $JSON = New-IntuneAppJSON -AppParams $ParameterSplat
            $JSON | Out-File -FilePath $JSONOutputPath -Force -Confirm:$false
        }
        #endregion CreateJSON
        #region CreateIntuneWin
        # Create .intunewin file
        if ($NoIntuneWin -eq $false) {
            Write-Verbose "Creating .intunewin file for $ApplicationName"
            # If source files are multiple files, create a temp folder and copy the files to it
            if ($SourceFiles.count -gt 1) {
                # Create a Temp folder to store SourceFiles
                $TempFolder = New-Item -Path "$OutputFolder\$ApplicationName.$Version" -ItemType Directory -Force
                Copy-item -Path $SourceFiles -Destination $TempFolder.FullName -Force -Confirm:$false
                $SourceFiles = $TempFolder.FullName
            }
            else {
                if ((Test-Path -Path $SourceFiles[0] -PathType Container) -eq $false) {
                    $SourceFiles = Split-Path -Path $SourceFiles[0] -Parent
                }
            }
            $IntunewinFullPath = Join-Path -Path $OutputFolder -ChildPath "$((Get-Item -Path "$MainInstallerFilePath\$MainInstallerFileName" -ErrorAction SilentlyContinue).BaseName).intunewin"
            $ExistingIntunewinTest = Test-Path -Path $IntunewinFullPath
            $MainInstallerFileFullPath = "$MainInstallerFilePath\$MainInstallerFileName"
            $CreateIntuneWin = $true
            if ($Overwrite -eq $true -and $ExistingIntunewinTest -eq $true) {
                Write-Verbose "Overwriting existing .intunewin file"
                Remove-Item -Path $IntunewinFullPath -Force -Confirm:$false
            }
            elseif ($ExistingIntunewinTest -eq $true) {
                Write-Error "The .intunewin file already exists, use -Overwrite to replace it."
                $CreateIntuneWin = $false
                return       
            }
            if ($CreateIntuneWin -eq $true) {
                try {
                    Start-Process -FilePath $IntuneToolsPath -ArgumentList "-c $SourceFiles -o $OutputFolder -s $MainInstallerFileFullPath -q" -Wait -WindowStyle Hidden -ErrorAction Stop | Out-Null
                }
                catch {
                    Write-Error $_.Exception.Message
                    return
                }
            }
        }
        #endregion CreateIntuneWin
        #region PublishIntune
        # Publish to Intune
        if ($Publish -eq $true) {
            Write-Verbose "Publishing $ApplicationName to Intune"
            try {
                
            }
            catch {
                Write-Error $_.Exception.Message
                return
            }
        }
    }
    end {
        # Cleanup
        if ($NoCleanUp -eq $false -and $Publish -eq $true) {
            Write-Verbose "Cleaning up temporary files"
            if ($SourceFiles.count -gt 1) {
                Remove-Item -Path $TempFolder.FullName -Recurse -Force -Confirm:$false
            }
            if ($NoJson -eq $false) {
                Remove-Item -Path "$OutputFolder\$ApplicationName.$Version.json" -Force -Confirm:$false
            }
            if ($NoIntuneWin -eq $false) {
                Remove-Item -Path $IntunewinFullPath -Force -Confirm:$false
            }
        }
    }
}