diff --git a/IntuneWinAppUtil.exe b/IntuneWinAppUtil.exe
new file mode 100644
index 0000000..566b5e0
Binary files /dev/null and b/IntuneWinAppUtil.exe differ
diff --git a/PackageMyPrinters.ps1 b/PackageMyPrinters.ps1
new file mode 100644
index 0000000..4cfebff
--- /dev/null
+++ b/PackageMyPrinters.ps1
@@ -0,0 +1,368 @@
+Set-Location -Path $PSScriptRoot
+#Log Dir
+$LogDir = ".\Logs"
+New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
+$LogPath = Join-Path $LogDir "SkippedPrinters.csv"
+
+# Show installed printers and let an admin pick one or many
+$SelectedPrinters = Get-Printer | Out-GridView -Title 'Select Printers to Migrate to Intune' -PassThru
+Select-Object Name,DriverName,PortName,ComputerName,ShareName |
+
+#Create Directory Structure
+New-Item -Path .\Drivers -ItemType Directory
+
+if (-not $SelectedPrinters) {
+ Write-Host "No printers selected." -ForegroundColor Yellow
+ return
+}
+
+# Get default B&W Flag
+$defaultbw = Read-Host "**Do you want to default printers to black and white? (Type Y or N and press enter)"
+$defaultbw = $defaultbw.Trim().ToUpper()
+
+# Get default Duplex Flag
+$defaultDP = Read-Host "**Do you want to default printers to duplex printing? (Type Y or N and press enter)"
+$defaultDP = $defaultDP.Trim().ToUpper()
+
+ForEach ($selectedprinter in $selectedprinters) {
+If ($selectedprinter.ShareName) {
+$PrinterName = $selectedprinter.ShareName
+}
+else {
+$PrinterName = $selectedPrinter.Name
+}
+$PortName = $selectedPrinter.PortName
+$PrinterIP = (Get-PrinterPort -Name $PortName).PrinterHostAddress
+$DriverName = $selectedprinter.DriverName
+
+#Grab the 64-bit driver if there are multiple listed and check for INF path. Skip if no INF path.
+$Driver = Get-PrinterDriver -Name $DriverName | Where-Object PrinterEnvironment -eq 'Windows x64' | Select-Object -First 1
+
+#Skip if no driver:
+if (!$Driver) {
+$logskipped = [pscustomobject]@{
+ PrinterName = $PrinterName
+ DriverName = $DriverName
+ PortName = $PortName
+ PrinterIP = $PrinterIP
+ PrinterEnvironment = $Driver.PrinterEnvironment
+ InfPath = $Driver.InfPath
+ Reason = "No driver object present"
+ }
+$logskipped | Export-Csv -Path $LogPath -Append -NoTypeInformation
+Write-Host "Skipping '$printername' - There's no driver object found. See log for additional details." -ForegroundColor Red
+continue
+}
+
+#Skip Driver export if an integrated Windows/Microsoft driver (IPP or similar)
+if ($Driver.Manufacturer -eq 'Microsoft') {
+$logskipped = [pscustomobject]@{
+ PrinterName = $PrinterName
+ DriverName = $DriverName
+ PortName = $PortName
+ PrinterIP = $PrinterIP
+ PrinterEnvironment = $Driver.PrinterEnvironment
+ InfPath = $Driver.InfPath
+ Reason = "Microsoft driver - will be provided by OS/Windows Update"
+ }
+
+$logskipped | Export-Csv -Path $LogPath -Append -NoTypeInformation
+Write-Host "Skipping driver export for '$PrinterName' - Microsoft class driver (no export needed)" -ForegroundColor Yellow
+continue
+}
+
+#Skip drivers with no exportable INF
+ if (!$Driver.InfPath) {
+$logskipped = [pscustomobject]@{
+ PrinterName = $PrinterName
+ DriverName = $DriverName
+ PortName = $PortName
+ PrinterIP = $PrinterIP
+ PrinterEnvironment = $Driver.PrinterEnvironment
+ InfPath = $Driver.InfPath
+ Reason = "INF Path Empty. Cannot export with this script"
+ }
+$logskipped | Export-Csv -Path $LogPath -Append -NoTypeInformation
+Write-Host "Skipping driver export for '$PrinterName' - Microsoft class driver (no export needed)" -ForegroundColor Yellow
+continue
+}
+
+$DriverPath = $Driver.InfPath | Split-Path
+$DriverINF = $Driver.InfPath | Split-Path -Leaf
+
+#Copy Driver Files to directory for packaging
+If (Test-Path .\Drivers\$Drivername) {
+Write-Host "Driver directory already exist"
+}
+Else {
+$DriverDir = New-Item -Path .\ExportedPrinters\$PrinterName\driver -ItemType Directory
+Copy-Item -Path "$DriverPath\*" -Destination $DriverDir -Recurse
+
+#######################################################
+
+#Generate Install script for the printer
+$PkgDir = ".\ExportedPrinters\$PrinterName"
+$InstallPath = Join-Path $PkgDir 'Install.ps1'
+New-Item -ItemType Directory -Path $PkgDir -Force | Out-Null # in case folder wasn't created yet
+Copy-Item -path "$PSScriptRoot\printericon.jpg" -Destination $PkgDir
+
+# If default BW Y & Duplex Y
+If ($defaultbw.Trim().ToUpper() -eq "Y" -and $defaultDP.Trim().ToUpper() -eq "Y") {
+$install = @"
+# Auto-generated installer for: $PrinterName
+
+`$DriverINF = '$DriverINF'
+`$DriverName = '$DriverName'
+`$PortName = '$PortName'
+`$PrinterIP = '$PrinterIP'
+`$PrinterName = '$PrinterName'
+
+pnputil.exe /add-driver ".\Driver\`$DriverINF" /install
+Add-PrinterDriver -Name `$drivername -ErrorAction SilentlyContinue
+
+`$checkPortExists = Get-Printerport -Name `$portname -ErrorAction SilentlyContinue
+
+if (-not `$checkPortExists)
+{
+Add-PrinterPort -name `$portName -PrinterHostAddress `$PrinterIP
+}
+
+`$printDriverExists = Get-PrinterDriver -name `$DriverName -ErrorAction SilentlyContinue
+
+if (`$printDriverExists)
+{
+Add-Printer -Name `$PrinterName -PortName `$portName -DriverName `$DriverName
+}
+else
+{
+Write-Warning "Printer Driver not installed"
+}
+
+Set-PrintConfiguration -PrinterName `$PrinterName -Color `$false
+Set-PrintConfiguration -PrinterName `$PrinterName -DuplexingMode TwoSidedLongEdge
+
+SLEEP 30
+"@
+}
+
+# If Default BW not Y and Duplex not Y
+If ($defaultbw.Trim().ToUpper() -ne "Y" -and $defaultDP.Trim().ToUpper() -ne "Y") {
+$install = @"
+# Auto-generated installer for: $PrinterName
+
+`$DriverINF = '$DriverINF'
+`$DriverName = '$DriverName'
+`$PortName = '$PortName'
+`$PrinterIP = '$PrinterIP'
+`$PrinterName = '$PrinterName'
+
+pnputil.exe /add-driver ".\Driver\`$DriverINF" /install
+Add-PrinterDriver -Name `$drivername -ErrorAction SilentlyContinue
+
+`$checkPortExists = Get-Printerport -Name `$portname -ErrorAction SilentlyContinue
+
+if (-not `$checkPortExists)
+{
+Add-PrinterPort -name `$portName -PrinterHostAddress `$PrinterIP
+}
+
+`$printDriverExists = Get-PrinterDriver -name `$DriverName -ErrorAction SilentlyContinue
+
+if (`$printDriverExists)
+{
+Add-Printer -Name `$PrinterName -PortName `$portName -DriverName `$DriverName
+}
+else
+{
+Write-Warning "Printer Driver not installed"
+}
+
+Set-PrintConfiguration -PrinterName `$PrinterName -Color `$true
+Set-PrintConfiguration -PrinterName `$PrinterName -DuplexingMode OneSided
+
+SLEEP 30
+"@
+}
+
+# If Default BW Y and Duplex not Y
+If ($defaultbw.Trim().ToUpper() -eq "Y" -and $defaultDP.Trim().ToUpper() -ne "Y") {
+$install = @"
+# Auto-generated installer for: $PrinterName
+
+`$DriverINF = '$DriverINF'
+`$DriverName = '$DriverName'
+`$PortName = '$PortName'
+`$PrinterIP = '$PrinterIP'
+`$PrinterName = '$PrinterName'
+
+pnputil.exe /add-driver ".\Driver\`$DriverINF" /install
+Add-PrinterDriver -Name `$drivername -ErrorAction SilentlyContinue
+
+`$checkPortExists = Get-Printerport -Name `$portname -ErrorAction SilentlyContinue
+
+if (-not `$checkPortExists)
+{
+Add-PrinterPort -name `$portName -PrinterHostAddress `$PrinterIP
+}
+
+`$printDriverExists = Get-PrinterDriver -name `$DriverName -ErrorAction SilentlyContinue
+
+if (`$printDriverExists)
+{
+Add-Printer -Name `$PrinterName -PortName `$portName -DriverName `$DriverName
+}
+else
+{
+Write-Warning "Printer Driver not installed"
+}
+
+Set-PrintConfiguration -PrinterName `$PrinterName -Color `$false
+Set-PrintConfiguration -PrinterName `$PrinterName -DuplexingMode OneSided
+
+SLEEP 30
+"@
+}
+
+# If Default BW Y and Duplex not Y
+If ($defaultbw.Trim().ToUpper() -ne "Y" -and $defaultDP.Trim().ToUpper() -eq "Y") {
+$install = @"
+# Auto-generated installer for: $PrinterName
+
+`$DriverINF = '$DriverINF'
+`$DriverName = '$DriverName'
+`$PortName = '$PortName'
+`$PrinterIP = '$PrinterIP'
+`$PrinterName = '$PrinterName'
+
+pnputil.exe /add-driver ".\Driver\`$DriverINF" /install
+Add-PrinterDriver -Name `$drivername -ErrorAction SilentlyContinue
+
+`$checkPortExists = Get-Printerport -Name `$portname -ErrorAction SilentlyContinue
+
+if (-not `$checkPortExists)
+{
+Add-PrinterPort -name `$portName -PrinterHostAddress `$PrinterIP
+}
+
+`$printDriverExists = Get-PrinterDriver -name `$DriverName -ErrorAction SilentlyContinue
+
+if (`$printDriverExists)
+{
+Add-Printer -Name `$PrinterName -PortName `$portName -DriverName `$DriverName
+}
+else
+{
+Write-Warning "Printer Driver not installed"
+}
+
+Set-PrintConfiguration -PrinterName `$PrinterName -Color `$true
+Set-PrintConfiguration -PrinterName `$PrinterName -DuplexingMode TwoSidedLongEdge
+
+SLEEP 30
+"@
+}
+
+Set-Content -Path $InstallPath -Value $install -Encoding UTF8 -Force
+Write-Host "Created: $InstallPath" -ForegroundColor Green
+}
+
+#Generate Detection Script
+$detectionPath = Join-Path $pkgDir 'detection.ps1'
+$detectionScript = @"
+`$PrinterName = "$PrinterName"
+
+`$printerinstalled = Get-Printer -Name "`$PrinterName" -ErrorAction SilentlyContinue
+if (`$printerinstalled) {
+ Write-Output "Printer exists"
+ exit 0
+}
+else {
+ Write-Output "Printer not installed"
+ exit 1
+}
+"@
+
+Set-Content -Path $detectionPath -Value $detectionScript -Encoding UTF8 -Force
+Write-Host "Created: $detectionPath" -ForegroundColor Cyan
+
+#Generate Uninstall Script
+$uninstallPath = Join-Path $pkgDir 'uninstall.ps1'
+$uninstallScript = @"
+`$PrinterName = "$PrinterName"
+`Remove-Printer -Name "`$PrinterName"
+"@
+
+Set-Content -Path $uninstallPath -Value $uninstallScript -Encoding UTF8 -Force
+Write-Host "Created: $uninstallPath" -ForegroundColor Cyan
+
+#Build a manifest file with printer details
+$manifest = @{
+ PrinterName = $PrinterName
+ DriverName = $DriverName
+ DriverINF = $DriverINF
+ PortName = $PortName
+ PrinterIP = $PrinterIP
+ DriverSourcePath = $DriverPath
+ ExportedOnLocal = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss zzz")
+}
+
+#Save as manifest.json next to install.ps1
+$manifestPath = Join-Path $pkgDir 'manifest.json'
+$manifest | ConvertTo-Json -Depth 5 | Set-Content -Path $manifestPath -Encoding UTF8
+
+Write-Host "Created manifest: $manifestPath" -ForegroundColor Cyan
+}
+
+
+#Grab the IntuneWinAppUtil
+$dest = Join-Path (Get-Location) "IntuneWinAppUtil.exe"
+$url = "https://github.com/microsoft/Microsoft-Win32-Content-Prep-Tool/raw/master/IntuneWinAppUtil.exe"
+
+Write-Host "Downloading IntuneWinAppUtil.exe from GitHub..."
+
+ Invoke-WebRequest -Uri $url -OutFile $dest
+
+if (Test-Path $dest) {
+ Write-Host "Download successful" -ForegroundColor Green
+} else {
+ Write-Warning "Download failed. Please check the URL or your network." -Foreground Red
+}
+# Unblock the downloaded exe
+Unblock-File -Path $dest -ErrorAction SilentlyContinue
+
+# Ensure it's executable
+Start-Sleep 1
+
+
+#Package Printer Files for Win32 App Deployment
+#$IntuneWinAppUtil = ".\IntuneWinAppUtil.exe"
+$IntuneWinAppUtil = $dest
+$SourcePath = ".\ExportedPrinters"
+$PrinterFolders = Get-Childitem $SourcePath -Directory
+
+foreach ($PrinterFolder in $PrinterFolders) {
+ $setupFolder = $PrinterFolder.FullName
+ $printerName = $PrinterFolder.Name
+ $setupFile = "install.ps1"
+ $setupPath = Join-Path $setupFolder $setupFile
+
+ if (-not (Test-Path $setupPath)) {
+ Write-Warning "No install.ps1 in $setupFolder - skipping"
+ continue
+ }
+
+ Write-Host "Packaging $printerName for Intune deployment..." -ForegroundColor Cyan
+ & $IntuneWinAppUtil -c $setupFolder -s $setupFile -o $setupFolder -q
+ Write-Host "Successfully Created .intunewin for $printername" -ForegroundColor Green
+}
+
+$runuploadscript = Read-Host "**All printers & drivers have been exported and packaged for Intune upload. Do you want to upload these printers now?** (Type Y or N and press enter)"
+$runuploadscript = $runuploadscript.Trim().ToUpper()
+If ($runuploadscript.Trim().ToUpper() -eq "Y") {
+ Write-Host "User entered $runuploadscript - running script to upload printers to Intune" -ForegroundColor Yellow
+ Start-Sleep 2
+ & .\UploadIntuneWinPrinters.ps1
+}
+else {
+ Write-Host "User entered $runuploadscript - ending script" -ForegroundColor Yellow
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 930a027..0741dff 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,11 @@
+# My Fork:
+- Added toggle to default printers to B&W.
+- Added toggle to default to simplex (duplex is default typically).
+- Added line to unblock downloaded Intune packager.
+- Copies printer icon into printer directories to speed up manual importing.
+
# PrintServerToIntune
PrintServerToIntune is a tool that exports printers from a Windows print server (or workstation) as Intune Win32 Apps and uploads them to your Intune tenant as TCP/IP printers for your Entra-Joined or Hybrid-Joined workstations.
diff --git a/UploadIntuneWinPrinters.ps1 b/UploadIntuneWinPrinters.ps1
new file mode 100644
index 0000000..ea2a28a
--- /dev/null
+++ b/UploadIntuneWinPrinters.ps1
@@ -0,0 +1,311 @@
+function Upload-IntuneWinFile {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory)]
+ [string]$FilePath,
+
+ [Parameter(Mandatory)]
+ [string]$SasUrl,
+
+ [int]$ChunkSizeBytes = 16MB,
+
+ [switch]$SendContentMD5
+ )
+
+ if (-not (Test-Path $FilePath)) {
+ throw "File not found: $FilePath"
+ }
+
+ $blockIds = New-Object System.Collections.Generic.List[string]
+ $totalBytesSent = 0L
+
+ $handler = New-Object System.Net.Http.HttpClientHandler
+ $client = New-Object System.Net.Http.HttpClient($handler)
+ $client.Timeout = [TimeSpan]::FromMinutes(30)
+
+ $fs = [System.IO.File]::OpenRead($FilePath)
+ try {
+ $index = 0
+ $buffer = New-Object byte[] $ChunkSizeBytes
+
+ while (($read = $fs.Read($buffer, 0, $buffer.Length)) -gt 0) {
+ $blockIdPlain = ($index).ToString("0000000000")
+ $blockIdB64 = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($blockIdPlain))
+ $blockIds.Add($blockIdB64) | Out-Null
+
+ $blockUri = "{0}&comp=block&blockid={1}" -f $SasUrl, [Uri]::EscapeDataString($blockIdB64)
+
+ $chunkBytes = New-Object byte[] $read
+ [System.Buffer]::BlockCopy($buffer, 0, $chunkBytes, 0, $read)
+
+ $content = New-Object System.Net.Http.ByteArrayContent -ArgumentList (, $chunkBytes)
+
+ if ($SendContentMD5) {
+ $md5 = [System.Security.Cryptography.MD5]::Create().ComputeHash($chunkBytes)
+ $md5b64 = [Convert]::ToBase64String($md5)
+ $content.Headers.Add("Content-MD5", $md5b64)
+ }
+
+ $resp = $client.PutAsync($blockUri, $content).GetAwaiter().GetResult()
+ if (-not $resp.IsSuccessStatusCode) {
+ $err = $resp.Content.ReadAsStringAsync().GetAwaiter().GetResult()
+ throw "Put Block failed at index $index (size=$read, HTTP $([int]$resp.StatusCode)): $err"
+ }
+
+ $totalBytesSent += $read
+ $index++
+ }
+ }
+ finally {
+ $fs.Dispose()
+ }
+
+ $sb = New-Object System.Text.StringBuilder
+ [void]$sb.Append('')
+ $blockIds | ForEach-Object { [void]$sb.Append("$($_)") }
+ [void]$sb.Append('')
+ $xml = $sb.ToString()
+
+ $uriList = "$SasUrl&comp=blocklist"
+ $xmlContent = New-Object System.Net.Http.StringContent($xml, [Text.Encoding]::UTF8, "application/xml")
+
+ $xmlContent.Headers.Remove("Content-Type") | Out-Null
+ $xmlContent.Headers.Add("Content-Type","application/xml")
+
+ $req = New-Object System.Net.Http.HttpRequestMessage([System.Net.Http.HttpMethod]::Put, $uriList)
+ $req.Content = $xmlContent
+ $req.Headers.Add("x-ms-version","2019-12-12")
+
+ $resp2 = $client.SendAsync($req).GetAwaiter().GetResult()
+ if (-not $resp2.IsSuccessStatusCode) {
+ $err2 = $resp2.Content.ReadAsStringAsync().GetAwaiter().GetResult()
+ throw "Put Block List failed (HTTP $([int]$resp2.StatusCode)): $err2"
+ }
+
+ [pscustomobject]@{
+ FilePath = $FilePath
+ FileLength = (Get-Item $FilePath).Length
+ ChunkSizeBytes = $ChunkSizeBytes
+ BlocksUploaded = $blockIds.Count
+ BytesSent = $totalBytesSent
+ Finalized = $true
+ }
+}
+Start-Transcript -path ".\UploadIntuneWinPrinters.log"
+
+$modules = 'Microsoft.Graph.Authentication', 'Microsoft.Graph.DeviceManagement', 'Microsoft.Graph.Beta.DeviceManagement'
+Write-Host -ForegroundColor DarkYellow "Installing Required Modules if they're missing..."
+Foreach ($module in $modules) {
+if (Get-Module -ListAvailable -Name $module) {
+ Write-Host -ForegroundColor Yellow "$module module is already installed"
+}
+else {
+ Write-Host -ForegroundColor Yellow "Installing the $module Module for Current User"
+ Install-Module -Name $module -Scope CurrentUser -Force
+ Write-Host "Installed $module module for current user"
+}
+}
+
+#Login to Graph
+$scopes = @(
+ "DeviceManagementApps.ReadWrite.All",
+ "DeviceManagementConfiguration.ReadWrite.All",
+ "Files.ReadWrite.All"
+)
+Connect-MgGraph -Scopes $scopes
+
+#Root where all printer packages live
+$source = ".\ExportedPrinters"
+
+#Get Base64 value of image for app icon
+$imagefile = ".\printericon.jpg"
+$imageBytes = [System.IO.File]::ReadAllBytes((Resolve-Path $imageFile))
+$imageBase64 = [Convert]::ToBase64String($imageBytes)
+
+#Find out if we should make printers available to the all users group
+$assignmentresponse = Read-Host "Do you want to assign the printers as available to All Users? (Type Y or N)"
+$assignmentresponse = $assignmentresponse.Trim().ToUpper()
+If ($assignmentresponse -eq "Y") {
+ Write-Host "User entered $assignmentresponse - Printers will be assigned as available to All Users" -ForegroundColor Yellow
+}
+else {
+ Write-Host "User entered $assignmentresponse - Printers will be NOT be assigned" -ForegroundColor Yellow
+}
+
+Start-Sleep 2
+
+#Loop each printer folder and create Win32 App
+$PrinterFolders = Get-ChildItem $source -Directory
+:printerloop foreach ($Printerfolder in $PrinterFolders) {
+ $printerName = $Printerfolder.Name
+ $intunewinPath = Join-Path $Printerfolder.FullName "install.intunewin"
+ $appdetectPath = Join-Path $Printerfolder.FullName "detection.ps1"
+
+ if (-not (Test-Path $intunewinPath)) {
+ Write-Warning "No .intunewin found for $printerName — skipping"
+ continue
+ }
+ if (-not (Test-Path $appdetectPath)) {
+ Write-Warning "No detection.ps1 for $printerName — skipping"
+ continue
+ }
+ Write-Host "Creating Win32 App Shell for $printerName..." -ForegroundColor Cyan
+
+ #Create Win32 app shell
+ $body = @{
+ "@odata.type" = "#microsoft.graph.win32LobApp"
+ displayName = "Printer - $printerName"
+ description = "Installs printer $printerName with packaged driver."
+ publisher = "SMBtotheCloud"
+ isFeatured = $false
+ setupFilePath = "install.ps1"
+ fileName = "install.intunewin"
+ installCommandLine = '%windir%\sysnative\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -NoProfile -File .\install.ps1'
+ uninstallCommandLine = 'powershell.exe -executionpolicy bypass .\uninstall.ps1'
+ installExperience = @{ runAsAccount = "system" }
+ applicableArchitectures = "x64"
+ minimumSupportedOperatingSystem = @{ v10_2004 = $true }
+ detectionRules = @(
+ @{
+ "@odata.type" = "#microsoft.graph.win32LobAppPowerShellScriptDetection"
+ scriptContent = [Convert]::ToBase64String([IO.File]::ReadAllBytes($appdetectPath))
+ enforceSignatureCheck = $false
+ runAs32Bit = $false
+ }
+ )
+ returnCodes = @(
+ @{ type = "success"; returnCode = 0 },
+ @{ type = "success"; returnCode = 3010 },
+ @{ type = "failed"; returnCode = 1603 }
+ )
+ largeIcon = @{
+ type = "image/png"
+ value = "$imageBase64"
+ }
+ }
+
+#Send Win32 App Shell and get appID
+$app = Invoke-MgGraphRequest -Method POST -Uri "/beta/deviceAppManagement/mobileApps" -Body ($body | ConvertTo-Json -Depth 10 -Compress)
+$appId = $app.id
+
+#Create directory for extracted .intunewin contents, set locations and get info from detectionXML
+$tempRoot = Join-Path (Get-Location).Path "ExtractedIntuneWinFiles"
+$safePrinterName = ($PrinterName -replace '[<>:"/\\|?*]', '_')
+$temp = Join-Path $tempRoot ("$safePrinterName" + "_" + $appId)
+New-Item -ItemType Directory -Path $temp -Force | Out-Null
+Add-Type -AssemblyName System.IO.Compression.FileSystem
+[System.IO.Compression.ZipFile]::ExtractToDirectory($intunewinPath, $temp) #need to use this because of file extension
+[xml]$detectionxml = Get-Content (Join-Path $temp 'IntuneWinPackage\Metadata\Detection.xml')
+$unencryptedSize = [int64]$detectionxml.ApplicationInfo.UnencryptedContentSize
+$innerintunewin = Get-ChildItem -Path (Join-Path $temp 'IntuneWinPackage\Contents\') -Filter *.intunewin
+$encryptedsize = [int64]$innerintunewin.Length
+
+#Get Encryption Info from detection.xml for commit to finish Win32App creation
+$encXml = $detectionxml.ApplicationInfo.EncryptionInfo
+$commitBody = @{ fileEncryptionInfo = @{
+ encryptionKey = $encXml.EncryptionKey
+ fileDigest = $encXml.FileDigest
+ fileDigestAlgorithm = $encXml.FileDigestAlgorithm
+ initializationVector = $encXml.InitializationVector
+ mac = $encXml.Mac
+ macKey = $encXml.MacKey
+ profileIdentifier = $encXml.ProfileIdentifier
+}} | ConvertTo-Json -Depth 10
+
+#Set info for intunewin file. Need to send this to generate SAS URL.
+$packagejson = @{
+ name = (Split-Path $intunewinPath -Leaf)
+ size = $unencryptedSize
+ sizeEncrypted = $encryptedsize
+ manifest = $null
+ isDependency = $false
+ } | ConvertTo-Json -Depth 6
+
+#Create new Content Version
+$cv = Invoke-MgGraphRequest POST "/beta/deviceAppManagement/mobileApps/$AppId/microsoft.graph.win32LobApp/contentVersions" -Body "{}" -ContentType "application/json"
+$cvId = $cv.id
+
+#Register file upload for new CV
+$fileObj = Invoke-MgGraphRequest -Method POST -Uri "/beta/deviceAppManagement/mobileApps/$AppId/microsoft.graph.win32LobApp/contentVersions/$cvId/files" -Body $packageJson -ContentType "application/json"
+$fileID = $fileobj.id
+Write-Host "New Content Version $cvid has been created. Waiting for SAS URL to be generated..." -ForegroundColor Cyan
+
+#Wait for SAS URL to populate so we can upload intunewin
+do {
+ Start-Sleep 2
+ $fileObjstatus = Invoke-MgGraphRequest -Method GET -Uri "/beta/deviceAppManagement/mobileApps/$AppId/microsoft.graph.win32LobApp/contentVersions/$cvId/files/$($fileObj.id)"
+ } while (-not $fileObjstatus.azureStorageUri)
+Start-Sleep 2
+Write-Host "Starting upload of intunewin file to Intune" -ForegroundColor Cyan
+
+#upload .intunewin file
+$uploadResult = Upload-IntuneWinFile -FilePath $innerIntunewin.FullName -SasUrl $fileObjStatus.azureStorageUri -ChunkSizeBytes 16MB -SendContentMD5
+$uploadResult | Format-List
+
+start-sleep 3
+
+#Commit App
+Invoke-MgGraphRequest POST "/beta/deviceAppManagement/mobileApps/$AppId/microsoft.graph.win32LobApp/contentVersions/$cvId/files/$fileId/commit" -Body $commitBody -ContentType "application/json"
+
+#Point app at new CV after upload state moved to commitFileSuccess. Timeout of 90 seconds to prevent the script from hanging.
+Write-Host "App committed. Waiting for file upload state to move to success before assigning content version" -ForegroundColor Cyan
+$startTime = Get-Date
+$timeout = [TimeSpan]::FromSeconds(90)
+do {
+ Start-Sleep 2
+ $appstatus = Invoke-MgGraphRequest GET "/beta/deviceAppManagement/mobileApps/$AppId/microsoft.graph.win32LobApp/contentVersions/$cvId/files/$fileId`?$select=id,name,isCommitted,uploadState,size,sizeEncrypted"
+ Write-Host "Current State" - $appstatus.uploadState
+ $elapsed = (Get-Date) - $startTime
+ if ($elapsed -ge $timeout) {
+ Write-Warning "Timeout after 90s while waiting for $($PrinterFolder.Name). Deleting printer app and moving onto the next printer"
+ try {
+ Invoke-MgGraphRequest -Method DELETE -Uri "/beta/deviceAppManagement/mobileApps/$AppId"
+ Write-Host "Deleted orphaned app for $printerName" -ForegroundColor Yellow
+ }
+ catch {
+ Write-Warning "Failed to delete orphaned app for $printerName : $($_.Exception.Message)"
+ }
+ continue printerloop
+ }
+ if ($appstatus.uploadState -eq "commitFileFailed")
+ {
+ Write-Warning "Commit File Failed for $printername. Deleting App and Moving on to next printer"
+ try {
+ Invoke-MgGraphRequest -Method DELETE -Uri "/beta/deviceAppManagement/mobileApps/$AppId"
+ Write-Host "Deleted orphaned app for $printerName" -ForegroundColor Yellow
+ }
+ catch {
+ Write-Warning "Failed to delete orphaned app for $printerName : $($_.Exception.Message)"
+ }
+ continue printerloop
+ }
+ } while ($appstatus.uploadstate -ne "commitFileSuccess")
+
+$patchbody = @{
+"@odata.type" = "#microsoft.graph.win32LobApp"
+committedContentVersion = "$cvId"
+} | ConvertTo-Json
+
+Invoke-MgGraphRequest -Method PATCH -Uri "/beta/deviceAppManagement/mobileApps/$AppId" -Body $patchbody -ContentType "application/json"
+
+#Verify Commited version is correct:
+$app = Invoke-MgGraphRequest GET "/beta/deviceAppManagement/mobileApps/$AppId"
+Write-Host "Committed version (app) = $($app.committedContentVersion) (expected $cvId)"
+Write-Host "Finished creating deployment for $printername - Moving to the next printer in the list." -ForegroundColor Green
+
+#Assign to All Users if chosen
+If ($assignmentresponse -eq "Y") {
+ $assignment = @{
+ "@odata.type" = "#microsoft.graph.mobileAppAssignment"
+ intent = "available"
+ target = @{
+ "@odata.type" = "#microsoft.graph.allLicensedUsersAssignmentTarget"
+ }
+ } | ConvertTo-Json -Depth 5
+
+ Invoke-MgGraphRequest -Method POST -Uri "/beta/deviceAppManagement/mobileApps/$AppId/assignments" -Body $assignment -ContentType "application/json"
+}
+}
+
+Disconnect-MgGraph
+Stop-Transcript
\ No newline at end of file
diff --git a/printericon.jpg b/printericon.jpg
new file mode 100644
index 0000000..f5fb5c7
Binary files /dev/null and b/printericon.jpg differ