Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions IntuneWinAppUtilGUI.psd1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@{
RootModule = 'IntuneWinAppUtilGUI.psm1'
ModuleVersion = '1.0.6'
ModuleVersion = '1.0.7'
GUID = '7db79126-1b57-48d2-970a-4795692dfcfc'
Author = 'Giovanni Solone'
Description = 'GUI wrapper for IntuneWinAppUtil.exe with config file support and WPF interface.'
Expand All @@ -21,16 +21,9 @@
LicenseUri = 'https://opensource.org/licenses/MIT'
IconUri = 'https://raw.githubusercontent.com/gioxx/IntuneWinAppUtilGUI/main/Assets/icon.png'
ReleaseNotes = @'
- Bugfix: Delisted 1.0.4 from PowerShell Gallery and added again Show-IntuneWinAppUtilGUI to available commands.
- Bugfix: Removed any reference to ZIP uploads as setup files.
- Bugfix: Fixed PS 5.1 incompatibility in relative-path resolution ([System.IO.Path]::GetRelativePath is PS 7+).
- Bugfix: Final filename (of IntuneWin package) is proposed also if AppVersion is not specified in Invoke-AppDeployToolkit.ps1.
- Improved: Code cleanup, removed redundant GitHub download logic; refactoring.
- Improved: Validates setup file existence and type.
- Improved: Tries to create output folder when missing.
- Improved: Ensures exactly one ".intunewin" extension on output.
- Improved: If Source folder is not specified, it is inferred from Setup file.
- Improved: Added more inline comments for maintainability.
- Improved: Live Source/Output path length indicators.
- Improved: On Run, warns if the longest file path under Source exceeds Windows limits, showing the longest path found.
- Improved: Added UI note clarifying that Source path length is indicative and final check runs at packaging time.
'@
}
}
Expand Down
77 changes: 77 additions & 0 deletions Private/PathLengthHelpers.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
function Get-MaxFilePathInfo {
<#
.SYNOPSIS
Returns the longest full file path length under a root directory.
.DESCRIPTION
Enumerates files recursively and returns the maximum FullName length and the path.
If no files are found, returns the root path and its length.
.PARAMETER RootPath
The root directory to scan.
.OUTPUTS
PSCustomObject with Length and Path.
#>

[CmdletBinding()]
param([Parameter(Mandatory)][string] $RootPath)

try {
$maxLen = 0
$maxPath = $null
$foundAny = $false

foreach ($item in Get-ChildItem -Path $RootPath -Recurse -Force -File -ErrorAction SilentlyContinue) {
$len = $item.FullName.Length
if ($len -gt $maxLen) {
$maxLen = $len
$maxPath = $item.FullName
}
$foundAny = $true
}

if (-not $foundAny) {
$maxLen = $RootPath.Length
$maxPath = $RootPath
}

return [PSCustomObject]@{
Length = $maxLen
Path = $maxPath
}
} catch {
return $null
}
}

function Update-PathLengthIndicator {
<#
.SYNOPSIS
Updates a TextBlock with path length info and warning color.
.PARAMETER PathText
The path text to measure.
.PARAMETER Indicator
The TextBlock to update.
.PARAMETER Limit
The max length threshold.
#>

[CmdletBinding()]
param(
[Parameter()][AllowEmptyString()][string] $PathText,
[Parameter(Mandatory)][System.Windows.Controls.TextBlock] $Indicator,
[Parameter(Mandatory)][int] $Limit
)

if (-not $Indicator) { return }
$len = if ($PathText) { $PathText.Length } else { 0 }
if ($len -gt 0) {
$Indicator.Visibility = [System.Windows.Visibility]::Visible
$Indicator.Text = "Path length: $len/$Limit"
$Indicator.Foreground = if ($len -gt $Limit) {
[System.Windows.Media.Brushes]::Red
} else {
[System.Windows.Media.Brushes]::Gray
}
} else {
$Indicator.Visibility = [System.Windows.Visibility]::Collapsed
}
}
41 changes: 38 additions & 3 deletions Public/Show-IntuneWinAppUtilGui.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ function Show-IntuneWinAppUtilGUI {
if ([System.Threading.Thread]::CurrentThread.GetApartmentState() -ne 'STA') {
$modulePath = $MyInvocation.MyCommand.Module.Path
$shell = if ($PSVersionTable.PSEdition -eq 'Core') { 'pwsh' } else { 'powershell' }
$cmd = "Import-Module `"$modulePath`"; Show-IntuneWinAppUtilGUI"
if ($PSBoundParameters.ContainsKey('Debug')) { $cmd += " -Debug" }
Start-Process $shell -ArgumentList @(
'-NoProfile',
'-STA',
'-Command', "Import-Module `"$modulePath`"; Show-IntuneWinAppUtilGUI"
) | Out-Null
'-Command', $cmd
) -NoNewWindow | Out-Null
return
}

Expand Down Expand Up @@ -72,6 +74,8 @@ function Show-IntuneWinAppUtilGUI {
$SourceFolder = $window.FindName("SourceFolder")
$SetupFile = $window.FindName("SetupFile")
$OutputFolder = $window.FindName("OutputFolder")
$SourceFolderPathLength = $window.FindName("SourceFolderPathLength")
$OutputFolderPathLength = $window.FindName("OutputFolderPathLength")

$ToolPathBox = $window.FindName("ToolPathBox")
$ToolVersionText = $window.FindName("ToolVersionText")
Expand All @@ -88,11 +92,17 @@ function Show-IntuneWinAppUtilGUI {
$ClearButton = $window.FindName("ClearButton")
$ExitButton = $window.FindName("ExitButton")

$PathLengthLimit = 260

Update-PathLengthIndicator -PathText $SourceFolder.Text -Indicator $SourceFolderPathLength -Limit $PathLengthLimit
Update-PathLengthIndicator -PathText $OutputFolder.Text -Indicator $OutputFolderPathLength -Limit $PathLengthLimit

# When user types/pastes the source path manually, try to auto-suggest the setup file if found.
$SourceFolder.Add_TextChanged({
param($evtSender, $e)
$src = $SourceFolder.Text.Trim()
if ($src) { Set-SetupFromSource -SourcePath $src -SetupFileControl $SetupFile -FinalFilenameControl $FinalFilename }
Update-PathLengthIndicator -PathText $SourceFolder.Text -Indicator $SourceFolderPathLength -Limit $PathLengthLimit
})

# Preload config.json if it exists
Expand All @@ -112,7 +122,6 @@ function Show-IntuneWinAppUtilGUI {
try {
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
$SourceFolder.Text = $dialog.SelectedPath
Set-SetupFromSource -SourcePath $dialog.SelectedPath -SetupFileControl $SetupFile -FinalFilenameControl $FinalFilename
}
} finally {
$dialog.Dispose()
Expand Down Expand Up @@ -161,6 +170,11 @@ function Show-IntuneWinAppUtilGUI {
}
})

$OutputFolder.Add_TextChanged({
param($evtSender, $e)
Update-PathLengthIndicator -PathText $OutputFolder.Text -Indicator $OutputFolderPathLength -Limit $PathLengthLimit
})

# Browse for IntuneWinAppUtil.exe
$BrowseTool.Add_Click({
$dialog = New-Object System.Windows.Forms.OpenFileDialog
Expand Down Expand Up @@ -280,6 +294,27 @@ function Show-IntuneWinAppUtilGUI {
return
}

$pathWarnings = @()
if ($c.Length -gt $PathLengthLimit) { $pathWarnings += "Source folder: $($c.Length)/$PathLengthLimit" }
$maxFileInfo = Get-MaxFilePathInfo -RootPath $c
if ($null -ne $maxFileInfo -and $maxFileInfo.Length -gt $PathLengthLimit) {
$pathWarnings += "Max file path in source: $($maxFileInfo.Length)/$PathLengthLimit"
$pathWarnings += "Longest path: $($maxFileInfo.Path)"
}
if ($o.Length -gt $PathLengthLimit) { $pathWarnings += "Output folder: $($o.Length)/$PathLengthLimit" }
if ($pathWarnings.Count -gt 0) {
$msg = "One or more paths exceed $PathLengthLimit characters.`n`n" +
($pathWarnings -join "`n") +
"`n`nThis can cause IntuneWinAppUtil to fail on Windows.`nProceed anyway?"
$confirm = [System.Windows.MessageBox]::Show(
$msg,
"Path length warning",
[System.Windows.MessageBoxButton]::YesNo,
[System.Windows.MessageBoxImage]::Warning
)
if ($confirm -ne [System.Windows.MessageBoxResult]::Yes) { return }
}

# IntuneWinAppUtil.exe path check (or initialize/download if not set)
$toolPath = Initialize-IntuneWinAppUtil -UiToolPath ($ToolPathBox.Text.Trim())

Expand Down
14 changes: 13 additions & 1 deletion UI/UI.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
<TextBox Name="SourceFolder" Grid.Column="0" Margin="0,0,10,0" Padding="4"/>
<Button Name="BrowseSource" Content="Browse..." Grid.Column="1" Width="80" Padding="2"/>
</Grid>
<TextBlock Name="SourceFolderPathLength"
Text="Path length: 0/260"
Foreground="Gray"
FontSize="11"
Margin="0,4,0,0"
Visibility="Collapsed"/>
</StackPanel>

<!-- Setup File -->
Expand Down Expand Up @@ -86,6 +92,12 @@
<TextBox Name="OutputFolder" Grid.Column="0" Margin="0,0,10,0" Padding="4"/>
<Button Name="BrowseOutput" Content="Browse..." Grid.Column="1" Width="80" Padding="2"/>
</Grid>
<TextBlock Name="OutputFolderPathLength"
Text="Path length: 0/260"
Foreground="Gray"
FontSize="11"
Margin="0,4,0,0"
Visibility="Collapsed"/>
</StackPanel>

<!-- Tool Path -->
Expand Down Expand Up @@ -149,7 +161,7 @@

<!-- Info tooltip -->
<TextBlock Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2"
Text="⚠️ Source folder, setup file and output folder are required (*).&#x0a;ℹ️ Final filename is optional and used for renaming the .intunewin file. If not provided, the tool will generate a name based on the source folder.&#x0a;ℹ️ IntuneWinAppUtil Path is also optional. If not provided, the tool will automatically download the latest version from GitHub.&#x0a;&#x0a;Press ESC on the keyboard to close the application.&#x0a;Click on 'Run' button or press ENTER on the keyboard to execute the IntuneWinAppUtil with the provided parameters."
Text="⚠️ Source folder, setup file and output folder are required (*).&#x0a;ℹ️ The Source folder path length shown above is indicative; the final check runs at packaging time (Run) and considers the longest file path.&#x0a;ℹ️ Final filename is optional and used for renaming the .intunewin file. If not provided, the tool will generate a name based on the source folder.&#x0a;ℹ️ IntuneWinAppUtil Path is also optional. If not provided, the tool will automatically download the latest version from GitHub.&#x0a;&#x0a;Press ESC on the keyboard to close the application.&#x0a;Click on 'Run' button or press ENTER on the keyboard to execute the IntuneWinAppUtil with the provided parameters."
Foreground="Gray" FontSize="12" Margin="0,20,0,0" TextWrapping="Wrap"/>

<!-- GitHub Link -->
Expand Down