Network Printer inventory Using SCCM [Microsoft endpoint configuration manager]

SCCM HW inventory agent runs as the ‘SYSTEM’ and cannot see the end-users network drives and printers.

The following two step process will help circumvent the above stated limitation.

1) CREATE HKEY_LOCAL_MACHINE\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS PATH IN THE REGISTRY.

  • Create a SCCM package.
  • The package should run as administrator.
  • The package should run whether or not a user is logged on.

POWERSHELL PACKAGE 1 (Prerequisite):

if (!(Test-Path HKLM:\SOFTWARE\SCCMINVENTORY)) {new-item HKLM:\SOFTWARE\SCCMINVENTORY  -ErrorAction SilentlyContinue} 
$perm = get-acl HKLM:\SOFTWARE\SCCMINVENTORY  -ErrorAction SilentlyContinue 
$rule = New-Object System.Security.AccessControl.RegistryAccessRule("Authenticated Users","FullControl", "ContainerInherit, ObjectInherit", "InheritOnly", "Allow")  -ErrorAction SilentlyContinue 
$perm.SetAccessRule($rule) 
Set-Acl -Path HKLM:\SOFTWARE\SCCMINVENTORY $perm  -ErrorAction SilentlyContinue 
if (!(Test-Path HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS)) {new-item HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS -ErrorAction SilentlyContinue}
  • SAVE POWERSHELL FILE AS: PrinterInvRegSetup.ps1
  • SETUP THE SCCM PACKAGE/PROGRAM WITH COMMAND LINE:
%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\PowerShell.exe -NonInteractive -WindowStyle Hidden -noprofile -ExecutionPolicy Bypass -file .\PrinterInvRegSetup.ps1

2) CAPTURE CURRENT USER’S PRINTERS AND WRITE THOSE ENTRIES TO THE ABOVE CREATED REGISTRY KEYS.

  • Create a SCCM package
  • The package should be run only when a user is logged in.

 POWERSHELL PACKAGE 2 (Main):

$printers = Get-WMIObject -class Win32_Printer -ErrorAction SilentlyContinue|select-Object -Property ServerName,ShareName,Location,DriverName,PrintProcessor,PortName,Local |Where-Object {$_.Local -ne $true}-ErrorAction SilentlyContinue 
ForEach($printer in $printers){ 
    $PServerName= $printer.ServerName -replace ('\\','') 
    $PShareName = $printer.ShareName 
    $PLocation = $printer.Location 
    $PDriverName = $printer.DriverName 
    $PPrintProcessor = $printer.PrintProcessor 
    $PPortName = $printer.PortName 
    if ((Test-Path HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS)) { 
        if ((Test-Path "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName")) { 
            Remove-item "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName" -Force -ErrorAction SilentlyContinue 
        } 
        New-item "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName" -ErrorAction SilentlyContinue 
        New-ItemProperty "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName" -Name "PrintServer" -Value $PServerName -PropertyType "String" -ErrorAction SilentlyContinue 
        New-ItemProperty "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName" -Name "PrinterQueue" -Value $PShareName -PropertyType "String" -ErrorAction SilentlyContinue 
        New-ItemProperty "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName" -Name "PrinterLocation" -Value $PLocation -PropertyType "String" -ErrorAction SilentlyContinue 
        New-ItemProperty "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName" -Name "PrinterDriver" -Value $PDriverName -PropertyType "String" -ErrorAction SilentlyContinue 
        New-ItemProperty "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName" -Name "PrintProcessor" -Value $PPrintProcessor -PropertyType "String" -ErrorAction SilentlyContinue 
        New-ItemProperty "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName" -Name "PrinterPortName" -Value $PPortName -PropertyType "String" -ErrorAction SilentlyContinue 
        New-ItemProperty "HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS\$PShareName on $PServerName" -Name "DateInventoried" -Value $(get-date) -PropertyType "String" -ErrorAction SilentlyContinue 
    } 
}
  • SAVE POWERSHELL FILE AS: NetworkPrinterInventory.ps1
  • SETUP THE SCCM PACKAGE/PROGRAM WITH COMMAND LINE:
%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\PowerShell.exe -NonInteractive -WindowStyle Hidden -noprofile -ExecutionPolicy Bypass -file .\NetworkPrinterInventory.ps1

3) CREATE A DEPLOYMENT AND SET IT TO ‘RUN ALWAYS’ AND MAKE IT A REQUIREMENT.

  • Now deploy the second package and set the first package as a prerequisite (Check the box – Always run the prerequisite package)
  • The deployment should be set to run every 4 hours and ‘Always rerun’. Mark the deployment as required.

4) ADD THE FOLLOWING IN BETWEEN THE EXTENSION SECTION WITHIN YOUR CONFIGURATION.MOF.

//========================
// Added extensions Start
//========================

#pragma namespace ("\\\\.\\root\\cimv2")
#pragma deleteclass("NETWORKPRINTERS", NOFAIL)
[dynamic, provider("RegProv"), ClassContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\SCCMINVENTORY\\NETWORKPRINTERS")]
Class NETWORKPRINTERS
{
[key] string KeyName;
[PropertyContext("PrintServer")] String PrintServer;
[PropertyContext("PrinterQueue")] String PrinterQueue;
[PropertyContext("PrinterLocation")] String PrinterLocation;
[PropertyContext("PrinterDriver")] String PrinterDriver;
[PropertyContext("PrintProcessor")] String PrintProcessor;
[PropertyContext("PrinterPortName")] String PrinterPortName;
[PropertyContext("DateInventoried")] String DateInventoried;
};

//========================
// Added extensions end
//========================

5) SAVE THE BELOW DATA INTO A FILE CALLED ‘AWESOME.MOF’.

#pragma namespace (“\\\\.\\root\\cimv2\\SMS”)
#pragma deleteclass(“NETWORKPRINTERS”, NOFAIL)
[SMS_Report(TRUE),SMS_Group_Name("NETWORKPRINTERS"),SMS_Class_ID("NETWORKPRINTERS")]
Class NETWORKPRINTERS: SMS_Class_Template
{
[SMS_Report(TRUE),key] string KeyName;
[SMS_Report(TRUE)] String PrintServer;
[SMS_Report(TRUE)] String PrinterQueue;
[SMS_Report(TRUE)] String PrinterLocation;
[SMS_Report(TRUE)] String PrinterDriver;
[SMS_Report(TRUE)] String PrintProcessor;
[SMS_Report(TRUE)] String PrinterPortName;
[SMS_Report(TRUE)] String DateInventoried;
};

6) IMPORT ‘AWESOME.MOF’ INTO SCCM DEFAULT CLIENT SETTINGS.

  • Either import the above MOF file into the Client Setting/Default Client Settings/Hardware Inventory/Classes/Import. Select the option to import every thing.
  • Alternatively, if you have compiled the MOF manually on the PC, Add a new reporting class by clicking the ‘Add’ button and connecting to the PC and selecting the WMI class ‘NETWORKPRINTERS‘
    and that is it. The SCCM resource explorer should soon see the Network Printers.

Related Articles

SCCM task sequence UI – Set computer name and more during an SCCM task sequence deployment

It is always a unique challenge of having to build an OSD experience that includes providing a great user experience during the deployment of a new operating system.

The attached application would allow you to present a front-end to an active end-user who is executing the SCCM task sequence……

Keywords: SCCM tasksequence UI, SCCM Task Sequence User interface, SCCM task sequence Set computer name.

Responses

  1. I try this out, but i get always the error-message:

    Exception calling “SetAccessRule” with “1” argument(s): “Some or all identift references could not be translated.”
    At C:\…NetworkPrinterInvRegSetup.ps1:4 char:1
    + $perm.SetAccessRule($rule)
    +
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : IdentityNotMappedException

    Who can help me to fix this?

    1. Q1: Are you running the PowerShell as Administrator?

      Q2: Does the “Authenticated Users” account exist? (in theory this inbuilt account should exist).

      Try the following code. I’ve used “BUILTIN\Users” instead of “Authenticated Users”

      if (!(Test-Path HKLM:\SOFTWARE\SCCMINVENTORY)) {new-item HKLM:\SOFTWARE\SCCMINVENTORY  -ErrorAction SilentlyContinue} 
      $perm = get-acl HKLM:\SOFTWARE\SCCMINVENTORY  -ErrorAction SilentlyContinue 
      $rule = New-Object System.Security.AccessControl.RegistryAccessRule("BUILTIN\Users","FullControl", "ContainerInherit, ObjectInherit", "InheritOnly", "Allow")  -ErrorAction SilentlyContinue 
      $perm.SetAccessRule($rule) 
      Set-Acl -Path HKLM:\SOFTWARE\SCCMINVENTORY $perm  -ErrorAction SilentlyContinue 
      if (!(Test-Path HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS)) {new-item HKLM:\SOFTWARE\SCCMINVENTORY\NETWORKPRINTERS -ErrorAction SilentlyContinue}
      
  2. hi, thanks for this, i set it up today. Waiting for the admin to test out the config.mof. Was wondering what WQL query you used or what kind of report you now use to reveal all this printer info?

    1. I’ll answer the question for SCCM reporting via SQL. Similar WQL items can be found using the WQL builder.

      Use the following SQL views.

      v_GS_NETWORKPRINTERS – this view will be created when the configuration.mof file is processed by the SMS data loader.
      Join the above view with the V_R_System view on the column named ResourceID. The resourceID column will be found both views (v_GS_NETWORKPRINTERS and V_R_System)

  3. I have created the package and programs as mentioned in the article.
    The first script is creating the registry entries successfully as it is running in administrator or system context.
    But the second script which should run under user context is not adding the network printers of users to the registry key..
    Could you please help me how to resolve this.

DCOM hardening issue.

This application fails to authenticate with WMI on the SCCM server because Microsoft has not yet hardened DCOM on their Windows Preinstallation Environment. We are working on a different approach, but it will only be released during the first quarter of 2024. But until that time, the only workaround will be to uninstall the update corresponding to KB5004442.