### # Creeated: 03/11/2021 - georg@lysergic.dev # Modified: 09/11/2021 - georg@lysergic.dev - Added Intune API based app upload/creation # Modified: 10/11/2021 - georg@lysergic.dev - Added Intune API based app assignment # Modified: 10/11/2021 - georg@lysergic.dev - Added Retry block to catch notPublished assignment errors # # Required structure: # ..\Packages - Sources # ..\Intune - Intune Output # ..\Meta - Package specific configuration (version, architecture and detection method) # ./IntuneWinAppUtil.exe - Tool # ./ServiceUI.exe - System context wrapper # # Other prerequesites: # $ Connect-MSIntuneGraph -TenantID .onmicrosoft.com -ClientID -Verbose # Tip: utilize ./connect-.ps1 if available ### # to-do: move GroupID into a config file. allow for multiple groups. $GroupID = "" # Create IntuneWin blackbox files: Write-Host "`nBulk Action 1/2: " -ForegroundColor White -BackgroundColor Blue Write-Host "Processing of .intunewin files started ...`n" $init_name = "ServiceUI" $init_suffix = "exe" foreach ($app in Get-ChildItem ..\Packages\) { Copy-Item .\ServiceUI.exe ..\Packages\$app\ $basedir = "..\Intune" $outdir = "$basedir\$app" If (!(test-path $basedir\$app.intunewin)) { New-Item -ItemType Directory -Force -Path $outdir .\IntuneWinAppUtil.exe -c "..\Packages\$app" -s "$init_name.$init_suffix" -o "$outdir" Move-Item $outdir\$init_name.intunewin $basedir\$app.intunewin Remove-Item $outdir } else { Write-Host "Skipping IntuneWin creation: " -ForegroundColor Yellow -NoNewline Write-Host "An intunewin file for $app already exists." } } # Create Win32App objects in Intune and Upload the IntuneWin files we created above: Write-Host "`nBulk Action 2/2: " -ForegroundColor White -BackgroundColor Blue Write-Host "Processing of Intune Win32App objects started ...`n" foreach ($IntuneFile in Get-ChildItem ..\Intune\) { $Version = $null $Architecture = $null $ProductCode = $null $DetectionScriptFile = $null $Key = $null $ValueName = $null $ValueContent = $null $Operator = $null $IntuneWinPath = "..\Intune\$IntuneFile" $IntuneWinFile = "$IntuneFile" $DisplayNameConstruct = $IntuneWinFile.Replace("_"," ").Replace(".intunewin","") $app = $IntuneWinFile.Replace(".intunewin","") $DisplayName = "MEM - $DisplayNameConstruct" $Win32App = Get-IntuneWin32App -DisplayName "$DisplayName" If ($Win32App) { Write-Host "Skipping Win32App creation: " -ForegroundColor Yellow -NoNewline Write-Host "$DisplayName might already exist in Intune." } else { Write-Host "Creating and uploading Win32App: " -ForegroundColor Blue -NoNewline Write-Host "$DisplayName" If (Test-Path -Path ..\Meta\$app) { Get-Content ..\Meta\$app | Where-Object {$_.length -gt 0} | Where-Object {!$_.StartsWith("#")} | ForEach-Object { $var = $_.Split('=',2).Trim() Set-Variable -Scope Script -Name $var[0] -Value $var[1] } switch ($DetectionMethod) { msi { $DetectionRule = New-IntuneWin32AppDetectionRuleMSI -ProductCode "$ProductCode" } script { $DetectionRule = New-IntuneWin32AppDetectionRuleScript -ScriptFile $DetectionScriptFile -EnforceSignatureCheck $false -RunAs32Bit $false } registry-integer { $DetectionRule = New-IntuneWin32AppDetectionRuleRegistry -KeyPath "$Key" -ValueName "$ValueName" -IntegerComparison -IntegerComparisonOperator "$Operator" -IntegerComparisonValue "$ValueContent" } file { $DetectionRule = New-IntuneWin32AppDetectionRuleFile -FileOrFolder file -Path "$FilePath" -DetectionType exists -Existence } default { Write-Host "Error: " -ForegroundColor Red -NoNewline Write-Host "Broken metafile or invalid DetectionMethod. Aborting further processing." Exit 1 } } $InstallCommandLine = "ServiceUI.exe -process:explorer.exe `"Deploy-Application.exe`"" $UninstallCommandLine = "ServiceUI.exe -process:explorer.exe `"Deploy-Application.exe -DeploymentType Uninstall`"" $IntuneDescription = "$DisplayNameConstruct $Version $Architecture" $IntuneDisplayName = "$DisplayName $Version" If (test-path ..\Logos\$app.png) { $ImageFile = "..\Logos\$app.png" $Icon = New-IntuneWin32AppIcon -FilePath (Resolve-Path $ImageFile) Add-IntuneWin32App -FilePath (Resolve-Path $IntuneWinPath) -DisplayName $IntuneDisplayName -Description $IntuneDescription -Publisher "Atos" -InstallExperience "system" -RestartBehavior "suppress" -DetectionRule $DetectionRule -InstallCommandLine $InstallCommandLine -UninstallCommandLine $UninstallCommandLine -Icon $Icon } ElseIf (test-path ..\Logos\$app.jpg) { $ImageFile = "..\Logos\$app.jpg" $Icon = New-IntuneWin32AppIcon -FilePath (Resolve-Path $ImageFile) Add-IntuneWin32App -FilePath (Resolve-Path $IntuneWinPath) -DisplayName $IntuneDisplayName -Description $IntuneDescription -Publisher "Atos" -InstallExperience "system" -RestartBehavior "suppress" -DetectionRule $DetectionRule -InstallCommandLine $InstallCommandLine -UninstallCommandLine $UninstallCommandLine -Icon $Icon } ElseIf (test-path ..\Logos\$app.jpeg) { $ImageFile = "..\Logos\$app.jpeg" $Icon = New-IntuneWin32AppIcon -FilePath (Resolve-Path $ImageFile) Add-IntuneWin32App -FilePath (Resolve-Path $IntuneWinPath) -DisplayName $IntuneDisplayName -Description $IntuneDescription -Publisher "Atos" -InstallExperience "system" -RestartBehavior "suppress" -DetectionRule $DetectionRule -InstallCommandLine $InstallCommandLine -UninstallCommandLine $UninstallCommandLine -Icon $Icon } else { Add-IntuneWin32App -FilePath (Resolve-Path $IntuneWinPath) -DisplayName $IntuneDisplayName -Description $IntuneDescription -Publisher "Atos" -InstallExperience "system" -RestartBehavior "suppress" -DetectionRule $DetectionRule -InstallCommandLine $InstallCommandLine -UninstallCommandLine $UninstallCommandLine } } else { Write-Host "Skipping Win32App creation: " -ForegroundColor Yellow -NoNewline Write-Host "I couldn't find a metafile at ..\Meta\$app." } } # If the app output was empty earlier, it should now contain a freshly created app: If (!($Win32App)) { $Win32App = Get-IntuneWin32App -DisplayName "$DisplayName" } # Assign the app to our user group, if it is not assigned already: $Win32AppAssignment = Get-IntuneWin32AppAssignment -ID $Win32App.id If ($Win32AppAssignment) { Write-Host "Skipping Assignment: " -ForegroundColor Yellow -NoNewline Write-Host "$DisplayName seems to be assigned already." } Else { Add-IntuneWin32AppAssignmentGroup -Include -ID $Win32App.id -GroupID $GroupID -Intent "available" -Notification "hideAll" } $AssignmentLoop = $false $AssignmentTries = "3" [int]$AssignmentRetryCount = "0" do { $AssignmentRetryCount = $AssignmentRetryCount + 1 try { If ($Win32App.publishingState -eq 'notPublished') { Write-Host "Warning: " -ForegroundColor Yellow -NoNewline Write-Host "$DisplayName is not marked as `"published`" yet!" $AssignmentLoop = $false throw "1" } ElseIf ($Win32App.publishingState -eq 'published') { Write-Host "OK: " -ForegroundColor Green -NoNewline Write-Host "Finished processing of $DisplayName." $AssignmentLoop = $true } Else { Write-Host "Error: " -ForegroundColor Red -NoNewline Write-Host "Processing of $DisplayName failed. Unhandled publishingState. You should debug this." $AssignmentLoop = $false } } catch { If ($AssignmentRetryCount -ge $AssignmentTries) { Write-Host "Error: " -ForegroundColor Red -NoNewline Write-Host "Failed to aquire `"published`" state. Stopping further processing of $DisplayName." Write-Host "You might need to run this script again in a few minutes for the assignment to push. " -NoNewline Write-Host "If you already run this script twice and it still doesn't work, please delete the app from Intune before trying it again - consider using the following command:" Write-Host "`` Remove-IntuneWin32App -ID"$Win32App.id"`` `nGood luck!" $AssignmentLoop = $true #throw $_.Exception } Else { #Write-Host "Warning: " -ForegroundColor Yellow -NoNewline #Write-Host "Failed to aquire `"published`" state. Trying again in 20 seconds ..." Write-Host "Trying again in 20 seconds - " -NoNewline Write-Host "This was attempt $AssignmentRetryCount out of $AssignmentTries..." Start-Sleep -Seconds 20 $Win32App = Get-IntuneWin32App -DisplayName "$DisplayName" } } } while ($AssignmentLoop -eq $false) Write-Host "`n" } # EOF