Public/New-IntuneWin32AppPackage.ps1
|
function New-IntuneWin32AppPackage { <# .SYNOPSIS Creates an Intune Win32 application package (.intunewin file) from source files. .DESCRIPTION The New-IntuneWin32AppPackage function wraps application source files and the main setup file into an encrypted .intunewin package using Microsoft's IntuneWinAppUtil.exe tool. This package can then be uploaded to Microsoft Intune for Win32 app deployment. .PARAMETER SourceFolder The full path to the source folder containing the setup file and all dependency files. .PARAMETER SetupFile The complete setup file name including extension (e.g., Setup.exe or Installer.msi). .PARAMETER OutputFolder The full path to the output folder where the packaged .intunewin file will be saved. .PARAMETER Force Switch to overwrite an existing .intunewin file if already present in the output folder. .PARAMETER IntuneWinAppUtilPath The full path to the IntuneWinAppUtil.exe file. When not specified, the per-user tool folder (LocalApplicationData\tcs.intune.packaging) is used. When the tool is missing there you are asked before release v1.8.6 is downloaded (see AllowDownload). .PARAMETER AllowDownload Download IntuneWinAppUtil.exe to the per-user tool folder without asking when it is missing. The download is refused unless it is signed by Microsoft (see Get-IntunePackagingTool). .OUTPUTS System.Management.Automation.PSCustomObject Name, FileName, SetupFile and UnencryptedContentSize from the package metadata (Detection.xml), and Path of the .intunewin file. .EXAMPLE New-IntuneWin32AppPackage -SourceFolder "C:\Apps\MyApp" -SetupFile "setup.exe" -OutputFolder "C:\Packages" Creates an .intunewin package from the MyApp folder. .EXAMPLE New-IntuneWin32AppPackage -SourceFolder "C:\Apps\MyApp" -SetupFile "installer.msi" -OutputFolder "C:\Packages" -Force Creates an .intunewin package and overwrites any existing package in the output folder. .NOTES A missing source folder, setup file, output folder or tool, or a failure of IntuneWinAppUtil.exe, is a terminating error. An existing package without -Force is a non-terminating error and the package is not created. Both are reported to telemetry as failures. The source folder should contain all files required for the application installation. .LINK https://github.com/microsoft/Microsoft-Win32-Content-Prep-Tool #> [CmdletBinding(SupportsShouldProcess = $true)] [OutputType([PSCustomObject])] param( [parameter(Mandatory = $true, HelpMessage = "Specify the full path of the source folder where the setup file and all of it's potential dependency files reside.")] [ValidateNotNullOrEmpty()] [string]$SourceFolder, [parameter(Mandatory = $true, HelpMessage = "Specify the complete setup file name including it's file extension, e.g. Setup.exe or Installer.msi.")] [ValidateNotNullOrEmpty()] [string]$SetupFile, [parameter(Mandatory = $true, HelpMessage = "Specify the full path of the output folder where the packaged .intunewin file will be exported to.")] [ValidateNotNullOrEmpty()] [string]$OutputFolder, [parameter(Mandatory = $false, HelpMessage = "Specify to overwrite existing packaged .intunewin file if already present in output folder.")] [switch]$Force, [parameter(Mandatory = $false, HelpMessage = "Specify the full path to the IntuneWinAppUtil.exe file.")] [ValidateNotNullOrEmpty()] [string]$IntuneWinAppUtilPath = (Get-IntuneWinAppUtilPath), [parameter(Mandatory = $false, HelpMessage = "Download IntuneWinAppUtil.exe without asking when it is missing.")] [switch]$AllowDownload ) begin { $TelemetryArgs = @{ ModuleName = $MyInvocation.MyCommand.Module.Name ModuleVersion = [string]$MyInvocation.MyCommand.Module.Version CommandName = $MyInvocation.MyCommand.Name ExecutionID = [guid]::NewGuid().ToString() } Invoke-TelemetryCollection @TelemetryArgs -Stage Start -ClearTimer $TelemetryFailed = $false } process { try { if (-not (Test-Path -LiteralPath $SourceFolder -PathType Container)) { throw "Unable to detect specified source folder: $SourceFolder" } $SetupFilePath = Join-Path -Path $SourceFolder -ChildPath $SetupFile if (-not (Test-Path -LiteralPath $SetupFilePath -PathType Leaf)) { throw "Unable to detect specified setup file '$SetupFile' in source folder: $SourceFolder" } if (-not (Test-Path -LiteralPath $OutputFolder -PathType Container)) { throw "Unable to detect specified output folder: $OutputFolder" } $IntuneWinAppPackage = Join-Path -Path $OutputFolder -ChildPath "$([System.IO.Path]::GetFileNameWithoutExtension($SetupFile)).intunewin" if ((Test-Path -LiteralPath $IntuneWinAppPackage) -and -not $Force) { # The package is skipped, but other pipeline input is still processed $Exception = [System.IO.IOException]::new("The package '$IntuneWinAppPackage' already exists. Use -Force to overwrite it.") $Record = [System.Management.Automation.ErrorRecord]::new($Exception, 'PackageExists', [System.Management.Automation.ErrorCategory]::ResourceExists, $IntuneWinAppPackage) if (-not $TelemetryFailed) { $TelemetryFailed = $true Invoke-TelemetryCollection @TelemetryArgs -Stage End -Failed $true -Exception $Record } $PSCmdlet.WriteError($Record) return } if (-not $PSCmdlet.ShouldProcess($IntuneWinAppPackage, 'Create .intunewin package')) { return } $ToolParameters = @{ SourceFolder = $SourceFolder SetupFile = $SetupFilePath OutputFolder = $OutputFolder AllowDownload = $AllowDownload Overwrite = $Force } if ($PSBoundParameters.ContainsKey('IntuneWinAppUtilPath')) { $ToolParameters['ToolPath'] = $IntuneWinAppUtilPath } $Package = Invoke-IntuneWinAppUtil @ToolParameters -ErrorAction Stop $Info = Read-IntuneWinPackage -Path $Package.FullName -ErrorAction Stop [PSCustomObject]@{ Name = $Info.Name FileName = $Info.FileName SetupFile = $Info.SetupFile UnencryptedContentSize = $Info.UnencryptedContentSize Path = $Package.FullName } } catch { if (-not $TelemetryFailed) { $TelemetryFailed = $true Invoke-TelemetryCollection @TelemetryArgs -Stage End -Failed $true -Exception $_ } $PSCmdlet.ThrowTerminatingError($_) } } end { if (-not $TelemetryFailed) { Invoke-TelemetryCollection @TelemetryArgs -Stage End } } } |