Donnerstag, 15. November 2018

Drucker anmelden per Gruppenrichtlinie

Da die Druckerzuweisung an den Clients nicht so zuverlässig funktioniert wie ich es mir wünsche habe ich ein neues Skript geschrieben, welches die Druckereinstellungen der Schulkonsole als Gruppenrichtlinie anlegt. Diese Richtlinie läuft in meiner Schule nun parallel zum herkömmlichen Drucker Anmeldeskript. Außerdem habe ich für Notfälle auf den Desktop eine Verknüpfung "Drucker reparieren" angelegt, welche gpupdate.exe startet.

Bisher habe ich keine Drucker-Anmeldeprobleme mehr feststellen können, aber falls doch Probleme auftreten sollten löst ein gpupdate dieses nun direkt. 

Wichtig: Mit dem Skript wird die printers.xml aus einer Gruppenrichtlinie bearbeitet. Dazu müssen einzigartige GUID-Schlüssel erzeugt werden. Diese gibt es erst ab Powershell 5! Bitte gegebenenfalls updaten oder das Skript auf einem Windows 10 Rechner starten. 

Leider braucht das Skript eine Vorhandene GPO als Vorlage. Auf anfrage kann ich diese gerne versenden. Ihr könnt euch aber auch selbst eine Richtlinie basteln. Die Anleitung dazu folgt in kürze. 

Und hier geht es los:

$zielGPO = "paedMLL_Druckerverbinden"
#Wenn Force = $true ist wird die GPO bei jedem Durchlauf aktualisiert, sonst nur bei neuen Printerlist Dateien oder fehlender GPO. 
$force = $false

#Hilfsfunktion. Dank an den Author Adam Bell
function Get-SID{
    Param ($DSIdentity)
$ID = new-object System.Security.Principal.NTAccount($DSIdentity)
return $ID.Translate( [System.Security.Principal.SecurityIdentifier] ).toString()
# From Adam Bell http://www.leadfollowmove.com/archives/powershell/security-identifiers-sids-and-nt-account-name
}

#Alle printer-assignment Dateien werden eingelesen
$a= Import-Csv -Header A,B,C -Delimiter ":" -Path  (Get-ChildItem -Path "\\server\netlogon\univention-printer-assignment\" -Filter '*.printerlist').FullName# | % -begin {$i=0} -process {$_.B=$i; $i++ }
$i=0
#Druckerreiheinfolge wird vor dem Sortieren gesichert
foreach($as in $a){
    $as.B = $i
    $i++
}

#Doppenungen werden entfernt und Daten aufbereitet
# Danke an https://stackoverflow.com/questions/31343752/how-can-you-select-unique-objects-based-on-two-properties-of-an-object-in-powers
$csvDataUnique = $a |   Group-Object 'A','C' |   %{ $_.Group | Select 'A','C','B' -First 1} |   Sort 'C'
$csvDataUnique | foreach{$_.C=$_.C.Split(",")[0].Split("=")[1]}
$backup = $csvDataUnique
$GPOListe = $csvDataUnique |   Group-Object 'C' |   %{ $_.Group | Select 'C' -First 1} |   Sort 'C'
$GPOListe=$GPOListe.C

#Liste aller Räume und deren Drucker wird erstellt.
$DruckerListe=@()
foreach($GPO in $GPOListe){
    $sammlung=@()
    foreach($zuordnung in $csvDataUnique){
        if($GPO -eq $zuordnung.C){
            $item = New-Object -TypeName psobject
            $item | Add-Member -MemberType NoteProperty -Name DruckerName -Value $zuordnung.A
            $item | Add-Member -MemberType NoteProperty -Name DruckerReihenfolge -Value $zuordnung.B
            $item | Add-Member -MemberType NoteProperty -Name DruckerNummer -Value 0
            $sammlung+=$item
            }        
    }
    $DruckerAdd = New-Object -TypeName psobject
    $DruckerAdd | Add-Member -MemberType NoteProperty -Name Name -Value $GPO
    $DruckerAdd | Add-Member -MemberType NoteProperty -Name Server -Value "\\SERVER\"
    $DruckerAdd | Add-Member -MemberType NoteProperty -Name GruppenName -Value ("PAEDML-LINUX\$GPO")
    $DruckerAdd | Add-Member -MemberType NoteProperty -Name GruppenSID -Value (Get-SID $GPO)
    $DruckerAdd | Add-Member -MemberType NoteProperty -Name Id -Value ""
    $DruckerAdd | Add-Member -MemberType NoteProperty -Name DruckerZuordnung -Value $sammlung
    $DruckerListe+=$DruckerAdd
}
#Drucker werden wieder in Reihenfolge gebracht.
foreach($GPO in $DruckerListe){
    $GPO.DruckerZuordnung = $GPO.DruckerZuordnung | Sort-Object -Property DruckerReihenfolge
    $i=0
    while($i -le $GPO.DruckerZuordnung.Count-1){
        $GPO.DruckerZuordnung[$i].DruckerNummer = $i
        $i++
    }
}
#Es wird geprüft, ob die GPO bereits existiert. Sonst wird Sie importiert und mit der OU Schule verknüpft. 
try{
    $ignore = Get-GPO -Name $zielGPO -ErrorAction Stop}
catch{
    $result = import-gpo -BackupId 13F02EBD-2DAA-44B9-B31F-743FC7E91F4E -TargetName $zielGPO -path "\\backup\opsi_depot_rw\DruckerSetup" -CreateIfNeeded
    New-GPLink -name $zielGPO -target "ou=schule,dc=paedml-linux,dc=lokal" -LinkEnabled Yes -ErrorAction SilentlyContinue
    $force=$true
}
$Id=(Get-GPO -Name $zielGPO).Id
$file = '\\BACKUP\opsi_depot_rw\DruckerSetup\{13F02EBD-2DAA-44B9-B31F-743FC7E91F4E}\DomainSysvol\GPO\User\Preferences\Printers\Printers.xml'
$target = '\\Server\sysvol\paedml-linux.lokal\Policies\{'+$Id+'}\User\Preferences\Printers\Printers.xml'

[xml]$xdoc = Get-Content ($file)
foreach($Raum in $DruckerListe){
#Für jeden Raum werden nun die Drucker Aktionen hinzugefügt. 
    $Raum.Id=$result.Id
    $server=$Raum.server
    #Alle Drucker aus der Schulkonsole werde ersteinmal entfernt, so werden falsche zuordnungen oder Probleme mit der Druckersperre gelöst. 
    foreach($Drucker in $Raum.DruckerZuordnung){
        $BranchToClone = @($xdoc.Printers.SharedPrinter)[1].Clone()
        $BranchToClone.Properties.path= $server+$Drucker.DruckerName
        $BranchToClone.name= $Drucker.DruckerName
        $BranchToClone.status=$Drucker.DruckerName
        $newguid = [System.Guid]::NewGuid().toString()
        $BranchToClone.uid= "{" + "$newguid" + "}"
        $CurrentDateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
        $BranchToClone.Changed = "$CurrentDateTime"
        $ignore = $xdoc.Printers.AppendChild($BranchToClone)
    }
    #Nun werden alle Drucker angelegt, jeweils mit einer Zielgruppenadressierung für den jeweiligen Raum. 
    foreach($Drucker in $Raum.DruckerZuordnung){
        $BranchToClone = @($xdoc.Printers.SharedPrinter)[2].Clone()
        $newguid = [System.Guid]::NewGuid().toString()
        $BranchToClone.uid= "{" + "$newguid" + "}"
        $CurrentDateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
        $BranchToClone.Changed = "$CurrentDateTime"
        $BranchToClone.name=$Drucker.DruckerName
        $BranchToClone.status=$Drucker.DruckerName
        $BranchToClone.Filters.FilterGroup.name = $Raum.GruppenName
        $BranchToClone.Filters.FilterGroup.sid = $Raum.GruppenSID
        if($Drucker.DruckerNummer-eq 0){$BranchToClone.Properties.default="1"}
        $BranchToClone.Properties.path=$server+$Drucker.DruckerName
        $ignore = $xdoc.Printers.AppendChild($BranchToClone)
    }
}
#Die ersten 3 Knoten sind die Vorlagen-Knoten aus der Vorlage GPO
$nodedelete = $xdoc.Printers.SharedPrinter[0]
$ignore = $xdoc.Printers.RemoveChild($nodedelete)
$nodedelete = $xdoc.Printers.SharedPrinter[0]
$ignore = $xdoc.Printers.RemoveChild($nodedelete)
$nodedelete = $xdoc.Printers.SharedPrinter[0]
$ignore = $xdoc.Printers.RemoveChild($nodedelete)

#Änderungen werden nur angewendet, wenn Univention Printerlist Dateien vorliegen oder die GPO nicht vorhanden war. 
try{if($force -or ((Get-ChildItem "\\server\netlogon\univention-printer-assignment\" | Foreach {$_.LastWriteTime} | sort)[(Get-ChildItem "\\server\netlogon\univention-printer-assignment\" | Foreach {$_.LastWriteTime} | sort).Count-1] -gt (Get-Item $target| Foreach {$_.LastWriteTime}))){
        Write-Host "Neue Druckereinstellungen werden installiert."
        $xdoc.Save($target)
    }
    else{
        Write-Host "Keine neuen Druckereinstellungen gefunden."
    }
}
catch{
    Write-Host "Neue Druckereinstellungen werden installiert."
    $xdoc.Save($target)
}