none
Drucker in Win-VM erkennen RRS feed

  • Frage

  • Hallo zusammen

    Mein Problem ist folgendes:

    Gegeben ist ein Win7 in einer unter Linux laufenden VM. Durch die dadurch gegebene Entkoppelung der peripheren Hardware - hier der Drucker, fällt es nicht leicht etwas innerhalb von Win7 über den Status der Drucker zu erfahren. Die Aufgabe besteht darin, einem Laptop den jeweils richtigen Drucker als Standard zuzuordnen.

    Gegeben sind ein Netzwerkdrucker und ein lokaler USB-Drucker. Kann das Script den USB-Drucker nicht sehen, richtet es automatisch den Netzwerkdrucker als Standarddrucker ein. Sieht das Script den USB-Drucker, richtet es den als Standarddrucker ein.

    Hierfür habe ich mir dieses Powershell-Script geschrieben, welches den USB-Drucker zwar findet, ihn aber nicht als Standartdrucker setzt :-(

    Hier das Script:

    set-variable -name wahl ""
    set-variable -name wahl (Get-WmiObject -query "SELECT Name FROM Win32_Printer WHERE (Portname LIKE 'USB%') AND (WorkOffline = FALSE)" | ft Name)
    
    if ('$wahl' -notlike 'HP OfficeJet Pro 8210 PCL 6') {
    (Get-WMIObject -class Win32_Printer -Filter "Name='\\\\druckserver\\12345Printer'").SetDefaultPrinter() | Out-Null
     echo "                   Jobdrucker als Standard gesetzt"
    }
    
    else {
    (Get-WMIObject -class Win32_Printer -Filter "Name='HP OfficeJet Pro 8210 PCL 6'").SetDefaultPrinter() | Out-Null
     echo "                   Heimdrucker als Standard gesetzt"
    }
    
    clear-Variable wahl
    
    timeout /T 2 > $NULL

    Im Ergebnis wählt diese Script immer den Jobdrucker aus, egal ob der USB-Heimdrucker online ist, oder nicht.

    Wo liegt der Fehler im Script?

    Freitag, 23. August 2019 23:26

Antworten

  • Wo liegt der Fehler im Script?

    *der* Fehler impliziert, dass es nur einen gibt ;-) Das ist nicht der Fall.

    1. (kein Fehler, aber grober Unfug) Set-Variable brauchst Du hier nicht, normale Zuweisung genügt vollkommen.

    2. Eine Zuweisung der Ausgabe von Format-Table zu einer Variablen erzeugt ein Array of Strings: Header, Zeile 1, Zeile 2 usw. Wenn Du nur den Wert der Property 'Name' haben möchtest, entweder einfach adressieren:

    (Get-WmiObject -query "SELECT Name FROM Win32_Printer WHERE (Portname LIKE 'USB%') AND (WorkOffline = FALSE)").Name

    oder expandieren:

    (Get-WmiObject -query "SELECT Name FROM Win32_Printer WHERE (Portname LIKE 'USB%') AND (WorkOffline = FALSE)") | Select-Object -ExpandProperty Name

    Trifft die Bedingung auf mehr als einen Drucker zu, bekommst Du auch hier ein Array!!!

    3. Der Ausdruck '$wahl' hat immer den String-Wert Dollar-kleinW-kleinbA-kleinH-kleinL, im Gegensatz zu "$wahl", der zu dem Default-Cast von $wahl zu String ausgewertet wird. Das ist vermutlich der gröbste Fehler.

    4. -like bzw. -notlike mit einem String, der keine Platzhalter enthält, ist witzlos und prinzipiell äquivalent zu -eq bzw. -ne oder zumindest zu -ieq bzw. -ine

    5. Wenn Du der Meinug bist, dass die Ausführung im richtigen Zweig ankommt, nimm doch einfach | Out-Null weg unbd schau, was ausgegeben wird.

    6. "timeout" heißt in PowerShell Start-Sleep und tätigt auch keine Ausgaben, die man tot treten müßte

    7. Clear-Variable in der letzten Skriptzeile ist witzlos, denn danach ist der ganze PowerShell-Host beendet.


    Evgenij Smirnov

    http://evgenij.smirnov.de

    Samstag, 24. August 2019 09:45
  • Hi,
    wenn du einen String in einfache Anführungszeichen setzt, wird der String nicht aufgelöst sondern buchstäblich übernommen. D.h. bei

    if ('$wahl' ...
    wird nicht der Inhalt der Variable $Wahl, sondern der String $Wahl verglichen. Das ist das Problem.
    Ansonsten würde ich dir raten in Scripten auf ausführliche Debugging-Ausgaben zu setzen und Fehlerabfragen einzubauen, damit hättest du den Fehler sehr schnell gefunden. Das ist erstmal immer mehr Aufwand, macht sich aber beim ersten Debugging immer mehr als bezahlt.
    Außerdem ist es eine gute Idee Wertzuweisungen von Abfragen zu trennen, also in Abfragen Variablen zu nutzen. Der Befehl set-variable ist überflüssig
    Also z.b. so:


    cls
    $DebugPreference = "Continue"  # Setze auf "SilentlyContinue" oder 0 um Ausgaben zu deaktivieren
    $Error.Clear()
    
    $NwPrinter = "\\\\druckserver\\12345Printer"
    $UsbPrinter = "HP OfficeJet Pro 8210 PCL 6"
    
    $AvailablePrinters = Get-WmiObject -query "SELECT Name FROM Win32_Printer WHERE (Portname LIKE 'USB%') AND (WorkOffline = FALSE)" | Select -ExpandProperty Name
    Write-Debug "Verfügbare Drucker: `n`n$($AvailablePrinters | out-string)"
    
    If ($AvailablePrinters -contains $UsbPrinter) {
    	Write-Debug ">$UsbPrinter< gefunden."
    	$DefaultPrinter = $UsbPrinter
    }
    else {
    	Write-Debug ">$UsbPrinter< nicht gefunden."
    	$DefaultPrinter = $NwPrinter
    }
    
    Try {
    	(Get-WMIObject -class Win32_Printer -Filter "Name=`"$DefaultPrinter`"").SetDefaultPrinter() 
    	Write-Debug ">$DefaultPrinter< als Standarddrucker gesetzt."
    }
    Catch {
    	Write-Debug "Fehler beim Setzen des Standarddruckers >$DefaultPrinter<: $error"
    }

     
    viele Grüße, Denniver


    Blog: http://www.bytecookie.de

    Powershell Code Manager: Link
    (u.a. Codesnippets verwalten + komplexe Scripte graphisch darstellen)

    Hilf mit und markiere hilfreiche Beiträge mit dem "Abstimmen"-Button (links) und Beiträge die eine Frage von dir beantwortet haben, als "Antwort" (unten).
    Warum das Ganze? Hier gibts die Antwort.

    Samstag, 24. August 2019 10:00
    Moderator

Alle Antworten

  • Wo liegt der Fehler im Script?

    *der* Fehler impliziert, dass es nur einen gibt ;-) Das ist nicht der Fall.

    1. (kein Fehler, aber grober Unfug) Set-Variable brauchst Du hier nicht, normale Zuweisung genügt vollkommen.

    2. Eine Zuweisung der Ausgabe von Format-Table zu einer Variablen erzeugt ein Array of Strings: Header, Zeile 1, Zeile 2 usw. Wenn Du nur den Wert der Property 'Name' haben möchtest, entweder einfach adressieren:

    (Get-WmiObject -query "SELECT Name FROM Win32_Printer WHERE (Portname LIKE 'USB%') AND (WorkOffline = FALSE)").Name

    oder expandieren:

    (Get-WmiObject -query "SELECT Name FROM Win32_Printer WHERE (Portname LIKE 'USB%') AND (WorkOffline = FALSE)") | Select-Object -ExpandProperty Name

    Trifft die Bedingung auf mehr als einen Drucker zu, bekommst Du auch hier ein Array!!!

    3. Der Ausdruck '$wahl' hat immer den String-Wert Dollar-kleinW-kleinbA-kleinH-kleinL, im Gegensatz zu "$wahl", der zu dem Default-Cast von $wahl zu String ausgewertet wird. Das ist vermutlich der gröbste Fehler.

    4. -like bzw. -notlike mit einem String, der keine Platzhalter enthält, ist witzlos und prinzipiell äquivalent zu -eq bzw. -ne oder zumindest zu -ieq bzw. -ine

    5. Wenn Du der Meinug bist, dass die Ausführung im richtigen Zweig ankommt, nimm doch einfach | Out-Null weg unbd schau, was ausgegeben wird.

    6. "timeout" heißt in PowerShell Start-Sleep und tätigt auch keine Ausgaben, die man tot treten müßte

    7. Clear-Variable in der letzten Skriptzeile ist witzlos, denn danach ist der ganze PowerShell-Host beendet.


    Evgenij Smirnov

    http://evgenij.smirnov.de

    Samstag, 24. August 2019 09:45
  • Hi,
    wenn du einen String in einfache Anführungszeichen setzt, wird der String nicht aufgelöst sondern buchstäblich übernommen. D.h. bei

    if ('$wahl' ...
    wird nicht der Inhalt der Variable $Wahl, sondern der String $Wahl verglichen. Das ist das Problem.
    Ansonsten würde ich dir raten in Scripten auf ausführliche Debugging-Ausgaben zu setzen und Fehlerabfragen einzubauen, damit hättest du den Fehler sehr schnell gefunden. Das ist erstmal immer mehr Aufwand, macht sich aber beim ersten Debugging immer mehr als bezahlt.
    Außerdem ist es eine gute Idee Wertzuweisungen von Abfragen zu trennen, also in Abfragen Variablen zu nutzen. Der Befehl set-variable ist überflüssig
    Also z.b. so:


    cls
    $DebugPreference = "Continue"  # Setze auf "SilentlyContinue" oder 0 um Ausgaben zu deaktivieren
    $Error.Clear()
    
    $NwPrinter = "\\\\druckserver\\12345Printer"
    $UsbPrinter = "HP OfficeJet Pro 8210 PCL 6"
    
    $AvailablePrinters = Get-WmiObject -query "SELECT Name FROM Win32_Printer WHERE (Portname LIKE 'USB%') AND (WorkOffline = FALSE)" | Select -ExpandProperty Name
    Write-Debug "Verfügbare Drucker: `n`n$($AvailablePrinters | out-string)"
    
    If ($AvailablePrinters -contains $UsbPrinter) {
    	Write-Debug ">$UsbPrinter< gefunden."
    	$DefaultPrinter = $UsbPrinter
    }
    else {
    	Write-Debug ">$UsbPrinter< nicht gefunden."
    	$DefaultPrinter = $NwPrinter
    }
    
    Try {
    	(Get-WMIObject -class Win32_Printer -Filter "Name=`"$DefaultPrinter`"").SetDefaultPrinter() 
    	Write-Debug ">$DefaultPrinter< als Standarddrucker gesetzt."
    }
    Catch {
    	Write-Debug "Fehler beim Setzen des Standarddruckers >$DefaultPrinter<: $error"
    }

     
    viele Grüße, Denniver


    Blog: http://www.bytecookie.de

    Powershell Code Manager: Link
    (u.a. Codesnippets verwalten + komplexe Scripte graphisch darstellen)

    Hilf mit und markiere hilfreiche Beiträge mit dem "Abstimmen"-Button (links) und Beiträge die eine Frage von dir beantwortet haben, als "Antwort" (unten).
    Warum das Ganze? Hier gibts die Antwort.

    Samstag, 24. August 2019 10:00
    Moderator