EnhancedWin32DeployerAO.psm1
#Region '.\Public\Add-GuidToPs1Files.ps1' -1 function Add-GuidToPs1Files { <# .SYNOPSIS Adds a unique GUID and timestamp to the top of each .ps1 file in a specified directory. .DESCRIPTION This function searches for PowerShell script files (.ps1) within a specified subdirectory of a given root directory. It then prepends a unique GUID and a timestamp to each file for tracking purposes. This is useful for marking scripts in bulk operations or deployments. .PARAMETER AOscriptDirectory The root directory under which the target program folder resides. .PARAMETER programfoldername The name of the subdirectory containing the .ps1 files to be modified. .EXAMPLE Add-GuidToPs1Files -AOscriptDirectory "d:\Scripts" -programfoldername "MyProgram" Adds a tracking GUID and timestamp to all .ps1 files under "d:\Scripts\apps-winget\MyProgram". .NOTES Author: Your Name Date: Get the current date Version: 1.0 #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] # [ValidateScript({Test-Path $_})] [string]$AOscriptDirectory, [Parameter(Mandatory = $true)] [string]$programfoldername ) # Helper function for logging Begin { Write-EnhancedLog -Message "Starting to modify PowerShell files." -Level "INFO" -ForegroundColor Green } Process { $targetFolder = Join-Path -Path $AOscriptDirectory -ChildPath "apps-winget\$programfoldername" if (-Not (Test-Path -Path $targetFolder)) { Write-EnhancedLog -Message "The target folder does not exist: $targetFolder" -Level "ERROR" -ForegroundColor Red return } $ps1Files = Get-ChildItem -Path $targetFolder -Filter *.ps1 -Recurse if ($ps1Files.Count -eq 0) { Write-EnhancedLog -Message "No PowerShell files (.ps1) found in $targetFolder" -Level "WARNING" -ForegroundColor Yellow return } foreach ($file in $ps1Files) { try { $content = Get-Content -Path $file.FullName -ErrorAction Stop $pattern = '^#Unique Tracking ID: .+' $content = $content | Where-Object { $_ -notmatch $pattern } $guid = [guid]::NewGuid().ToString("D").ToLower() $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' $lineToAdd = "#Unique Tracking ID: $guid, Timestamp: $timestamp" $newContent = $lineToAdd, $content Set-Content -Path $file.FullName -Value $newContent -ErrorAction Stop Write-EnhancedLog -Message "Modified file: $($file.FullName)" -Level "VERBOSE" -ForegroundColor Yellow } catch { Write-EnhancedLog -Message "Failed to modify file: $($file.FullName). Error: $($_.Exception.Message)" -Level "ERROR" -ForegroundColor Red } } } End { Write-EnhancedLog -Message "Completed modifications." -Level "INFO" -ForegroundColor Cyan } } # Example usage: # Add-GuidToPs1Files -AOscriptDirectory $AOscriptDirectory #EndRegion '.\Public\Add-GuidToPs1Files.ps1' 86 #Region '.\Public\Compile-Win32_intunewin.ps1' -1 function Compile-Win32_intunewin { param( [Parameter(Mandatory)] [pscustomobject]$Prg, [Parameter(Mandatory)] [string]$Repo_winget, [Parameter(Mandatory)] [string]$Repo_Path, [Parameter(Mandatory)] [string]$Prg_Path ) Write-EnhancedLog -Message "Entering Compile-Win32_intunewin" -Level "WARNING" -ForegroundColor ([ConsoleColor]::Yellow) # Check for application image $Prg_img = if (Test-Path -Path (Join-Path -Path $Prg_Path -ChildPath "$($Prg.id).png")) { Join-Path -Path $Prg_Path -ChildPath "$($Prg.id).png" } else { "$Repo_Path\resources\template\winget\winget-managed.png" } # Download the latest IntuneWinAppUtil # Invoke-WebRequest -Uri $IntuneWinAppUtil_online -OutFile "$Repo_Path\resources\IntuneWinAppUtil.exe" -UseBasicParsing # Create the .intunewin file # Start-Process -FilePath "$Repo_Path\resources\IntuneWinAppUtil.exe" -ArgumentList "-c `"$Prg_Path`" -s install.ps1 -o `"$Prg_Path`" -q" -Wait -WindowStyle Hidden (when used in Linux do not use windowstyle hidden) # Start-Process -FilePath "$Repo_Path\resources\IntuneWinAppUtil.exe" -ArgumentList "-c `"$Prg_Path`" -s install.ps1 -o `"$Prg_Path`" -q" -Wait Upload-Win32App -Prg $Prg -Prg_Path $Prg_Path -Prg_img $Prg_img # Upload-Win32App -Prg $Prg -Prg_Path $Prg_Path Write-EnhancedLog -Message "Exiting Compile-Win32_intunewin" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green) } #EndRegion '.\Public\Compile-Win32_intunewin.ps1' 42 #Region '.\Public\Create-AADGroup.ps1' -1 function Create-AADGroup ($Prg) { # # Convert the Client Secret to a SecureString # $SecureClientSecret = ConvertTo-SecureString $connectionParams.ClientSecret -AsPlainText -Force # # Create a PSCredential object with the Client ID as the user and the Client Secret as the password # $ClientSecretCredential = New-Object System.Management.Automation.PSCredential ($connectionParams.ClientId, $SecureClientSecret) # # Connect to Microsoft Graph # Connect-MgGraph -TenantId $connectionParams.TenantId -ClientSecretCredential $ClientSecretCredential # Your code that interacts with Microsoft Graph goes here # Create Group # $grpname = "$($global:SettingsVAR.AADgrpPrefix )$($Prg.id)" Write-EnhancedLog -Message "setting Group Name" -Level "WARNING" -ForegroundColor ([ConsoleColor]::Yellow) $grpname = "SG007 - Intune - Apps - Microsoft Teams - WinGet - Windows Package Manager" if (!$(Get-MgGroup -Filter "DisplayName eq '$grpname'")) { # Write-Host " Create AAD group for assigment: $grpname" -Foregroundcolor cyan Write-EnhancedLog -Message " Did not find Group $grpname " -Level "WARNING" -ForegroundColor ([ConsoleColor]::Yellow) # $GrpObj = New-MgGroup -DisplayName "$grpname" -Description "App assigment: $($Prg.id) $($Prg.manager)" -MailEnabled:$False -MailNickName $grpname -SecurityEnabled } else { $GrpObj = Get-MgGroup -Filter "DisplayName eq '$grpname'" } Write-EnhancedLog -Message " Assign Group > $grpname < to > $($Prg.Name)" -Level "WARNING" -ForegroundColor ([ConsoleColor]::Yellow) Write-EnhancedLog -Message " calling Get-IntuneWin32App " -Level "WARNING" -ForegroundColor ([ConsoleColor]::Yellow) $Win32App = Get-IntuneWin32App -DisplayName "$($Prg.Name)" Write-EnhancedLog -Message " calling Get-IntuneWin32App - done " -Level "INFO" -ForegroundColor ([ConsoleColor]::Green) Write-EnhancedLog -Message " calling Add-IntuneWin32AppAssignmentGroup " -Level "WARNING" -ForegroundColor ([ConsoleColor]::Yellow) Add-IntuneWin32AppAssignmentGroup -Include -ID $Win32App.id -GroupID $GrpObj.id -Intent "available" -Notification "showAll" Write-EnhancedLog -Message " calling Add-IntuneWin32AppAssignmentGroup - done " -Level "INFO" -ForegroundColor ([ConsoleColor]::Green) } #EndRegion '.\Public\Create-AADGroup.ps1' 47 #Region '.\Public\Get-CustomWin32AppName.ps1' -1 function Get-CustomWin32AppName { [CmdletBinding()] param( [string]$PRGID ) process { if (-not [string]::IsNullOrWhiteSpace($PRGID)) { return $PRGID # Directly return PRGID if it's valid } else { return "DefaultAppName" # Fallback if PRGID is not provided } } } # Get-CustomWin32AppName #EndRegion '.\Public\Get-CustomWin32AppName.ps1' 19 #Region '.\Public\Invoke-PrinterInstallation.ps1' -1 function Invoke-PrinterInstallation { <# .SYNOPSIS Installs or uninstalls printer drivers based on JSON configuration files. .DESCRIPTION This PowerShell function reads printer installation settings from a specified printer configuration JSON file (printer.json) and application configuration JSON file (config.json). It constructs and optionally executes command lines for installing or uninstalling printer drivers. The function proceeds only if the 'PrinterInstall' attribute in the application configuration is set to true. .PARAMETER PrinterConfigPath The full file path to the printer configuration JSON file (printer.json). This file contains the printer settings such as PrinterName, PrinterIPAddress, PortName, DriverName, InfPathRelative, InfFileName, and DriverIdentifier. .PARAMETER AppConfigPath The full file path to the application configuration JSON file (config.json). This file contains application-wide settings including the 'PrinterInstall' flag that controls whether the installation or uninstallation should proceed. .EXAMPLE .\Invoke-PrinterInstallation -PrinterConfigPath "d:\path\to\printer.json" -AppConfigPath "d:\path\to\config.json" Executes the Invoke-PrinterInstallation function using the specified printer and application configuration files. It constructs and displays the install and uninstall commands based on the configurations. .INPUTS None. You cannot pipe objects to Invoke-PrinterInstallation. .OUTPUTS String. Outputs the constructed install and uninstall commands to the console. .NOTES Version: 1.0 Author: Your Name Creation Date: The Date Purpose/Change: Initial function development .LINK URL to more information if available #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$PrinterConfigPath, # Path to printer.json [Parameter(Mandatory = $true)] [string]$AppConfigPath # Path to config.json ) Begin { Write-EnhancedLog -Message "Starting Invoke-PrinterInstallation" -Level "INFO" -ForegroundColor Green } Process { try { if (-not (Test-Path -Path $PrinterConfigPath)) { Write-EnhancedLog -Message "Printer configuration file not found at path: $PrinterConfigPath" -Level "ERROR" -ForegroundColor Red throw "Printer configuration file not found." } if (-not (Test-Path -Path $AppConfigPath)) { Write-EnhancedLog -Message "Application configuration file not found at path: $AppConfigPath" -Level "ERROR" -ForegroundColor Red throw "Application configuration file not found." } $appConfig = Get-Content -Path $AppConfigPath -Raw | ConvertFrom-Json if ($appConfig.PrinterInstall -eq $true) { $printerConfig = Get-Content -Path $PrinterConfigPath -Raw | ConvertFrom-Json $InstallCommandLine = "%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -windowstyle hidden -executionpolicy bypass -File ""install.ps1""" $UninstallCommandLine = "%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -windowstyle hidden -executionpolicy bypass -File ""uninstall.ps1""" $printerConfig.psobject.Properties | ForEach-Object { $InstallCommandLine += " -$($_.Name) `"$($_.Value)`"" $UninstallCommandLine += " -$($_.Name) `"$($_.Value)`"" } Write-EnhancedLog -Message "Install and Uninstall command lines constructed successfully" -Level "VERBOSE" -ForegroundColor Cyan # Return a custom object containing both commands $commands = [PSCustomObject]@{ InstallCommand = $InstallCommandLine UninstallCommand = $UninstallCommandLine } return $commands } else { Write-EnhancedLog -Message "PrinterInstall is not set to true in the application configuration. No commands will be executed." -Level "WARNING" -ForegroundColor Yellow } } catch { Write-EnhancedLog -Message "An error occurred: $_" -Level "ERROR" -ForegroundColor Red } } End { Write-EnhancedLog -Message "Invoke-PrinterInstallation completed" -Level "INFO" -ForegroundColor Green } } # # Define paths to the configuration files # $printerConfigPath = Join-Path -Path $PSScriptRoot -ChildPath "printer.json" # $appConfigPath = Join-Path -Path $PSScriptRoot -ChildPath "config.json" # Invoke-PrinterInstallation -PrinterConfigPath $printerConfigPath -AppConfigPath $appConfigPath #EndRegion '.\Public\Invoke-PrinterInstallation.ps1' 108 #Region '.\Public\Remove-IntuneWinFiles.ps1' -1 function Remove-IntuneWinFiles { <# .SYNOPSIS Removes all *.intuneWin files from a specified directory. .DESCRIPTION This function searches for all files with the .intuneWin extension in the specified directory and removes them. It logs actions taken and any errors encountered using the Write-EnhancedLog function. .PARAMETER DirectoryPath The path to the directory from which *.intuneWin files will be removed. .EXAMPLE Remove-IntuneWinFiles -DirectoryPath "d:\Users\aollivierre\AppData\Local\Intune-Win32-Deployer\apps-winget" Removes all *.intuneWin files from the specified directory and logs the actions. .NOTES Ensure you have the necessary permissions to delete files in the specified directory. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$DirectoryPath ) process { Write-EnhancedLog -Message "Starting to remove *.intuneWin files from $DirectoryPath recursively." -Level "INFO" -ForegroundColor ([ConsoleColor]::Green) try { # Include -Recurse to search within all subdirectories $files = Get-ChildItem -Path $DirectoryPath -Filter "*.intuneWin" -Recurse -ErrorAction Stop if ($files.Count -eq 0) { Write-EnhancedLog -Message "No *.intuneWin files found in $DirectoryPath." -Level "INFO" -ForegroundColor ([ConsoleColor]::Yellow) } else { foreach ($file in $files) { Remove-Item $file.FullName -Force -ErrorAction Stop Write-EnhancedLog -Message "Removed file: $($file.FullName)" -Level "INFO" -ForegroundColor ([ConsoleColor]::Green) } } } catch { Write-EnhancedLog -Message "Error removing *.intuneWin files: $_" -Level "ERROR" -ForegroundColor ([ConsoleColor]::Red) throw $_ # Optionally re-throw the error to handle it further up the call stack. } Write-EnhancedLog -Message "Completed removal of *.intuneWin files from $DirectoryPath recursively." -Level "INFO" -ForegroundColor ([ConsoleColor]::Green) } } #EndRegion '.\Public\Remove-IntuneWinFiles.ps1' 56 #Region '.\Public\Upload-Win32App.ps1' -1 function Upload-Win32App { param( [Parameter(Mandatory = $true)] [pscustomobject]$Prg, [Parameter(Mandatory = $true)] [string]$Prg_Path, [string]$Prg_img, [string]$Win32AppsRootPath, [string]$linetoadd, [Parameter(Mandatory = $true)] [pscustomobject]$config ) Write-EnhancedLog -Message "Entering Upload-Win32App" -Level "WARNING" Write-EnhancedLog -Message "Uploading: $($Prg.name)" -Level "WARNING" $InstallCommandLines = Set-InstallCommandLine -config $config Log-Params -Params @{ Prg = $Prg Prg_Path = $Prg_Path Prg_img = $Prg_img } $paths = Prepare-Paths -Prg $Prg -Prg_Path $Prg_Path -Win32AppsRootPath $Win32AppsRootPath $IntuneWinFile = Create-IntuneWinPackage -Prg $Prg -Prg_Path $Prg_Path -destinationPath $paths.destinationPath Upload-IntuneWinPackage -Prg $Prg -Prg_Path $Prg_Path -Prg_img $Prg_img -config $config -IntuneWinFile $IntuneWinFile -InstallCommandLine $InstallCommandLines.InstallCommandLine -UninstallCommandLine $InstallCommandLines.UninstallCommandLine # Start-Sleep -Seconds 10 # Write-EnhancedLog -Message "Calling Create-AADGroup for $($Prg.name)" -Level "WARNING" # Create-AADGroup -Prg $Prg # Write-EnhancedLog -Message "Completed Create-AADGroup for $($Prg.name)" -Level "INFO" } function Set-InstallCommandLine { param( [Parameter(Mandatory = $true)] [pscustomobject]$config ) if ($config.serviceUIPSADT -eq $true) { $InstallCommandLine = "ServiceUI.exe -process:explorer.exe Deploy-Application.exe -DeploymentType install -Deploymode Interactive" $UninstallCommandLine = "ServiceUI.exe -process:explorer.exe Deploy-Application.exe -DeploymentType Uninstall -Deploymode Interactive" } elseif ($config.PSADT -eq $true) { $InstallCommandLine = "Deploy-Application.exe -DeploymentType install -DeployMode Interactive" $UninstallCommandLine = "Deploy-Application.exe -DeploymentType Uninstall -DeployMode Interactive" } else { $InstallCommandLine = "%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -windowstyle hidden -executionpolicy bypass -command .\install.ps1" $UninstallCommandLine = "%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -windowstyle hidden -executionpolicy bypass -command .\uninstall.ps1" } return @{ InstallCommandLine = $InstallCommandLine UninstallCommandLine = $UninstallCommandLine } } function Prepare-Paths { param( [Parameter(Mandatory = $true)] [pscustomobject]$Prg, [Parameter(Mandatory = $true)] [string]$Prg_Path, [Parameter(Mandatory = $true)] [string]$Win32AppsRootPath ) if (-not (Test-Path -Path $Prg_Path)) { Write-EnhancedLog -Message "Source path $Prg_Path does not exist. Creating it." -Level "INFO" New-Item -Path $Prg_Path -ItemType Directory -Force } $destinationRootPath = Join-Path -Path $Win32AppsRootPath -ChildPath "Win32Apps" if (-not (Test-Path -Path $destinationRootPath)) { New-Item -Path $destinationRootPath -ItemType Directory -Force } $destinationPath = Join-Path -Path $destinationRootPath -ChildPath $Prg.name if (-not (Test-Path -Path $destinationPath)) { New-Item -Path $destinationPath -ItemType Directory -Force } Write-EnhancedLog -Message "Destination path created: $destinationPath" -Level "INFO" return @{ destinationPath = $destinationPath } } function Create-IntuneWinPackage { param( [Parameter(Mandatory = $true)] [pscustomobject]$Prg, [Parameter(Mandatory = $true)] [string]$Prg_Path, [Parameter(Mandatory = $true)] [string]$destinationPath ) try { Write-EnhancedLog -Message "Creating .intunewin package..." -Level "INFO" $setupFile = "install.ps1" # $Win32AppPackage = New-IntuneWin32AppPackage -SourceFolder $Prg_Path -SetupFile $setupFile -OutputFolder $destinationPath -Verbose -Force:$true # using New-IntuneWinPackage instead of New-IntuneWin32AppPackage because it creates a .intunewin file in a cross-platform way both on Windows and Linux New-IntuneWinPackage -SourcePath $Prg_Path -DestinationPath $destinationPath -SetupFile $setupFile -Verbose # Write-Host "Package creation completed successfully." -ForegroundColor Green Write-EnhancedLog -Message "Package creation completed successfully." -Level "INFO" $IntuneWinFile = Join-Path -Path $destinationPath -ChildPath "install.intunewin" # $IntuneWinFile = $Win32AppPackage.Path Write-EnhancedLog -Message "IntuneWinFile path set: $IntuneWinFile" -Level "INFO" return $IntuneWinFile } catch { Write-EnhancedLog -Message "Error creating .intunewin package: $_" -Level "ERROR" Write-Host "Error creating .intunewin package: $_" -ForegroundColor Red exit } } function Upload-IntuneWinPackage { param( [Parameter(Mandatory = $true)] [pscustomobject]$Prg, [Parameter(Mandatory = $true)] [string]$Prg_Path, [Parameter(Mandatory = $true)] [string]$Prg_img, [Parameter(Mandatory = $true)] [pscustomobject]$config, [Parameter(Mandatory = $true)] [string]$IntuneWinFile, [Parameter(Mandatory = $true)] [string]$InstallCommandLine, [Parameter(Mandatory = $true)] [string]$UninstallCommandLine ) try { $DisplayName = "$($Prg.Name)" Write-EnhancedLog -Message "DisplayName set: $DisplayName" -Level "INFO" $DetectionRule = Create-DetectionRule -Prg_Path $Prg_Path $RequirementRule = Create-RequirementRule $Icon = Set-AppIcon -Prg_img $Prg_img $IntuneAppParams = @{ FilePath = $IntuneWinFile Icon = $Icon DisplayName = "$DisplayName ($($config.InstallExperience))" Description = "$DisplayName ($($config.InstallExperience))" Publisher = $config.Publisher AppVersion = $config.AppVersion Developer = $config.Developer Owner = $config.Owner CompanyPortalFeaturedApp = [System.Convert]::ToBoolean($config.CompanyPortalFeaturedApp) InstallCommandLine = $InstallCommandLine UninstallCommandLine = $UninstallCommandLine InstallExperience = $config.InstallExperience RestartBehavior = $config.RestartBehavior DetectionRule = $DetectionRule RequirementRule = $RequirementRule InformationURL = $config.InformationURL PrivacyURL = $config.PrivacyURL Verbose = $true } # Log-Params -Params $IntuneAppParams # Create a copy of $IntuneAppParams excluding the $Icon $IntuneAppParamsForLogging = $IntuneAppParams.Clone() $IntuneAppParamsForLogging.Remove('Icon') Log-Params -Params $IntuneAppParamsForLogging Write-EnhancedLog -Message "Calling Add-IntuneWin32App with IntuneAppParams - in progress" -Level "WARNING" $Win32App = Add-IntuneWin32App @IntuneAppParams Write-EnhancedLog -Message "Win32 app added successfully. App ID: $($Win32App.id)" -Level "INFO" Write-EnhancedLog -Message "Assigning Win32 app to all users..." -Level "WARNING" Add-IntuneWin32AppAssignmentAllUsers -ID $Win32App.id -Intent "available" -Notification "showAll" -Verbose Write-EnhancedLog -Message "Assignment completed successfully." -Level "INFO" } catch { Write-EnhancedLog -Message "Error during IntuneWin32 app process: $_" -Level "ERROR" Write-Host "Error during IntuneWin32 app process: $_" -ForegroundColor Red exit } } function Create-DetectionRule { param( [Parameter(Mandatory = $true)] [string]$Prg_Path ) Write-EnhancedLog -Message "Creating detection rule..." -Level "WARNING" $detectionScriptPath = Join-Path -Path $Prg_Path -ChildPath "check.ps1" if (-not (Test-Path -Path $detectionScriptPath)) { Write-Warning "Detection rule script file does not exist at path: $detectionScriptPath" } else { $DetectionRule = New-IntuneWin32AppDetectionRuleScript -ScriptFile $detectionScriptPath -EnforceSignatureCheck $false -RunAs32Bit $false } Write-EnhancedLog -Message "Detection rule set (calling New-IntuneWin32AppDetectionRuleScript) - done" -Level "INFO" return $DetectionRule } function Create-RequirementRule { Write-EnhancedLog -Message "Setting minimum requirements..." -Level "WARNING" $RequirementRule = New-IntuneWin32AppRequirementRule -Architecture "x64" -MinimumSupportedWindowsRelease "W10_1607" Write-EnhancedLog -Message "Minimum requirements set - done" -Level "INFO" return $RequirementRule } function Set-AppIcon { param( [Parameter(Mandatory = $true)] [string]$Prg_img ) $Icon = New-IntuneWin32AppIcon -FilePath $Prg_img Write-EnhancedLog -Message "App icon set - done" -Level "INFO" return $Icon } #EndRegion '.\Public\Upload-Win32App.ps1' 247 |