## 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)
}

## Dienstag, 10. Juli 2018

### Remote Desktop Connection Manager in der paedML Linux

Ich wurde gerade auf den Remote Desktop Connection Manager von Microsoft aufmerksam gemacht. Es ist eine Verwaltungssoftware für Remotedesktop Verbindungen (RDP) und bietet die Möglichkeit verschiedene RDP Verbindungen nach Gruppen sortiert in einem User Interface darzustellen und Verbindungen per Mausklick zu öffnen. Um diese Nutzen zu können, muss man mit Opsi das Paket rdp-zugriff auf allen Benötigten Clients auszurollen.
Mit dem Manager ist es nun möglich alle Aufgaben, welche lokal am Client per Adminaccout erledigt werden müssen, bequem per Remote Verbindung durchzuführen. Vor allem zur Installation von Programmen ohne Opsi-Pakete kann dies von großem Nutzen sein.
Da die paedML-Linux immer die gleichen Standardcontainer verwendet habe ich daher ein Kleines Skript zusammengestellt, welches die per Schulkonsole angelegte Computerraumstruktur direkt in den Manager importiert. Das Powershell Skript erstellt dann eine Datei "schule.rdg", welche direkt im Manager geöffnet werden kann.
Das Skript verwendet die hier zur Verfügung gestellten Methoden zum Anlegen der Struktur, vielen Dank an den Autor. Zum Ausführen das Skript in die Powershell kopieren und ausführen. Der Dateipfad/Name lässt sich über $pfad anpassen:

> $pfad = ".\schule.rdg"
> function New-RDCManFile
> {
> Param(
> [Parameter(Mandatory = $true)]
> [String]$FilePath,
> [Parameter(Mandatory = $true)]
> [String]$Name
> )
> BEGIN
> {
> [string]$template = @'
> <?xml version="1.0" encoding="utf-8"?>
> <RDCMan programVersion="2.7" schemaVersion="3">
> <file>
> <credentialsProfiles />
> <properties>
> <expanded>True</expanded>
> <name></name>
> </properties>
> </file>
> <connected />
> <favorites />
> <recentlyUsed />
> </RDCMan>
> '@
> $FilePath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($FilePath)
> if(Test-Path -Path $FilePath)
> {
> Write-Error -Message 'File Already Exists'
> }
> else
> {
> $xml = New-Object -TypeName Xml
> $xml.LoadXml($template)
> }
> }
> PROCESS
> {
> $File = (@($xml.RDCMan.file.properties)[0]).Clone()
> $File.Name = $Name
> $xml.RDCMan.file.properties |
> Where-Object -FilterScript {
> $_.Name -eq ''
> } |
> ForEach-Object -Process {
> [void]$xml.RDCMan.file.ReplaceChild($File,$_)
> }
> }
> END
> {
> $xml.Save($FilePath)
> }
> }
> function New-RDCManGroup
> {
> Param(
> [Parameter(Mandatory = $true)]
> [String]$FilePath,
> [Parameter(Mandatory = $true)]
> [String]$Name
> )
> BEGIN
> {
> $FilePath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($FilePath)
> if(Test-Path -Path $FilePath)
> {
> $xml = New-Object -TypeName XML
> $xml.Load($FilePath)
> }
> else
> {
> Write-Error -Exception $_.Exception
> throw $_.Exception
> }
> }
> PROCESS
> {
> $group = $xml.CreateElement('group')
> $grouproperties = $xml.CreateElement('properties')
> $groupname = $xml.CreateElement('name')
> $groupname.set_InnerXML($Name)
> $groupexpanded = $xml.CreateElement('expanded')
> $groupexpanded.set_InnerXML('False')
> [void]$grouproperties.AppendChild($groupname)
> [void]$grouproperties.AppendChild($groupexpanded)
> [void]$group.AppendChild($grouproperties)
> [void]$xml.RDCMan.file.AppendChild($group)
> }
> END
> {
> $xml.Save($FilePath)
> }
> }
> function New-RDCManServer
> {
> Param(
> [Parameter(Mandatory = $true)]
> [String]$FilePath,
> [Parameter(Mandatory = $true)]
> [String]$GroupName,
> [Parameter(Mandatory = $true)]
> [String]$Server,
> [Parameter(Mandatory = $true)]
> [String]$DisplayName
> )
> BEGIN
> {
> $FilePath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($FilePath)
> if(Test-Path -Path $FilePath)
> {
> $xml = New-Object -TypeName XML
> $xml.Load($FilePath)
> }
> else
> {
> Write-Error -Exception $_.Exception
> throw $_.Exception
> }
> }
> PROCESS
> {
> $ServerNode = $xml.CreateElement('server')
> $serverproperties = $xml.CreateElement('properties')
> $servername = $xml.CreateElement('name')
> $servername.set_InnerXML($Server)
> $serverdisplayname = $xml.CreateElement('displayName')
> $serverdisplayname.set_InnerXML($DisplayName)
> [void]$serverproperties.AppendChild($servername)
> [void]$serverproperties.AppendChild($serverdisplayname)
> [void]$ServerNode.AppendChild($serverproperties)
> $group = @($xml.RDCMan.file.group) | Where-Object -FilterScript {
> $_.properties.name -eq $groupname
> }
> [void]$group.AppendChild($ServerNode)
> }
> END
> {
> $xml.Save($FilePath)
> }
> }
> New-RDCManFile -FilePath $pfad -Name Schule
> New-RDCManGroup -FilePath $pfad -Name "Admin"
> New-RDCManServer -FilePath $pfad -DisplayName "AdminVm" -Server "AdminVm" -Group "Admin"
> [ADSI]$domain = "LDAP://CN=raeume,CN=groups,OU=schule, DC=paedml-linux,DC=lokal"
> $alleGruppen = ($domain.Children.distinguishedName | ForEach-Object {[ADSI]"LDAP://$_"}).cn
> foreach($gruppe in $alleGruppen){
> New-RDCManGroup -FilePath $pfad -Name $gruppe
> $pcsInGruppe = (New-Object System.DirectoryServices.DirectoryEntry((New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=Group)(name=$($gruppe)))")).FindOne().GetDirectoryEntry().Path)).member | % { (New-Object System.DirectoryServices.DirectoryEntry("LDAP://"+$_)) } | Sort-Object sAMAccountName | SELECT @{name="User Name";expression={$_.Name}},@{name="User sAMAccountName";expression={$_.sAMAccountName}}
> foreach($client in $pcsInGruppe){
> write-host $client.'User Name' "wird zu" $gruppe "hinzugefügt"
> $client = $client.'User Name'
> New-RDCManServer -FilePath $pfad -DisplayName $client -Server $client -Group $gruppe
> }
> }

Da die Schulstruktur nun angelegt ist kann die erstellte Datei per Doppelklick im Remote Desktop Connection Manager geöffnet werden. Um mehrere Client-PCs verwalten zu können kann es sinnvoll sein zeitweise das Admin Passwort zu hinterlegen. Damit sind die gewünschten PCs nur noch einen Doppelklick von der Verwaltung entfernt. Klicken Sie Dazu mit der rechten Maustaste auf
"Schule" --> "Properties"
Dort wählen Sie die Logon Credentials, deaktivieren "Inherit..." und können nun das Passwort hinterlegen und mit OK bestätigen. Über "File" --> "save schule.rdg" kann das Passwort (verschlüsselt) auch auf dauer in der Datei hinterlegt werden.
Wenn Sie mit dem Administrieren der Remote-PCs fertig sind kann es sinnvoll sein das Passwort an dieser Stelle wieder zu entfernen, da diese Datei den Zugriff auf alle Client-PCs der Schule ermöglicht.

## Montag, 2. Juli 2018

### Opsi mit Powershell steuern

Der Opsi Config Editor ist ein sehr mächtiges Werkzeug. In meiner Schule haben wir allerdings über 300 Clients was dem Editor zu schaffen macht. Das setzen von Produktkonfigurationen für ganze PC-Räume kann daher etwas an den Nerven nagen.
Opsi bietet aber auch eine Web-API für die Steuerung per Skript.
Ich werde hier auf deren Steuerung per Powershell eingehen.
Um einen Befehl an Opsi zu senden verwende ich die "Invoke-RestMethod" Cmdlet.
Dieser muss die Adresse von Opsi, eine Authentifizierung und der Opsi-Aufruf mitgegeben werden.

> Invoke-RestMethod -uri $Adresse -headers $Benutzer -method post -body $Aufruf

Die Adresse ist ein String mit der Adresse der API,

> $Adresse = 'https://10.1.0.2:4447/rpc'

Für die Authentifizierung kann der Administrator oder der schoolopsiadmin verwendet werden. Das Passwort des letzteren ist auf dem Server in /etc/schoolopsiadmin.secret abgelegt. Leider gibt es meines Wissens keine Möglichkeit das Passwort per Powershell abzufragen, daher liegt das Passwort in meinem Skript zusätzlich in "H:\Skripte\opsiadmin.txt".

> $pair = "$('schoolopsiadmin'):$(Get-Content H:\Skripte\opsiadmin.txt)"
> $encodedCreds = ([System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair)))
> $Benutzer = @{Authorization = "Basic $encodedCreds"}

Mit -method post wird angegeben, dass etwas an den Server gesendet wird.
Letztlich folgt der Body. Dieser Parameter ist im JSON Format zu übergeben und kann daher direkt als Powershell-Ojekt erstellt werden und dann zu JSON übersetzt werden. Um Befehle zu testen kann man den interaktiven Modus der Opsi-Api über https://10.1.0.2:4447/interface verwenden. Da die meisten Aufrufe Attribute und Filter erlauben hier eine Vorlage:

> $Aufruf = ConvertTo-Json(@{ method = "Methode";params = @(@("optionalerParameter1", "oParam2"), @{FilterAttribut1 = "Wert1", FilterA2 = "Wert2"});id = 1}))

In der Praxis kann dies Um auf dem Client pc1 das Paket 7zip auf setup zu stellellen:

> $Aufruf = ConvertTo-Json( @{ method = "setProductActionRequest"; params = @("7zip", "pc1.paedml-linux.lokal", "setup"); id = 1})

Um die Installierten Pakete auf pc1 von Opsi zu erfragen

> $Aufruf = ConvertTo-Json(@{ method = "productOnClient_getObjects";params = @(@(), @{clientId = "pc1.paedml-linux.lokal"});id = 1}))

Natürlich können anstelle von Texten auch Variablen benutzt werden.
Um bei einem Computerraum alle installierten Produkte zu aktualisieren muss eine Abfrage an das Opsi-Depot gestellt werden und die Paketversionen mit denen auf den Clients vergleichen werden. Dies kann für alle Computer aus einer Raumguppe durchgeführt werden. Das fertige Skript könnte z.B. so aussehen:

> $computerraum= 'schule-raum1'
> $nachInstallationHerunterfahren=$true
> $ClientListe=((New-Object System.DirectoryServices.DirectoryEntry((New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=Group)(name=$($computerraum)))")).FindOne().GetDirectoryEntry().Path)).member | % { (New-Object System.DirectoryServices.DirectoryEntry("LDAP://"+$_)) } | Sort-Object sAMAccountName | SELECT @{name="User Name";expression={$_.Name}},@{name="User sAMAccountName";expression={$_.sAMAccountName}})."User Name"
> [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
> $nichtUpdaten = {"ms_office", "set-registry-keys", "rdp-zugriff", "shutdownwanted", "windomain", "windows10-upgrade", "ms-sql-2012ee"}
> #Login Variablen
> $urlJSON = 'https://10.1.0.2:4447/rpc'
> $user = "schoolopsiadmin"
> $pass = Get-Content H:\Skripte\opsiadmin.txt
> $pair = "$($user):$($pass)"
> $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
> $basicAuthValue = "Basic $encodedCreds"
> $Headers = @{
> Authorization = $basicAuthValue
> }
> Write-Host "Frage Depot ab"
> $Depot = (Invoke-RestMethod -uri $urlJSON -Headers $Headers -method post -body (ConvertTo-Json(@{ method = "productOnDepot_getObjects";params = @();id = 1}))).result
> foreach($zielClient in $ClientListe){
> $zielClient = ($zielClient+=".paedml-linux.lokal").ToLower()
> Write-Host "Frage Client" $zielClient "ab"
> $Client = (Invoke-RestMethod -uri $urlJSON -Headers $Headers -method post -body (ConvertTo-Json(@{ method = "productOnClient_getObjects";params = @(@(), @{clientId = $zielClient});id = 1}))).result
> #ProductOnDepot - $pd
> #ProductOnClient - $pc
> $updateFlag=$false
> foreach($pd in $Depot){
> foreach($pc in $Client){
> if(($pd.productId -eq $pc.productId) -and ($pc.installationStatus -eq "installed") -and ($pc.productType -eq "LocalbootProduct") -and (-not($nichtUpdaten -match $pc.productId)) -and ((-not $pc.productId.StartsWith("opsi"))-or ($pc.productId -eq "opsi-client-agent")-or ($pc.productId -eq "opsi-configed"))){
> Write-Host
> Write-Host "Client:" $zielClient
> Write-Host $pd.productId -ForegroundColor Yellow
> Write-Host " Client Version: "$pc.productVersion
> Write-Host " Depot Version: "$pd.productVersion
> if(($pc.productVersion -eq $pd.productVersion)-and ($pc.packageVersion -eq $pd.packageVersion)){
> Write-Host "--> kein Update notwendig" -ForegroundColor Green
> }
> else{
> $updateFlag=$true
> if((($pc.productVersion -eq $pd.productVersion)) -and ($pc.packageVersion -ne $pd.packageVersion)){Write-Host "--> neues Paket vorhanden, " -ForegroundColor Red}
> Write-Host "--> neue Version wird auf setup gesetzt. " -ForegroundColor Red
> $Produkt = $pd.productId
> #$strAction= (ConvertTo-Json(@{ method = "setProductActionRequest";params = @($Produkt, $zielClient, "setup");id = 1}))
> $ignoreOutput = Invoke-RestMethod -uri $urlJSON -Headers $Headers -method post -body (ConvertTo-Json(@{ method = "setProductActionRequest";params = @($Produkt, $zielClient, "setup");id = 1}))
> }
> }
> }
> }
> if($updateFlag){
> if($nachInstallationHerunterfahren){
> write-host "Nach Installation" $zielClient "herunterfahren"
> $ignoreOutput = Invoke-RestMethod -uri $urlJSON -Headers $Headers -method post -body (ConvertTo-Json(@{ method = "setProductActionRequest";params = @("shutdownwanted", $zielClient, "once");id = 1}))
> }
> write-host "Update wird gestartet"
> $ignoreOutput = Invoke-RestMethod -uri $urlJSON -Headers $Headers -method post -body (ConvertTo-Json(@{ method = "hostControlSafe_fireEvent";params = @("on_demand", $zielClient);id = 1}))
> }
> else{Write-Host "Für" $zielClient "wurden keine Updates gefunden."}
> }

Das Skript sucht zuerst alle Clients des PC-Raumes, welcher unter $computerraum angegeben wird. Nun prüft das Skript jeden Computer ob die Versionen installierter Programme von denen im Depot abweichen. Falls ja, werden die Produkte auf "setup" gesetzt und eine Installation "on_demand" ausgeführt. Ebenso wird "shutdownwanted auf "once" gesetzt, falls dies nicht mit der Variable $nachInstallationHerunterfahren=$false unterbunden wird.
D.h. das Skript arbeitet alle PCs des Raumes ab, startet die Installation und fährt die PCs im Anschluss herunter.

## Montag, 25. Juni 2018

### "Vertrauen Sie diesem Drucker"-Warnungen beseitigen

Bei der regulären Einrichtung von Druckern bekommen Clients nach dem Anmelden immer wieder die "Vertrauen Sie diesem Drucker"-Warnung. Um den Windows-CLients das Vertrauen wieder zu geben müssen Sie den Clients den Druckerserver per GPO bekannt machen. (Quelle)
Öffnen Sie dazu den Gruppenrichtlinien Editor auf der AdminVM. (Start --> "gpmc.msc")
Erstellen und verknüpfen Sie bei der OU "schule" eine neue Gruppenrichtlinie mit einem Namen, z.B. "Einstellungen Drucker".
Mit einem rechtsklick auf die neu erstellte Richtlinie und einem Klick auf "Bearbeiten" öffnen Sie den Gruppenrichtlinienverwaltungs-Editor. Öffnen Sie hier
Computerkonfiguration --> Richtlinien --> Administrative Vorlagen --> Drucker.
Wählen Sie aus der rechts angezeigten Liste von Einstellungen "Point-and-Print-Einschränkungen" mit einem Doppelklick aus. Dort müssen Sie "Aktiviert" anklicken. Setzen Sie ein Häckchen bei "Benutzer können Point-und-Print nur mit folgenden Servern verwenden. Bei "Vollqualifizierte Servernamen" tragen Sie

> server.paedml-linux.lokal

ein.
Falls Sie auch einen anderen Print-Server verwenden, wie z.B. in meinem Artikel über die AdminVM als Druckerserver tragen Sie diesen durch ein Semikolon getrennt ebenfalls ein.

> server.paedml-linux.lokal; adminvm.paedml-linux.lokal

Nun setzen Sie noch die Sicherheitshinweise jeweils auf "nicht anzeigen".Bestätigen Sie die Einstellungen mit rechts unten mit "OK".
Mit einem Doppelklick auf "Point-und-Print für Pakete" öffen Sie nun eine zweite Einstellung.
Klicken Sie hier ebenfalls auf "Aktivieren". Bei den Servernamen klicken Sie auf "Anzeigen" und tragen bei "Inhalte anzeigen" den Server und gegebenenfalls alternative Druckerserver an.

> server.paedml-linux.lokal

Mit einem Klick auf "OK" ist die Richtlinie fertig.
Denken Sie daran, dass Gruppenrichtlinien teilweise erst mit einer Verzögerung am Client eingelesen werden. Um die Resultate sofort Prüfen zu können können Starten Sie den Client neu und melden sich als Administrator an. Geben Sie dann

> gpupdate /force

ein um die Richtlinien neu zu laden.

## Dienstag, 5. Juni 2018

### SMART Notebook Proxyfenster beseitigen

Die digitalen White-Boards unserer Schule verwenden die Software SMART Notebook. Die Software öffnet nach dem Starten jedoch ein Login-Fenster für die Proxy-Einstellungen. Dieses Fenster muss dann vor jeder Benutzung der digitalen Tafel 3 mal weggeklickt werden. Um diesen Umstand zu ändern muss man eine Außnahmeregelung mi Proxyserver für den jeweiligen PC anlegen.

### Vorgehen:

Öffnen Sie Putty, verbinden sich zum Server (10.1.0.1) und melden sich als root an. Navigieren Sie in das Verzeichnis /etc/squid3

> cd /etc/squid3/

und machen Sie eine Backup-Kopie der Datei local.conf

> cp local.conf local.conf.bak

Nun editieren Sie die Datei local.conf mit einem Editor Ihrer Wahl, z.B. mc oder vi.
Dort fügen Sie pro Client oder IP-Range (Falls alle freizuschaltenden Cliengts in einem IP Bereich liegen) die Zugriffe ohne Proxy authentifizierung frei.

> acl SMART1 src 10.1.0.55/32
> http_access allow SMART1

SMART1 ist ein Pseudonym für die Regel, es könnte auch ein anderer Name gewählt werden. Die IP-Adresse ist die des PCs auf dem die Smart-Software freigeschaltet werden soll. Die IP können Sie aus der Schulkonsole /Rechner(Schulen) entnehmen. Das /32 bedeutet, dass nur die Angegebene IP freigeschaltet wird. Falls sich mehrere freizuschaltende Rechner in einem IP-Bereich befinden kann auch ein ganzer Bereich freigeschaltet werden. Verwenden Sie z.B. die Subnet-Calculator.com um einen geeigneten Bereich zu bestimmen.
Nach dem Speichern der Datei sollten Sei den Squid Service neu starten.

> service squid3 restart

Die freigeschalteten Rechner sollten nun keine Anmeldung mehr benötigen.
Vorsicht: Eine INTERNETSPERRE kann an diesem PC nun NICHT MEHR aktiviert werden! Der Jugendschutzfilter ist davon jedoch nicht beeinflusst.

### Beispiele:

Das Freischalten mehrer PCs kann z.B. so aussehen.

> acl SMART1 src 10.1.0.55/32
> acl SMART2 src 10.1.0.68/32
> acl SMART3 src 10.1.0.53/32
> acl SMART4 src 10.1.0.99/32
> http_access allow SMART1
> http_access allow SMART2
> http_access allow SMART3
> http_access allow SMART4

Wenn die freizuschaltenden PCs die IP-Adressen 10.1.0.201 bis 10.1.0.206 sind kann der Eintrag auch wie folgt aussehen, siehe Subnet-Calculator.com:

> acl SMART src 10.1.0.201/29

> http_access allow SMART

### Druckerinstallation OHNE Probleme ABER OHNE Schulkonsolensteuerung

## Vorwort:

Die Verteilung von Druckern über die Schulkonsole bietet einige Vorteile, wie die zentrale Moderation von Druckern, Druckerwarteschlange usw. Die Installation über den SERVER bringt aber auch viele Probleme mit sich, Treiber, welche sich nicht hochladen/installieren lassen. Warnungen wie „Vertrauen Sie diesem Drucker“, deren Beseitigung ich hier beschreibe, usw.
Eine Alternative dazu kann daher sein, die AdminVM als Druckserver einzusetzen. Dies bietet gegenüber der Server-Verteilung ebenfalls Vorteile: Treiber werden ohne Fehler installiert und an Clients verteilt. Die Drucker können ins Druckerverzeichnis aufgeführt und von jedem Benutzer „hinzugebucht“ werden. Die Verteilung der Drucker kann z.B. über Gruppenrichtlinien gelöst werden.
VORSICHT: Einstellungen der Schulkonsole sind völlig unabhängig der hier gemachten Einstellungen, damit verlieren Sie die Kontrolle der Drucker über die Schulkonsole.
Nachtrag: Ich habe gerade einen Artikel bei Microsoft entdeckt, der relativ exakt die gleichen Schritte für den Windows Server 2012 beschreibt. Das hätte mir viel Zeit und Nerven erspart. Damit die Seite nicht nochmal verloren geht, hier der Link: Drucker auf Windows Server 2012.

## Vorgehen:

1. AdminVM als Druckserver einrichten,
2. Freigeben der Drucker über Gruppenrichtlinien,
3. Setzten der Standarddrucker über Gruppenrichtlinien

### 1. AdminVM als Druckserver einrichten

Die Einrichtung läuft analog zum Administratorhandbuch Kapitel 6.5.
Laden Sie vorbereitend für Ihren Drucker die aktuellsten Treiber für Ihre Windows-Version herunter und entpacken Sie ihn, z.B. mit 7Zip.
Auf der AdminVM drücken Sie die Windows-Taste und öffnen Sie den „Ausführen“-Dialog. In dem sich neu öffnenden Fenster geben Sie „printmanagement.msc“ ein und drücken Sie anschließend auf „OK“. Es öffnet sich das Fenster „Druckerverwaltung“.
Dort ist bereits die ADMINVM (lokal) hinterlegt, da jeder Windows PC automatisch einen Druckerserver installiert hat. Wenn Sie von einem anderen Windows PC aus Arbeiten wollen können Sie printmanagement.msc auch von einem anderen Windows Client aus öffnen. Dazu geben Sie analog zum Handbuch für Administratoren Kapitel 6.5.1 den Namen des Druckerservers an, also ADMINVM oder 10.1.0.13 (Die IP-Adresse der AdminVM)
Klicken Sie in der Druckverwaltung auf ADMINVM und auf Drucker.
Mit einem Rechtsklick auf „Drucker“ können Sie „Drucker hinzufügen“ wählen.
Klicken Sie „Einen neuen TCP/IP- oder Webdienste-Drucker über IP Adresse oder Hostnamen hinzufügen“ und anschließend auf „Weiter“.
Stellen Sie den Gerätetyp auf TCP-IP-Gerät und Hostname oder IP-Adresse auf die Adresse des Druckers. Diese können Sie z.B. aus der Schulkonsole entnehmen. (Schulkonsole/Drucker/Druckername enthält die IP des Druckers)
Falls Sie einen völlig neuen Drucker anlegen wollen müssen Sie wie üblich diesem über die Schulkonsole über „Rechner (Schulen)“ → „Hinzufügen“ → „Gerät mit IP-Adresse“ dem Drucker eine IP-Adresse zuweisen.
Beim Anschlussname können Sie den Druckernamen des neuen Druckers eingeben. Mit einem Klick auf „Weiter“ wird der Drucker nun angesprochen und erkannt.
Im folgenden Fenster klicken Sie auf „Einen neuen Treiber installieren“ und auf „Weiter“.
Klicken Sie auf „Datenträger“, „Durchsuchen“ und wählen Sie den Ordner des Druckertreibers. Im Ordner müssen Sie die „inf-Datei“ finden und anklicken, diese befindet sich oft in einem Ordner mit einer Bezeichnung „x64“ oder „64bit“. Nach einem Klick auf „Weiter“ wird eine Liste von Druckern angezeigt, welche im Treiber vorhanden sind. Wählen Sie wenn möglich den Treiber Ihres Druckers aus. Oft ist jedoch auch nur ein „Universaltreiber“ vorhanden, dieser sollte ebenfalls funktionieren. Nach einem Klick auf weiter werden die Freigabeeinstellungen geöffnet.
Geben Sie bei „Druckername“ und „Freigabename“ jeweils den Namen ein, unter welchem der Drucker im Netzwerk geführt werden soll.
Nach zwei letzten Klicks auf „Weiter“ wird der Drucker installiert und erstellt.
OPTIONAL: Jetzt können Sie den Drucker im Verzeichnis auflichten lassen. VORSICHT: durch diese Einstellung kann JEDER Benutzer im Netzwerk den Drucker auswählen und darauf drucken, ohne dass dies eingeschränkt werden kann. Mit einem Rechtsklick auf den Drucker erscheint im Menü „In Verzeichnis auflisten“, nach dem aktivieren kann der Drucker in der ganzen Schule gefunden werden.
klicken Sie dazu z.B. in Word bei der Druckerauswahl auf „Druckerhinzufügen…“.

### 2. Freigeben der Drucker über Gruppenrichtlinien

Das Freigeben von Druckern über Gruppenrichtlinien ist von Microsoft gut vorbereitet, jedoch ist aufgrund der vom Server vorgegebenen Struktur vorerst kein setzen des Standarddruckers möglich.
Klicken Sie mit rechter Maustaste auf den Drucker und wählen Sie „Mit Gruppenrichtlinie bereitstellen…“
Bei der Wahl des Gruppenrichtlinienobjekts klicken Sie auf „Durchsuchen…“. Klicken Sie mit einem Doppelklick die Organisationseinheit „schule.paedml-linux.lokal“ an und anschließend auf „Neues Gruppenrichtlinienobjekt erstellen“.
Geben Sie dem neuen Gruppenlinienobjekt einen Namen, welcher die Zuordnung von Druckern zu einem Computerraum wiederspiegelt, z.B. „Drucker Raum 15“ oder „Drucker Lehrerzimmer“.
Falls bei einem weiteren Drucker für den gleichen Raum bereits ein Gruppenrichtlinienobjekt existiert erstellen Sie kein neues. Die vorhandenen Richtlinien werden nach einem Klick auf „schule.paedml-linux.lokal“ aufgelistet, wählen Sie dort die passende Richtlinie aus.
Aktivieren Sie nun die Checkbox „Die Computer, auf die…“ und klicken Sie auf „Hinzufügen“. Damit ist der Drucker per Gruppenrichtlinie freigegeben.
Diese Richtlinie gilt vorerst für alle Computer von „schule.paedml-linux.lokal“. Dies muss nun eingeschränkt werden. Klicken Sie auf die Windows-Taste und geben Sie „gpmc.msc“ ein. (Dies ist nur als Administrator möglich).
Öffnen Sie „Gesamtstruktur“ → „Domänen“ → „paedml-linux.lokal“ → „schule“ und suchen Sie dort Ihre neue Richtlinie.
In der Sicherheitsfilterung muss nun „Authentifizierte Benutzer“ entfernt werden. Wählen Sie dazu diese aus und klicken Sie auf „Entfernen“.
In der Sicherheitsfilterung müssen nun alle Benutzer und Computer hinzugefügt werden, auf welche Druckereinstellungen wirken sollen, die Computer des Computerraumes, und alle Schuler und Lehrer.
Klicken Sie auf in der Sicherheitsfilterung auf „Hinzufügen“. Im Fenster „Benutzer, Computer oder Gruppe auswählen“ geben Sie den Namen des Computerraumes mit dem präfix „schule-“ ein, z.B. „schule-raum15“. Nach einem Klick auf Namen überprüfen wird die Raumgruppe erkannt. Bestätigen Sie mit „OK“.
Fügen Sie auf gleiche Weise die Gruppen „schueler-schule“ und „lehrer-schule“ hinzu.

### 3. Setzten der Standarddrucker über Gruppenrichtlinien

Zum setzten der Standarddrucker muss die Gruppenrichtlinie bearbeitet werden.
Klicken Sie mit der rechten Maustaste auf das Gruppenlinienobjekt und wählen Sie „Bearbeiten…“
Es öffnet sich der Gruppenlinienverwaltungs-Editor. Öffnen Sie hier die Struktur „Benutzerkonfiguration“ → „Einstellungen → „Systemsteuerungseinstellungen“ → „Drucker“. Mit einem Rechtsklick in den weißen Bereich wählen Sie „Neu“ → „Freigegebene Drucker“.
Klicken Sie die Checkbox „Drucker als Standarddrucker festlegen…“ an und wählen danach auf dem Knopf „ … “ den Standarddrucker des Raumes. Klicken Sie bei der Druckersuche dazu auf „Jetzt suchen“, da der Drucker jetzt im Verzeichnis aufgelistet ist wird er unten angezeigt. Bestätigen Sie mit „OK“.
VORSICHT: Wenn der Drucker nicht im Verzeichnis aufgelistet wurde müssen Sie den Freigabepfad von Hand eingeben, z.B. \\ADMINVM\Drucker5.
Vielen Dank an Herrn Unmüssig für den Hinweis.
Das Setzen des Standard Druckers darf nur in diesem Computerraum angewendet werden. Klicken Sie dazu oben auf den Reiter „Gemeinsame Optionen“ und klicken Sie „Zielgruppenadressierung auf Elementebene“ an. Wählen Sie dann die „Zielgruppenadressierung“. Im Zielgruppenadressierungseditor klicken Sie auf „Neues Element“ und wählen „Sicherheitsgruppe“.
Jetzt wählen Sie auf dem Knopf „ … “ den Computerraum aus, z.B. „schule-Raum15“ und klicken auf „Namen überprüfen“. Bestätigen Sie mit „OK“.
Aktivieren Sie den Auswahlknopf „Computer in der Gruppe“. Klicken Sie auf „OK“.
Damit sind die Drucker von einem Windows PC freigegeben, dem Computerraum werden zugeordnete Drucker zugeteilt und der Benutzer des Raumes bekommt einen Standarddrucker zugeordnet.

## Montag, 4. Juni 2018

### "Bitte deaktivieren Sie Ihren Adblocker!"

Ich wurde gerade informiert das beim Aufruf von einigen Webseiten aus der Schule ein "Bitte deaktivieren Sie Ihren Adblocker!" Fenster eingeblendet wird.
Die paedML Linux verwendet jedoch keine lokalen Adblocker weshalb das "deaktivieren" etwas schwer fällt. Im Whiltelisting der paedML "rumzumurksen" um "hoffentlich" diese Seiten sehen zu können ist ebenfalls nicht all zu leicht. Aber natürlich kann man auch Feuer mit Feuer bekämpfen. Die Installation von uBlock Origin, einem AdBlocker löst das Problem prompt. Wunderbar, jetzt muss ich gegen Adblocker Warunungen einen Adblocker installieren... Dies ist eigentlich nicht im Sinne des Erfinders, jedoch zur Zeit die einzig mir bekannte Möglichkeit diese Seiten aufrufbar zu halten. Wenn Sie weitere/bessere Möglichkeiten kennen entsprechende Seiten anzuzeigen, ohne deren Monetarisierung zu unterlaufen, würde ich mich über Feedback freuen.

Die Installation von uBlock Origins auf den Clients können Sie per Gruppenrichtlinie durchführen, wie in dieser Quelle beschrieben:
Erstellen oder öffnen Sie eine passende Gruppenrichtlinie.
Unter Benutzerkonfiguration --> Administrative Vorlagen --> Google Chrome --> Erweiterungen wählen Sie die Einstellung --> "Liste der Apps und Erweiterungen konfigurieren, deren Installation erzwungen wurde". Diese müssen Sie "Aktivieren" und unter "Anzeigen" die ID der Erweiterung und der Updateserver hinterlegen. Für uBlock Origin ist dies der Wert:

> cjpalhdlnbpafiamejdnhcphjbkeiagm;https://clients2.google.com/service/update2/crx

Stellen Sie wie immer sicher, dass die Richtlinie von allen Computerkonten und Nutzern gelesen werden kann, z.B. mit "Authenticated Users" in welchem sowohl PC als auch Benutzerkonten liegen.
Neuere Posts Ältere Posts Startseite
Abonnieren Posts (Atom)