Archive for the ‘Drucker’ Category

Treiberversion von Windowsdruckertreibern ermitteln

20 Januar 2023

Lange Zeit gab es unter Windows nur die Druckertreiberversion 3. Als Windows Vista auf die Bühne kam brachte dies XPS-Druckertreiber-Unterstützung mit und damit Version 4.

Da Version 4 Druckertreiber selbst heute noch teilweise Probleme machen, z. B. beim Schachtwechsel bei bestimmten Druckjobs, ist man auf die Version 3 Druckertreiber angewiesen.

Wie kann man nun feststellen, ob man es mit einem V3 oder V4-Druckertreiber zu tun hat?

Eigentlich wäre die Sache recht simpel, man ruft z. B.

PS > Get-Printer -name ‚OneNote for Windows 10’|Get-PrinterDriver
Get-PrinterDriver : Es wurden keine MSFT_PrinterDriver-Objekte gefunden, bei denen die Name-Eigenschaft gleich
"OneNote for Windows 10" ist. Überprüfen Sie den Wert der Eigenschaft, und versuchen Sie es erneut.
In Zeile:1 Zeichen:44
+ Get-Printer -name ‚OneNote for Windows 10’|Get-PrinterDriver
+                                            ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (OneNote for Windows 10:String) [Get-PrinterDriver], CimJobException
    + FullyQualifiedErrorId : CmdletizationQuery_NotFound_Name,Get-PrinterDriver

Wie immer, könnte so einfach sein. Aber leider schafft es Powershell nicht die Verknüpfung zwischen Druckerwarteschlange und Druckertreiber aufzulösen.

In diesem Beispiel wird aber beschrieben, wie mittels WMI die fehlende Verbindung zwischen beiden hergestellt werden kann, nämlich mittels der Win32_DriverForDevice-Klasse.

https://devblogs.microsoft.com/scripting/how-can-i-retrieve-information-about-the-printer-driver-used-by-a-printer/

In Powershell gegossen, sieht das dann so aus:

PS> $printerName=’OneNote for Windows 10′
PS> $printer=gwmi win32_printer -Filter "Name=’$printerName’"
PS> $printerDriver=gwmi -Query "Associators Of {Win32_Printer.DeviceID=’$($printer.DeviceID)‘} WHERE AssocClass = Win32_DriverForDevice Role=Antecedent"
PS> $printerDriver.Version
4

Oder nun als einfache Funktion:

Function Get-PrinterDriverFromPrinter {
[CmdletBinding()]
Param(
  [String]$Name
)

$printer=gwmi win32_printer -Filter "Name=’$Name’" 
If ($printer) {
  $printerDriver=gwmi -Query "Associators Of {Win32_Printer.DeviceID=’$($printer.DeviceID)‘} WHERE AssocClass = Win32_DriverForDevice Role=Antecedent"
  If ($printerDriver) {
   $printerDriver
  }
}
}

Somit kann man diesen Aufruf zur Ermittlung der Druckertreiberversion verwenden:

PS> (Get-PrinterDriverFromPrinter -Name ‚OneNote for Windows 10‘).Version
4

Geist-Druckertreiber unter Windows los werden

26 Juli 2021

Bei Windows kommt es häufiger als erwünscht vor, dass aufgrund von Updates oder Löschaktionen teile der Druckertreiber übrig bleiben.

Manchmal ist der Druckerhersteller schuld, aber im Grunde ist es Microsoft, da trotz Einzug von V4-Druckertreibern immer noch alles abwärtskompatibel sein muss und gleichzeitig klar ist, dass eigentlich jeder nur PDFs erstellen will und der Drucker sich dann um den Ausdruck kümmert. Aber egal. Problem waren Druckertreiber die nicht mehr funktionieren aber immer noch in der Druckerauswahl auftauchen und dort irgendwie raus sollen.

Ein Punkt an dem man heutzutage fündig wird ist in der Registrierung unter HKLM\System\CurrentControlSet\Enum\SWD\PRINTENUM. Evtl. braucht man aber Systemrechte um hier etwas löschen zu können, ist mittlerweile stark von der Windowsversion abhängig. Hiermit gehts dann: https://www.tiraniddo.dev/2020/02/getting-interactive-service-account.html

IP-Adresse von WSD-Drucker per Powershell ermitteln

9 November 2016

Offensichtlich gibt es keine einfache Methode die IP-Adresse eines WSD-Druckers per Eingabeaufforderung zu ermitteln. Per GUI ist es klar, dass man in der Systemsteuerung bei Geräte und Drucker bei den Eigenschaften (nicht Druckereigenschaften) fündig wird. Leider wird bei Windows 10 in der Modernen Oberfläche aber auch diese Sache ausgespart. Wäre es nicht schön so eine wichtige Information direkt per Commandline zu bekommen?

Zunächst brauchen wir einen Drucker,  jeder sollte sich hier seinen eigenen WSD-fähigen Drucker aussuchen:

$printer=Get-Printer|out-gridview –passthru

Die weitere Beschreibung macht aber nur Sinn, wenn man einen WSD-fähigen Drucker hat. Wobei alle modernen Drucker mit Netz- oder WLAN-Anschluss dies unterstützten. Es funktioniert nicht, wenn der Drucker per USB angeschlossen ist!

Nun brauchen wir vom Drucker den Druckerport über den die Kommunikation läuft und vom Druckerport brauchen wir den Universal Resource Name:

$deviceURN = (Get-PrinterPort -Name $printer.PortName).DeviceUUID

Damit bekommt man dann sowas zurück: URN:UUID:6D4FF0CE-6B11-11D8-8020-001E8F1CF942. Mit dieser Information kann man noch nicht viel anfangen aber es ist eine eindeutige ID, welche nur dem spezifischen Drucker, weltweit einmalig zugeordnet ist. Mit dieser ID kann man nun in der Registrierung unter HKEY_LOCAL_MACHINE:\SYSTEM\CurrentControlSet\Enum\SWD\DAFWSDProvider\ fündig werden:

$location =  (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Enum\SWD\DAFWSDProvider\$deviceURN" –Name LocationInformation).LocationInformation

In $location steht nun bereits die IP-Adresse und sieht z. B. so aus: http://192.168.0.138:80/wsd/mex. Fast am Ziel, man kann nun die IP-Adresse ganz einfach extrahieren:

([System.UriBuilder]::new($location)).host

Nun hat man endlich die IP-Adresse des Druckers. Um das alles etwas zu vereinfachen hier eine kleine Funktion:

Function Get-IPAddressFromWSDDevice ($Printer) {

$deviceURN = (Get-PrinterPort -Name $printer.PortName).DeviceUUID
$location =  (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Enum\SWD\DAFWSDProvider\$deviceURN" –Name LocationInformation).LocationInformation
([System.UriBuilder]::new($location)).host

}

Noch ein Hinweis. Da leider die passenden Cmdlets erst ab Windows 8 aufwärts verfügbar sind, wird diese Methode nicht auf Windows 7 funktionieren. Die hier gezeigte Variante funktioniert übrigens auch bei IPv6-Adressen.

Postscript direkt an Drucker unter Windows senden

28 Oktober 2016

Im Reigen mit dem direkten Drucken von Daten an Drucker unter Windows steht als nächstes dass direkte Drucken von Postscript auf dem Programm. Durch die hier https://newyear2006.wordpress.com/2016/10/17/direkte-kommunikation-mit-druckern-unter-windows-von-powershell-aus/ vorgestellte Methode um Druckern direkt Daten unterjubeln zu können und die hier https://newyear2006.wordpress.com/2016/10/27/direktes-drucken-von-pdf-dateien-unter-windows-und-wie-man-die-farbprofiluntersttzung-eines-druckers-testen-kann/ vorgestellte Methode um direkt PDF-Dateien zu drucken, wollen wir uns nun Postscript zuwenden. Man kann davon ausgehen, dass ein Drucker welcher bereits die PDF-Ausgabe beherrscht auch die Ausgabe von Postscript kann.

Zunächst, wie beim Artikel beim Druck der PDF-Dateien beschrieben (siehe dort für mehr Details), muss die Printer Language gesetzt werden, diesmal aber anstatt PDF auf Postscript:

# {ESC}%-12345X
$kb=@(27,37,45,49,50, 51, 52, 53, 88)
# Zeilenumbruch
$lfb=@(13, 10)
# Sprache einstellen:
$lb=[System.Text.Encoding]::ASCII.GetBytes("@PJL ENTER LANGUAGE = Postscript")

So jetzt brauchen wir auch etwas Postscript:

$pss=@"
/Times-Roman findfont
32 scalefont
setfont
100 200 translate
45 rotate
2 1 scale
newpath
0 0 moveto
(Testausdruck) true charpath
0.5 setlinewidth
0.4 setgray
stroke
showpage
"@

Die Erklärung zu diesem Meisterwerk findet man hier unter Text (Example4): http://paulbourke.net/dataformats/postscript/.

Dieses Postscript muss nun noch in ein Bytearray umgewandelt werden und schon kann es an den Drucker gesendet werden:

$ps=[System.Text.Encoding]::ascii.GetBytes($pss)
$out = $kb + $lb + $lfb + $ps + $kb

$p=Get-Printer|Out-GridView -PassThru -Title "Bitte Postscript Drucker wählen"
Out-RawPrinter -Printer $p -ByteArray $out -DocTitle "Postscript Direktdruck!"

Da Postscript im Prinzip eine vollständige Programmiersprache ist, kann man auch rekursive Programme ausführen um z. B. Fraktale zu generieren:

$pss=@"

%!PS-Adobe-1.0
%%Title:Random Fern
%%Creator:Eric Wicklund
% Last modified: MLO 02 Jan 1993 11:24:14
% Changed: 'save' and 'restore' statements (incorrect grammar);
% length added, and set to 0.001 (0 does not work with Post 1.7).
/m1 [ 0.00 0.00 0.00 0.16 0.00 0.00 ] def
/m2 [ 0.85 -0.04 0.04 0.85 0.00 1.60 ] def
/m3 [ 0.20 0.23 -0.26 0.22 0.00 1.60 ] def
/m4 [ -0.15 0.26 0.28 0.24 0.00 0.44 ] def
/point 72 def
%/length 0 def
/length 0.001 def
%%EndProlog
%%Page: 1 1
/zzz save def
% will draw inside a 8 inch square centered on 8.5 by 11 inch page
4.25 point mul 1.5 point mul translate
0.8 point mul dup scale
% x coordinate ranges from -5 to 5
% y coordinate ranges from 0 to 10
1 setlinecap
0.005 setlinewidth
% First point at origin
0 0
150000 {
% Pick a transformation matrix probabilistically
   /r rand 100 mod def
   r 1 lt { /m m1 def }
 { r 86 lt { /m m2 def }
 { r 93 lt { /m m3 def }
           { /m m4 def } ifelse } ifelse } ifelse
% Make a linear transformation, then
% plot a point at current location
   m transform 2 copy moveto
   length length rlineto
   stroke
} repeat
showpage
zzz restore
%%Trailer

"@
Das Script für den Baum stammt von hier: 
http://www.pvv.ntnu.no/~andersr/fractal/PostScript.html
Wer sich beim Thema Postscript und Fraktale vertiefen möchte, dem sei 
dieses Dokument “Julia fractals in PostScript” von Kees van der Laan
empfohlen: https://www.ntg.nl/maps/45/03.pdf.
Mhh, da kommt mir eine Idee. Wenn es Grafikkarten gibt, die für 
Berechnungen herangezogen werden, warum dann nicht auch Drucker?

Direktes Drucken von PDF-Dateien unter Windows und wie man die Farbprofilunterstützung eines Druckers testen kann

27 Oktober 2016

Es gibt viele Möglichkeiten Dateien unter Windows auszudrucken. Das witzige ist, dass oft Dateien mehrfach aufbereitet werden, bis sie überhaupt am Ende beim Drucker landen. Wäre es nicht toll, wenn man z. B. eine PDF-Datei zum Drucken hätte, wenn man diese unter Umgehung des Druckertreibers direkt an den Drucker senden könnte?

Wie man RAW-Dateien direkt an einen Drucker unter Windows senden kann, wurde bereits hier beschrieben: https://newyear2006.wordpress.com/2016/10/17/direkte-kommunikation-mit-druckern-unter-windows-von-powershell-aus/. Diese Variante kann man nun ausbauen, um eben auch PDF-Dateien ohne weitere Zwischenbearbeitung drucken zu können. Natürlich funktioniert diese Methode nur, wenn der Zieldrucker auch PDF-Dateien direkt verarbeiten kann! Im Zweifel gilt probieren über studieren.

Wir brauchen also die Funktion Out-RAWPrinter aus dem oben verlinkten Blogartikel. Dann müssen wir die PDF-Datei laden:

$pdf = Get-Content –Path C:\Temp\Test.PDF –Encoding Byte

$pdf enthält nun ein Bytearray. Leider lässt sich dies noch nicht direkt an Out-RawPrinter übergeben, denn dem Drucker muss noch mitgeteilt werden, welche Sprache bzw. Dateiformat da kommt. Dies ist aber ganz einfach über die Printer Job Language PJL möglich. Hier die Referenz dazu: http://h20565.www2.hp.com/hpsc/doc/public/display?docId=emr_na-bpl13208. Erfunden wurde die PJL von HP, wird aber mittlerweile auch von anderen Druckerherstellern verwendet bzw. verstanden.

In unserem Fall soll die Sprache auf PDF gestellt werden. Dies erreicht man, indem man @PJL ENTER LANGUAGE = PDF an den Drucker sendet. Damit der Drucker aber auch darauf achtet und reagiert muss noch seine Aufmerksamkeit durch einen spezielle Zeichenfolge erregt werden, indem man {ESC}%-12345X vorab und hinterher sendet. In Kombination sieht das dann so aus:

# {ESC}%-12345X
$kb=@(27,37,45,49,50, 51, 52, 53, 88)
# Zeilenumbruch
$lfb=@(13, 10)
# Sprache einstellen:
$lb=[System.Text.Encoding]::ASCII.GetBytes("@PJL ENTER LANGUAGE = PDF")
# alles Zusammensetzen
$out = $kb + $lb + $lfb + $pdf + $kb

In $out steht nun das komplette Bytearray. Das sieht dann z. B. so aus:

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

1B 25 2D 31 32 33 34 35 58 40 50 4A 4C 20 45 4E  .%-12345X@PJL EN
54 45 52 20 4C 41 4E 47 55 41 47 45 20 3D 20 50
  TER LANGUAGE = P
44 46
0D 0A
25 50 44 46 2D 31 2E 34 0D 0A 25 E2  DF..%PDF-1.4..%â
E3 CF D3 0D 0A 25 0D 0A 25 77 50 44 46 33 20 62  ãÏÓ..%..%wPDF3 b
79 20 57 50 43 75 62 65 64 20 47 6D 62 48 20 56  y WPCubed GmbH V
33 2E 36 35 5B 34 30 32 36 35 33 32 31 36 5D 20  3.65[402653216]

am Ende so:

65 65 30 63 31 32 32 62 64 32 66 38 63 34 3E 5D  ee0c122bd2f8c4>]
0D 0A 2F 49 6E 66 6F 20 32 20 30 20 52 0D 0A 3E  ../Info 2 0 R..>
3E 0D 0A 73 74 61 72 74 78 72 65 66 0D 0A 31 39  >..startxref..19
37 32 35 31 0D 0A 25 25 45 4F 46 0D 0A 1B 25 2D  7251..%%EOF...%-
31 32 33 34 35 58
                                12345X

Und jetzt noch alles an den Drucker:

$p=Get-Printer|Out-GridView -PassThru -Title "Bitte Drucker wählen"
Out-RawPrinter -Printer $p -ByteArray $out -DocTitle "PDF Direktdruck!"

Verwendet man diese Methode, muss man aber damit rechnen, dass der Ausdruck manchmal anders aussieht, als erwartet. Denn PDF ist nicht immer gleich PDF, bzw. PDF kann je nach Gerät unterschiedlich interpretiert werden.

Was kann man damit anstellen? Ja man könnte sein Gerät z. B. auf direkte Kompatibilität von ICC v4 Profil Farbraumunterstützung testen http://www.color.org/version4pdf.pdf.

$iccv4=(Invoke-WebRequest -Uri http://www.color.org/version4pdf.pdf).Content
$out = $kb+$lb+$lfb+$iccv4$x+$kb
$p=Get-Printer|Out-GridView -PassThru -Title "Bitte Drucker wählen"
Out-RawPrinter -Printer $p -ByteArray $out -DocTitle "PDF Direktdruck!"

Spannend so eine Sache!

Direkte Kommunikation mit Druckern unter Windows von Powershell aus

17 Oktober 2016

Manchmal ist es hilfreich, wenn man unter Windows direkt etwas ausdrucken kann. Direkt in diesem Fall bedeutet aber nicht über die üblichen Wege einen Druckertreiber anzusprechen, sondern, dass man direkt Steuerzeichen an einen Drucker senden kann. Man hat z. B. einen Druck in eine Datei umgeleitet und möchte nun diese Datei später an den Drucker senden. Dies ist mit den üblichen unter Powershell zur Verfügung stehenden Cmdlets wie Out-Printer nicht möglich.

Aber wie immer kann man das .Net Framework zu Hilfe nehmen. Grundlage für diesen Artikel ist der Knowledge Base Artikel https://support.microsoft.com/en-us/kb/322091. Dieser beschreibt die direkte Kommunikation mit Druckern unter C#. Hier hat sich nun jemand bereits die Mühe gemacht die Grundlage des Artikels an Powershell anzupassen: http://panchosoft.blogspot.de/2013/07/imprimir-en-impresora-de-etiquetas-sato.html. Das interessante an dieser Methode ist, dass es keine Rolle spielt, ob der Drucker per LPT- oder USB-Schnittstelle mit dem Rechner verbunden ist, noch ob mittels Netzwerk über TCP/IP oder WSD-Diensten mit ihm kommuniziert wird.

Die Daten finden mittels dieser Methode immer in Reinform ihren Weg zum Drucker, unabhängig vom Anschluss bzw. Übertragungsweg. Die generelle Druckvorgehensweise unter Windows ist hier beschrieben: https://msdn.microsoft.com/en-us/library/windows/desktop/dd145115%28v=vs.110%29.aspx.

Ein Aspekt ist noch wichtig. Es gibt sogenannte Typ 3 und Typ 4 Druckertreiber, dazu ein anderes Mal mehr. Typ 4 kommen verstärkt seit Windows 8 und nachfolgend zum Einsatz. Damit der Ansatz mit dem direkten senden von Daten an den Drucker klappt, muss dies berücksichtigt werden: https://msdn.microsoft.com/en-us/library/windows/desktop/ff686812(v=vs.110).aspx.

Hier zunächst das gesamte Script:

# Powershell RAW Print

$src = @‘
using System;
using System.Runtime.InteropServices;

public class RawPrinterHelper
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
  [MarshalAs(UnmanagedType.LPStr)]
  public string pDocName;
  [MarshalAs(UnmanagedType.LPStr)]
  public string pOutputFile;
  [MarshalAs(UnmanagedType.LPStr)]
  public string pDataType;
}

  [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

  [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  public static extern bool ClosePrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

  [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  public static extern bool EndDocPrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  public static extern bool StartPagePrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  public static extern bool EndPagePrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

}

‚@

Add-Type -TypeDefinition $src -Language CSharpVersion3

function Out-RawPrinter {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$True, ParameterSetName="Printer", Position=0)]
        [PSTypeName(‚Microsoft.Management.Infrastructure.CimInstance#ROOT/StandardCimv2/MSFT_Printer‘)]
        [ciminstance]
        $Printer,
        [Parameter(Mandatory=$True, ParameterSetName="PrinterName", Position=0)]
        [String]$PrinterName,

        [String]$Output,
        [Byte[]]$ByteArray,
        [String]$DocTitle = "Powershell RAW print",
        [String]$DataType
    )

    If ($PSCmdlet.ParameterSetName -eq "PrinterName") {
        $Printer = Get-Printer $PrinterName
    }

    #
    If (((-Not ($Output)) -and (-Not ($ByteArray)))) {
        throw "Need some data, either by providing -Output or -ByteArray"
    }

    If ($Output) {
        $ByteArray = [System.Text.Encoding]::ASCII.GetBytes($Output)
        Write-Verbose "converted Output via ASCII-Encoding into ByteArray"
    }

    # DOCInfo Struktur erzeugen
    $di=New-Object RawPrinterHelper+DOCINFOA

    If (-Not ($DataType)) {
        # https://support.microsoft.com/en-us/kb/2779300 defines XPS_PASS
        If ((Get-PrinterDriver -Name $Printer.DriverName).MajorVersion -eq 4) {
            $di.pDataType = "XPS_PASS"
        } else {
            $di.pDataType = "RAW"
        }
    } else {
        $di.pDataType = $DataType
    }
    Write-Verbose "Type: $($di.pDataType)"
    $di.pDocName= $DocTitle

    # benötigte Variablen
    $hPrinter=[IntPtr]::Zero
    $dwWritten=0
    $result = $false

    If ([RawPrinterHelper]::OpenPrinter($Printer.Name.Normalize(), [ref] $hPrinter, [intptr]::Zero)) {
        If ([RawPrinterHelper]::StartDocPrinter($hPrinter, 1, $di)) {
            #$result = [RawPrinterHelper]::StartPagePrinter($hPrinter)
            $pa=[System.Runtime.InteropServices.GCHandle]::Alloc($ByteArray, [System.Runtime.InteropServices.GCHandleType]::Pinned)
            $result = [RawPrinterHelper]::WritePrinter($hPrinter, $pa.AddrOfPinnedObject(), $ByteArray.Length, [ref] $dwWritten);$Win32Error =  [ComponentModel.Win32Exception][System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
            # Win32Error, see http://www.exploit-monday.com/2016/01/properly-retrieving-win32-api-error.html
            Write-Verbose "$dwwritten Bytes sent to Printer ‚$($Printer.Name)‘, expected: $($ByteArray.Length)"
            $pa.Free()
            #$result = [RawPrinterHelper]::EndPagePrinter($hPrinter)
            $result = [RawPrinterHelper]::EndDocPrinter($hPrinter)
        }
        $result = [RawPrinterHelper]::ClosePrinter($hPrinter)
    }

}

Wie immer ist das Script nicht schön in dieser Darstellung aber es funktioniert per Copy&Paste.

Zunächst braucht man einen Druckernamen:

PS > Get-Printer| select Name

Name
—-
HP Officejet Pro X576 MFP PCL6
HP LaserJet A4/Letter PS Class Driver
HP Universal Printing PCL 6 (v6.3.0)
Microsoft XPS Document Writer
Microsoft Print to PDF
Fax
An OneNote 2013 senden

Nun wählt man am besten einen aus, in diesem Fall den ersten:

PS > $p=(get-printer)[0]
PS > $p

Name                           ComputerName    Type         DriverName
—-                           ————    —-         ———-
HP Officejet Pro X576 MFP PCL6                 Local        HP Officejet Pro X576

Nun kann man diesem Drucker Daten zukommen lassen:

$Schachttest ="$([char]27)&l4HSchacht1$([char]12)"+"$([char]27)&l1HSchacht2$([char]12)"

Out-RawPrinter –Printer $p –Output $Schachttest

Der etwas verkünstelte String druckt bei einem HP-Drucker zwei Seiten, eine vom Schacht1 (manueller) und eine vom Schacht2. Würde man in diesem Fall Out-Printer benutzen, dann würden die Steuerzeichen nicht interpretiert und als Text oder nichtdarstellbare Zeichen gedruckt.

Da die Umwandlung des Strings bei Out-RawPrinter mittels ASCII-Encoding stattfindet, stößt man auch schnell an eine Grenze, wenn man bestimmte Umlaute drucken möchte. Deshalb gibt es noch den Paramter –ByteArray anstatt –Output, somit kann man eine eigene Umwandlung durchführen und die Daten übergeben.

Dies kann man sich auch zunutze machen, wenn man einen Ausdruck in einer Datei umgelenkt hat und diese Datei dann später drucken möchte. Hier exemplarisch, wie man vorgeht:

$DruckDaten = Get-Content DruckDatei.PRN –Encoding Byte
Out-RawPrinter –Printer $p –ByteArray $DruckDaten

Neben diesen Möglichkeiten zur Kommunikation mit Druckern, möchte ich noch auf SNMP hinweisen, welches auch unter Windows 10 immer noch funktioniert, wie hier beschrieben: https://newyear2006.wordpress.com/2016/07/10/hp-netzwerkdrucker-per-remote-und-reboot-txt-neu-starten-nix-klappt-aber-snmp-bringt-die-lsung/.

HP Netzwerkdrucker per Remote und Reboot.TXT neu starten – nix klappt aber SNMP bringt die Lösung

10 Juli 2016

Beim Rumspielen mit verschiedenen HP-Druckereigenschaften kommen einem manchmal Zweifel, ob alles noch korrekt reagiert. Aus diesem Grund sollte man den betreffenden Drucker von Zeit zu Zeit neu starten um nach einem Neustart die betreffenden Reaktionen zu testen. Im konkreten Fall handelt es sich um einen “HP LaserJet MFP M426fdw”, also ein recht aktuelles Modell.

Blöd nur, dass Varianten mittels einer reboot.txt, wie hier https://community.spiceworks.com/how_to/122155-how-to-reboot-an-hp-printer-remotely oder hier http://dxpetti.com/blog/?p=706 beschrieben nicht funktionieren. Übrigens, FTP-Druck wurde explizit aktiviert, sonst kann man den Drucker per FTP nicht anfahren. Die kompliziertere Variante für Reboot.TXT sieht übrigens so aus:

%-12345X@PJL COMMENT
@PJL DMINFO ASCIIHEX="040006020501010301040105"
%-12345X

Allerdings muss man wissen, dass vor % noch ein ein ASCII-Zeichen mit Code 27 steht. Man kann die passende Datei mittels Powershell ganz einfach so erzeugen:

# {ESC}%-12345X
$k=[System.Text.Encoding]::ASCII.GetString(@(27,37,45,49,50, 51, 52, 53, 88))
$lf=[System.Text.Encoding]::ASCII.GetString(@(13, 10))
$i=’@PJL COMMENT‘
$c=’@PJL DMINFO ASCIIHEX="040006020501010301040105"‘
#$c=’@PJL DMCMD ASCIIHEX="040006020501010301040105"‘

$k + $i + $lf + $c + $lf + $k | set-content -Encoding Ascii -Path "$($env:USERPROFILE)\Reboot.txt"

Aber auch mit der korrekten Escape-Sequenz am Anfang klappte es nicht!

Auch hier wird wieder die ganz einfache reboot.txt Variante beschrieben: https://www.experts-exchange.com/questions/24432791/Rebooting-HP-Jetdirect-remotley.html. Klappt natürlich nicht, aber es war etwas von einem Reboot mittels SNMP beschrieben. Hier soll set OID .1.3.6.1.2.1.43.5.1.1.3.1 with Integer "4" gesetzt werden.

Aha, SNMP das uralte Protokoll. Selbst HP geht darauf aber noch ein und verwendet es für bestimmte Aufgaben, hier ein aktuelles Dokument aus April 2016: http://h20564.www2.hp.com/hpsc/doc/public/display?docId=c01840676.

Tatsächlich findet man bei der Suche nach der OID und Powershell Scripte, wie hier: http://forum.support.xerox.com/t5/Copying-Faxing-Scanning/Schedule-printer-reboot/m-p/176844#M5393. Das Script ist zwar nicht 1:1 übertragbar aber damit wird der Weg klar.

Selbst in Windows 10 gibt es eine OLE SNMP-Klasse https://msdn.microsoft.com/en-us/library/windows/hardware/ff554433(v=vs.85).aspx, welche man mittels Powershell ganz einfach für diesen Zweck einsetzen kann:

$PrinterIP = "192.168.1.87" # hier die tatsächliche IP des Druckers setzen
$SNMP = New-Object -ComObject olePrn.OleSNMP
$SNMP.Open($PrinterIP, "public")
$SNMP.Set(".1.3.6.1.2.1.43.5.1.1.3.1",4)
$SNMP.Close()

Sofort nach absetzen des Set-Befehls startet der Drucker neu! Und was dabei noch interessant ist, es klappt auch mit anderen Druckerfabrikaten.

Samsung Drucker Netzwerkschnittstelle SyncThru Web Service Passwort

15 Juli 2015

Weil zum x-ten Male mir das Ding bei Kunden über den Weg läuft, hier das Standardpasswort von Samsung Druckern die per Netzwerkschnittstelle ihren SyncThru Web Service anbieten.

Benutzer: admin
Passwort: sec00000

Hier die Lösung: http://www.techsupportforum.com/forums/f109/samsung-clp-325w-syncthru-password-reset-546108.html#post3630688.

Der Artikel beschreibt auch, dass man bei älteren Varianten von Syncthru frühers nur ein Kennwort eingeben musste, was den letzten acht Zeichen der MAC-Adresse des Druckers entsprach. Es werden auch noch weitere Dinge besprochen.

Probleme beim Drucker umbenennen unter Windows

22 Januar 2015

Bei einem Kunden mit Windows 8.1 gab es beim Umbenennen eines Druckers folgende Meldung:

[Window Title]
Druckereigenschaften

[Main Instruction]
Die Druckereinstellungen konnten nicht gespeichert werden.

Es ist bereits ein Drucker oder eine Druckerfreigabe mit diesem Namen vorhanden. Verwenden Sie einen anderen Namen für den Drucker.

[OK]

Wenn man aber bei den Druckern geschaut hat, war nix von einem Drucker mit diesem Namen zu sehen. Es war allerdings davor ein Drucker mit diesem Namen da, denn dieser wurde zuvor gelöscht. Blöd war nur, dass in dessen Druckerwarteschlange noch ein kaputter Druckvorgang war und somit scheinbar der Druckvorgang nicht abgeschlossen werden konnte. Wie ich auf diese gewagte These komme?

Na ganz einfach so: Mittels dieses Artikels https://newyear2006.wordpress.com/2014/07/09/gruppierung-bei-windows-druckern-aufheben/ über diesen Punkt

shell:::{2227A280-3AEA-1069-A2DE-08002B30309D}

die Ansicht geändert, dass alle Druckertreiber einzeln dargestellt wurden. Dabei war aber noch nichts vom Ghost-Druckertreiber zu sehen. Nun aber die versteckten Dateien eingeblendet. Also ALT-Taste gedrückt, damit das Menü “Datei Bearbeiten Ansicht Extras” erscheint und dort bei Extras die Ordneroptionen aufgerufen. Hier wiederum das Register Ansicht ausgewählt und den Punkt “Ausgeblendete Dateien, Ordner und Laufwerke anzeigen” aktiviert. Schwups war der Ghostdruckertreiber zu sehen und konnte nun entfernt werden. Denkste!

Beim Versuch den Druckertreiber zu löschen erschien diese Fehlermeldung:

[Window Title]
Druckereigenschaften

[Main Instruction]
Die Druckereigenschaften können nicht angezeigt werden.

Überprüfen Sie den Druckernamen, und stellen Sie sicher, dass der Drucker mit dem Netzwerk verbunden ist.

[OK]

Was jetzt? Logischerweise Neustart des Rechners oder vielleicht nur Neustart der Druckerwarteschlange, dann ist der Ghost-Druckertreiber weg und das Umbenennen des ursprünglichen Druckertreibers ist möglich.

Drucker mittels Powershell in Windows 8.1 kopieren

30 September 2014

Leider gibt es seit Jahren unter Windows keine einfache Möglichkeit einen Drucker zu kopieren. Gemeint sind die Drucker die nach Aufruf von

Control Printers

angezeigt werden.

Dank Powershell ist dies nun unter Windows 8.1 mit den Drucker-Cmdlets  sehr einfach möglich.

Man ruft einfach

Get-Printer | Out-GridView -Title "Quelldrucker auswählen" -PassThru | foreach {Add-Printer -DriverName $_.DriverName -Name "$($_.Name) Kopie" -PortName $_.PortName}

auf und bekommt eine Auswahl der installierten Drucker angezeigt, kann den gewünschten auswählen und klickt auf OK. Man bekommt den neuen Drucker mit dem Namen des alten und dem Anhängsel Kopie angelegt.

Wie immer gibt es aber eine Ausnahme: Leider funktioniert obige Methode nicht bei Druckern die von einem anderen Rechner kommen, die also über die Variante \\Server\Freigabe angesprochen werden. Wird solch ein Drucker versucht zu kopieren, erscheint diese Fehlermeldung:

Add-Printer : Der angegebene Anschluss ist nicht vorhanden. Verwenden Sie "add-printerport", um einen neuen Anschluss hinzuzufügen, oder geben Sie einen vorhandenen
Anschluss an.
In Zeile:1 Zeichen:81
+ Get-Printer | Out-GridView -Title "Quelldrucker auswählen" -PassThru | foreach { …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (MSFT_Printer:ROOT/StandardCimv2/MSFT_Printer) [Add-Printer], CimException
    + FullyQualifiedErrorId : HRESULT 0x80070704,Add-Printer

Wenn man man einen Drucker kopiert hat, fällt auf, dass dieser nicht unbedingt direkt zu sehen ist. In diesem Fall ist dieser Artikel interessant: https://newyear2006.wordpress.com/2014/07/09/gruppierung-bei-windows-druckern-aufheben/

Leider werden bei obiger Methode noch nicht die Einstellungen des zu kopierenden Druckers mitübertragen. D. h. die Kopie des Druckers hat immer die Standardeinstellungen, wie nach einer Neuinstallation des Druckertreibers. Dazu aber ein anderes Mal mehr…