Last active
October 16, 2025 16:41
-
-
Save Hesamedin/cde8eee8abd0c44e007925c75a2a0b99 to your computer and use it in GitHub Desktop.
Based on https://stackoverflow.com/a/79444551/513413, the script deploys .ipa/.apk/.aab files to Intune. It woly works on Windows machines (tested on Azure Windows server 2025)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Uploads an iOS or Android application binary (.ipa, .apk, .aab) to Microsoft Intune. | |
| .DESCRIPTION | |
| This script automates the process of uploading a new version of a Line-of-Business (LOB) application to Microsoft Intune. | |
| It handles authentication, file encryption, uploading to Azure Storage, and committing the new version to the specified Intune application. | |
| The script automatically detects the application type based on the file extension of the AppFilePath parameter. | |
| - For .ipa files, it extracts the version and build number from the Info.plist file. | |
| - For .apk or .aab files, it uses the 'aapt' tool to extract the versionName and versionCode. Ensure 'aapt' is available in the system's PATH when uploading Android apps. | |
| .PARAMETER AppName | |
| The display name of the application in Intune. | |
| .PARAMETER AppFilePath | |
| The local path to the application binary file (.ipa, .apk, or .aab). | |
| .PARAMETER AppPublisher | |
| The publisher of the application. | |
| .PARAMETER AppBundleId | |
| The bundle identifier (for iOS) or package name (for Android) of the application (e.g., com.company.appname). | |
| .PARAMETER IntuneAppId | |
| The existing App ID in Intune for the application that will be updated. | |
| .PARAMETER IntuneTenantId | |
| The Azure Tenant ID where Intune is located. | |
| .PARAMETER IntuneClientId | |
| The Client ID of the Azure AD application registration with permissions to manage Intune. | |
| .PARAMETER IntuneClientSecret | |
| The Client Secret of the Azure AD application registration. | |
| .EXAMPLE | |
| ./intune_deploy.ps1 | |
| -AppName "My Awesome App" ` | |
| -AppFilePath "./path/to/my-app.ipa" ` | |
| -AppPublisher "My Company" ` | |
| -AppBundleId "com.mycompany.app" ` | |
| -IntuneAppId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ` | |
| -IntuneTenantId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ` | |
| -IntuneClientId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ` | |
| -IntuneClientSecret "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | |
| #> | |
| param( | |
| [Parameter(Mandatory=$true)] | |
| [string]$AppName, | |
| [Parameter(Mandatory=$true)] | |
| [string]$AppFilePath, | |
| [Parameter(Mandatory=$true)] | |
| [string]$AppPublisher, | |
| [Parameter(Mandatory=$true)] | |
| [string]$AppBundleId, | |
| [Parameter(Mandatory=$true)] | |
| [string]$IntuneAppId, | |
| [Parameter(Mandatory=$true)] | |
| [string]$IntuneTenantId, | |
| [Parameter(Mandatory=$true)] | |
| [string]$IntuneClientId, | |
| [Parameter(Mandatory=$true)] | |
| [string]$IntuneClientSecret | |
| ) | |
| # Define variables for Intune app | |
| $appDisplayName = $AppName | |
| $sourceFile = $AppFilePath | |
| $publisher = $AppPublisher | |
| $bundleId = $AppBundleId | |
| # Define authentication variables | |
| $intuneAppId = $IntuneAppId | |
| $tenantId = $IntuneTenantId | |
| $applicationId = $IntuneClientId | |
| $clientSecret = $IntuneClientSecret | |
| # Get authentication token | |
| $body = @{ | |
| grant_type = "client_credentials" | |
| client_id = $applicationId | |
| client_secret = $clientSecret | |
| scope = "https://graph.microsoft.com/.default" | |
| } | |
| $tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Method Post -Body $Body -ContentType "application/x-www-form-urlencoded" | |
| $accessToken = $tokenResponse.access_token | |
| $headers = @{ | |
| Authorization = "Bearer $accessToken" | |
| } | |
| function UploadAzureStorageChunk($sasUri, $id, $body){ | |
| $uri = "$sasUri&comp=block&blockid=$id"; | |
| $request = "PUT $uri"; | |
| $iso = [System.Text.Encoding]::GetEncoding("iso-8859-1"); | |
| $encodedBody = $iso.GetString($body); | |
| $headers = @{ | |
| "x-ms-blob-type" = "BlockBlob" | |
| }; | |
| if ($logRequestUris) { Write-Host $request; } | |
| if ($logHeaders) { WriteHeaders $headers; } | |
| try { | |
| Invoke-WebRequest $uri -Method Put -Headers $headers -Body $encodedBody; | |
| } catch { | |
| Write-Host -ForegroundColor Red $request; | |
| Write-Host -ForegroundColor Red $_.Exception.Message; | |
| throw; | |
| } | |
| } | |
| function FinalizeAzureStorageUpload($sasUri, $ids){ | |
| $uri = "$sasUri&comp=blocklist"; | |
| $request = "PUT $uri"; | |
| $xml = '<?xml version="1.0" encoding="utf-8"?><BlockList>'; | |
| foreach ($id in $ids) { | |
| $xml += "<Latest>$id</Latest>"; | |
| } | |
| $xml += '</BlockList>'; | |
| if ($logRequestUris) { Write-Host $request; } | |
| if ($logContent) { Write-Host -ForegroundColor Gray $xml; } | |
| try { | |
| Invoke-RestMethod $uri -Method Put -Body $xml; | |
| } catch { | |
| Write-Host -ForegroundColor Red $request; | |
| Write-Host -ForegroundColor Red $_.Exception.Message; | |
| throw; | |
| } | |
| } | |
| function UploadFileToAzureStorage($sasUri, $filepath){ | |
| # Chunk size = 1 MiB | |
| $chunkSizeInBytes = 1024 * 1024; | |
| # Read the whole file and find the total chunks. | |
| #[byte[]]$bytes = Get-Content $filepath -Encoding byte; | |
| # Using ReadAllBytes method as the Get-Content used alot of memory on the machine | |
| [byte[]]$bytes = [System.IO.File]::ReadAllBytes($filepath); | |
| $chunks = [Math]::Ceiling($bytes.Length / $chunkSizeInBytes); | |
| # Upload each chunk. | |
| $ids = @(); | |
| $cc = 1 | |
| for ($chunk = 0; $chunk -lt $chunks; $chunk++){ | |
| $id = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($chunk.ToString("0000"))); | |
| $ids += $id; | |
| $start = $chunk * $chunkSizeInBytes; | |
| $end = [Math]::Min($start + $chunkSizeInBytes - 1, $bytes.Length - 1); | |
| $body = $bytes[$start..$end]; | |
| Write-Progress -Activity "Uploading File to Azure Storage" -status "Uploading chunk $cc of $chunks" ` | |
| -percentComplete ($cc / $chunks*100) | |
| $cc++ | |
| UploadAzureStorageChunk $sasUri $id $body; | |
| } | |
| Write-Progress -Completed -Activity "Uploading File to Azure Storage" | |
| Write-Host | |
| # Finalize the upload. | |
| FinalizeAzureStorageUpload $sasUri $ids; | |
| } | |
| function Get-IpaVersionInfo($ipaPath) { | |
| Write-Host "Extracting version info from '$ipaPath'..." | |
| $tempDir = [System.IO.Path]::Combine($env:TEMP, [System.Guid]::NewGuid().ToString()) | |
| New-Item -ItemType Directory -Path $tempDir | Out-Null | |
| try { | |
| Add-Type -AssemblyName System.IO.Compression.FileSystem | |
| [System.IO.Compression.ZipFile]::ExtractToDirectory($ipaPath, $tempDir) | |
| $payloadPath = Join-Path -Path $tempDir -ChildPath "Payload" | |
| $appPath = (Get-ChildItem -Path $payloadPath -Directory).FullName | |
| $plistPath = Join-Path -Path $appPath -ChildPath "Info.plist" | |
| if (-not (Test-Path -LiteralPath $plistPath)) { | |
| throw "Could not find Info.plist at '$plistPath'" | |
| } | |
| [xml]$plist = Get-Content -LiteralPath $plistPath | |
| $versionNode = $plist.SelectSingleNode("//key[text()='CFBundleShortVersionString']/following-sibling::string[1]") | |
| $buildNode = $plist.SelectSingleNode("//key[text()='CFBundleVersion']/following-sibling::string[1]") | |
| if (-not ($versionNode -and $buildNode)) { | |
| throw "Could not find version or build number keys in Info.plist" | |
| } | |
| $version = $versionNode.'#text' | |
| $buildNumber = $buildNode.'#text' | |
| Write-Host " - Found Version: $version" | |
| Write-Host " - Found Build Number: $buildNumber" | |
| return [PSCustomObject]@{ | |
| Version = $version | |
| BuildNumber = $buildNumber | |
| } | |
| } | |
| finally { | |
| if (Test-Path -LiteralPath $tempDir) { | |
| Remove-Item -Recurse -Force -LiteralPath $tempDir | |
| } | |
| } | |
| } | |
| function Get-ApkVersionInfo($apkPath) { | |
| Write-Host "Extracting version info from '$apkPath' using aapt..." | |
| try { | |
| $aaptOutput = aapt dump badging $apkPath | |
| $versionName = $aaptOutput | Select-String -Pattern "versionName='([^']+)'" | ForEach-Object { $_.Matches[0].Groups[1].Value } | |
| $versionCode = $aaptOutput | Select-String -Pattern "versionCode='([^']+)'" | ForEach-Object { $_.Matches[0].Groups[1].Value } | |
| if (-not ($versionName -and $versionCode)) { | |
| throw "Could not parse version name or code from aapt output." | |
| } | |
| Write-Host " - Found Version: $versionName" | |
| Write-Host " - Found Build Number: $versionCode" | |
| return [PSCustomObject]@{ | |
| Version = $versionName | |
| BuildNumber = $versionCode | |
| } | |
| } | |
| catch { | |
| Write-Host "Failed to get version info from APK. Ensure 'aapt' is in your PATH." -ForegroundColor Red | |
| throw | |
| } | |
| } | |
| function GenerateKey{ | |
| try { | |
| $aes = [System.Security.Cryptography.Aes]::Create(); | |
| $aesProvider = New-Object System.Security.Cryptography.AesCryptoServiceProvider; | |
| $aesProvider.GenerateKey(); | |
| $aesProvider.Key; | |
| } finally { | |
| if ($null -ne $aesProvider) { $aesProvider.Dispose(); } | |
| if ($null -ne $aes) { $aes.Dispose(); } | |
| } | |
| } | |
| function GenerateIV{ | |
| try { | |
| $aes = [System.Security.Cryptography.Aes]::Create(); | |
| $aes.IV; | |
| } finally { | |
| if ($null -ne $aes) { $aes.Dispose(); } | |
| } | |
| } | |
| function EncryptFileWithIV($sourceFile, $targetFile, $encryptionKey, $hmacKey, $initializationVector){ | |
| $bufferBlockSize = 1024 * 4; | |
| $computedMac = $null; | |
| try { | |
| $aes = [System.Security.Cryptography.Aes]::Create(); | |
| $hmacSha256 = New-Object System.Security.Cryptography.HMACSHA256; | |
| $hmacSha256.Key = $hmacKey; | |
| $hmacLength = $hmacSha256.HashSize / 8; | |
| $buffer = New-Object byte[] $bufferBlockSize; | |
| $bytesRead = 0; | |
| $targetStream = [System.IO.File]::Open($targetFile, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write, [System.IO.FileShare]::Read); | |
| $targetStream.Write($buffer, 0, $hmacLength + $initializationVector.Length); | |
| try { | |
| $encryptor = $aes.CreateEncryptor($encryptionKey, $initializationVector); | |
| $sourceStream = [System.IO.File]::Open($sourceFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read); | |
| $cryptoStream = New-Object System.Security.Cryptography.CryptoStream -ArgumentList @($targetStream, $encryptor, [System.Security.Cryptography.CryptoStreamMode]::Write); | |
| $targetStream = $null; | |
| while (($bytesRead = $sourceStream.Read($buffer, 0, $bufferBlockSize)) -gt 0) { | |
| $cryptoStream.Write($buffer, 0, $bytesRead); | |
| $cryptoStream.Flush(); | |
| } | |
| $cryptoStream.FlushFinalBlock(); | |
| } finally { | |
| if ($null -ne $cryptoStream) { $cryptoStream.Dispose(); } | |
| if ($null -ne $sourceStream) { $sourceStream.Dispose(); } | |
| if ($null -ne $encryptor) { $encryptor.Dispose(); } | |
| } | |
| try { | |
| $finalStream = [System.IO.File]::Open($targetFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::Read) | |
| $finalStream.Seek($hmacLength, [System.IO.SeekOrigin]::Begin) > $null; | |
| $finalStream.Write($initializationVector, 0, $initializationVector.Length); | |
| $finalStream.Seek($hmacLength, [System.IO.SeekOrigin]::Begin) > $null; | |
| $hmac = $hmacSha256.ComputeHash($finalStream); | |
| $computedMac = $hmac; | |
| $finalStream.Seek(0, [System.IO.SeekOrigin]::Begin) > $null; | |
| $finalStream.Write($hmac, 0, $hmac.Length); | |
| } finally { | |
| if ($null -ne $finalStream) { $finalStream.Dispose(); } | |
| } | |
| } finally { | |
| if ($null -ne $targetStream) { $targetStream.Dispose(); } | |
| if ($null -ne $aes) { $aes.Dispose(); } | |
| } | |
| $computedMac; | |
| } | |
| function EncryptFile($sourceFile, $targetFile){ | |
| $encryptionKey = GenerateKey; | |
| $hmacKey = GenerateKey; | |
| $initializationVector = GenerateIV; | |
| # Create the encrypted target file and compute the HMAC value. | |
| $mac = EncryptFileWithIV $sourceFile $targetFile $encryptionKey $hmacKey $initializationVector; | |
| # Compute the SHA256 hash of the source file and convert the result to bytes. | |
| $fileDigest = (Get-FileHash $sourceFile -Algorithm SHA256).Hash; | |
| $fileDigestBytes = New-Object byte[] ($fileDigest.Length / 2); | |
| for ($i = 0; $i -lt $fileDigest.Length; $i += 2){ | |
| $fileDigestBytes[$i / 2] = [System.Convert]::ToByte($fileDigest.Substring($i, 2), 16); | |
| } | |
| # Return an object that will serialize correctly to the file commit Graph API. | |
| $encryptionInfo = @{}; | |
| $encryptionInfo.encryptionKey = [System.Convert]::ToBase64String($encryptionKey); | |
| $encryptionInfo.macKey = [System.Convert]::ToBase64String($hmacKey); | |
| $encryptionInfo.initializationVector = [System.Convert]::ToBase64String($initializationVector); | |
| $encryptionInfo.mac = [System.Convert]::ToBase64String($mac); | |
| $encryptionInfo.profileIdentifier = "ProfileVersion1"; | |
| $encryptionInfo.fileDigest = [System.Convert]::ToBase64String($fileDigestBytes); | |
| $encryptionInfo.fileDigestAlgorithm = "SHA256"; | |
| $fileEncryptionInfo = @{}; | |
| $fileEncryptionInfo.fileEncryptionInfo = $encryptionInfo; | |
| $fileEncryptionInfo; | |
| } | |
| function WaitForFileProcessing($fileUri, $stage){ | |
| $attempts= 60; | |
| $waitTimeInSeconds = 1; | |
| $successState = "$($stage)Success"; | |
| $pendingState = "$($stage)Pending"; | |
| $file = $null; | |
| while ($attempts -gt 0) { | |
| $file = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceAppManagement/$fileUri" -Method GET -Headers $headers -ContentType "application/json" | |
| # MakeGetRequest $fileUri; | |
| if ($file.uploadState -eq $successState) { | |
| break; | |
| } elseif ($file.uploadState -ne $pendingState) { | |
| Write-Host "File processing response (failure):" -ForegroundColor Red | |
| Write-Host ($file | ConvertTo-Json -Depth 10) | |
| throw "File upload state is not success: $($file.uploadState)"; | |
| } | |
| Start-Sleep $waitTimeInSeconds; | |
| $attempts--; | |
| } | |
| if ($null -eq $file) { | |
| throw "File request did not complete in the allotted time."; | |
| } | |
| $file; | |
| } | |
| Function Test-SourceFile(){ | |
| param( | |
| [parameter(Mandatory=$true)] | |
| [ValidateNotNullOrEmpty()] | |
| $sourceFile | |
| ) | |
| try { | |
| if(!(test-path "$sourceFile")){ | |
| Write-Host "Source File '$sourceFile' doesn't exist..." -ForegroundColor Red | |
| throw | |
| } | |
| } catch { | |
| Write-Host -ForegroundColor Red $_.Exception.Message; | |
| Write-Host | |
| break; | |
| } | |
| } | |
| ################################################################################# | |
| ################################################################################# | |
| Write-Host "== Step 0: Prep source ==" -ForegroundColor Yellow | |
| Write-Host "Checking source '$sourceFile'..." -ForegroundColor Yellow | |
| Test-SourceFile "$sourceFile" | |
| # Get version info and set LOB type based on file type | |
| $fileExtension = [System.IO.Path]::GetExtension($sourceFile).ToLower() | |
| $binaryInfo = $null | |
| $lobType = $null | |
| if ($fileExtension -eq ".ipa") { | |
| $binaryInfo = Get-IpaVersionInfo -ipaPath $sourceFile | |
| $lobType = "microsoft.graph.iosLOBApp" | |
| } | |
| elseif ($fileExtension -eq ".apk" -or $fileExtension -eq ".aab") { | |
| $binaryInfo = Get-ApkVersionInfo -apkPath $sourceFile | |
| $lobType = "microsoft.graph.androidLOBApp" | |
| } | |
| else { | |
| throw "Unsupported file type '$fileExtension'. Only '.ipa', '.apk', and '.aab' are supported." | |
| } | |
| $version = $binaryInfo.Version | |
| $buildNumber = $binaryInfo.BuildNumber | |
| # Creating temp file name from Source File path | |
| $tempFile = [System.IO.Path]::Combine([System.IO.Path]::GetDirectoryName($sourceFile), "$([System.IO.Path]::GetFileNameWithoutExtension($sourceFile))_temp.bin") | |
| # Creating filename variable from Source File Path | |
| $fileName = [System.IO.Path]::GetFileName("$sourceFile") | |
| Write-Host "== Step 1: Lookup app ==" -ForegroundColor Yellow | |
| if (-not $intuneAppId) { | |
| throw "The '$intuneAppId' variable is not set. Please provide the ID of the existing Intune application." | |
| } | |
| $appId = $intuneAppId | |
| Write-Host "Using Intune App ID: $appId" | |
| Write-Host | |
| Write-Host "Validating application in Intune..." -ForegroundColor Yellow | |
| try { | |
| $mobileApp = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps/$appId" -Method GET -Headers $headers | |
| $mobileApp | ConvertTo-Json | |
| $expectedODataType = "#$lobType" | |
| if ($mobileApp.'@odata.type' -ne $expectedODataType) { | |
| throw "The specified application's type '$($mobileApp.'@odata.type')' does not match the uploaded file's expected type '$expectedODataType'." | |
| } | |
| } catch { | |
| Write-Host "Failed to retrieve or validate the Intune application with ID '$appId'." -ForegroundColor Red | |
| if ($_.Exception.Response -and $_.Exception.Response.Content) { | |
| Write-Host ($_.Exception.Response.Content | Out-String) | |
| } else { | |
| Write-Host $_ | |
| } | |
| throw | |
| } | |
| # Get the content version for the new app (this will always be 1 until the new app is committed). | |
| Write-Host "== Step 2: New content version ==" -ForegroundColor Yellow | |
| Write-Host | |
| $contentVersionUri = "mobileApps/$appId/$lobType/contentVersions"; | |
| $contentVersion = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceAppManagement/$contentVersionUri" -Method POST -Headers $headers -Body "{}" -ContentType "application/json" | |
| $contentVersion | ConvertTo-Json -Depth 10 | |
| Write-Host "== Step 3: Encrypt IPA ==" -ForegroundColor Yellow | |
| Write-Host | |
| Write-Host "Encrypting '$sourceFile'..." -ForegroundColor Yellow | |
| $encryptionInfo = EncryptFile $sourceFile $tempFile; | |
| $Size = (Get-Item "$sourceFile").Length | |
| $EncrySize = (Get-Item "$tempFile").Length | |
| Write-Host "== Step 4: Register file ==" -ForegroundColor Yellow | |
| Write-Host | |
| Write-Host "Creating Intune file entry..." -ForegroundColor Yellow | |
| $contentVersionId = $contentVersion.id; | |
| $fileBody = @{ | |
| "@odata.type" = "#microsoft.graph.mobileAppContentFile" | |
| name = $filename | |
| size = $Size | |
| sizeEncrypted = $EncrySize; | |
| } | |
| if ($lobType -eq "microsoft.graph.iosLOBApp") { | |
| Write-Host "Building manifest payload for iOS..." -ForegroundColor Yellow | |
| [string]$manifestXML = '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>items</key><array><dict><key>assets</key><array><dict><key>kind</key><string>software-package</string><key>url</key><string>{UrlPlaceHolder}</string></dict></array><key>metadata</key><dict><key>AppRestrictionPolicyTemplate</key> <string>http://management.microsoft.com/PolicyTemplates/AppRestrictions/iOS/v1</string><key>AppRestrictionTechnology</key><string>Windows Intune Application Restrictions Technology for iOS</string><key>IntuneMAMVersion</key><string></string><key>CFBundleSupportedPlatforms</key><array><string>iPhoneOS</string></array><key>MinimumOSVersion</key><string>9.0</string><key>bundle-identifier</key><string>bundleid</string><key>bundle-version</key><string>bundleversion</string><key>kind</key><string>software</string><key>subtitle</key><string>LaunchMeSubtitle</string><key>title</key><string>bundletitle</string></dict></dict></array></dict></plist>' | |
| $manifestXML = $manifestXML.replace("bundleid","$bundleId") | |
| $manifestXML = $manifestXML.replace("bundleversion","$version") | |
| $manifestXML = $manifestXML.replace("bundletitle","$appDisplayName") | |
| $Bytes = [System.Text.Encoding]::ASCII.GetBytes($manifestXML) | |
| $EncodedText =[Convert]::ToBase64String($Bytes) | |
| $fileBody.manifest = $EncodedText; | |
| } | |
| $filesUri = "mobileApps/$appId/$lobType/contentVersions/$contentVersionId/files"; | |
| $file = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceAppManagement/$filesUri" -Method POST -Headers $headers -Body ($fileBody | ConvertTo-Json -Depth 10) -ContentType "application/json" | |
| $file | convertTo-Json -Depth 10 | |
| Write-Host "== Step 5: Wait for SAS ==" -ForegroundColor Yellow | |
| Write-Host | |
| Write-Host "Waiting for upload URL..." -ForegroundColor Yellow | |
| $fileId = $file.id; | |
| $fileUri = "mobileApps/$appId/$lobType/contentVersions/$contentVersionId/files/$fileId" | |
| $file = WaitForFileProcessing $fileUri "AzureStorageUriRequest" | |
| $file | convertTo-Json -Depth 10 | |
| Write-Host "== Step 6: Upload blob ==" -ForegroundColor Yellow | |
| Write-Host | |
| Write-Host "Uploading encrypted IPA..." -f Yellow | |
| $sasUri = $file.azureStorageUri; | |
| UploadFileToAzureStorage $sasUri $tempFile | |
| Write-Host "== Step 7: Commit file ==" -ForegroundColor Yellow | |
| Write-Host | |
| Write-Host "Finalising file in Intune..." -ForegroundColor Yellow | |
| $commitFileUri = "mobileApps/$appId/$lobType/contentVersions/$contentVersionId/files/$fileId/commit" | |
| Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceAppManagement/$commitFileUri" -Method POST -Headers $headers -Body ($encryptionInfo | ConvertTo-Json -Depth 10) -ContentType "application/json" | |
| Write-Host "== Step 8: Wait commit ==" -ForegroundColor Yellow | |
| Write-Host | |
| Write-Host "Waiting for commit completion..." -ForegroundColor Yellow | |
| $file = WaitForFileProcessing $fileUri "CommitFile" | |
| $file | convertTo-Json -Depth 10 | |
| Write-Host "== Step 9: Update app ==" -ForegroundColor Yellow | |
| Write-Host | |
| Write-Host "Saving version/build to Intune..." -ForegroundColor Yellow | |
| $commitAppUri = "mobileApps/$appId"; | |
| $commitAppBody = @{ | |
| "@odata.type" = "#$lobType" | |
| "displayName" = $appDisplayName | |
| "publisher" = $publisher | |
| "versionNumber" = $version | |
| "buildNumber" = $buildNumber | |
| "committedContentVersion" = $contentVersionId | |
| } | |
| Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceAppManagement/$commitAppUri" -Method PATCH -Headers $headers -Body ($commitAppBody | ConvertTo-Json -Depth 10) -ContentType "application/json" | |
| $commitApp = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps/$appId" -Method GET -Headers $headers -ContentType "application/json" | |
| $commitApp | ConvertTo-Json -Depth 10 | |
| Write-Host "Removing Temp file '$tempFile'..." -f Gray | |
| Remove-Item -Path "$tempFile" -Force |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment