Public/Update-IntuneWin32AppPackageFile.ps1
function Update-IntuneWin32AppPackageFile { <# .SYNOPSIS Update the package content file for an existing Win32 app. .DESCRIPTION Update the package content file for an existing Win32 app. .PARAMETER ID Specify the ID for a Win32 application. .PARAMETER FilePath Specify a local path to where the win32 app .intunewin file is located. .NOTES Author: Nickolaj Andersen Contact: @NickolajA Created: 2020-10-01 Updated: 2023-09-04 Version history: 1.0.0 - (2020-10-01) Function created 1.0.1 - (2021-04-01) Updated token expired message to a warning instead of verbose output 1.0.2 - (2021-08-31) Updated to use new authentication header 1.0.3 - (2021-08-31) Fixed an issue where the PATCH operation would remove the largeIcon property value of the Win32 app 1.0.4 - (2023-01-20) Updated regex pattern for parameter FilePath 1.0.5 - (2023-09-04) Updated with Test-AccessToken function #> [CmdletBinding(SupportsShouldProcess = $true)] param( [parameter(Mandatory = $true, HelpMessage = "Specify the ID for a Win32 application.")] [ValidateNotNullOrEmpty()] [string]$ID, [parameter(Mandatory = $true, HelpMessage = "Specify a local path to where the win32 app .intunewin file is located.")] [ValidateNotNullOrEmpty()] [ValidateScript({ # Check if file name contains any invalid characters if ((Split-Path -Path $_ -Leaf).IndexOfAny([IO.Path]::GetInvalidFileNameChars()) -ge 0) { throw "File name '$(Split-Path -Path $_ -Leaf)' contains invalid characters" } else { # Check if full path exist if (Test-Path -Path $_) { # Check if file extension is intunewin if ([System.IO.Path]::GetExtension((Split-Path -Path $_ -Leaf)) -like ".intunewin") { return $true } else { throw "Given file name '$(Split-Path -Path $_ -Leaf)' contains an unsupported file extension. Supported extension is '.intunewin'" } } else { throw "File or folder does not exist" } } })] [string]$FilePath ) Begin { # Ensure required authentication header variable exists if ($Global:AuthenticationHeader -eq $null) { Write-Warning -Message "Authentication token was not found, use Connect-MSIntuneGraph before using this function"; break } else { if ((Test-AccessToken) -eq $false) { Write-Warning -Message "Existing token found but has expired, use Connect-MSIntuneGraph to request a new authentication token"; break } } # Set script variable for error action preference $ErrorActionPreference = "Stop" } Process { # Attempt to gather all possible meta data from specified .intunewin file Write-Verbose -Message "Attempting to gather additional meta data from .intunewin file: $($FilePath)" $IntuneWinXMLMetaData = Get-IntuneWin32AppMetaData -FilePath $FilePath -ErrorAction Stop if ($IntuneWinXMLMetaData -ne $null) { Write-Verbose -Message "Successfully gathered additional meta data from .intunewin file" # Retrieve Win32 app by ID from parameter input Write-Verbose -Message "Querying for Win32 app using ID: $($ID)" $Win32App = Invoke-IntuneGraphRequest -APIVersion "Beta" -Resource "mobileApps/$($ID)" -Method "GET" if ($Win32App -ne $null) { # Create Content Version for the Win32 app Write-Verbose -Message "Attempting to create contentVersions resource for the Win32 app" $Win32AppContentVersionRequest = Invoke-IntuneGraphRequest -APIVersion "Beta" -Resource "mobileApps/$($Win32App.id)/microsoft.graph.win32LobApp/contentVersions" -Method "POST" -Body "{}" if ([string]::IsNullOrEmpty($Win32AppContentVersionRequest.id)) { Write-Warning -Message "Failed to create contentVersions resource for Win32 app"; break } else { Write-Verbose -Message "Successfully created contentVersions resource with ID: $($Win32AppContentVersionRequest.id)" # Extract compressed .intunewin file to subfolder $IntuneWinFilePath = Expand-IntuneWin32AppCompressedFile -FilePath $FilePath -FileName $IntuneWinXMLMetaData.ApplicationInfo.FileName -FolderName "Expand" if ($IntuneWinFilePath -ne $null) { # Create a new file entry in Intune for the upload of the .intunewin file Write-Verbose -Message "Constructing Win32 app content file body for uploading of .intunewin file" $Win32AppFileBody = [ordered]@{ "@odata.type" = "#microsoft.graph.mobileAppContentFile" "name" = $IntuneWinXMLMetaData.ApplicationInfo.FileName "size" = [int64]$IntuneWinXMLMetaData.ApplicationInfo.UnencryptedContentSize "sizeEncrypted" = (Get-Item -Path $IntuneWinFilePath).Length "manifest" = $null "isDependency" = $false } # Create the contentVersions files resource $Win32AppFileContentRequest = Invoke-IntuneGraphRequest -APIVersion "Beta" -Resource "mobileApps/$($Win32App.id)/microsoft.graph.win32LobApp/contentVersions/$($Win32AppContentVersionRequest.id)/files" -Method "POST" -Body ($Win32AppFileBody | ConvertTo-Json) if ([string]::IsNullOrEmpty($Win32AppFileContentRequest.id)) { Write-Warning -Message "Failed to create Azure Storage blob for contentVersions/files resource for Win32 app" } else { # Wait for the Win32 app file content URI to be created Write-Verbose -Message "Waiting for Intune service to process contentVersions/files request" $FilesUri = "mobileApps/$($Win32App.id)/microsoft.graph.win32LobApp/contentVersions/$($Win32AppContentVersionRequest.id)/files/$($Win32AppFileContentRequest.id)" $ContentVersionsFiles = Wait-IntuneWin32AppFileProcessing -Stage "AzureStorageUriRequest" -Resource $FilesUri # Upload .intunewin file to Azure Storage blob Invoke-AzureStorageBlobUpload -StorageUri $ContentVersionsFiles.azureStorageUri -FilePath $IntuneWinFilePath -Resource $FilesUri # Retrieve encryption meta data from .intunewin file $IntuneWinEncryptionInfo = [ordered]@{ "encryptionKey" = $IntuneWinXMLMetaData.ApplicationInfo.EncryptionInfo.EncryptionKey "macKey" = $IntuneWinXMLMetaData.ApplicationInfo.EncryptionInfo.macKey "initializationVector" = $IntuneWinXMLMetaData.ApplicationInfo.EncryptionInfo.initializationVector "mac" = $IntuneWinXMLMetaData.ApplicationInfo.EncryptionInfo.mac "profileIdentifier" = "ProfileVersion1" "fileDigest" = $IntuneWinXMLMetaData.ApplicationInfo.EncryptionInfo.fileDigest "fileDigestAlgorithm" = $IntuneWinXMLMetaData.ApplicationInfo.EncryptionInfo.fileDigestAlgorithm } $IntuneWinFileEncryptionInfo = @{ "fileEncryptionInfo" = $IntuneWinEncryptionInfo } # Create file commit request $CommitResource = "mobileApps/$($Win32App.id)/microsoft.graph.win32LobApp/contentVersions/$($Win32AppContentVersionRequest.id)/files/$($Win32AppFileContentRequest.id)/commit" $Win32AppFileCommitRequest = Invoke-IntuneGraphRequest -APIVersion "Beta" -Resource $CommitResource -Method "POST" -Body ($IntuneWinFileEncryptionInfo | ConvertTo-Json) # Wait for Intune service to process the commit file request Write-Verbose -Message "Waiting for Intune service to process the commit file request" $CommitFileRequest = Wait-IntuneWin32AppFileProcessing -Stage "CommitFile" -Resource $FilesUri # Update committedContentVersion property for Win32 app Write-Verbose -Message "Updating committedContentVersion property with ID '$($Win32AppContentVersionRequest.id)' for Win32 app with ID: $($Win32App.id)" $Win32AppFileCommitBody = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobApp" "committedContentVersion" = $Win32AppContentVersionRequest.id "largeIcon" = $Win32App.largeIcon } $Win32AppFileCommitBodyRequest = Invoke-IntuneGraphRequest -APIVersion "Beta" -Resource "mobileApps/$($Win32App.id)" -Method "PATCH" -Body ($Win32AppFileCommitBody | ConvertTo-Json) # Handle return output Write-Verbose -Message "Successfully updated Win32 app and committed file content to Azure Storage blob" $Win32AppRequest = Invoke-IntuneGraphRequest -APIVersion "Beta" -Resource "mobileApps/$($Win32App.id)" -Method "GET" Write-Output -InputObject $Win32AppRequest } # Cleanup extracted .intunewin file in Extract folder Remove-Item -Path (Split-Path -Path $IntuneWinFilePath -Parent) -Recurse -Force -Confirm:$false | Out-Null } } } else { Write-Warning -Message "Query for Win32 app using '$($ID)' returned empty response" } } else { Write-Warning -Message "Unable to retrieve required meta data from .intunewin file: $($FilePath)" } } } |