Montag, 23. April 2018

Schülerordner Links erstellen

Über Freigaben --> Home-Verzeichnisse Schueler --> _klassen können Lehrer die Ordner der Schühler ihrer Klassen anklicken. Da diese jedoch Links auf Linuxbasis sind können diese nicht kopiert werden.

Um eine "Windows Kopie" des Ordners "_klassen" anzulegen habe ich ein kleines Powershell Skript geschrieben. Es erstellt die gleiche Ordnerstruktur des Ordners "_klassen", ändert jedoch die Links zu den Schülerverzeichnissen zu Windows Links. Der neue Ordner liegt laut Skript auf c:\klassen. Er könnte als Alternative mit zwei Unterstrichen als "__klassen" in den Ordner der Schülerverzeichnisse gelegt werden. Dann kann sich jeder Kollege die Links seiner Klasse auch herauskopieren. 


Hier das (einfache) Skript
$a = Get-ChildItem -Path '\\server\Home-Verzeichnisse Schueler\_klassen\'
foreach ($as in $a){
    $b = Get-ChildItem -Path ('\\server\Home-Verzeichnisse Schueler\_klassen\' + $as.Name)
    New-Item -ItemType directory -Path ("c:\klassen\"+$as.Name)
    foreach ($bs in $b){
        write-host $bs.Name
        $WshShell = New-Object -comObject WScript.Shell
        $Shortcut = $WshShell.CreateShortcut("c:\klassen\"+$as.Name+"\"+$bs.Name+".lnk")
        $Shortcut.TargetPath = ("\\server\Home-Verzeichnisse Schueler\"+$bs.Name)
        $Shortcut.Save()
    }
}
Das vorige Skript ließt den Ordner _klassen aus und erstellt eine Kopie mit Windows Links.
Es ist aber auch möglich alle Informationen direkt aus dem LDAP Verzeichnis zu lesen. Das Skript wird dadurch etwas Komplizierter, legt jedoch z.B. auch wirklich nur Klassen an, nicht auch von lehrern angelegte Gruppen.

$speicherpfad="c:\klassen\"
[ADSI]$domain = "LDAP://CN=klassen, CN=schueler,CN=groups,OU=schule, DC=paedml-linux,DC=lokal"
$klassen = $domain.Children.distinguishedName | ForEach-Object {[ADSI]"LDAP://$_"}
New-Item -force -ItemType directory -Path ($speicherpfad)
foreach($k in $klassen){
    New-Item -force -ItemType directory -Path ($speicherpfad + $k.Name.Replace("schule-", ""))
    $schueler = $k.Member | ForEach-Object {[ADSI]"LDAP://$_"}
    foreach($s in $schueler){
        if($s.memberOf[0].Contains("schueler")){
            $WshShell = New-Object -comObject WScript.Shell
            $Shortcut = $WshShell.CreateShortcut("o:\klassen\"+$k.Name.Replace("schule-", "")+"\"+$s.displayName+".lnk")
            $Shortcut.TargetPath = ("\\server\Home-Verzeichnisse Schueler\"+$s.Name)
            $Shortcut.Save()
        }
    }
}
Damit Dateien und Ordner, welche nicht(mehr) benötigt werden, entfernt werden, kann das Skript den jeweiligen Ordner Inhalt auslesen. Falls die Dateien keine Entsprechungen im LDAP finden können Sie gelöscht werden. Das Skript wird dadurch um einiges länger, der "klassen" Ordner ist dadurch aber immer aktuell und ein Abbild der LDAP Struktur, gelöschte Klassen oder Schüler-Links werden entfernt usw.
$speicherpfad="\\server\Home-Verzeichnisse Schueler\__klassen\"
Write-Host "Zielordner ist " $speicherpfad
$start = (Get-Date)
[ADSI]$domain = "LDAP://CN=klassen, CN=schueler,CN=groups,OU=schule, DC=paedml-linux,DC=lokal"
$klassen = $domain.Children.distinguishedName | ForEach-Object {[ADSI]"LDAP://$_"}
#Alle Dateien und Ordner im Speicherpfad bekommen das Attribut Entfernen=$true. Wenn der Ordner existieren muss wird es später wieder auf $false gesetzt.
$alteOrdner = Get-ChildItem -Path ($speicherpfad)
$alteOrdner | Add-Member -NotePropertyName Entfernen -NotePropertyValue $true
$maxi = $alteOrdner|measure
New-Item -force -ItemType directory -Path ($speicherpfad) | Out-Null
$zaehler=0
foreach($k in $klassen){
 
    #Fortschrittsanzeige, falls unerwünscht, mit # auskommentieren.
    $zaehler=$zaehler+1
    write-host ([math]::round(($zaehler/($klassen.Count)*100),0))"%"
 
    #Für jeden existierenden Ordner wird geprüft, ob es eine Klasse mit dem gleichen Namen gibt. Falls nicht bleibt das Attribut Entfernen auf $true.
    for ($i=0;$i -lt $maxi.Count; $i++){
        if($k.Name.Replace("schule-", "") -like $alteOrdner[$i] ){ 
            $alteOrdner[$i].Entfernen = $false 
        }
    }
    New-Item -force -ItemType directory -Path ($speicherpfad + $k.Name.Replace("schule-", "")) | Out-Null
 
    # $zwischenspeicher enthält alle Dateien des jeweiligen Klassenordners
    $zwischenspeicher = Get-ChildItem -Path ($speicherpfad + $k.Name.Replace("schule-", ""))
    # Für jede Datei wird das Attribut Entfernen auf $true gesetzt
    $zwischenspeicher  | Add-Member -NotePropertyName Entfernen -NotePropertyValue $true
 
    $schueler = $k.Member | ForEach-Object {[ADSI]"LDAP://$_"}
    foreach($s in $schueler){
        if($s.memberOf[0].Contains("schueler")){
            $WshShell = New-Object -comObject WScript.Shell
            $Shortcut = $WshShell.CreateShortcut($speicherpfad+$k.Name.Replace("schule-", "")+"\"+$s.displayName+".lnk")
            $Shortcut.TargetPath = ("\\server\Home-Verzeichnisse Schueler\"+$s.Name)
            $Shortcut.Save()
        }
        $max = $zwischenspeicher |measure
        #Falls die Datei durch LDAP bestätigt wurde wird Entfernen = $false
        for ($i=0;$i -lt $max.Count; $i++) {
                if($zwischenspeicher[$i].baseName -like $s.displayName){
                    $zwischenspeicher[$i].Entfernen = $false;
                }
        }
    }
    #Dateien mit Entfernen = $true löschen.
    #Links zu Schülerordnern, welche nichtmehr in der LDAP Gruppe der Klasse vorhanden sind.
    foreach($z in $zwischenspeicher){
        if($z.Entfernen){
            Remove-Item -Path ($z.FullName) -Recurse -force
        }
    }
}
#Ordner mit Entfernen=$true löschen.
foreach($o in $alteOrdner){
    if($o.Entfernen){
             Remove-Item -Path $o.FullName -Recurse -force
    }
}
#Leere Ordner löschen
Get-ChildItem -Path $speicherpfad -Recurse -Force | Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } | Remove-Item -Force -Recurse
$Ende = (Get-Date)
write-host "Das Sript lief für" ([math]::round(($ende - $start).TotalSeconds,0))"Sekunden"

(Erinnerung aus dem Shutdown-Aktikel) Skript Zeit-gesteuert ausführen

Zum zeit-gesteuerten Ausführen öffnen Sie die AdminVM, drücken Sie die Windows-taste und geben Sie "Aufgabenplanung" ein.
Klicken Sie auf "Aufgabe erstellen..." und geben Sie der Aufgabe einen Namen, z.B. "Schulcomputer herunterfahren".
Wählen Sie den Reiter "Trigger" und klicken Sie auf "Neu" und legen Sie hier Ihren Zeiplan an.
Stellen Sie eine Startzeit ein, z.B. 8:00:00 und Täglich. Klicken Sie auf "Wiederholen jede: " und stellen Sie 30 Minuten für die Dauer von 12 Stunden ein.Klicken Sie nun auf OK.
Im Reiter "Aktionen" klicken Sie auf "Neu". Die Aktion "Programm starten" ist voreingestellt. Bei Programm Tragen Sie "Powershell.exe" ein. Bei Parametern Tragen Sie
-ExecutionPolicy Bypass h:\PFAD\meinSkript.ps
ein. Mit einem Klick auf OK sollte das Skript nun täglich alle 30 Minuten ausgeführt werden.
Quelle

Montag, 16. April 2018

Opsi Statusfenster ausschalten.

Standardmäßig erscheint nach jeder Benutzeranmeldung ein kleines Opsi Fenster. In manchen Fällen schließt sich dieses erst relativ spät. Außerdem hat dieses Fenster unangenehme Eigenschaften, z.B. wenn man die Bildschirmauflösung ändert.
Hier möchte ich beschreiben, wie man das Fenster ausblenden kann.

Standardtwert setzen

Als erstes muss der Standartwert für das Ausblenden gesetzt werden.
Nach den öffnen von "Opsi-Configed Local" klicken Sie auf Server-Konfiguration.


Klicken Sie dann auf "Host-Parameter" --> "opsiclientd". Dort klicken Sie auf den Schlüssel "opsiclientd.event.user_login.active" und setzen den Wert auf "false". Bestätigen Sie dies mit einem Klick auf das rote Häkchen. Nun ist der Wert für alle neuen Clients gesetzt und wirksam.
Klicken Sie auf den linken Knopf neben der Server-Konfiguration um zur normalen Übersicht (der Client-Konfiguration) zurück zu kommen.

Werte für vorhandene Clients setzen


Wenn Sie bereits Clients ausgerollt haben müssen Sie den Wert für diese nochmals von Hand setzen.
Markieren Sie die Clients. Auf der rechten Seite finden Sie neben den Reitern "Produktkonfiguration" und "Netboot-Produkte" auch den Reiter "Host-Parameter". Klicken Sie auf "Host-Parameter" --> "opsiclientd". Dort klicken Sie auf den Schlüssel "opsiclientd.event.user_login.active" und setzen den Wert auf "false". Bestätigen Sie dies mit einem Klick auf das rote Häkchen.
Nun muss der Opsi-Client neu aufgespiet werden. Klicken Sie auf Produktkonfiguration und setzen Sie "opsi-client-agent" auf "setup".
Nach einem Neustart und der darauf folgenden neuionstallation des Opsi Agenten ist die Änderung nun wirksam.

Mittwoch, 11. April 2018

Tipparbeit sparen: Admin Anmeldung

Einer der ersten Tricks, welche mir von unserem Dienstleister (Danke Michael!!) verraten wurden habe ich so verinnerlicht, dass ich über deren Besonderheit gar nicht mehr nachdachte.

tl;dr


Login Domänenadmin
p\administrator
Login lokaler Admin
.\administrator

Erklärung


Bei der Anmeldung als Domänen Administrator muss man Windows sagen, an welcher Domäne man sich anmeldet (da es auch einen lokalen Admin gibt).

Der Benutzername ist dann:
paedml-linux\administrator
Samba juckt das aber nicht, es akzeptiert fast jede Zeichenfolge als Domänen-Admin, z.B.
p\administrator
Natürlich geht auch
ichwillnachhause\administrator
paedml-murmelbahn\administrator :) 

Umgekehrt möchte man sich manchmal auch als lokaler Administrator anmelden. Dazu muss man als Domäne die Bezeichnung des PCs eingeben.
computer16\administrator
Da der Computername zum Zeitpunkt der Anmeldung nicht angezeigt wird, kann das etwas anstrengend sein. Aber dafür hat Windows eine eigene Abkürzung eingebaut, die Unabhängig von der paedML an jedem Windows-Domänen PC funktioniert.
.\administrator
meldet sich am lokalen Gerät an, der Name dieses Gerätes wird dann freundlicherweise sogar eingeblendet

Dienstag, 27. März 2018

PCs Herunterfahren

In meiner Schule gibt es nicht nur Computerräume, in jedem Klassenzimmer stehen PCs, welche immer benutzbar sein müssen. Aber wie werden diese ausgeschaltet?

Um dieses Problem zu lösen habe ich ein Powershell-Skript geschrieben, welche die PCs herunterfahren kann. Das Skript wird auf der AdminVM alle 30 Minuten ausgeführt und fährt PCs herunter, falls dies erforderlich ist.

Da mein Skript nicht ohne weiteres auf alle Schulen übertragbar ist möchte ich hier eine Anleitung zum eigenen Zusammenbau geben.Speichern Sie das Skript z.B. auf dem Homelaufwerk des Administrators in einem Order "Skripte" unter einem Namen Ihrer Wahl ab, z.B. "herunterfahren.ps1".

1. Welche Rechner sollen heruntergefahren werden?

Sie können per Powershell Rechner aus Raumgruppen auslesen.
Um allen Rechnern einer Raumgruppe 'schule-Klassenzimmer' einen Shutdown-Befehl zu schicken müssen Sie die Rechner auslesen. Dies funktioniert mit folgendem Befehl:
$groupname = 'schule-Klassenzimmer'
$a = (New-Object System.DirectoryServices.DirectoryEntry((New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=Group)(name=$($groupname)))")).FindOne().GetDirectoryEntry().Path)).member | % { (New-Object System.DirectoryServices.DirectoryEntry("LDAP://"+$_)) } | Sort-Object sAMAccountName | SELECT @{name="User Name";expression={$_.Name}},@{name="User sAMAccountName";expression={$_.sAMAccountName}}

Jedem dieser PCs schicken Sie nun den Stop-Computer Befehl.

foreach($as in $a){     
Stop-Computer -ComputerName $as.'User Name' -force -ErrorAction SilentlyContinue
}
Wenn Sie dieses Skript zur gewünschten Zeit ausführen, werden die PCs des Raumes heruntergefahren.

2. Bedingungen zum Herunterfahren

Sie können das Skript auch alle 30 minuten ausführen lassen. Dann ist es sinnvoll, wenn geprüft wird, ob die Comuter heruntergefahren werden sollen oder nicht. Dafür können Sie eine Variable setzen und abfragen.
$herunterfahren=$false...
...
...
if($herunterfahren){     
$groupname = 'schule-Klassenzimmer'     
$a = (New-Object System.DirectoryServices.DirectoryEntry((New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=Group)(name=$($groupname)))")).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($as in $a){           
Stop-Computer -ComputerName $as.'User Name' -force -ErrorAction SilentlyContinue       
}}
Nun müssen Sie noch prüfen, ob das Herunterfahren gesetzt werden muss. Dafür können Sie die Abschaltzeit in eine Variable ablegen.
$abschaltZeit = 17
Nun können Sie Prüfen ob die PCs heruntergefahren werden sollen, wenn z.B. die Aktuelle Stunde größer gleich der abschaltZeit ist.
if($heute.Hour -ge $abschaltZeit){   
$herunterfahren=$true
}
In meiner Schule starten die PCs per Bios Einschaltzeit. D.h. die PCs fahren jeden Werktag um 7.40 hoch. In den Ferien ist dies jedoch ein Problem, die PCs sollen möglichst direkt wieder ausgeschaltet werden. Dazu können Sie Prüfen, ob gerade Schulferien vorliegen. Dazu können Sie den aktuellen Ferienkalender von Schulferien.org ICAL herunterladen.
Laden Sie den Inhalt der Datei in Powershell
$ferien = Get-Content -Path "H:\PFAD\ferien_baden-wuerttemberg_2018.ics"
Nun müssen Sie die Prüfen ob das heutige Datum zwischen einem Ferienbeginn und einem Ferienende liegt.
$heute = get-date
foreach($zeile in $ferien){   
if($zeile.toString().Contains("DTSTART")){         
$anfang =[datetime]::ParseExact($zeile.toString().Substring($zeile.Length-8),'yyyyMMdd',$null)   
}   
if($zeile.toString().Contains("DTEND")){       
$ende =[datetime]::ParseExact($zeile.toString().Substring($zeile.Length-8),'yyyyMMdd',$null)    
if (($heute -ge $anfang) -and ($heute -le $ende)){                 
$herunterfahren = $true    
}}}
Für meine Schule frage ich bei den Ferien noch ab, ob es vor 9Uhr morgens ist. Nur dann setze ich das Herunterfahren aufgrund von Ferien. So stellen Sie sicher, dass von Hand eingeschaltete PCs ab 9Uhr nicht alle 30 Minuten abgeschaltet werden.
 if (($heute -ge $anfang) -and ($heute -le $ende) -and ($heute.Hour -le 9)){
Wenn Sie diesen Teil über der Prüfung if($herunterfahren){ einfügen werden die Computer nur heruntergefahren, wenn Ferien sind oder die Abschaltzeit erreicht wurde.

3. Skript Zeit-gesteuert ausführen. 

Zum zeit-gesteuerten Ausführen öffnen Sie die AdminVM, drücken Sie die Windows-taste und geben Sie "Aufgabenplanung" ein.
Klicken Sie auf "Aufgabe erstellen..." und geben Sie der Aufgabe einen Namen, z.B. "Schulcomputer herunterfahren".
Wählen Sie den Reiter "Trigger" und klicken Sie auf "Neu" und legen Sie hier Ihren Zeiplan an.
Stellen Sie eine Startzeit ein, z.B. 8:00:00 und Täglich. Klicken Sie auf "Wiederholen jede: " und stellen Sie 30 Minuten für die Dauer von 12 Stunden ein.Klicken Sie nun auf OK.
Im Reiter "Aktionen" klicken Sie auf "Neu". Die Aktion "Programm starten" ist voreingestellt. Bei Programm Tragen Sie "Powershell.exe" ein. Bei Parametern Tragen Sie
-ExecutionPolicy Bypass h:\PFAD\meinSkript.ps
ein. Mit einem Klick auf OK sollte das Skript nun täglich alle 30 Minuten ausgeführt werden.
Quelle

4. Erweiterungen

Wenn Sie beim Erstellen des Skripts eine Rückgabe in die Konsole wünschen können Sie
Write-Host "Ein Text" 
Write-Host $eineVariable 
Write-Host "Oder auch " $beides 
ausgeben lassen.

Powershell ist ein sehr mächtiges Werkzeug zur Administration von Computern. Ich habe versucht bei der Beschreibung nur das nötigste einzubauen. In meinem eigenen Skript führe ich noch Logdateien, kann die Namen der Ferien auslesen, Rechner aus mehreren Raumgruppen ansteuern uvm. Diese Erweiterungen führen an dieser Stelle allerdings etwas zu weit. Bei Rückfragen oder Anmerkungen senden Sie mir gerne Feedback.Mein vorläufiges Skript finden Sie unter Punkt 6.

5. Ausblick: Herunterfahren abhängig vom WebUntis Stundenplan. 

Mein letztes Projekt war es, zu Prüfen ob das Klassenzimmer in der WebUntis-Sundenplan-Software belegt ist. Sobald das Zimmer an einem Tag nicht mehr gebucht ist werden die PCs heruntergefahren. Das Problem hierbei ist vor allem, dass die Namen der Computer in den Klassenzimmern nicht zwingend mit den in WebUntis hinterlegten Raumnamen übereinstimmt. Die Umsetzung können Sie im Skript unten sehen, das genaue Vorgehen werde ich in einem extra Blog-Eintrag dokumentieren.

6. Mein Skript (ohne Gewähr, Stand März 2018)

Powershell

$d = Get-Content -Path "H:\Skripte\ferien_baden-wuerttemberg_2018.ics"
$abschaltZeit = 17
$raumGruppen =  'schule-Jahnstr', 'schule-KlassenzimmerBerlin'
$raumGruppenUntis = 'schule-Jahnstr'

$success = $false
$ferien=$false
$spaet = $false
$heute = get-date

                $log = "Das Skript wurde um " +$heute+" ausgeführt."
                Out-File -FilePath 'H:\Skripte\logXtreme.txt' -Append -InputObject $log



#### Ließt die Ferien in der Datei $d aus. Falls das heuteige Datum in den Ferien liegt wird $success zu $true #### 

if($heute.Hour -le 9){
### Vor 9 Uhr wird geprüft, ob ein Ferientag vorliegt und heruntergefahren, ab 9Uhr nichtmehr. ###
foreach($ds in $d){
    
    if($ds.toString().Contains("SUMMARY")){
        $testFerien =$ds.toString().TrimStart("SUMMARY:")
    }
    
    if($ds.toString().Contains("DTSTART")){
        $anfang =[datetime]::ParseExact($ds.toString().Substring($ds.Length-8),'yyyyMMdd',$null)

    }
    if($ds.toString().Contains("DTEND")){
        $ende =[datetime]::ParseExact($ds.toString().Substring($ds.Length-8),'yyyyMMdd',$null)

    if (($heute -ge $anfang) -and ($heute -le $ende))
    {
            $success = $true
            $ferien=$testFerien
    }

    }
}
}

#### Prüft, ob die Uhrzeit später als die Abschaltzeit ist, falls ja, wird $spaet ztu $true ####

if($heute.Hour -ge $abschaltZeit){
    $spaet=$true
}
else{
    $spaet=$false
}

#### Falls $success oder $spaet gesetzt ist, werden die PCs angesprochen und gegebenenfalls Heruntergefahren ####

if($success -Or $spaet){
    if($success){
           $log = "Es sind " +$ferien+" Computer fahren herunter"
           Out-File -FilePath 'H:\Skripte\logXtreme.txt' -Append -InputObject $log


    }
    if($spaet){
           $log = "Alle Computer werden um " + $heute + " heruntergefahren"
           Out-File -FilePath 'H:\Skripte\logXtreme.txt' -Append -InputObject $log
    }

    foreach($groupname in $raumGruppen){
        $a = (New-Object System.DirectoryServices.DirectoryEntry((New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=Group)(name=$($groupname)))")).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($as in $a)
        {
            Stop-Computer -ComputerName $as.'User Name' -force -ErrorAction SilentlyContinue
        }
    }
}


### Prüft für jeden PC in der RaumGruppe $raumGruppenUntis, ob er einen Eintrag im Stundenplan hat. Für gefundene PCs wird geprüft, ob der Unterricht gerade vorbei ist und dann gegebenenfalls heruntergefahren ###

foreach($groupname in $raumGruppenUntis){
    $a = (New-Object System.DirectoryServices.DirectoryEntry((New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=Group)(name=$($groupname)))")).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($as in $a)
    {
### Das Skript Pythonskript raumabfrage.py wird mit einem Raum als Parameter aufgerufen und leifert den Stundenplan dieses Raumes für den heutigen Tag zurück ###
        $untisAusgabe = python 'H:\Skripte\raumabfrage.py' $as.'User Name'
        if($untisAusgabe.Contains('datetime')){
            write-host "PC " $as.'User Name' " in Untis Gefunden"
            $stelleZeit = $untisAusgabe.LastIndexOf('datetime.time')+14
            $stelleDatum = $untisAusgabe.LastIndexOf('datetime.date')+14
            $a = $untisAusgabe.Substring($stelleDatum, $untisAusgabe.Substring($stelleDatum).IndexOf(')'))+", "+$untisAusgabe.Substring($stelleZeit, $untisAusgabe.Substring($stelleZeit).IndexOf(')'))
            $b = $a.Split(",")
            $a=$null
            foreach($bs in $b){
                $bs = $bs.Trim()
                $bs = [int]$bs
                $bs = $bs.ToString("00")
                $a+=$bs
            }
            $endZeit=[datetime]::ParseExact($a,'yyyyMMddHHmm',$null).AddMinutes(45)
            Write-Host "Letzte Stunde " $endZeit
            $heute = Get-Date
            Write-Host "Aktuelle Zeit " $heute
            if(($endZeit.AddMinutes(10) -lt $heute)-and($endZeit.AddMinutes(40) -gt $heute))
            {

                Stop-Computer -ComputerName $as.'User Name' -force -ErrorAction SilentlyContinue
                Write-Host "Der Computer " $as.'User Name' " wird heruntergefahren"
                $log = 'PC '+ $as.'User Name' + ' wurde um ' + $heute + ' heruntergefahren, letzte Stunde endete ' + $endZeit
                Out-File -FilePath 'H:\Skripte\logXtreme.txt' -Append -InputObject $log
            }
            


        }
    }
}

Python 

(Skript erwartet Bezeichnung des Raumes als Parameter)

import webuntis
import datetime
import sys
s = webuntis.Session(
    server='https://zensiert.webuntis.com',
    username='benutzer',
    password='passwort',
    school='schulname',
    useragent='Kontaktdaten des Administrators'
)
s.login()
today = datetime.date.today()
room = s.rooms().filter(name=sys.argv[1])[0]
table = s.timetable(room=room, start=today, end=today).to_table()
print (table)

s.logout()


Nachtrag: 
Bei weiteren Recherchen habe ich zwei weitere nützliche Skripte entdeckt:

  1. WebUntis direkt über Powershell
  2. Sitzungsanzeige über die Powershell 

Beide Quellen werde ich versuchen in meine Anleitung zum Herunterfahren in Zukunft einzuarbeiten. 



Montag, 12. März 2018

Gruppenrichtlinien Tipps und Tricks

Hier eine Sammlung von nützlichen GPO Einstellungen, Tipps und Tricks. 


Automatisch Webseite/Programme nach Benutzer-Anmelung starten

Da wir an unserer Schule mit Untis arbeiten, sollen Benutzer, welche sich in Klassenzimmern anmelden, automatisch die Webseite gestartet bekommen.
Dazu muss eine Gruppenrichtlinie erstellt werden, in der Reichenfolge weit genug nach oben geschoben.
In Computerkonfiguration --> Richtlinien --> Administrative Vorlagen --> System --> Anmelden --> "Diese Programme bei der Benutzeranmeldung ausführen" auf aktiviert stellen und bei den auszuführenden Elemente
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://www.google.de
eingeben. Bei der Sicherheitsfilterung kann Authentifizierte Benutzer entfernt werden und eine Computergruppe hinzugefügt werden, z.B. schule-klassenzimmer

Automatisch DisplaySwitch.exe /clone

Um einem Rechner beim Anmelden automatisch zum Clonen der Bildschrime zu bringen kann man auch DisplaySwitch.exe /clone entsprechend per GPO ausführen lassen. 
In Computerkonfiguration --> Richtlinien --> Administrative Vorlagen --> System --> Anmelden --> "Diese Programme bei der Benutzeranmeldung ausführen" auf aktiviert stellen und bei den auszuführenden Elemente "C:\Windows\System32\DisplaySwitch.exe /clone" eintragen. Bei der Sicherheitsfilterung sollten nur PCs oder PC Gruppen eingetragen werden, bei denen das Klonen ausgeführt werden soll. 
Dadurch können sich Kolleginnen und Kollegen den Bildschirm nach belieben auf Erweitert, Clone usw. einstellen ohne dass diese Einstellung für folgende Unterrichtsstunden Auswirkungen hat, da sie immer wieder auf den Standard zurückgesetzt wird. 

Windows 10 Schneller Benutzerwechsel (auch aus dem Sperrbildschrim) wieder einschalten:

Nach einigen Minuten sperrt Windows 10 Benutzer, welche inaktiv sind. Dies verhindert z.B. unbefugten Zugriff auf Home-Laufwerke. Da beim Raumwechsel von Klassen sich immer wieder ein neuer Benutzer anmelden können muss, muss dies auch über den Sperrbildschrim erreichbar sein.

Um diese Option zu aktivieren erstellen Sie eine neue Gruppenrichtlinie (GPO) und verknüpfen Sie diese mit der Organisationseinheit (OU) schule.
Unter Computerkonfiguration --> Richtlinien --> Administrative Vorlagen --> System --> Anmelden --> "Einstiegspunkte für die schnelle Benutzerumschalteung ausblenden" muss auf Nein gesetzt werden. Achten Sie dabei darauf, dass die Richtlinie in der Hirarchie weit oben steht, da ansonsten die Standardrichtlinien den Wert wieder überschreiben.

Systemsteuerungselemente wieder einblenden

Die Systemsteuerung in Windows 10 ist aufgrund der Gruppenrichtlinien im Auslieferungszustand komplett gesperrt. Wenn Benutzer aber z.B. Bluetoothgeräte koppeln wollen oder die Anzeigeeinstellungen anpassen möchten muss dies angepasst werden.
Dazu muss (wie immer) eine Gruppenrichtlinie angelegt werden, welche in der Reihenfolge weit genug oben ist.
In Computerkonfiguration --> Richtlinien --> Administrative Vorlagen --> Systemsteuerung 
Dort muss "Zugriff auf Systemsteuerung und PC-Einstellungen nicht zulassen" auf  "Deaktiviert"
und "Nur angegebene Systemsteuerungssymbole anzeigen" auf Aktiviert gestellt werden. Bei den Systemsteuerungssymbolen kann man nun die Elemente Einblenden, z.B. "Display"
Die Namen aller Einstellungen finden sich hier.

Montag, 29. Januar 2018

Druckerguide: Zusammenfassung

Druckereinstellungen to rule them all:

Originaltreiber per Handbuch einarbeiten. Falls es funktioniert: perfekt, ansonsten:


Zielsetzung: 

CUPS einen Treiber zuweisen, welcher Farbe/Features unterstützt und "halbwegs" kompatibel ist. Windows einen Treiber hochladen, welcher die benötigten Features beherrscht.
In den folgenden Beispielen werden NUR mitgelieferte CUPS Treiber verwendet.

Beispiele: 

XEROX WorkCenter 7830: 


  • CUPS: XEROX WorkCenter 133 
  • Printermanagement.msc: MS Publisher Color oder WorkCenter 133 für duplex (download XEROX )

Kyocera Farbdrucker: (z.B. P6026cdn, FS-C5200dn) 

  • CUPS: HP Color LaserJet 2500 Foomatic/pxlcolor
  • Printermanagement.msc: MS Publisher Color oder "Generic PostScript Color" (Download KYOCERA.) 

Kyocera SW-Drucker

  • CUPS: misc; none
  • Printermanagement.msc: MS Publisher Color oder die veränderten Treiber "Kyocera Classic Universaldriver PCL6 (A4)" für Duplex (hier geht´s zur Anleitung )


VORSICHT: Sackgassen und Fehlversuche, meine Erfahrungen:

Vielversprechende Wege welche trotzdem in einer Sackgasse endeten:
Einen Treiber per Installationsprogramm des Herstellers zu installieren und ihn anschließend im Printmanagement über "Treiber hinzufügen" über die Herstellerliste zu installieren führte bei unseren Druckern NUR zu FEHLERn.
Die PPD Dateien (z.B. des Xerox 7830 ) werden ebenfalls nicht von printermanagement akzeptiert.

Farbdrucker und CUPS

Falls es für einen Drucker einen offiziellen Treiber gibt der in der Druckverwaltung eingebunden werden kann ist alles wunderbar. Aber was, wenn nicht?

Das Common Unix Printing System, CUPS wird über die Schulkonsole mit den Druckerinformationen versorgt. Um bei einem Farbdrucker farbig drucken zu können habe ich in meiner Schule für die Xerox Workcenter 7820 den CUPS Treiber "Xerox WorkCentre Pro 133 Foomatic/Postscript" eingestellt. Zusammen mit dem Treiber Generic PostScript Color drucken diese dann auch farbig.

Je nach dem, über welches Protokoll der Windows Treiber den Drucker ansteuert funkt CUPS dazwischen und ändert z.B. einen Farbdruck auf monochrom.

Daher haben unsere Farbdrucker die Treiber Xerox WorkCentre Pro 133 Foomatic/Postscript (für XEROX WorkCenter 7830) oder HP Color LaserJet 2500 Foomatic/pxlcolor (für unsere Kyocera Farbdrucker). Diese funktionieren nun mit einem Standard Farbdruckertreiber wie dem mitgelieferten "MS Publisher Color" oder dem "Generic PostScript Color" aus dem vorigen Blogeintrag.