Jump to content

Drucker per Powershell Skript einbinden


Der letzte Beitrag zu diesem Thema ist mehr als 180 Tage alt. Bitte erstelle einen neuen Beitrag zu Deiner Anfrage!

Empfohlene Beiträge

Hi, da das hier mein erster Beitrag ist sorry sollte hier etwas Falsch machen.

 

Ich hab folgendes Skript geschrieben um Drucker anhand des PC name im Standortfeld auf dem Printserver auf den Druckern zuweisen zukönnen.

Das Skript funktioniert wunderbar wenn man es mit einem Domain Admin ausführt.
 

# Setze den Print Server und den aktuellen PC-Namen
$printServer = "VM-PRINTSERVER"
$currentPCName = $env:COMPUTERNAME
$printerToSetAsDefault = "*$currentPCName"+"_d*"  # Setzen Sie den Standarddrucker für PCName_D

# Pfad für den Ordner
$scriptFolder = "$env:USERPROFILE\Documents\Drucker_Skript"

# Prüfe, ob der Ordner vorhanden ist, und erstelle ihn gegebenenfalls
if (-not (Test-Path -Path $scriptFolder -PathType Container)) {
    New-Item -Path $scriptFolder -ItemType Directory | Out-Null
}

# Lösche Logdateien, die älter als 31 Tage sind
$oldLogs = Get-ChildItem -Path $scriptFolder -Filter "Drucker_Skript_Log_*.txt" | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-31) }
$oldLogs | ForEach-Object {
    Remove-Item $_.FullName -Force
}

# Öffne die Drucker Übersicht im Windows Explorer 
Start-Process "C:\Windows\explorer.exe" -ArgumentList "shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\0\::{2227A280-3AEA-1069-A2DE-08002B30309D}"

# Warte 3 Sekunden
Start-Sleep -Seconds 3

# Pfad für die LOG-Datei
$errorLogPath = Join-Path $scriptFolder "Drucker_Skript_Log_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt"

# Überprüfe die Erreichbarkeit des Printservers
$printServerReachable = Test-Connection -ComputerName $printServer -Count 1 -Quiet

# Funktion zum Hinzufügen eines Druckers mithilfe von rundll32.exe
function Add-PrinterUsingRundll32 {
    param (
        [string]$printerName
    )

    try {
        # Verwende rundll32.exe, um den Drucker hinzuzufügen
        Write-Host "Füge Drucker $printerName zu $currentPCName hinzu..."
        $command = "rundll32.exe printui.dll,PrintUIEntry /y /n `"\\$printServer\$printerName`""
        Invoke-Expression -Command $command

        # Schreibe Erfolgsmeldung in die Protokolldatei
        "Drucker $printerName wurde zu $currentPCName hinzugefügt." | Out-File -FilePath $errorLogPath -Append
    } catch {
        # Bei einem Fehler, erstelle eine LOG-Datei im Skriptordner
        $errorMessage = "Fehler beim Hinzufügen des Druckers: $($error[0].Exception.Message)"
        $errorMessage | Out-File -FilePath $errorLogPath -Append
    }
}

# Funktion zum Entfernen eines Druckers vom PC
function Remove-PrinterFromPC {
    param (
        [string]$printerName
    )
    
    try {
        # Drucker vom PC entfernen
        Write-Host "Entferne Drucker $printerName von $currentPCName..."
        Remove-Printer -Name $printerName -ErrorAction Stop

        # Schreibe Erfolgsmeldung in die Protokolldatei
        "Drucker $printerName wurde von $currentPCName entfernt." | Out-File -FilePath $errorLogPath -Append
    } catch {
        # Bei einem Fehler, erstelle eine LOG-Datei im Skriptordner
        $errorMessage = "Fehler beim Entfernen des Druckers: $($error[0].Exception.Message)"
        $errorMessage | Out-File -FilePath $errorLogPath -Append
    }
}

# Funktion zum Hinzufügen eines Druckers zum PC basierend auf dem Standortfeld
function Add-PrinterToPCBasedOnLocation {
    param (
        [string]$printerName,
        [string]$location
    )

    try {
        # Überprüfe, ob der PC-Name im Standortfeld vorhanden ist
        if ($location -like "*$currentPCName*" -or $location -like "*$currentPCName"+"_d*" -or $location -like "*$currentPCName"+"_D*") {
            Write-Host "Füge Drucker $printerName zu $currentPCName hinzu..."
        
            # Hier verwenden wir das .NET-Objekt für das Hinzufügen des Druckers
            $printer = (New-Object -ComObject WScript.Network).AddWindowsPrinterConnection("\\$printServer\$printerName")
            
            # Setze den Drucker als Standard, wenn er den Kriterien entspricht
            if ($printerName -eq $printerToSetAsDefault) {
                Add-PrinterUsingRundll32 -printerName $printerName
                Write-Host "Standarddrucker wurde auf $printerName festgelegt."
            }
            
            # Schreibe Erfolgsmeldung in die Protokolldatei
            "Drucker $printerName wurde zu $currentPCName hinzugefügt." | Out-File -FilePath $errorLogPath -Append
        }
    } catch {
        # Bei einem Fehler, erstelle eine LOG-Datei im Skriptordner
        $errorMessage = "Fehler beim Hinzufügen des Druckers: $($error[0].Exception.Message)"
        $errorMessage | Out-File -FilePath $errorLogPath -Append
    }
}

# Drucker vom PC entfernen (vor dem Hinzufügen neuer Drucker)
$existingPrinters = Get-WmiObject -Class Win32_Printer 

if ($printServerReachable) {
    foreach ($existingPrinter in $existingPrinters) {
        # Gib den Namen des Druckers an, den du nicht entfernen möchtest
        $printersToExclude = @("STARFACE Fax", "Fax", "Microsoft Print to PDF", "Microsoft XPS Document Writer")

        # Überprüfe, ob der aktuelle Drucker der auszuschließende Drucker ist
        # Überprüfe, ob der aktuelle Drucker in der Liste der auszuschließenden Drucker ist
        if ($printersToExclude -notcontains $existingPrinter.Name) {
            Remove-PrinterFromPC -printerName $existingPrinter.Name
        }
    }
} else {
    $errorServerUnreachable = "Printserver $printServer ist nicht erreichbar."
    $errorServerUnreachable | Out-File -FilePath $errorLogPath -Append
    Write-Host "FEHLER: $errorServerUnreachable Drucker werden nicht entfernt."
    Write-Host "Skript wird beendet."
    exit 1
}

# Hole die Liste der Drucker vom Print Server
$printers = Get-WmiObject -Class Win32_Printer -ComputerName $printServer

foreach ($printer in $printers) {
    $location = $printer.Location
    $assignedPCs = $location -split ';'

    foreach ($assignedPC in $assignedPCs) {
        # Füge Drucker zum PC basierend auf dem Standortfeld hinzu
        Add-PrinterToPCBasedOnLocation -printerName $printer.Name -location $assignedPC.Trim()
    }
}

# Warte 2 Sekunden
Start-Sleep -Seconds 2

# Funktion zum Durchsuchen der Drucker und zum Schreiben ins Log
function SearchAndLogPrinters {
    param (
        [string]$searchTerm,
        [string]$logFilePath
    )
    
    $printers = Get-WmiObject -Query "SELECT * FROM Win32_Printer"
    
    foreach ($printer in $printers) {
        $location = $printer.Location
        if ($location -like "*$searchTerm*") {
            $logMessage = "PC-Name: $searchTerm, Drucker: $($printer.Name), Standort: $location"
            Add-Content -Path $logFilePath -Value $logMessage
            # Druckernamen vor dem Festlegen des Standarddruckers ins Log schreiben
            $logMessage = "Ausgewählter Drucker: $($printer.Name)"
            Add-Content -Path $logFilePath -Value $logMessage
            # Aufrufen der Funktion zum Festlegen des Standarddruckers
            SetDefaultPrinter -printerName $printer.Name
        }
    }
}

# Funktion zum Festlegen des Standarddruckers
function SetDefaultPrinter {
    param (
        [string]$printerName
    )

    rundll32.exe printui.dll,PrintUIEntry /y /n "$printerName"
}

# Aufrufen der Funktion und Suche nach dem PC-Namen
SearchAndLogPrinters -searchTerm $currentPCName -logFilePath $errorLogPath

Write-Host "Vorgang abgeschlossen."

 

Jetzt scheiter ich leider daran das Skript mit normalen Rechten auszuführen als Fehlermeldung bekomme ich diese:
 

Get-WmiObject : Zugriff verweigert
In C:\Users\Max.Mustermann\Desktop\Drucker Skript Test 19.ps1:127 Zeichen:13
+ $printers = Get-WmiObject -Class Win32_Printer -ComputerName $printSe ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Wie kann ich am Sichersten den Zugriff auf den Printserver gewährleisten?

Gibt es hier evtl einen möglichkeit mit einer AD Sicherheisgruppe zuarbeiten?
Oder kann man das Skript evtl mit einem Zertifikart so ausstatten das er Printserver nur diese Skript Aktzeptiert?

 

 

bin für jede idee Dankbar

 



 

Link zu diesem Kommentar

Hi,

 

$printers = Get-WmiObject -Class Win32_Printer -ComputerName $printServer

um Remote WMI abzufragen benötigen deine User passende Berechtigungen: Setting Namespace Security with the WMI Control - Win32 apps | Microsoft Learn

 

Ansonsten hat die PowerShell auch eigene CMDlets fürs Printer Management (PrintManagement Module | Microsoft Learn) evtl. kommst du damit besser zurecht.

 

Generell würde ich in die Drucker der User nicht wirklich viel Energie stecken. Ich bin da bei diesem Motto: Drucker verteilen und bereitstellen - Gruppenrichtlinien

Zitat

Frage: Was ist der beste Weg Drucker an die Benutzer/Computer zu verteilen?
Antwort: Ganz einfach, es gibt keinen, man macht das nicht.

 

Ich mach das nicht mehr. Ich tue mir das nicht mehr an. Das muss der User selber können!

 

Gruß

Jan

Link zu diesem Kommentar

Hi Jan,

Danke für die Antowet mit den CMDlets hab ich leider bei der Standart Drucker vergabe nicht viel erfolg gehabt.

Wir haben bereits Gruppenrichtlinen im Einsatzt welche aber gefühlt nur in 80% der Fälle klappen.

Daher die Idee es mit einem Skript zu lösen. Hoffe ja immer noch das wir bald uns zu einer Followme Lösung bekommen.

MFG

Luca

Link zu diesem Kommentar

Ich hab die DCOM berechtigungen gesetzt jetzt Funktioniert auch alles.

Danke für den Link. Nun bekomme ich aber leider sobald ein Zweiter Benutzer das Skript ausgeführt hat folgende Fehlermeldung

Get-WmiObject : Fehler beim Anbieter
In Zeile:127 Zeichen:13
+ $printers = Get-WmiObject -Class Win32_Printer -ComputerName $printSe ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], ManagementException
    + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

 

Nach ca. 1 Stunden tritt der Fehler erst wieder auf wenn ein Zweiter Benutzer auch das Skript ausführt.
Benutzer 1 konnte das Skript davor 20 mal ohne Problem ausführen.

 

Jemand einen idee?

MFG
Luca

bearbeitet von FrettchenSkript
Link zu diesem Kommentar
  • 4 Wochen später...
Am 12.9.2023 um 17:08 schrieb daabm:

Jan hat nicht gesagt, daß Ihr das per Gruppenrichtlinie machen sollt (das ist glaub auch die schlechteste aller Varianten). Er hat gesagt, daß sogar Gruppenrichtlinien.de sagt "mach es einfach nicht. Gib dem User ne Kurzanleitung, wie es geht, und laß es ihn selber machen."

 

Wie so oft gibt es da verschiedene Ansätze. Die Fragen die man sich hier stellen muss sind bei jeglicher Automation immer die gleichen. Egal ob Produktion oder IT. Manchen Aufwand holt man zwar objektiv gesehen nie rein, der Alltag ist aber z.B. für die Mitarbeiter weniger stressig, die Fehlerquote tiefer, weniger Ressourcen werden vergeudet oder man sammelt einfach nur Cookie Points bei den Mitarbeiter (Aus Sicht der IT, des Chefs etc.).

Bei statischen Arbeitsplätzen wie Produktion, Lager oder automatisierten/definierten Prozessabläufen lohnt sich eine Automatisierung imho immer. Die Verkäuferin im Supermarkt verbindet ihren Kassenzetteldrucker auch nicht selbst. ;-)

 

Der grosse Vorteil ist, dass man Bereinigungen für falsch verbundene Drucker, nicht mehr vorhandene Drucker, Umstellung auf FQDN, verschiedene Standortermittlungsverfahren (Thinclients mit denen sich auf die eigene VM verbunden wird, Zeroclients, Files etc.) mit in ein zentrales Script einfliessen lassen kann. Alles im grunde recht Primitiv aber wirkungsvoll. Die Druckerliste selbst kann ein Textfile sein, welches z.B. jemand aus der Abteilung pflegt. Ein richtig oder falsch gibt es lediglich WIE man die Drucker verbindet und da ist die primitivste Variante auch heute fast immer noch die beste (rundll32). Das Ob hängt von der Umgebung ab.

 

 

Ein vollautomatisches Beispiel: Eine Betriebssoftware haben wir so angepasst, dass alle Drucker darin gespeichert sind und die ID's der Fächer mit den jeweiligen Papiertypen verküpft werden. Was nicht verknüpft ist, landet auf dem Mehrzweck mit einer Bestätigung am Screen, dass man das Papier eingelegt hat bevor der Druck rausgeht. Pro Abteilung. Die Software ermittelt den Standort des Clients und wählt das Standard-Preset aller Drucker der Abteilung aus. Der User kann die Ziel-Abteilung manuell ändern. Er wählt nie einen Drucker aus, er wechselt nur die Zielabteilung für den Ausdruck wenn das gewünscht ist. Die Drucker werden von der Anwendung verbunden. Wird ein Drucker ersetzt, müssen meistens lediglich die ID's der Fächer und allenfalls der Name angepasst werden, bleibt der Hersteller identisch, nichtmal das. Minimalster Administrationsaufwand.

Das ganze war einmal aufwändig und wird nun seit bald 25 Jahren verwendet. Der Aufwand wurde schon längstens reingeholt. Nur die Ermittlung des Standorts musste teilweise modernisiert werden als VM's hinzugekommen sind welche mit dem Mitarbeiter mitgehen. Da haben wir dann die Session-Daten aus der Registry ausgelesen.

Andere Software löst das teilweise mit einem zentralen Druck-Management auf einem Server, in diesem Fall war das so einfacher und vor allem ohne eine zusätzliche Software mit einer vergleichsweise einfachen Änderungen möglich.

 

 

Dann gibt es noch ein ganz praktisches Admin-Problem. Die meisten händisch von Usern verbunden Drucker werden via NetBios Namen und nicht via FQDN verbunden. Das gibt spätestens wenn die ganzen Security Flags der letzten Monate enforced werden viel Spass. Ist einigermassen gruselig das aufzuräumen. Kann natürlich geschult werden, aber es dürften noch sehr viele Drucker falsch verbunden sein. ;)

 

 

Am 12.9.2023 um 09:59 schrieb FrettchenSkript:

Das Skript funktioniert wunderbar wenn man es mit einem Domain Admin ausführt.

Mal ganz unabhängig von den Druckern, es gibt keinen einzigen vernünftigen Grund, dass man ein Domain-Admin Konto zum verbinden von Druckern hernimmt. Auch nicht für die Administration von Clients. Nicht mal zum testen. Der Domain Admin ist eigentlich rein für die Administration des DC's da. Egal wie gross die Umgebung ist und sollte so weit weg wie möglich von allem sein was mit Druckern zu tun hat. ;-)

 

Das hinzufügen von z.B. einer Domänen-Client-Admingruppen zur lokalen Admingruppe der Clients kann man sehr easy mit GPO's steuern. Und gleichzeitig mit GPO's verhindern, dass sich Domain oder andere Server-Admins auf Clients verbinden.

bearbeitet von Weingeist
Link zu diesem Kommentar
Der letzte Beitrag zu diesem Thema ist mehr als 180 Tage alt. Bitte erstelle einen neuen Beitrag zu Deiner Anfrage!

Schreibe einen Kommentar

Du kannst jetzt antworten und Dich später registrieren. Falls Du bereits ein Mitglied bist, logge Dich jetzt ein.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor-Fenster leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

×
×
  • Neu erstellen...