PSADT - Deploy Printer Driver & Install Printer

Hello,

I developed a script using PSADT to deploy print drivers to computers and then to install that printer on client devices. I am deploying the script via Intune with the command “Deploy-Application.exe -DeploymentType Install”.

If I manually start the script with admin priviledges on my test client, the script works as intended, however on the intune managed device, only the Deploy-Application script is getting executed without the additional script I have it configured. Please see attached the 2 scripts I have created:

Deploy-Application.ps1:

[CmdletBinding()]
Param (
    [Parameter(Mandatory = $false)]
    [ValidateSet('Install', 'Uninstall', 'Repair')]
    [String]$DeploymentType = 'Install',
    [Parameter(Mandatory = $false)]
    [ValidateSet('Interactive', 'Silent', 'NonInteractive')]
    [String]$DeployMode = 'Interactive',
    [Parameter(Mandatory = $false)]
    [switch]$AllowRebootPassThru = $false,
    [Parameter(Mandatory = $false)]
    [switch]$TerminalServerMode = $false,
    [Parameter(Mandatory = $false)]
    [switch]$DisableLogging = $false
)

Try {
    ## Set the script execution policy for this process
    Try {
        Set-ExecutionPolicy -ExecutionPolicy 'ByPass' -Scope 'Process' -Force -ErrorAction 'Stop'
    }
    Catch {
    }

    ##*===============================================
    ##* VARIABLE DECLARATION
    ##*===============================================
    ## Variables: Application
    [string]$appVendor = 'D&C Contab'
    [string]$appName = 'Konica Minolta D&C Contab'
    [string]$appVersion = '1.0.0.1'
    [string]$appArch = 'x86/x64'
    [string]$appLang = 'EN'
    [string]$appRevision = '01'
    [string]$appScriptVersion = '1.0.0'
    [string]$appScriptDate = '2023-09-06'
    [string]$appUninstallGUID = '{}'
    [string]$appScriptAuthor = 'Radu Stefan Ciubotaru'
    ##*===============================================
    ## Variables: Install Titles (Only set here to override defaults set by the toolkit)
    [String]$installName = ''
    [String]$installTitle = ''

    ##* Do not modify section below
    #region DoNotModify

    ## Variables: Exit Code
    [Int32]$mainExitCode = 0

    ## Variables: Script
    [String]$deployAppScriptFriendlyName = 'Deploy Application'
    [Version]$deployAppScriptVersion = [Version]'3.9.3'
    [String]$deployAppScriptDate = '02/05/2023'
    [Hashtable]$deployAppScriptParameters = $PsBoundParameters

    ## Variables: Environment
    If (Test-Path -LiteralPath 'variable:HostInvocation') {
        $InvocationInfo = $HostInvocation
    }
    Else {
        $InvocationInfo = $MyInvocation
    }
    [String]$scriptDirectory = Split-Path -Path $InvocationInfo.MyCommand.Definition -Parent

    ## Dot source the required App Deploy Toolkit Functions
    Try {
        [String]$moduleAppDeployToolkitMain = "$scriptDirectory\AppDeployToolkit\AppDeployToolkitMain.ps1"
        If (-not (Test-Path -LiteralPath $moduleAppDeployToolkitMain -PathType 'Leaf')) {
            Throw "Module does not exist at the specified location [$moduleAppDeployToolkitMain]."
        }
        If ($DisableLogging) {
            . $moduleAppDeployToolkitMain -DisableLogging
        }
        Else {
            . $moduleAppDeployToolkitMain
        }
    }
    Catch {
        If ($mainExitCode -eq 0) {
            [Int32]$mainExitCode = 60008
        }
        Write-Error -Message "Module [$moduleAppDeployToolkitMain] failed to load: `n$($_.Exception.Message)`n `n$($_.InvocationInfo.PositionMessage)" -ErrorAction 'Continue'
        ## Exit the script, returning the exit code to SCCM
        If (Test-Path -LiteralPath 'variable:HostInvocation') {
            $script:ExitCode = $mainExitCode; Exit
        }
        Else {
            Exit $mainExitCode
        }
    }

    #endregion
    ##* Do not modify section above
    ##*===============================================
    ##* END VARIABLE DECLARATION
    ##*===============================================

    If ($deploymentType -ine 'Uninstall' -and $deploymentType -ine 'Repair') {
        ##*===============================================
        ##* PRE-INSTALLATION
        ##*===============================================
        [String]$installPhase = 'Pre-Installation'

        ## <Perform Pre-Installation tasks here>

        ##*===============================================
        ##* INSTALLATION
        ##*===============================================
        [String]$installPhase = 'Installation'

        Write-Log "Installing drivers..."
        foreach ($driver in Get-ChildItem -Path $dirfiles) {
            Get-Item "$dirfiles\$($driver.Name)\*\*.inf" | ForEach-Object {

                Write-Log "INF: $_"

                pnputil.exe /Add-Driver "$_"
                Add-PrinterDriver "$($driver.Name)"
            }
        }

        ##*===============================================
        ##* POST-INSTALLATION
        ##*===============================================
        [String]$installPhase = 'Post-Installation'

        Write-Log "Copying script.ps1 to C:\Windows\Temp"
        Copy-Item -Path "$dirSupportFiles\Script.ps1" -Destination "C:\Windows\Temp\" -Force
		
        Execute-ProcessAsUser -Path "$PSHOME\powershell.exe" -Parameters "-Command & { & `"C:\Windows\Temp\Script.ps1`"; Exit `$LastExitCode }" -Wait

        Remove-Item -Path "C:\Windows\Temp\Script.ps1" -Force
        Write-Log "Removing script.ps1 from C:\Windows\Temp"

    }
    ElseIf ($deploymentType -ieq 'Uninstall') {
        ##*===============================================
        ##* PRE-UNINSTALLATION
        ##*===============================================
        [String]$installPhase = 'Pre-Uninstallation'

        ## <Perform Pre-Uninstallation tasks here>

        ##*===============================================
        ##* UNINSTALLATION
        ##*===============================================
        [String]$installPhase = 'Uninstallation'

        Remove-Printer "Konica Minolta D&C Office"
        Remove-PrinterPort -Name "IP_printer-office.dc-contab.root" 

        ##*===============================================
        ##* POST-UNINSTALLATION
        ##*===============================================
        [String]$installPhase = 'Post-Uninstallation'

        Remove-RegistryKey -Key "HKLM:\SOFTWARE\$appVendor\Applications\$appName" -ContinueOnError:$True
        Remove-RegistryKey -Key "HKLM:\SOFTWARE\$appVendor\Detection\$appName" -ContinueOnError:$True	

    }
    ElseIf ($deploymentType -ieq 'Repair') {
        ##*===============================================
        ##* PRE-REPAIR
        ##*===============================================
        [String]$installPhase = 'Pre-Repair'

        ## Show Welcome Message, close Internet Explorer with a 60 second countdown before automatically closing
        Show-InstallationWelcome -CloseApps 'iexplore' -CloseAppsCountdown 60

        ## Show Progress Message (with the default message)
        Show-InstallationProgress

        ## <Perform Pre-Repair tasks here>

        ##*===============================================
        ##* REPAIR
        ##*===============================================
        [String]$installPhase = 'Repair'

        ## Handle Zero-Config MSI Repairs
        If ($useDefaultMsi) {
            [Hashtable]$ExecuteDefaultMSISplat = @{ Action = 'Repair'; Path = $defaultMsiFile; }; If ($defaultMstFile) {
                $ExecuteDefaultMSISplat.Add('Transform', $defaultMstFile)
            }
            Execute-MSI @ExecuteDefaultMSISplat
        }
        ## <Perform Repair tasks here>

        ##*===============================================
        ##* POST-REPAIR
        ##*===============================================
        [String]$installPhase = 'Post-Repair'

        ## <Perform Post-Repair tasks here>


    }
    ##*===============================================
    ##* END SCRIPT BODY
    ##*===============================================

    ## Call the Exit-Script function to perform final cleanup operations
    If ($deploymentType -ne 'Uninstall') {
        Set-RegistryKey -Key "HKLM:\SOFTWARE\$appVendor\Applications\$appName" -Name "InstallStatus" -Value '1' -Type String -ContinueOnError:$True
        # Set Intune detection regkey
        Set-RegistryKey -Key "HKLM:\SOFTWARE\$appVendor\Detection\$appName" -Name 'Version' -Type 'String' -Value "$appVersion"
    }
    Exit-Script -ExitCode $mainExitCode
}
Catch {
    Set-RegistryKey -Key "HKLM:\SOFTWARE\$appVendor\Applications\$appName" -Name "InstallStatus" -Value '0' -Type String -ContinueOnError:$True
    [Int32]$mainExitCode = 60001
    [String]$mainErrorMessage = "$(Resolve-Error)"
    Write-Log -Message $mainErrorMessage -Severity 3 -Source $deployAppScriptFriendlyName
    Show-DialogBox -Text $mainErrorMessage -Icon 'Stop'
    Exit-Script -ExitCode $mainExitCode
}

Script.ps1:

Start-Transcript -Path "C:\Windows\Logs\Software\Install-Printer Konica Minolta D&C Contab.log"
if (Test-Connection 'printer-office.dc-contab.root' -Count 1) {
	$DriverName = "KONICA MINOLTA Universal PCL"
	$printerName = "Konica Minolta D&C Office"
	$portName = "IP_printer-office.dc-contab.root"	
	$PortAddress = "printer-office.dc-contab.root"
	$checkPortExists = Get-Printerport -Name $portname -ErrorAction SilentlyContinue
	if (-not $checkPortExists) {
		Add-PrinterPort -name $portName -PrinterHostAddress $PortAddress
	}
	Add-Printer -Name $printerName -PortName $portName -DriverName $DriverName
}
else {
}
Stop-Transcript

Now I might be doing something wrong, but I do not have any idea what. From the PSADT logs I am getting no errors that I can see, the ExecuteAsUser task is succesfully being created and executed as the script intends.

Please provide assistance on this topic.

Can you clarify if you are deploying the application from Intune as System or as User?

Deployed as System. I tried splitting up the script in 2 parts, one installs the driver and one installs the printer, like this it worked.

I think this is by behaviour, Older printer drivers need to be installed using Admin rights (System or an Admin account), Normal users can not install drivers, I’m sure you know this hence why you are doing the Execute-ProcessAsUser to run you Script.ps1

Before we go down a rabbit hole… in your script.ps1 can you output to the transcript what user the script is being executed as, the following should capture this

[System.Security.Principal.WindowsIdentity]::GetCurrent().Name

I suspect that even though you are using the PSADT to Execute-ProcessAsUser I wonder if it is still being run as System for some reason? - Which would sort of explain why it appears to run correctly, but the current user does not see the printer.

This is quite a good detailed blog article about installing Printer drivers using Intune

N.B. If the printer supports more modern Universal Print you also have the option of using an Intune Device Configuration profile to install cloud printers onto users devices, which is more elegant and gets around the Print Nightmare security issue. We use this on both our Hybrid AD Joined and Azure AD Joined devices
Microsoft guide:

1 Like

Hello,

The issue is that the part where Script.ps1 is supposed to run, is not happening. The script gets coppied to C:\Windows\Temp\Script.ps1 and than removed but the execution does not happen.

Regarding Universal Print provisioning, I was hopping that I could try that but 1 printer is not supported (older model) and the other one Epson C878R, even thought it look like it’s supported I do not see any documentation for it. On MS site it’s supported but I can’t see the same thing over on the Epson site. Plus, I see no option inside the printer for that.

You can use essentially any printer that doesn’t support a direct connection to the cloud by installing the Universal Print connector on a computer, thus creating a modern print server.

2 Likes