Comprehensive Zebra Scanner PowerShell Interaction Documentation

Overview

This documentation provides a detailed guide on using PowerShell scripts to interact with Zebra scanners via the Interop.CoreScanner.dll. It covers how to retrieve scanner information, handle various events like barcode data events, and translate C# and C++ API calls into PowerShell commands. It also includes the full scripts you provided, along with explanations of their components.


Prerequisites

  • PowerShell Version: Ensure PowerShell version 5 or higher is installed on your system.
  • Zebra SDK: The Zebra Scanner SDK must be installed, and the Interop.CoreScanner.dll should be located at C:\Program Files\Zebra Technologies\Barcode Scanners\Common\.
  • Permissions: Run PowerShell with administrative privileges to ensure all commands execute successfully.

Common Components

Loading the DLL

Each script begins by loading the Interop.CoreScanner.dll, which provides methods and properties necessary for interacting with the scanner hardware.


[System.Reflection.Assembly]::LoadFile("C:\Program Files\Zebra Technologies\Barcode Scanners\Common\Interop.CoreScanner.dll") | Out-Null

Creating the Scanner Object

The scripts create an instance of CCoreScannerClass, the primary class for scanner interactions.


$ScannerObject = New-Object Interop.CoreScanner.CCoreScannerClass

Initializing Variables

Several variables are initialized to manage scanner operations and store results.


$Status = 0
$AppHandle = 0
$OutXML = ""
$ScannerCount = 0

Opening the Scanner Connection

The Open method is used to establish a connection with the scanner, taking parameters such as application handle and scanner types.


$ScannerTypes = New-Object int16[] 11
$ScannerTypes[0] = 1
$NumberOfScannerTypes = [int16] 1
$ScannerObject.Open($AppHandle, $ScannerTypes, $NumberOfScannerTypes, [ref] $Status)

Retrieving Scanner Data

GetScanners retrieves information about the connected scanners and stores it in an XML format.


$ScannerObject.GetScanners([ref] $ScannerCount, $ScannerIDList, [ref] $OutXML, [ref] $Status)

Process-Out-XML Function

The Process-Out-XML function is designed to parse and format the XML data returned from the scanner. This function extracts useful information about the scanners and formats it for display.

Key Points:

  1. XML Parsing:
    • The function begins by creating an instance of System.Xml.XmlDocument. This class allows for easy manipulation and querying of XML data.
    
    $XmlContent = New-Object -TypeName System.Xml.XmlDocument
    $XmlContent.LoadXml($XML)
    
    
  2. Extracting Scanner Information:
    • The function uses the scanners and scanner nodes from the XML to extract details about each connected scanner.
    • It pipes the extracted data to Format-Table, which organizes the data into a readable table format.
    
    $XmlContent.scanners.scanner | Format-Table -AutoSize @{Name = 'Scanner ID'; Expression = {$_.scannerID}}, @{Name = 'Host Mode'; Expression = {$_.type}}, @{Name = 'Model Number'; Expression = {$_.modelnumber}}, @{Name = 'Serial Number'; Expression = {$_.serialnumber}}, @{Name = 'Date of Manufacture'; Expression = {$_.DoM}}, @{Name = 'Scanner Firmware Version'; Expression = {$_.firmware}}, @{Name = 'Config Name'; Expression = {$_.configname}}
    
    
  3. Processing and Formatting Output:
    • The main purpose of this function is to transform the raw XML data into a human-readable format, making it easy to review scanner attributes like ID, model number, serial number, and firmware version.
    • The scripts use Format-Table to neatly display the processed output data, making it easier to read and interpret.

Logging

Start-Transcript is used to log script execution details, which is helpful for troubleshooting and auditing.


Start-Transcript -Append -Path "$PSScriptRoot\YourLogFile.log.txt"


Translating API Commands to PowerShell

C# and C++ API calls references are available here.

The Zebra scanner API provides several commands that can be used to control and interact with scanners. Here’s how these commands translate into PowerShell:

Scanner ID

In the SDK context, scanner ID uniquely identifies a scanner device connected to the CoreScanner driver, and is required to communicate programmatically with the device. Developers need to call the GetScanners method of the CoreScanner API in order to retrieve the scanner IDs of connected devices. For example, to switch on a scanner's red LED, the scanner ID of that particular scanner must be obtained to provide that value in the <scannerID> element of inXML of the ExecCommand method call.

During each CoreScanner driver instance, scanner IDs are sequentially assigned to each connected device. When the CoreScanner driver is restarted, the array of connected scanners is reinitialized and previous scanner IDs may no longer be valid. In this case, the GetScanners method must be executed to obtain the new scanner IDs.

During a single CoreScanner driver instance, an RSM (Remote Scanner Management) supported scanner that is unplugged, and reconnected retain its unique scanner ID. However, a non-RSM device is assigned a different scanner ID each time it is reconnected.

  1. Open command:
    • C# Syntax:
      
      void Open(int reserved, System.Array sfTypes, short lengthOfTypes, out int status);
      
      
    • PowerShell Translation:
      
      $ScannerTypes = New-Object int16[] 11
      $ScannerTypes[0] = 1
      $ScannerObject.Open($AppHandle, $ScannerTypes, $NumberOfScannerTypes, [ref] $Status)
      
      
  2. GetScanners command:
    • C# Syntax:
      
      void GetScanners(out short numberOfScanners, System.Array sfScannerIDList, out string outXML, out int status);
      
      
    • PowerShell Translation:
      
      $ScannerObject.GetScanners([ref] $ScannerCount, $ScannerIDList, [ref] $OutXML, [ref] $Status)
      
      
  3. ExecCommand:
    • C# Syntax:
      
      void ExecCommand(int opcode, ref string inXML, out string outXML, out int status);
      
      
    • PowerShell Translation:
      
      $ScannerObject.ExecCommand($OpCode, [ref] $InXML, [ref] $OutXML, [ref] $Status)
      
      
  4. Close command:
    • C# Syntax:
      
      void Close(int reserved, out int status);
      
      
    • PowerShell Translation:
      
      $ScannerObject.Close($AppHandle, [ref] $Status)
      
      

Reference

Refer to the Appendix of Barcode Scanner SDK for Windows for more details. It covers the followings.

  • Error/Status Codes.
  • Methods Invoked Through ExecCommand Or ExecCommandAsync.
  • Action Attributes and Values

NOTE: For a list of a scanner's supported attribute (parameter) numbers and definitions, refer to the Product Reference Guide for that model scanner, available from the Zebra Support website at http://www.zebra.com/support. Attributes include configuration parameters, monitored data, and asset tracking information.

References:


Event Handling in PowerShell

To handle events in PowerShell, you must use the RegisterForEvents method in your C# code block, specifying the event types you wish to subscribe to. Once events are registered, they can be handled using PowerShell's Register-ObjectEvent.

Event Registration for Barcode Data

In the script for handling barcode data scan events, a process is set up to register for barcode events and handle them as they occur.

Event Handling (Barcode Events)

C# Syntax:


void OnBarcodeEvent(short eventType, ref string pscanData);

PowerShell Integration:

The event handling is set up in PowerShell by integrating C# code using Add-Type to define and handle events.

Key Points

  • Define a Delegate:

    A delegate BarcodeEventHandler is defined in C#. This delegate specifies the signature for methods that can handle barcode events.

    
    public delegate void BarcodeEventHandler(int dataType, string pscanData);
    
    
  • Event Handling Class:

    The CoreScannerWrapper class encapsulates the logic for handling barcode events. It includes an event OnBarcode which is triggered whenever a barcode is scanned.

    
    public static event BarcodeEventHandler OnBarcode;
    
    
  • Registering for Events:

    The RegisterForEvents method configures the scanner to listen for specific events (in this case, barcode events). It constructs an XML string to specify which events to register.

    
    string inXml = "<inArgs><cmdArgs><arg-int>1</arg-int><arg-int>1</arg-int></cmdArgs></inArgs>";
    
    coreScannerObject.GetType().InvokeMember("ExecCommand", BindingFlags.InvokeMethod, null, coreScannerObject, new object[] { 1001, inXml, out outXml, status });
    
    
  • Event Callback:

    The BarcodeEvent method serves as the callback that processes barcode data when an event is received. It uses the OnBarcode event to notify subscribers of new barcode data.

    
    public void BarcodeEvent(int dataType, string pscanData) {
        if (OnBarcode != null) {
            OnBarcode(dataType, pscanData);
        }
    }
    
    
  • PowerShell Integration:

    In PowerShell, Register-ObjectEvent is used to bind the event handler to a PowerShell action, allowing barcode data to be processed in real-time within the script.

    
    $ActionBarcodeEvent = { Write-Host $event.SourceArgs }
    Register-ObjectEvent -InputObject $ScannerWrapperObject -SourceIdentifier "BarcodeEvents" -EventName "OnBarcode" -Action $ActionBarcodeEvent
    
    

Event Registration for PNP Events

PNP (Plug and Play) events notify the script when a scanner is physically or logically attached to or detached from the host. In the script for handling firmware updates, a process is set up to register for PNP events and handle them as they occur.

Event Handling (PNP Events)

C# Syntax:


void OnPNPEvent(SHORT eventType, BSTR *ppnpData)

PowerShell Integration:

The event handling is set up in PowerShell by integrating C# code using Add-Type to define and handle events.

Key Points

  • Define a Delegate:

    A delegate CoreScannerEventHandler is defined in C#. This delegate specifies the signature for methods that can handle PNP and RMD events.

    
    public delegate void CoreScannerEventHandler(int eventType, string pscanData);
    
    
  • Event Handling Class:

    The CoreScannerWrapper class encapsulates the logic for handling plug and play events. It includes an OnPNPEvent which is triggered whenever an attach or detach event is received.

    
    public static event CoreScannerEventHandler OnPNPEvent;
    
    
  • Registering for Events:

    The RegisterForEvents method configures the scanner to listen to specific events (in this case, PNP events). It constructs an XML string to specify which events to register.

    
    string inXml = "<inArgs><cmdArgs><arg-int>1</arg-int><arg-int>16</arg-int></cmdArgs></inArgs>";
    
    coreScannerObject.GetType().InvokeMember("ExecCommand", BindingFlags.InvokeMethod, null, coreScannerObject, new object[] { 1001, inXml, out outXml, status });
    
    
  • Event Callback:

    The PNPEvent method serves as the callback that processes PNP data when an event is received. It uses the OnPNPEvent to notify subscribers of new PNP data.

    
    private void PNPEvent(int eventType, string data)
    {
        if (OnPNPEvent != null)
        {
            OnPNPEvent(eventType, data);
        }
    }
    
    
  • PowerShell Integration:

    In PowerShell, Register-ObjectEvent is used to bind the event handler to a PowerShell action, allowing PNP data to be processed in real-time within the script.

    
    $ActionPNPEvent = { Write-Host $event.SourceArgs }
    Register-ObjectEvent -InputObject $ScannerEventWatcher -SourceIdentifier "PNPEvents" -EventName "OnPNPEvent" -Action $ActionPNPEvent
    
    

Event Registration for RMD Events

In the script for handling firmware updates and configuration uploads, a process is set up to register for RMD events and handle them as they occur.

Event Handling (RMD Events)

C# Syntax:


void OnScanRMDEvent(SHORT eventType, BSTR *prmdData)

PowerShell Integration:

The event handling is set up in PowerShell by integrating C# code using Add-Type to define and handle events.

Key Points

  • Define a Delegate:

    A delegate CoreScannerEventHandler is defined in C#. This delegate specifies the signature for methods that can handle PNP and RMD events.

    
    public delegate void CoreScannerEventHandler(int eventType, string pscanData);
    
    
  • Event Handling Class:

    The CoreScannerWrapper class encapsulates the logic for handling RMD events. It includes an OnScanRMDEvent which is triggered whenever an RMD event is received.

    
    public static event CoreScannerEventHandler OnScanRMDEvent;
    
    
  • Registering for Events:

    The RegisterForEvents method configures the scanner to listen to specific events (in this case, RMD events). It constructs an XML string to specify which events to register.

    
    string inXml = "<inArgs><cmdArgs><arg-int>1</arg-int><arg-int>8</arg-int></cmdArgs></inArgs>";
    
    coreScannerObject.GetType().InvokeMember("ExecCommand", BindingFlags.InvokeMethod, null, coreScannerObject, new object[] { 1001, inXml, out outXml, status });
    
    
  • Event Callback:

    The ScanRMDEvent method serves as the callback that processes RMD data when an event is received. It uses the OnScanRMDEvent to notify subscribers of new RMD data.

    
    private void ScanRMDEvent(int eventType, string data)
    {
        if (OnScanRMDEvent != null)
        {
            OnScanRMDEvent(eventType, data);
        }
    }
    
    
  • PowerShell Integration:

    In PowerShell, Register-ObjectEvent is used to bind the event handler to a PowerShell action, allowing RMD data to be processed in real-time within the script.

    
    $ActionRMDEvent = { Write-Host $event.SourceArgs }
    Register-ObjectEvent -InputObject $ScannerEventWatcher -SourceIdentifier "RMDEvents" -EventName "OnScanRMDEvent" -Action $ActionRMDEvent
    
    

API Events

The following events are supported and can be registered using the Zebra API:

  1. ImageEvent: Triggered when an imaging scanner captures images in image mode.
  2. VideoEvent: Triggered when an imaging scanner captures video in video mode.
  3. BarcodeEvent: Triggered when a scanner captures barcodes.
  4. PNPEvent: Triggered when a scanner is attached or detached.
  5. ScanRMDEvent: Receives RMD Events when updating firmware of the scanner.
  6. CommandResponseEvent: Received after an asynchronous command execution.
  7. IOEvent: Received when an exclusively claimed device is accessed by another client application.
  8. ScannerNotificationEvent: Received when a SNAPI scanner changes its operational mode.
  9. BinaryDataEvent: Triggered when an IDC-supported imaging scanner captures an image in Intelligent Document Capture (IDC) or Signature Capture mode.

PowerShell Scripts: Examples and Use Cases

Overview

This section provides full examples of PowerShell scripts to demonstrate their usage and functionality.

As with C++ and C# development, a CoreScanner instance must first be opened, followed by the GetScanners method call to discover connected scanner devices. Clear here to learn more about the documentation.

Full Script Examples

Retrieve Asset Information

This script queries and logs the asset information of connected scanners.


# Description : Following script query the asset information of the connected scanners timely. Support PSVersion 5+.
# Copyright : ©2026 Zebra Technologies Corp. and/or its affiliates.

# Log everything, file will create in the script execution folder.
# Comment the following line if logging is not required.
Start-Transcript -Append -Path $PSScriptRoot"\CoreScanner_AssetInfo.log.txt"

# Process GetScanners out XML and list the asset information
Function Process-Out-XML ($XML)
{
    $XmlContent = New-Object -TypeName System.Xml.XmlDocument
    $XmlContent.LoadXml($XML)

    # Pipe asset information
    $XmlContent.scanners.scanner | Format-Table -AutoSize @{Name = 'Scanner ID'; Expression = {$_.scannerID}},
                                                            @{Name = 'Host Mode'; Expression = {$_.type}}, 
                                                            @{Name = 'Model Number'; Expression = {$_.modelnumber}},
                                                            @{Name = 'Serial Number'; Expression = {$_.serialnumber}},
                                                            @{Name = 'Date of Manufacture'; Expression = {$_.DoM}},
                                                            @{Name = 'Scanner Firmware Version'; Expression = {$_.firmware}}
}

# Main script to execute
Invoke-Command -ScriptBlock {
    # Initialize CoreScanner
    Write-Output "$(Get-Date) Loading Interop.CoreScanner.dll";		
	[System.Reflection.Assembly]::LoadFile("C:\Program Files\Zebra Technologies\Barcode Scanners\Common\Interop.CoreScanner.dll")|Out-Null;		
	$ScannerObject = New-Object Interop.CoreScanner.CCoreScannerClass;

    # Initialize
	$Status = 0;
	$AppHandle = 0;
    $OutXML = "";
    $ScannerCount = 0;
    
    # For all scanners, set to 1
	$ScannerTypes = New-Object int16[] 11;
	$ScannerTypes[0] = 1;
	
    # For all scanner types, set to 1
	$NumberOfScannerTypes = [int16] 1;

    $ScannerIDList = New-Object int16[] 255;
	
    # Invoke Open API		
	$ScannerObject.Open($AppHandle, $ScannerTypes, $NumberOfScannerTypes, [ref] $Status);
	Write-Output "$(Get-Date) Scanner.Open() Status: $Status";

    # Invoke GetScanners API, process XML to query scanners
    $ScannerObject.GetScanners([ref] $ScannerCount, $ScannerIDList, [ref] $OutXML, [ref] $Status)
    Write-Output "$(Get-Date) GetScanners API Invoke Status: $Status";
    Write-Output "$(Get-Date) Number of Connected Scanner(s) to the Host: $ScannerCount";
    
    Process-Out-XML -XML $OutXML;
}

Retrieve Barcode Data Scan Events

This script sets up and handles barcode scan events using a C# wrapper.


# Description : Following script query the scanner barcode events. Support PSVersion 5+.
# Copyright : ©2026 Zebra Technologies Corp. and/or its affiliates.

# Main script to execute
Invoke-Command -ScriptBlock {

add-Type -typedef @"
using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace CoreScannerWrapperLib
{
    public delegate void BarcodeEventHandler(int dataType, string pscanData);
    
    /// <summary>
    /// CoreScanner Wrapper for barcode events
    /// </summary>
    public class CoreScannerWrapper
    {
        public static event BarcodeEventHandler OnBarcode;

        private const int EventTypeBarcode = 1;
        private const short NumberOfScannerTypes = 1;
        private const int StatusFalse = -1;

        private Type objType;
        private object coreScannerObject = null;
        private int appHandle = 0;
        private short[] scannerTypes = new short[NumberOfScannerTypes];

        // Initialize CoreScanner COM object
        public CoreScannerWrapper()
        {
            string progId = "CoreScanner.CoreScanner";
            objType = Type.GetTypeFromProgID(progId);
            coreScannerObject = Activator.CreateInstance(objType);
        }

        public int Open()
        {
            int status = StatusFalse;
            short numberOfTypes = 1;
            short[] scannerTypes = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            scannerTypes[0] = 1;

            coreScannerObject.GetType().InvokeMember("Open", BindingFlags.InvokeMethod, null,
                coreScannerObject, new object[]
                {
                    appHandle,scannerTypes, numberOfTypes, status
                });
            RegisterForEvents();
            return status;
        }

        public void RegisterForEvents()
        {
            string inXml = "";
            string outXml = "";
            long status = -1;
            int opCodeRegisterForEvents = 1001;
            int eventIdCount = 1; // Number of events to register (only barcode events)
            int[] eventIdList = new int[eventIdCount];
            // Register for barcode events only
            eventIdList[0] = EventTypeBarcode;

            string eventIds = String.Join(",", eventIdList);
            inXml = "<inArgs>" +
                    "<cmdArgs>" +
                    "<arg-int>" + eventIdCount + "</arg-int>" + // Number of events to register
                    "<arg-int>" + eventIds + "</arg-int>" + // Event id list of events to register for
                    "</cmdArgs>" +
                    "</inArgs>";
           
            // Call register for events
            status=ExecCommand(opCodeRegisterForEvents, // Opcode: Register for events
                inXml, // Input XML
                out outXml // Output XML 
                ); // Command execution success/failure return status  
           
            MethodInfo method =
                this.GetType().GetMethod("BarcodeEvent",
                    BindingFlags.NonPublic | BindingFlags.Instance);

            MethodInfo barcodeEventCallbackMethod = this.GetType().GetMethod("BarcodeEvent", BindingFlags.Public| BindingFlags.Instance);
            BarcodeEventHandler callback  = (BarcodeEventHandler) Delegate.CreateDelegate(typeof(BarcodeEventHandler), this, barcodeEventCallbackMethod, false);

            Guid sourceId = new Guid("981E3D8B-C756-4195-A702-F198965031C6");   // CoreScanner events GUID
            int dispId = 3;  // Barcode data disp id
            ComEventsHelper.Combine(coreScannerObject, sourceId, dispId, callback);
        }

        public void BarcodeEvent(int dataType,  string pscanData)
        {
            if (OnBarcode != null)
            { 
                OnBarcode(dataType, pscanData);
            }
        }

        public int ExecCommand(int opCode, string inXml, out string outXml)
        {
            int status = StatusFalse;
            outXml = "";

            ParameterModifier[] mods = new ParameterModifier[] { new ParameterModifier(4) };
            mods[0][2] = true;
            mods[0][3] = true;

            object[] parameters = new object[4];
            parameters[0] = opCode;
            parameters[1] = inXml;
            parameters[2] = "";
            parameters[3] = StatusFalse;

            coreScannerObject.GetType().InvokeMember("ExecCommand", BindingFlags.InvokeMethod, null, coreScannerObject, parameters, mods, null, null);
            outXml = (string)parameters[2];
            status = (int)parameters[3];
            return status;
        }

        public int Close()
        {
            int status = StatusFalse;
            coreScannerObject.GetType().InvokeMember("Close", BindingFlags.InvokeMethod, null,
                coreScannerObject, new object[]
                {
                    appHandle, status
                });
            return status;
        }
    }
}
"@

	# Add-Type -TypeDefinition $Source -Language CSharp 
	$ScanneWrapperObject = New-Object CoreScannerWrapperLib.CoreScannerWrapper;

    Write-Output "Starting --------------------"

    $Action = {   
       Write-Host $event.SourceArgs
    }

    Register-ObjectEvent -InputObject $ScanneWrapperObject -SourceIdentifier "BarcodeEvents" -EventName "OnBarcode"  -Action  $Action

    $stat= $ScanneWrapperObject.Open();

    Write-Output "Scan barcodes now --------------------"
    for (($i = 0); $i -lt 10; $i++) {
        Start-Sleep -Seconds 1
    }
    $stat= $ScanneWrapperObject.Close();
    Write-Output "Closing CoreScanner";
    Unregister-Event -SourceIdentifier "BarcodeEvents"
}

Scanner Configuration Load

This script loads the configurations into the scanner.


# Description : Following script loading the configuration into the scanner. Support PSVersion 5+.
# Copyright : ©2026 Zebra Technologies Corp. and/or its affiliates.

# Initialize CoreScanner
[System.Reflection.Assembly]::LoadFile("C:\Program Files\Zebra Technologies\Barcode Scanners\Common\Interop.CoreScanner.dll")|Out-Null;		
$global:ScannerObject = New-Object Interop.CoreScanner.CCoreScannerClass;

# Command return status codes
$global:StatusSuccess = 0
$global:StatusFailed = -1
$global:MultiScannerLoading = 0;
$global:SelectScannerID = 0;


# Display scanner information
# param  $XML : scanner list xml to display
Function Process-Out-XML ($XML)
{
    $XmlContent = New-Object -TypeName System.Xml.XmlDocument
    $XmlContent.LoadXml($XML)

    # Pipe asset information
    $XmlContent.scanners.scanner | Format-Table -AutoSize @{Name = 'ID'; Expression = {$_.scannerID}},
                                                            @{Name = 'Host Mode '; Expression = {$_.type}}, 
                                                            @{Name = 'Model Number '; Expression = {$_.modelnumber}},
                                                            @{Name = 'Serial Number '; Expression = {$_.serialnumber}},
                                                            @{Name = 'Date of Manufacture '; Expression = {$_.DoM}},
                                                            @{Name = 'Firmware Version '; Expression = {$_.firmware}}
}

# Open CoreScanner
# param  $CurrentHandle : Current application handle
# param  $CommandStatus : Command success/fail return status
Function OpenScanner([ref] [int] $CurrentHandle,[ref][int] $CommandStatus) {

    $hApp = 0;
    $StatusValue = $StatusFailed
    # For all scanners, set to 1
	$ScannerTypes = New-Object int16[] 11
	$ScannerTypes[0] = 1;
	
    # For all scanner types, set to 1
	$NumberOfScannerTypes = [int16] 1

    # Open CoreScanner
    $ScannerObject.Open($hApp, $ScannerTypes, $NumberOfScannerTypes, [ref] $StatusValue)

     if ($StatusValue -eq $StatusSuccess) {
           Write-Output "Open Success"
           $CurrentHandle.Value=$hApp
     } else  {
           Write-Output "Open Failed : error code :$StatusValue"
     } 
     $CommandStatus.Value= $StatusValue
}


# Close CoreScanner
# param  $CurrentHandle : Current application handle
# param  $CommandStatus : Command success/fail return status
Function CloseScanner([int]$CurrentHandle,[ref] [int] $CommandStatus) {

    $StatusValue = $StatusFailed;
    # Close CoreScanner
    $ScannerObject.Close($CurrentHandle, [ref] $StatusValue)

    if ($StatusValue -eq $StatusSuccess) {
          Write-Output "Close Success"
    } else  {
          Write-Output "Close Failed : error code :$StatusValue"
    } 
    $CommandStatus.Value= $StatusValue
}

# Process GetScanners out XML and list the asset information
# param  $OutputXml : Output scanner list xml
# param  $NumScanners : Connected scanner count
# param  $CommandStatus : Command success/fail return status
Function GetScanners([ref] [string] $OutputXML, [ref] [int] $NumScanners, [ref] [int] $CommandStatus) {

    $StatusValue = $StatusFailed

    # GetScanners - scanner id list
    $ScannerIDList = New-Object int16[] 255

    # GetScanners - total scanner count
    $CurrentScannerCount = 0

    $CommandOutputXML=""
    
    # Get List of scanners
    $ScannerObject.GetScanners([ref] $CurrentScannerCount,$ScannerIDList, [ref] $CommandOutputXML, [ref] $StatusValue)
     if ($StatusValue -eq $StatusSuccess) {
       $OutputXML.Value = $CommandOutputXML
       $NumScanners.Value =  $CurrentScannerCount
       Write-Output "GetScanners Success"
    } else  {
        Write-Output "GetScanners Failed : error code :$StatusValue"
    } 
    $CommandStatus.Value= $StatusValue
    Write-Output "Number of Connected Scanner(s) to the Host: $ScannerCount"
    Process-Out-XML -XML $CommandOutputXML

}

#Load Configuration to specified scanner 
#param $inXml: Input xml with configuration file path
#param $CommandStatus : Command success/fail return status
Function LoadConfiguration($inXml,[ref] [int] $CommandStatus) {
    Write-Output "Loading Configuration Started"
    $StatusValue = $StatusFailed

    $CommandOutputXML=""
    $OpcodeLoadConfig = 5020  # load configuration opcode
    $ScannerObject.ExecCommand($OpcodeLoadConfig, [ref] $inXml, [ref] $CommandOutputXML, [ref]$StatusValue)
    $CommandStatus.Value= $StatusValue
}

if ($args.Count -eq 0) {
    Write-Output "No configuration file specified : Usage : LoadScannerConfig.ps1 <scanner config file path> <specified scanner id (optional)>"
    return
}

$ConfigFileName = $args[0]

if ($args.Count -eq 2) {
    if ($args[1] -match '^\d+$') {
        $SelectScannerID = [int]$args[1]
        $MultiScannerLoading = 0
    } else {
        Write-Output "Invalid scanner ID specified. It must be a number."
        return
    }
} else {
    $MultiScannerLoading = 1
}

$AppHandle = 0
$Status = $StatusFailed
$OutXML = ""
$ScannerCount = 0
$ConfigFileInvalid = 601
$DeviceIncompatible = 602
$ConfigFileFormatInvalid = 603

# Validate configuration file path
if (-not (Test-Path $ConfigFileName)) {
    Write-Output "Config File not valid"
    return
}

# Open CoreScanner
OpenScanner ([ref]$AppHandle) ([ref]$Status)
if ($Status -ne $StatusSuccess) {
    Write-Output "CoreScanner Open Failed"
    return 
}

# Get connected scanners
GetScanners ([ref]$OutXML) ([ref]$ScannerCount) ([ref]$Status)
if ($Status -ne $StatusSuccess) {
    Write-Output "GetScanners Failed : error code :$Status"
    CloseScanner $AppHandle ([ref]$Status)
    return
}

if ($ScannerCount -le 0) {
    Write-Output "No scanners found"
    CloseScanner $AppHandle ([ref]$Status)
    return
}

$XmlScannerList = New-Object -TypeName System.Xml.XmlDocument
$XmlScannerList.LoadXml($OutXML)

Function Load-Config-To-Scanner {
    param (
        [int]$ScannerId,
        [string]$ConfigFileName
    )
    $ConfigInXml = "<inArgs><scannerID>$ScannerId</scannerID><cmdArgs><arg-string>$ConfigFileName</arg-string></cmdArgs></inArgs>"
    $Status = $StatusFailed

    LoadConfiguration $ConfigInXml ([ref]$Status)
    switch ($Status) {
        $StatusSuccess         { Write-Output "Configuration Load for Scanner : $ScannerId  - Success" }
        $ConfigFileInvalid     { Write-Output "Configuration Load for Scanner : $ScannerId  - Failed : Config File Invalid" }
        $DeviceIncompatible    { Write-Output "Configuration Load for Scanner : $ScannerId  - Failed : Device Incompatible with Config File" }
        $ConfigFileFormatInvalid { Write-Output "Configuration Load for Scanner : $ScannerId  - Failed : Config File Format Invalid" }
        default               { Write-Output "Configuration Load for Scanner : $ScannerId  - Failed : error code :$Status" }
    }
}

if ($MultiScannerLoading -eq 0) {
    # Single scanner loading: use selected scanner ID
    Load-Config-To-Scanner -ScannerId $SelectScannerID -ConfigFileName $ConfigFileName
} else {
    # Multi scanner loading: iterate all scanners
    foreach ($scanner in $XmlScannerList.scanners.scanner) {
        $CurrentScannerId = [int]$scanner.scannerID
        Load-Config-To-Scanner -ScannerId $CurrentScannerId -ConfigFileName $ConfigFileName
    }
}

# Close CoreScanner
CloseScanner $AppHandle ([ref]$Status)

Firmware Download

This script download the firmware into the scanner.


# Description : Following script download the firmware (Plug-in/DAT) into the scanner. Support PSVersion 5+.
# Copyright : ©2026 Zebra Technologies Corp. and/or its affiliates.

# Log everything, file will create in the script execution folder.
Start-Transcript -Append -Path $PSScriptRoot"\CoreScanner_GetAttributes.log.txt"

Function Get-Scanner-Attribute-Values($XML)
{
    $XmlContent = New-Object -TypeName System.Xml.XmlDocument
    $XmlContent.LoadXml($XML)

    # Pipe attribute list
    $ScannerID = $XmlContent.outArgs.scannerID
    Write-Output "Scanner ID : $ScannerID" 

    $XmlContent.outArgs.('arg-xml').response.attrib_list.attribute | Format-Table -AutoSize @{Name = 'Attribute ID'; Expression = {$_.id}},
                                                                                            @{Name = 'Name'; Expression = {$_.name}},
                                                                                            @{Name = 'Data Tyoe'; Expression = {$_.datatype}},
                                                                                            @{Name = 'Permission'; Expression = {$_.permission}},
                                                                                            @{Name = 'Value'; Expression = {$_.value}}
}

Function Sample()
{
    Write-Output "RMD Events"
}

# Main script to execute
Invoke-Command -ScriptBlock {
    # Initialize CoreScanner
    Write-Output "$(Get-Date) Loading Interop.CoreScanner.dll";		
	[System.Reflection.Assembly]::LoadFile("C:\Program Files\Zebra Technologies\Barcode Scanners\Common\Interop.CoreScanner.dll")|Out-Null;		
	$ScannerObject = New-Object Interop.CoreScanner.CCoreScannerClass;

    # Initialize
	$Status = 0;
	$AppHandle = 0;
    $OutXML = "";
    
    # For all scanners, set to 1
	$ScannerTypes = New-Object int16[] 11;
	$ScannerTypes[0] = 1;
	
    # For all scanner types, set to 1
	$NumberOfScannerTypes = [int16] 1;
			
	Write-Output "$(Get-Date) Scanner.Open() Invoke";
	$ScannerObject.Open($AppHandle, $ScannerTypes, $NumberOfScannerTypes, [ref] $Status);
	Write-Output "$(Get-Date) Scanner.Open() Status: $Status";

    # Register for RMD events
    $InXML = "";
    $InXML += "<inArgs>";
    $InXML += "<cmdArgs>";
    $InXML += "<arg-int>1</arg-int>"; # Number of event types to register. In this case only the RMD event type.
    $InXML += "<arg-int>8</arg-int>"; # Event type.
    $InXML += "</cmdArgs>";
    $InXML += "</inArgs>";

    # Opcode for register for events
    $REGISTER_FOR_EVENTS = 1001;

    Write-Output "$(Get-Date) Invoke ExecCommand - Register for Events.";
    $ScannerObject.ExecCommand($REGISTER_FOR_EVENTS, [ref] $InXML, [ref] $OutXML, [ref] $Status)

    Write-Output $Status;

    # Register event handler.....

    #Register-ObjectEvent -InputObject $ScannerObject -EventName ScanRMDEvent -Action {Write-Host "EMD Event Recieved"}
    
    $ScannerObject.add_ScanRMDEvent("Sample");

    #.................................

    # Opcode for firmware download.
    $UPDATE_FIRMWARE_DAT = 5016;
    $UPDATE_FIRMWARE_PLUGIN = 5017;

    # Firmware DAT/Plug-in file path. Choose the correct opcode based on the file type.
    # Following is the 123Scan default Plug-ins folder path.
    $FIRMWARE_FILE_PATH = "C:\ProgramData\123Scan2\Plug-ins\DS9208\DS9208-COMMON DL MODELS-S\022\DS9208-COMMON DL MODELS-S-022.SCNPLG";

    # Scanner ID. For the multiple scanner write a loop statement accoringly.
    $SCANNER_ID = 1;

    $InXML = "";
    $InXML += "<inArgs>";
    $InXML += "<scannerID>";
    $InXML += $SCANNER_ID
    $InXML += "</scannerID>";
    $InXML += "<cmdArgs>";
    $InXML += "<arg-string>";
    $InXML += $FIRMWARE_FILE_PATH;
    $InXML += "</arg-string>";
    $InXML += "<arg-int>2</arg-int>";
    $InXML += "</cmdArgs>";
    $InXML += "</inArgs>";

    Write-Output "$(Get-Date) Invoke ExecCommand - Firmware Download.";
    $ScannerObject.ExecCommand($UPDATE_FIRMWARE_PLUGIN, [ref] $InXML, [ref] $OutXML, [ref] $Status)

    Write-Output $Status;
        
    <#foreach($ScannerID in $ScannerIDList)
    {
        if($ScannerID -ne 0)
        {
            $InXML = ""
            $InXML += "<inArgs>"
            $InXML += "<scannerID>"
            $InXML += $ScannerID
            $InXML += "</scannerID>"
            $InXML += "<cmdArgs><arg-xml><attrib_list>"
            $InXML += $AttributeList -join ","
            $InXML += "</attrib_list></arg-xml></cmdArgs>"
            $InXML += "</inArgs>"

            Write-Output "$(Get-Date) Invoke ExecCommand.";
            $ScannerObject.ExecCommand(5001, [ref] $InXML, [ref] $OutXML, [ref] $Status)

            Get-Scanner-Attribute-Values($OutXML)
        }
    }#>
}

Get Attributes from the Scanner

This script query the attribute values of the given attributes on all the connected scanners.


# Description : Following script query the attribute values of the given attributes on all the connected scanners. Support PSVersion 5+.
# Copyright : ©2026 Zebra Technologies Corp. and/or its affiliates.

# Log everything, file will create in the script execution folder.
Start-Transcript -Append -Path $PSScriptRoot"\CoreScanner_GetAttributes.log.txt"

Function Get-Scanner-Attribute-Values($XML)
{
    $XmlContent = New-Object -TypeName System.Xml.XmlDocument
    $XmlContent.LoadXml($XML)

    # Pipe attribute list
    $ScannerID = $XmlContent.outArgs.scannerID
    Write-Output "Scanner ID : $ScannerID" 

    $XmlContent.outArgs.('arg-xml').response.attrib_list.attribute | Format-Table -AutoSize @{Name = 'Attribute ID'; Expression = {$_.id}},
                                                                                            @{Name = 'Name'; Expression = {$_.name}},
                                                                                            @{Name = 'Data Type'; Expression = {$_.datatype}},
                                                                                            @{Name = 'Permission'; Expression = {$_.permission}},
                                                                                            @{Name = 'Value'; Expression = {$_.value}}
}

# Main script to execute
Invoke-Command -ScriptBlock {
    # Initialize CoreScanner
    Write-Output "$(Get-Date) Loading Interop.CoreScanner.dll";		
	[System.Reflection.Assembly]::LoadFile("C:\Program Files\Zebra Technologies\Barcode Scanners\Common\Interop.CoreScanner.dll")|Out-Null;		
	$ScannerObject = New-Object Interop.CoreScanner.CCoreScannerClass;

    # Initialize
	$Status = 0;
	$AppHandle = 0;
    $OutXML = "";
    
    # For all scanners, set to 1
	$ScannerTypes = New-Object int16[] 11;
	$ScannerTypes[0] = 1;
	
    # For all scanner types, set to 1
	$NumberOfScannerTypes = [int16] 1;

    # Attribute list, comma separated
    [int[]]$AttributeList = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

    # Scanner IDs list, comma separated
    [int[]]$ScannerIDList = 1
			
	Write-Output "$(Get-Date) Scanner.Open() Invoke";
	$ScannerObject.Open($AppHandle, $ScannerTypes, $NumberOfScannerTypes, [ref] $Status);
	Write-Output "$(Get-Date) Scanner.Open() Status: $Status";
        
    foreach($ScannerID in $ScannerIDList)
    {
        if($ScannerID -ne 0)
        {
            $InXML = ""
            $InXML += "<inArgs>"
            $InXML += "<scannerID>"
            $InXML += $ScannerID
            $InXML += "</scannerID>"
            $InXML += "<cmdArgs><arg-xml><attrib_list>"
            $InXML += $AttributeList -join ","
            $InXML += "</attrib_list></arg-xml></cmdArgs>"
            $InXML += "</inArgs>"

            Write-Output "$(Get-Date) Invoke ExecCommand.";
            $ScannerObject.ExecCommand(5001, [ref] $InXML, [ref] $OutXML, [ref] $Status)

            Get-Scanner-Attribute-Values($OutXML)
        }
    }
}

Set Attributes in the Scanner

This script set the attribute values of the given scanner.


# Description : Following script set the attribute values of the given scanner. Support PSVersion 5+.
# Copyright : ©2026 Zebra Technologies Corp. and/or its affiliates.

# Log everything, file will create in the script execution folder.
Start-Transcript -Append -Path $PSScriptRoot"\CoreScanner_SetAttributes.log.txt"


Function Get-Scanner-Attribute-Values($XML)
{
    $XmlContent = New-Object -TypeName System.Xml.XmlDocument
    $XmlContent.LoadXml($XML)

    # Pipe attribute list
    $ScannerID = $XmlContent.outArgs.scannerID
    Write-Output "Scanner ID : $ScannerID" 

    $XmlContent.outArgs.('arg-xml').response.attrib_list.attribute | Format-Table -AutoSize @{Name = 'Attribute ID'; Expression = {$_.id}},
                                                                                            @{Name = 'Name'; Expression = {$_.name}},
                                                                                            @{Name = 'Data Type'; Expression = {$_.datatype}},
                                                                                            @{Name = 'Permission'; Expression = {$_.permission}},
                                                                                            @{Name = 'Value'; Expression = {$_.value}}
}

# Main script to execute
Invoke-Command -ScriptBlock {
    # Initialize CoreScanner
    Write-Output "$(Get-Date) Loading Interop.CoreScanner.dll";		
	[System.Reflection.Assembly]::LoadFile("C:\Program Files\Zebra Technologies\Barcode Scanners\Common\Interop.CoreScanner.dll")|Out-Null;		
	$ScannerObject = New-Object Interop.CoreScanner.CCoreScannerClass;

    # Initialize
	$Status = 0;
	$AppHandle = 0;
    $OutXML = "";
    
    # For all scanners, set to 1
	$ScannerTypes = New-Object int16[] 11;
	$ScannerTypes[0] = 1;
	
    # For all scanner types, set to 1
	$NumberOfScannerTypes = [int16] 1;

    # Attribute list, comma separated
    $AttributeList = @(("0", "F", "True"), ("1", "F", "True"), ("2", "F", "True"))

    # Scanner IDs list, comma separated
    [int[]]$ScannerIDList = 1
			
	Write-Output "$(Get-Date) Scanner.Open() Invoke";
	$ScannerObject.Open($AppHandle, $ScannerTypes, $NumberOfScannerTypes, [ref] $Status);
	Write-Output "$(Get-Date) Scanner.Open() Status: $Status";
        
    foreach($ScannerID in $ScannerIDList)
    {
        if($ScannerID -ne 0)
        {
            $InXML = "<inArgs>"
            $InXML += "<scannerID>"
            $InXML += $ScannerID
            $InXML += "</scannerID>"
            $InXML += "<cmdArgs><arg-xml><attrib_list>"

            #$InXML += $AttributeList -join ","
            foreach($AttributeValue in $AttributeList)
            {
                $InXML += "<attribute>"
                $InXML += "<id>"
                $InXML += $AttributeValue[0]
                $InXML += "</id>"
                $InXML += "<datatype>"
                $InXML += $AttributeValue[1]
                $InXML += "</datatype>"
                $InXML += "<value>"
                $InXML += $AttributeValue[2]
                $InXML += "</value>"
                $InXML += "</attribute>"
            }

            $InXML += "</attrib_list></arg-xml></cmdArgs>"
            $InXML += "</inArgs>"

            Write-Output "$(Get-Date) Invoke ExecCommand.";
            $ScannerObject.ExecCommand(5004, [ref] $InXML, [ref] $OutXML, [ref] $Status)
            Write-Output "$(Get-Date) SetAttribute command status : $Status";
        }
    }
}

Scanner Host Mode Switching

This script switch all the connected scanners into the given host mode.


# Description : Following script switch all the connected scanners into the given host mode. Support PSVersion 5+.
# Copyright : ©2026 Zebra Technologies Corp. and/or its affiliates.

# Log everything, file will create in the script execution folder.
# Comment the following line if logging is not required.
Start-Transcript -Append -Path $PSScriptRoot"\CoreScanner_SwitchHostMode.log.txt"

# Main script to execute
Invoke-Command -ScriptBlock {
    # Initialize CoreScanner
    Write-Output "$(Get-Date) Loading Interop.CoreScanner.dll";		
	[System.Reflection.Assembly]::LoadFile("C:\Program Files\Zebra Technologies\Barcode Scanners\Common\Interop.CoreScanner.dll")|Out-Null;		
	$ScannerObject = New-Object Interop.CoreScanner.CCoreScannerClass;

    # Initialize
	$Status = 0;
	$AppHandle = 0;
    $OutXML = "";
    $InXML = "";
    $ScannerCount = 0;
    
    # For all scanners, set to 1
	$ScannerTypes = New-Object int16[] 11;
	$ScannerTypes[0] = 1;
	
    # For all scanner types, set to 1
	$NumberOfScannerTypes = [int16] 1;

    # Scanner IDs list, comma separated
    [int[]]$ScannerIDList = 1

    # Host modes
    $HOST_MODE_USB_IBMHID = "XUA-45001-1"
    $HOST_MODE_USB_IBMTT = "XUA-45001-2"
    $HOST_MODE_USB_HIDKB = "XUA-45001-3"
    $HOST_MODE_USB_OPOS = "XUA-45001-8"
    $HOST_MODE_USB_SNAPI_WITH_IMAGING = "XUA-45001-9"
    $HOST_MODE_USB_SNAPI_WITHOUT_IMAGING = "XUA-45001-10"
    $HOST_MODE_USB_CDC = "XUA-45001-11"
	
    # Invoke Open API		
	$ScannerObject.Open($AppHandle, $ScannerTypes, $NumberOfScannerTypes, [ref] $Status);
	Write-Output "$(Get-Date) Scanner.Open() Status: $Status";

    foreach($ScannerID in $ScannerIDList)
    {
        if($ScannerID -ne 0)
        {
            $InXML += "<inArgs>"
	        $InXML += "<scannerID>"
            $InXML += $ScannerID
            $InXML += "</scannerID>"
	        $InXML += "<cmdArgs>"
		    $InXML += "<arg-string>"
            $InXML += $HOST_MODE_USB_IBMHID # Host mode to switch
            $InXML += "</arg-string>"
		    $InXML += "<arg-bool>FALSE</arg-bool>" # Silent switch, True - enable, False - disable
    		$InXML += "<arg-bool>FALSE</arg-bool>" # Permanent change, True - enable, False - disable
	        $InXML += "</cmdArgs>"
            $InXML += "</inArgs>"
        }
    }

    # Switch scanner host mode
    $ScannerObject.ExecCommand(6200, [ref] $InXML, [ref] $OutXML, [ref] $Status)
    Write-Output "$(Get-Date) Switched to SNAPI status : $Status";
}