Mittwoch, 9. September 2020

ssh mit public key

ich habe dazu schon mehrfach was geschrieben - aber man lernt ja immer wieder dazu. Deshalb noch ein ziemlich komprimierter Artikel: Ein HowTo für die Automatisierung von Remote Aufgaben in FHEM über ssh. 

Ich habe den Artikel primär so geschrieben, dass der ssh Zugang für einen anderen als den aktuellen user eingerichtet wird. Für den aktuell angemeldeten Benutzer ist die Beschreibung aber fast gleich, nur einfacher. Zunächst die Voraussetzungen in der FHEM Kommandozeile testen/schaffen. (Im Terminal einfach {qx()} weglassen).

FHEM läuft unter dem Benutzer fhem?

{qx(whoami)}

Dieser Benutzer hat schon einen RSA Public Key?

{qx(ls -lha .ssh/id_rsa.pub)}

Falls noch kein RSA Key existiert (oder ein Neuer gebraucht wird) wird so ein Key ohne Passphrase erzeugt:

{qx(ssh-keygen -f ~/.ssh/id_rsa -P "" -t rsa)}

Einrichtung

Der folgende Code wird im Terminalfenster auf einem Linux System ausgeführt und zeigt die Einrichtung für verschiedene Zielsysteme. Bitte nur den zutreffenden Code ausführen! Während der Einrichtung wird das Passwort des Benutzers auf dem Zielsystem u.U. mehrfach abgefragt.

sudo -su fhem               # entfällt für den aktuellen Benutzer
ziel=user@host              # Benutzer und Host einmal eintragen
#### Linux System
ssh-copy-id -i ~/.ssh/id_rsa $ziel
#### Windows System
scp ~/.ssh/id_rsa.pub $ziel:key.tmp
ssh $ziel "mkdir .ssh&type key.tmp >>.ssh\\authorized_keys&del key.tmp"
#### openwrt / dropbear
cat ~/.ssh/id_rsa.pub | ssh $ziel "p='/etc/dropbear';akey=\$p'/authorized_keys'; pub=\$(cat ); umask 077; test -d \$p || mkdir \$p; test -f \$akey || echo \$pub >\$akey; grep -q \"\$(echo \$pub)\" \$akey || echo \$pub >>\$akey"
# Erfolgstest 
ssh $ziel                   # Test für den passwortfreien Zugang - Remote session!
exit                        # aus der ssh Test session vom Remotehost!
exit                        # aus der Anmeldung vom user fhem!  

Was passiert im Detail?

Wichtig ist, dass der RSA Key ohne Passphrase erzeugt wurde! Sonst wird bei der Verwendung des Schlüssel wieder ein Passwort abgefragt und die Ausführung von Befehlen per ssh funktioniert nicht automatisch! Die Einrichtung geschieht für den einzelnen Benutzer, nicht für das gesamte System!

Bei der Einrichtung wird

  • der remote Host Schlüssel als vertraut in die lokale Schlüsseldatei (known_hosts) hinterlegt, und
  • der Schlüssel des lokalen Benutzers in der Schlüsseldatei (authorized_keys) des remote Benutzers als vertraut hinterlegt. 

Durch Verwendung der Schlüssel kann nun die Autorisierung ohne weitere interaktive Abfrage erfolgen. Der lokale Benutzer kann sich als remote Benutzer am remote System anmelden.

Verwendung von sudo im Script

Schon zum shutdown des systems braucht man erhöhte Rechte. Diese werden z.B. über sudo erreicht, aber auch da muss man wieder verhindern, dass nach dem Passwort gefragt wird! Die Systeme sind da unterschiedlich voreingestellt. Bei manchen wird immer mal nach dem Passwort gefragt, bei manchen nie. Verantwortlich ist der Inhalt der (zutreffenden) Datei - /etc/sudoers bzw. /etc/sudoers.d/010_pi-nopasswd. 

Beispiele (debian, Raspberry OS)

# User privilege specification
root    ALL=(ALL:ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

Ist der User Mitglied in der Gruppe sudo, dann wird er bei der ersten Verwendung nochmal nach dem Passwort gefragt, auch wenn er sich gerade neu angemeldet hat.   

pi ALL=(ALL) NOPASSWD: ALL

Der Benutzer pi muss niemals sein Passwort extra bei der Verwendung von sudo eingeben.

Empfehlung

Extra Benutzer anlegen und über eine Datei nach dem Vorbild /etc/sudoers.d/010_pi-nopasswd die Abfrage des Passwortes verhindern. Diese Dateien immer mit dem Editor visudo bearbeiten! 

Sicherheit

Die Anmeldung an einem System mit ssh und einem rsa Schlüssel ist so sicher wie der Account der den Schlüssel lesen und verwenden kann. Der Schlüssel ist so abgelegt, das er exklusiv nur von dem jeweiligen Benutzer gelesen/verwendet werden kann.

Durch die hier beschriebene Einrichtung, hat der Benutzer Zugriff auf ein zweites System. Hat der Benutzer im zweiten System sudo Rechte, hat fhem sudo Rechte an diesem System.

Wird fhem kompromittiert wird damit ein zweiter Benutzer  und ein zweites System kompromittiert.


Mittwoch, 26. August 2020

Crash Recovery

Das System verhält sich komisch? Raspbian bleibt beim Start hängen?

Die SD Card als Datenträger beim Raspberry soll ja häufig den Geist aufgeben. Ich hatte das noch nie, ich behaupte immer das passiert bevorzugt wenn Datenbanken im Spiel sind - aber jetzt hatte es einen Kumpel aus heiterem Himmel getroffen. Ohne Datenbank, ohne aktuellem Backup. Ich konnte ihm helfen und daraus ist dieser Artikel geworden.

Was tun?

Zutaten

  • Neue SD Card für das neue System, Größe "egal"
  • USB Stick oder zweite SD Card + Reader mit dem Speicherplatz mindestens der alten SD Card.
  • Image Tool  (win32diskimager, USB Image Tool, Etcher oder mit Linux Bordmitteln dd.)

In jedem Fall eine Kopie der SD Card anfertigen: Imagedatei ablegen.

Die Originalkarte sollte nicht weiter manipuliert werden und meist ist eine Reparatur der defekten Karte weder sinnvoll noch möglich!

Den Raspberry neu machen

  • neue SD Card, 
  • aktuelles Raspbian Image aufspielen, 
  • starten, 
  • FHEM Setup.

systemctl stop fhem

Dateisystem prüfen und Zugriff herstellen

Die 1:1 Kopie auf dem USB Stick (oder SD Card in SD Reader) in den Raspberry stecken. 

Achtung: Das geht bei einem Pi ab Version 2 nach meiner Erfahrung gut. Ein 1er Exemplar würde ich zum Stecken herunterfahren, er wird beim einstecken von selbst neu starten. 

Oder die Imagedatei direkt mounten, siehe weiter unten.

Danach sollte sich folgendes Bild ergeben:

pi@raspib31:~ $ lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda           8:0    1 29,8G  0 disk
├─sda1        8:1    1 41,7M  0 part
└─sda2        8:2    1   15G  0 part
mmcblk0     179:0    0 14,9G  0 disk
├─mmcblk0p1 179:1    0  256M  0 part /boot
└─mmcblk0p2 179:2    0 14,7G  0 part /
Der USB "Stick" wird als sda erkannt, die interessante Partition ist sda2. Für die jetzt folgende Reparatur darf sda2 nicht gemountet sein/werden! 
Ein erster Check ohne Optionen erledigt offenbar schon mal alles, mir ist nicht klar in welchem Fall welche zusätzlichen Optionen (oft empfohlen -l, Hilfe mit -h) notwendig sind.
Alle weiteren Befehle erfordern erhöhte Rechte, deswegen erstmal sudo su. 
Die Ausgabe ist nur ein Beispiel und kann je nach Fehler völlig anders sein!
sudo su
fsck /dev/sda2
# fsck from util-linux 2.33.1
# e2fsck 1.44.5 (15-Dec-2018)
# /dev/sda2: recovering journal
# Setting free inodes count to 899857 (was 899863)
# Setting free blocks count to 3338902 (was 3339342)
# /dev/sda2: clean, 46703/946560 files, 577130/3916032 blocks

SD Card mounten 

Jetzt die interessante Partition mounten und hoffen dass etwas lesbar ist.
mkdir /mnt/sda2
mount /dev/sda2 /mnt/sda2

Alte Dateien kopieren

Alle Dateien von dem alten System werden kopiert und die rechte entsprechend gesetzt, zuletzt wird das USB Gerät ausgeworfen. In der Hoffnung, dass nichts wichtiges kaputt ist! Idee: Man könnte die Backup Dateien ausschließen  oder rsync verwenden.
cp -R /mnt/sda2/opt/fhem/* /opt/fhem/
chown -R fhem: /opt/fhem/
umount /mnt/sda2

System prüfen

systemctl start fhem

Das kann eine Weile dauern, z.B. wenn Moduldateien fehlerhaft sind. Der Ungeduldige kann derweil ins Log schauen.

tail /opt/fhem/log/fhem-$(date +%Y)-$(date +%m).log

Wenn das System Fehler zu defekten Modulen liefert, nach dem Start in FHEM erstmal ein update versuchen.

update force

Neu starten und System wieder prüfen

systemctl restart fhem

Wenn es doch nicht läuft

  • Es fehlen System Pakete? Da hatte ich hier schon mal was geschrieben.
  • Wenigsten mit der fhem.cfg neu anfangen, notfalls eine Alte aus dem restoreDir pfad. Siehe Wikiartikel.
  • Ist eine Backupdatei in /opt/fhem/backup vorhanden? Einfach das letzte Backup versuchen, siehe hier.

Alternative - Image Datei direkt mounten

Die kopierte Image Datei wird direkt als Block Laufwerk eingebunden. Ich habe dazu hier eine gute Erklärung gefunden. Das sieht alles etwas komplizierter aus, aber eigentlich spart man die Zeit für die Kopie auf den USB Stick und man muss nichts stecken.

Zunächst den Pfad zum Image z.B. über cifs (SMB) einbinden:
sudo su
# SMB Laufwerk mounten
mp="/mnt/daten"
mkdir $mp
mount -t cifs -o username=UserName,password=Passwort //server/sicherung $mp
# Loop Device erstellen
img="$mp/fhem/raspib3/kopieSdDefekt.img"
ldev=$(losetup --show -f -P "$img")
An der Stelle hat man quasi "den USB Stick gesteckt" d.h. man hat einen /dev/ Eintrag den man wie ein angeschlossenes Laufwerk behandeln kann. Dies(e) Gerät(e) anzeigen:
losetup -l
Jetzt kann man wie oben beschrieben fsck ausführen. dafür kann man einfach die Variable $ldev verwenden:
fsck ${ldev}p2
Ist der Vorgang erfolgreich kann man die Partitionen mounten:
#Alle Partitionen mounten
for part in ${ldev}p*
do 
  dst=/mnt/$(basename $part)
  echo "mkdir $dst"
  echo "mount $part $dst"
done
Nachdem man analog zu oben die Dateien kopiert hat, kann man alles wieder aufräumen:
umount /mnt/loop0*
rm -R /mnt/loop0*
losetup -D
umount $mp

Backup einrichten!

Siehe dazu auch meinem Artikel zur externen Sicherung des FHEM backups.


Sonntag, 7. Juni 2020

Worx Landroid per MQTT

Vor einem Jahr habe ich den neuen Mähroboter an FHEM angebunden. Nach einiger Zeit wurde mir irgendwie klar: Die Cloud Anbindung des Roboters läuft doch mit MQTT!?
Die Anbindung über zwei nodejs Services und ein FHEM Modul erschien mir ziemlich aufwendig:
 Cloud-MQTT - iobroker.worx - fhem-landroid-s - 74_LANDROID.pm
Ein Beitrag im Forum gab die entscheidenden Hinweise. Ich habe das ganze noch etwas weiter geführt und mich dabei auch mal etwas eingehender mit attrTemplate beschäftigt.

Vorbereitung

Zur Vorbereitung der Installation braucht man ein Tool um die Informationen für den Zugang zum Cloudserver zu bekommen.
  • Broker Server Adresse
  • Board ID z.B. bei den 2019 Modellen PRM100
  • Mac zwölf stellig
  • SSL Zertifikat AWS.p12
  • Eine neue Uuid -> kann einfach selbst erzeugt werden: 
    • cat /proc/sys/kernel/random/uuid 
    • oder im Browser hier .
Ich habe die Version V0.0.24 - Net.zip verwendet. Das Tool erfordert keine Installation. Man trägt einfach seinen Cloudzugang ein, nach der Verbindung zeigt das Tool die notwendigen Daten und das Zertifikat liegt im gleichen Pfad.
Das Zertifikat muss noch zerlegt werden, um es in FHEM mit MQTT2_CLIENT verwenden zu können.

Einrichtung

Mit scp kopiert man die Datei AWS.p12 auf den FHEM Server: 
scp "d:\Downloads\V0.0.24 - Net\AWS.p12" pi@raspib3:

Ab hier sind die Befehle für die FHEM Kommandozeile oder die Raw Definition aufbereitet!

Das Zertifikat muss zerlegt werden damit fhem die Dateien verwenden kann.
"openssl pkcs12 -in /home/pi/AWS.p12 -nokeys -passin pass: -out aws.cer -clcerts"
"openssl pkcs12 -in /home/pi/AWS.p12 -nodes -passin pass: -out aws.key -nocerts"
"chmod 0600 aws.*"
Die Template Datei kann man jederzeit aktualisieren ohne ein komplettes Update machen zu müssen. Nichtsdestotrotz muss FHEM halbwegs aktuell sein und attrTemplate funktioniert.
{ Svn_GetFile("FHEM/lib/AttrTemplate/mqtt2.template", "FHEM/lib/AttrTemplate/mqtt2.template", sub(){ AttrTemplate_Initialize() }) }
Jetzt in FHEM den Connector zum Broker herstellen und testen.
define MQTT_Worx MQTT2_CLIENT <broker-server-adresse>:8883
attr MQTT_Worx SSL 1
attr MQTT_Worx autocreate simple
{my $uuid=qx(cat /proc/sys/kernel/random/uuid);;fhem("attr MQTT_Worx clientId android-$uuid")}
attr MQTT_Worx keepaliveTimeout 600
attr MQTT_Worx mqttVersion 3.1.1
attr MQTT_Worx msgAfterConnect <BoardID>/<MAC>/commandIn {}
attr MQTT_Worx sslargs SSL_version:TLSv12 SSL_cert_file:aws.cer SSL_key_file:aws.key SSL_use_cert:1
attr MQTT_Worx subscriptions <BoardID>/<MAC>/commandOut
Hat man alles richtig gemacht, geht der state des Devices MQTT_Worx sofort auf opened.

Wechselt der Status hektisch zwischen opened und disconnected stimmt etwas mit dem Zertifikat nicht.

Die erste Übertragung sollte automatisch ein neues MQTT_DEVICE erstellen.

Auf dieses Device wird jetzt das Template angewendet und damit konfiguriert.
set MQTT2_.*:FILTER=IODev=MQTT_Worx attrTemplate worx_landroid
Die Readings und die Steuerung sind ähnlich das Moduls 74_LANDROID.pm
Problemlösung
Bleibt der Connector MQTT_Worx auf disconnected -> die Zertifikate prüfen:
{qx(ls -lha /opt/fhem/aws.*)}

Das Ergebnis sollte in etwa so aussehen:
-rw------- 1 fhem dialout 1.4K Jun  9 13:27 /opt/fhem/aws.cer
-rw------- 1 fhem dialout 1.8K Jun  9 13:27 /opt/fhem/aws.key/

Support

Es gibt dazu auch einen Beitrag im Forum.

Sonntag, 31. Mai 2020

sonos2mqtt - so weit bin ich

An diesem Artikel wird immer noch gearbeitet!
Ich habe derzeit die aktuellste Anleitung ins FHEM Wiki geschrieben, aufgeteilt in 2 Artikel.

sonos2mqtt ist (ein 2 Jahre altes?) Projekt welches aktiv entwickelt wird, offenbar primär für die Anbindung an Homeassistent. Aber von der Sache her ist es eine Bridge Sonos - MQTT.
Ich habe die "lokale Installation" gewählt (es gibt auch eine Docker Version).
Aus meiner Sicht ist die Sache unkritisch, man kann es in jede Umgebung einbinden.

Voraussetzungen für diese Anleitung

  • Nodejs und pm2 installiert - Anleitung
  • MQTT2_SERVER bereits in FHEM definiert - Anleitung.
    • Damit die Automatik funktioniert: autocreate simple (default) 
  • FHEM aktuell - Stand mindestens 28.7.2020
  • Alles läuft auf einer Maschine (localhost)

Setup auf Systemebene

Diese Abschnitt wird auf der Kommandoebene von Linux ausgeführt (Terminal).
Man installiert die aktuelle sonos2mqtt Release Version (siehe Projekt Webseite):
sudo npm install -g sonos2mqtt
Es wird derzeit heftig entwickelt, die Installation oder Aktualisierung auf eine neue Beta Version geht mit dem gleichen Befehl und der Zusatz Angabe zur Beta, Beispiel "sonos2mqtt@3.0.6-beta.3".

Man kann kurz überprüfen ob bisher alles gut gegangen ist und die Version abfragen:
node /usr/lib/node_modules/sonos2mqtt --version

Setup in FHEM

Die Einbindung in FHEM erfolgt wesentlich mit generischen MQTT2_DEVICEs. Eine Bridgedevice fungiert als Verteil- und Auffangstation für MQTT Nachrichten. Dadurch werden die Player als separate MQTT2_DEVICEs erzeugt. Ein paar Templates vereinfachen die Konfiguration.

Der folgende Code ist für die Raw Definiton bzw. Kommandozeile von FHEM und realisiert diese Schritte:
  • definiere die Bridge mit Template, der Topic (default: sonos) wird abgefragt!
    • Das Template definiert 2 notify welche die Player automatisch konfigurieren:
      • Das Erste wird getriggert wenn ein MQTT2_RINCON_ Device definiert wird. Es wird das Basistemplate für Player angewendet und die Abfrage der ZonenInfo gestartet.
      • Das Zweite wird beim Eintreffen der ZonenInfo gestartet und konfiguriert den Player "fein".  
  • starte die sonos2mqtt Bridge auf Systemebene im Kontext User fhem
  • nach kurzer Zeit sollten die Player fertig sein.
Nur falls es noch keinen MQTT2_SERVER gibt:
define mqtt2s MQTT2_SERVER 1883 global
attr mqtt2s room MQTT_IO
Dieser Codeschnipsel richtet die Bridge manuell ein und startet die automatische Erzeugung der Player. 
define SonosBridge MQTT2_DEVICE
attr SonosBridge IODev mqtt2s
attr SonosBridge room MQTT2_DEVICE
sleep global:ATTR.SonosBridge.stateFormat.connected;"pm2 -s start sonos2mqtt"
set SonosBridge attrTemplate sonos2mqtt_bridge_comfort
Ist die Bridge schon automatisch erzeugt worden, wendet man nur das Template an. Ein rename ist empfohlen!
Nach wenigen Sekunden sollten alle Player sichtbar sein.

Funktioniert alles, baut man zum Abschluss noch den automatischen Start für sonos2mqtt:
define n_pm2_sonos notify global:INITIALIZED "pm2 -s start sonos2mqtt"

Sprachausgabe - der "speak" Befehl mit Boardmitteln

Verwendet wird ein Befehl ähnlich wie in der Sonos Umgebung:
set Player speak <volume> text
Drei Geräte sind notwendig:
  1. Text2Speech im Servermodus, erzeugt mp3 Dateien im cache Verzeichnis
  2. Ein HTTP Server stellt die Dateien im gleichen Verzeichnis bereit
  3. Ein notify übergibt dem Player die mp3 Datei als http Link
defmod SonosTTS Text2Speech none
attr SonosTTS TTS_UseMP3Wrap 1
attr SonosTTS userReadings httpName:lastFilename.* {'http://'.ReadingsVal($name,'host','set host first').':8083/fhem/'.ReadingsVal($name,'lastFilename','')}
deleteattr SonosTTS TTS_CacheFileDir
setreading SonosTTS host {(qx(hostname -s|tr -d '\n'))}
#setreading SonosTTS host {((split(' ', qx(hostname -I)))[0])}

defmod SonosSpeakWeb HTTPSRV cache cache SonosSpeakWeb

defmod n_SonosSpeak notify SonosTTS:playing:.0 {fhem("set ".ReadingsVal($NAME,"Player","")." notify ".ReadingsVal($NAME,"volume","")." ".ReadingsVal($NAME,"httpName",""))}
Wichtig ist, dass das Sonos System den Host im Link zur Datei richtig auflösen kann. Deshalb wird der Hostname des Servers im Readings host des TTS Device als Name oder IP Adresse abgelegt!

Man kann auch die bestehende Sonos Umgebung verwenden:
  • Samba installiert, 
  • Freigabe SonosSpeak auf /var/SonosSpeak. 
Dazu wird Text2Speech etwas anders konfiguriert:
define SonosTTS Text2Speech none
attr SonosTTS TTS_CacheFileDir /var/SonosSpeak
attr SonosTTS userReadings cifsName:lastFilename.* {my $host=ReadingsVal($name,'host','set host first');;my $lastFileName=ReadingsVal($name,'lastFilename','');;my @arr=split('/',$lastFileName);;$arr[0]='x-file-cifs:/';;$arr[1]=$host;;join('/',@arr)}
Der folgende Code (Raw Def ) ergänzt bei allen Playern den Speak Befehl in der setList.
{my @list = devspec2array('MQTT2_RINCON_.*');;\
 foreach (@list) {\
   my $setList=AttrVal($_,'setList','');;\
   my @arr=split("\n",$setList);;\
   if ($setList!~m/speak:textField/) {\
     push @arr , q(  speak:textField { my $tts="SonosTTS";;my $payload = $EVENT;;$payload =~ s/$EVTPART0 $EVTPART1 //g;; fhem("setreading $tts Player $NAME;;setreading $tts volume $EVTPART1;;set $tts tts $payload");;"{}"});;\
   }\
   $setList=join "\n",@arr;;\
   $setList=~s/;;/;;;;/g;;\
   fhem("attr $_ setList $setList")\
 }}
Der setter sendet nur eine leere Message an sonos2mqtt (muss man überlegen ob das richtig ist). Die eigentliche Arbeit tut der Perlcode davor:
  1. den Player als reading hinterlegen
  2. den volume Wert im Reading hinterlegen
  3. Text2Speech anweisen die mp3 Datei aus dem text zu erzeugen.
Ich verwende hier das Text2Speech Device gleich als temporären Zwischenspeicher. Man könnte auch ein Sonos Status Device dafür verwenden. 

Etwas Optik - devStateIcon

Eine ganz schlichte Variante:
attr MQTT2_RINCON_.* devStateIcon (STOPPED|PAUSED_PLAYBACK):rc_PLAY:toggle PLAYING:rc_PAUSE:pause .*:refresh:play
Und eine viel aufwendigere:
attr MQTT2_RINCON_.* devStateIcon {\
my $wpix = '250px';;\
my $groupname = ReadingsVal($name,'groupName','0');;\
my $sgroupname = (split(' ',ReadingsVal($name,'groupName','')))[0];;\
my $uuidtoname = (devspec2array('DEF='.ReadingsVal($name,'coordinatorUuid','0')))[0];;\
my $vol = ReadingsVal($name,'volume','');;\
my $img = ReadingsVal($name,'currentTrack_AlbumArtUri','');;\
my $mystate = $name eq $uuidtoname \
  ? ReadingsVal($name,'state','FEHLER') : ReadingsVal($uuidtoname,'state','');;\
my $playpic = $mystate eq 'PLAYING'\
  ? 'rc_PAUSE@red'    : $mystate eq 'PAUSED_PLAYBACK'\
  ? 'rc_PLAY@green'   : $mystate eq 'STOPPED'\
  ? 'rc_PLAY@green'   : $mystate eq 'TRANSITIONING'\
  ? 'rc_PLAY@blue'    : $mystate eq 'set_next'\
  ? 'rc_NEXT@blue'    : $mystate eq 'set_previous'\
  ? 'rc_PREVIOUS@blue': $mystate eq 'set_volumeUp'\
  ? 'rc_VOLUP@blue'   : $mystate eq 'set_volumeDown'\
  ? 'rc_VOLDOWN@blue' : $mystate eq 'set_mute'\
  ? 'rc_MUTE@blue'    : 'rc_PLAY@yellow';;\
my $mutecmd = ReadingsVal($name,'mute','0') eq 'false'?'on':'off';;\
my $mutepic = $mutecmd eq 'on'?'rc_MUTE':'rc_VOLUP';;\
my $show = 'FEHLER';;\
my $currentTrack_Artist = ReadingsVal($name,'currentTrack_Artist','FEHLER');;\
my $currentTrack_Title = ReadingsVal($name,'currentTrack_Title','FEHLER');;\
if ($currentTrack_Title =~ 'x-sonosapi-stream:'){$currentTrack_Title=''};;\
my $currentTrack = $mystate eq 'TRANSITIONING'\
  ? 'Puffern...' : $currentTrack_Artist.' - '.$currentTrack_Title;;\
my $nextTrack_Artist = ReadingsVal($name,'nextTrack_Artist','FEHLER');;\
my $nextTrack_Title = ReadingsVal($name,'nextTrack_Title','FEHLER');;\
my $nextTrack = $nextTrack_Artist.' - '.$nextTrack_Title;;\
my $previouspic = 'rc_PREVIOUS';;\
my $nextpic = 'rc_NEXT';;\
my $voldownpic = 'rc_VOLDOWN';;\
my $voluppic = 'rc_VOLUP';;\
my $leavegrouppic = 'rc_LEFT';;\
my $showlg = ReadingsVal($name,"name","0") ne $groupname ? "<a href=\"/fhem?cmd.dummy=set $name leaveGroup&XHR=1\">".FW_makeImage($leavegrouppic)."</a>" : "";;\
if (($mystate eq 'PLAYING')\
  || ($mystate eq 'TRANSITIONING' )\
  || ($mystate eq 'set_next' )\
  || ($mystate eq 'set_previous' )\
  || ($mystate eq 'set_volumeUp' )\
  || ($mystate eq 'set_volumeDown' )\
  || ($mystate eq 'set_mute' )) { \
    my $shownp = ReadingsVal($name,'name','') eq $sgroupname \
    ? "<a href=\"/fhem?cmd.dummy=set $name previous&XHR=1\">".FW_makeImage($previouspic)."</a>\
       <a href=\"/fhem?cmd.dummy=set $name next&XHR=1\">".FW_makeImage($nextpic)."</a>" : "";;  \
    $show = "$showlg <a href=\"/fhem?cmd.dummy=set $name toggle&XHR=1\">".FW_makeImage($playpic)."</a>\
    <a href=\"/fhem?cmd.dummy=set $name volumeDown&XHR=1\">".FW_makeImage($voldownpic)."</a>\
    $shownp\
    <a href=\"/fhem?cmd.dummy=set $name volumeUp&XHR=1\">".FW_makeImage($voluppic)."</a>\
    &nbsp;;&nbsp;;&nbsp;;&nbsp;;\
    <a href=\"/fhem?cmd.dummy=set $name mute $mutecmd&XHR=1\">".FW_makeImage($mutepic)."</a><br>";;\
  \
    if (ReadingsVal($name,'name','') eq $sgroupname) {\
      $show = ReadingsVal($name,'currentTrack_TrackUri','') =~ 'spdif'\
      ? 'TV': ReadingsVal($name,'enqueuedMetadata_UpnpClass','FEHLER') ne 'object.item.audioItem.audioBroadcast'\
      ? "$show<marquee style='width: $wpix'>Aktueller Track: $currentTrack<br>Nächster Track: $nextTrack</marquee>"\
      : "$show<marquee style='width: $wpix'>Radio: $currentTrack</marquee>"\
    }\
    elsif (ReadingsVal($name,'name','') ne $groupname) {\
      $show = "$show Master: $sgroupname"}\
    }\
    else {\
      $show = $name eq $uuidtoname\
      ? "$showlg <a href=\"/fhem?cmd.dummy=set $name toggle&XHR=1\">".FW_makeImage($playpic)."</a>"\
      : "$showlg <a href=\"/fhem?cmd.dummy=set $name toggle&XHR=1\">".FW_makeImage($playpic)."</a><br>Master: $sgroupname"\
    }\
  "<div>\
   <table>\
     <tr>\
       <td><div style='display: inline-block;; margin-right: 5px;; border: 1px solid lightgray;;\
              height: 4.00em;; width: 4.00em;; background-image: url($img);; background-size: contain;;'></div></td>\
       <td>$show</td>\
     </tr>\
   </table>\
   </div>"\
}

Tipps zur Verwendung der Player

Die automatische Konfiguration setzt den alias entsprechend dem Namen im Sonos vergeben. Die langen MQTT2_RINCON_ Namen sind unhandlich und schlecht lesbar. Man kann Player mit einem devspec ansprechen, das simpelste ist:
set alias=Büro ...
Oder alle Player
set model=sonos2mqtt_speaker leaveGroup

Was passiert im Hintergrund?

Das Template "sonos2mqtt_bridge_comfort" wendet ein Template auf das Bridge Device an und definiert zwei notify für die automatische Konfiguration.
Das Erste triggert auf den autocreate Event, wendet ein Template für den Player an und fragt über MQTT weitere Informationen für den Player ab.
define n_configSonos1 notify global:DEFINED.MQTT2_RINCON_[A-Z0-9]+ sleep 1;;set $EVTPART1 attrTemplate sonos2mqtt_speaker;;set $EVTPART1 x_raw_payload {"command": "adv-command","input": {"cmd":"GetZoneInfo","reply":"ZoneInfo"}}
Das zweite notify triggert auf die Namen der Player wenn als Antwort auf den Request von notify 1 das Reading IPAdresse gesetzt wird.
defmod n_configSonos2 notify MQTT2_RINCON_[A-Z0-9]+:IPAddress:.* {\
  no warnings 'experimental::smartmatch';;\
  my @tv = ("S14","S11");;\
  my $url="http://$EVTPART1:1400";;\
  my $xmltext = GetFileFromURL("$url/xml/device_description.xml");;\
  my ($mn)=$xmltext =~ /<modelNumber>(S[0-9]+)/;;\
  my ($img)=$xmltext =~ /<url>(.*)<\/url>/;;\
  my $icon="Sonos2mqtt_icon-$mn";;\
  my $setList=AttrVal($NAME,'setList','');;\
  fhem("setreading $NAME modelNumber $mn");;\
  fhem("\"wget -qO ./www/images/default/$icon.png $url$img\"");;\
  fhem("attr $NAME icon $icon;;sleep 4 WI;;set WEB rereadicons");;\
  if ($mn ~~ @tv) {$setList=~s/input:Queue \{/input:Queue,TV \{/};;\
  $setList=~s/;;/;;;;/g;;\
  fhem("attr $NAME setList $setList")\
}
Mit diesem Befehl wird das Anlegen aller Player getriggert:
"pm2 start sonos2mqtt"

Radio starten

In der setList sind derzeit die einzelnen Steuerbefehle. setAVTUri setzt zwar eine neue Abspielquelle, stoppt aber den Player und beginnt nicht automatisch mit spielen. Eigentlich wäre es aber praktisch.

Anmerkung: Der Befehl playUri ist im aktuellen Template enthalten! 

Die Sonos Umgebung braucht offenbar dazu einen Moment, meine derzeitige Idee ist also:
  1. setAVTUri ausführen
  2. 1 sec später den play Befehl starten
Die Ergänzung in der setList sähe also so aus:
playUri:textField {fhem("set $NAME setAVTUri $EVTPART1; sleep 1; set $NAME play")}
Als vorübergehende Lösung für sowas wie Radiosender habe ich mir so etwas gebaut. Das notify schreibt den Titel und die uri beim Start (auch über die Sonos App) in den Dummy. Diesen kann man dann selbst zum Starten verwenden: [Titel:DeutschlandfunkKultur]
define Titel dummy
define n_MQTT2_RINCON notify MQTT2_RINCON_[0-9A-Z]{17}:currentTrack_Title:.* {my $title=ReadingsVal($NAME,"enqueuedMetadata_Title","");;$title=~s/\W//g;;my $uri=ReadingsVal($NAME,"currentTrack_TrackUri","");;fhem("setreading Titel $title $uri") }

Nicht einfach default

Hat man den MQTT2_SERVER anders definiert, nicht lokal bzw. mit allowed abgesichert, muss beim Start von sonos2mqtt der Parameter --mqtt übergeben werden. 
Dem pm2 Befehl folgenden durch die Angabe "--" die weiteren Parameter für sonos2mqtt.
"pm2 start sonos2mqtt -- --mqtt mqtt://myuser:the_secret_password@192.168.0.3:1800"
Mit dem Parameter --prefix könnte man den Basistopic setzen (default: sonos).

Weitere Entwicklung

Für die weitere Entwicklung ist im Player der set Punkt x_raw_payload eingebaut. Damit kann einfach json Payload "publishen". Das Original Beispiel aus der Doku, Sound abspielen:
{
  "command": "notify",
  "input": {
    "trackUri": "https://cdn.smartersoft-group.com/various/pull-bell-short.mp3",
    "onlyWhenPlaying": false,
    "timeout": 10,
    "volume": 15,
    "delayMs": 700
  }
}

Werte abfragen

Der Entwickler von sonos2mqtt hat jetzt auch die Abfrage ermöglicht. Um bei Get Befehlen etwas zurück zu bekommen, muss ein Topic übergeben werden:
{
  "command": "adv-command",
  "input": {
    "cmd": "GetFavoriteRadioStations",
    "reply": "DougRadio"
  }
}
Das Beispiel fragt die Favoriten ab. Die Ergebnisse erscheinen dann in einem Reading mit der Struktur Result_8_ItemId. Weiter Informationen findet man hier.

Anmerkung/Tipps

Anstatt FHEM komplett zu aktualisieren kann man auch nur die Templates neu laden:
{ Svn_GetFile("FHEM/lib/AttrTemplate/mqtt2.template", "FHEM/lib/AttrTemplate/mqtt2.template", sub(){ AttrTemplate_Initialize() }) }

Mir ist aufgefallen, dass offenbar System abhängig der Ordner node_modules bei dieser Installationsart an unterschiedlichen Orten angelegt wird! Ich hatte /usr/lib/node_modules und /node_modules. Der Befehl sudo find / -name "sonos2mqtt" hilft dabei den richtigen Pfad zu finden.

Will man auf Systemebene mit pm2 sono2mqtt monitoren o.ä. muss man dies als User fhem tun. Ein anderer hat auf die Umgebung keinen Zugriff!
sudo -su fhem pm2 list

ToDo


code

code

Mittwoch, 13. Mai 2020

systemd unit file

Ich habe mich etwas mit systemd, speziell dem unit file von fhem und dem Start von für FHEM notwendigen Komponenten beschäftigt.
Für detailliertere Information wird diese Seite als Start empfohlen.

Die Datei fhem.service ist ein systemd unit file und wird bei der debian Installation von FHEM mit ausgeliefert.
Änderungen an dieser Datei sind normalerweise nicht notwendig. Man sollte zumindest genau wissen was man tut!
Ich möchte hier ein paar Fälle behandeln, wo das notwendig wird und dabei auch ein paar Erkenntnisse und Tipps aufschreiben.

Unit File - ein paar kurze Erklärung

Den aktuellen Inhalt kann man jederzeit anschauen:
systemctl cat fhem
Stand Mai 2020 hat die Datei folgenden Inhalt:

Inhalt fhem.service

# $Id: fhem.service 19235 2019-04-21 13:26:17Z betateilchen $

[Unit]
Description=FHEM Home Automation
Wants=network.target
After=network.target
#Requires=postgresql.service
#After=postgresql.service
#Requires=mysql.service
#After=mysql.service

[Service]
Type=forking
User=fhem
Group=dialout
WorkingDirectory=/opt/fhem
ExecStart=/usr/bin/perl fhem.pl fhem.cfg
#ExecStart=/usr/bin/perl fhem.pl configDB
Restart=always

[Install]
WantedBy=multi-user.target

Erklärung ausgewählter Parameter

Wants= die angegebene Services werden benötigt, fhem startet aber trotzdem falls die Services nicht gestartet werden können.
Requires= wenn der Service nicht gestartet werden kann, wird fhem nicht gestartet.
After= bewirkt, dass fhem nach dem Service (der Gruppe) gestartet wird. Das ist wichtig damit Services die für fhem notwendig sind schon gestartet sind. Benötig fhem z.B. Datenbanken sind die entsprechenden  Zeilen einzubauen oder durch entfernen des Kommentarzeichens (#) zu aktivieren.
Die eben genannten Optionen können mehrfach oder mit mehreren, Komma getrennten Einträgen vorkommen.
User=fhem bewirkt das der Services mit user fhem gestartet wird. Falls fhem mit dem user root gestartet wird, startet fhem.pl einen neuen Prozess unter dem User fhem.
Group=dialout Es wird die Gruppe dialout zum Start benutzt.
Beide Zeilen können für den normalen Start von FHEM auch auskommentiert werden.

Zusätzlicher Parameter

ExecStartPre= Hier kann ein Shell Befehl stehen, der vor dem Start des eigentlichen Service (ExecStart=) ausgeführt wird. Diese Zeile kann auch mehrfach vorkommen. Bei wenigen Zeilen kann man sich die Auslagerung in separate Scripte sparen.

Prozesse vor dem FHEM Start ausführen

Ziel ist es sicherzustellen, dass für den Start von FHEM alle Voraussetzungen erfüllt sind, z.B.
  • Hardware aktiviert
  • Datenbank gestartet
  • Systemprozess läuft (z.B. Bluetooth gestartet)
  • eigenen Prozessen ist gestartet 
Dazu gibt es mehrere Lösungswege:
  • die Datei fhem.service modifizieren
  • einen separaten Service implementieren
  • Abhängigkeiten definieren

Ein Script zusammen mit FHEM starten

1. Script bereitstellen
Dazu wird eine Scriptdatei erzeugt, Beispiel:
sudo nano /opt/fhem/ExecStartPre.sh
Den Code (Beispiele am Ende) hier einfügen und die Datei speichern und Editor verlassen (ctrl+s ctrl+x).

2. ExecStartPre aktivieren
Um ein Script mit root Rechten in der fhem.service unit auszuführen, müssen drei Zeilen in der Datei geändert werden.
sudo systemctl edit --full fhem
Vor der Zeile ExecStart= wir diese Zeile eingefügt:
ExecStartPre= bash /opt/fhem/ExecStartPre.sh
Die beiden Zeilen User und Group muss man auskommentieren, da die Unit sonst mit dem User fhem ausgeführt wird.
#User=fhem
#Group=dialout
Achtung: Die Gruppenmitgliedschaft des Users fhem (z.B. gpio) ist beim Systemstart an der Stelle noch nicht wirksam.

3. Änderungen aktivieren
Die Änderungen werden erst nach einem daemon-reload aktiv und nach einem restart wirksam.
#sudo systemctl daemon-reload # nur notwendig wenn nicht systemctl edit verwendet wurde
sudo systemctl restart fhem
Den Erfolg auch nach einem komplette Neustart testen!

Ein Script mit separater service unit starten

Wir erstellen quasi einen eigenen Service - Vorteil: Die fhem.service braucht man nicht verändern.

1. Script bereitstellen
Das Beispiel hier in einem allgemeinerem Pfad:
sudo nano /user/local/bin/EnableXX.sh
Den Code (Beispiele am Ende) hier einfügen und die Datei speichern und Editor verlassen (ctrl+s ctrl+x).

2. unit file erzeugen
Man erstellt eine neues unit file.
sudo systemctl edit --full --force enablexx.service
Mit folgendem Inhalt
[Unit]
Description=EnableXX
Before=fhem.service
#After=network.target

[Service]
Type=oneshot
ExecStart=bash /user/local/bin/EnableXX.sh
StandardOutput=journal

[Install]
WantedBy=multi-user.target

Die Zeile Before=fhem.service stellt sicher, dass der Start vor FHEM erfolgt

3. Service aktivieren
#sudo systemctl daemon-reload # nur notwendig wenn nicht systemctl edit verwendet wurde
sudo systemctl enable enablexx
sudo systemctl start enablexx
Den Erfolg auch nach einem komplette Neustart testen!

Start von anderen Services abhängig machen

In der fhem.service unit kann man sicherstellen, dass ein Service fertig gestartet wurde bevor fhem startet. Dazu kann man im unit Abschnitt zwei Zeilen einfügen (bzw. Kommentar entfernen):
Wants=xxx.service
After=xxx.service
Man kann auch erzwingen, dass FHEM nicht startet falls die Voraussetzungen nicht erfüllt sind. Dafür muss anstatt Wants= Requires= verwendet werden.

Hinweise und Tipps

Ausgaben im Script

Ausgaben mit echo landen im /var/log/syslog. Das Log kann man mit diesem Befehl anzeigen:
cat /var/log/syslog
Ist das Logfile zu unübersichtlich kann man sich auch z.B. nur 15 Zeilen nach systemd Ausgabe des unit files anzeigen lassen.
cat /var/log/syslog|grep -A 15 "FHEM Home"

Editieren von unit files

Es wird die integrierte Methode von systemctl empfohlen. Diese hat den Vorteil das nach dem Speichern automatisch ein daemon-reload durchgeführt wird.
sudo systemctl edit --full fhem
Typischerweise wird nano zum editieren geöffnet.
ctrl+s speichert die Datei
ctrl+x verlässt den Editor

Tipp für Windows

Windows 10 verfügt seit der Version 1709 über einen integrierten ssh Client, zusätzliche Tools wie putty & co sind nicht notwendig. Mit der Tastenkombination Windows + r die Ausführen Zeile öffnen und einfach den ssh Befehl eingeben:
ssh pi@raspib2
ssh -t pi@raspib2 sudo systemctl edit --full fhem
ssh -t pi@raspib2 sudo systemctl cat fhem; bash

Beispielcode

Diese Codebeispiel ist auf dem Raspberry Pi ausführbar und lässt vor dem Start von FHEM die grüne LED (ACT) blinken.
Beispiel 1: 3 mal kurz und 3 mal lang
# Lass die ACT LED (grün) am Pi 3 mal kurz und 3 mal lang blinken
ANZAHL=3
#Status (Standard [mmc0] )sichern
trigger=$(cat /sys/class/leds/led0/trigger|grep -o "\[.*\]"|tr -d [+])
#umschalten auf manuell
echo "none" >/sys/class/leds/led0/trigger
#blinken
for ((i=1 ; i<=$(( $ANZAHL * 2 )) ; i++ )); do
  echo $(( $i % 2 )) >/sys/class/leds/led0/brightness
  sleep 0.3
done
for ((i=1 ; i<=$(( $ANZAHL * 2 )) ; i++ )); do
  echo $(( $i % 2 )) >/sys/class/leds/led0/brightness
  sleep 1
done
#Status wieder herstellen
echo $trigger >/sys/class/leds/led0/trigger

Beispiel 2: Morsezeichen "FHEM"
echo "starte pre Script "
# act LED
led="/sys/class/leds/led0/brightness"
Status sichern
trigger=$(cat /sys/class/leds/led0/trigger|grep -o "\[.*\]"|tr -d [+])
# Zeichenfolge FHEM als Morsecode ausgeben
# Zeichen F · · − ·
echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2
echo 1 >$led;sleep 0.2;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.1;echo 0 >$led
sleep 0.4
# Zeichen H · · · ·
echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2
echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.1;echo 0 >$led
sleep 0.4
# Zeichen E ·
echo 1 >$led;sleep 0.1;echo 0 >$led
sleep 0.4
# Zeichen M − −
echo 1 >$led;sleep 0.2;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.2;echo 0 >$led
sleep 0.4
echo $trigger >/sys/class/leds/led0/trigger

Der Start von fhem.pl

Beim normalen Start der fhem.pl wird der Startprozess ziemlich schnell wieder beendet und ein neuer Prozess im Hintergrund gestartet. In der Doku steht dazu:
Falls FHEM als root gestartet wurde, und ein OS-Benutzer fhem existiert, dann wechselt FHEM nach dem start zu diesem Benutzer (via setuid).
Wird fhem.pl mit einem normalen User gestartet, wird der Hintergundprozess mit diesem User fortgeführt. Dies führt in der Regel zu Berechtigungsproblemen:

  • kein Schreibzugriff auf  Dateien die User fhem gehören (Logdateien usw.)

D.h.: Es ist nicht zwingend notwendig fhem.pl initial mit User fhem zu starten.

Code Block

Sonntag, 16. Februar 2020

Windows Server 2012 Foundation - Hyper-V Treiber installieren

Microsoft hat irgendwie umfangreich verhindert, dass man Windows Server 2012 Foundation in Hyper-V virtualisieren kann. Blöd wenn man eine produktiven Server hat, mit dem man ein paar Untersuchungen anstellen will. Virtualisierung / Hyper-V ist dafür nun mal eine Super Sache.
Es gibt einen guten Artikel, der mir sehr weiter geholfen hat.
Da die Situation nach einer Virtualisierung erstmal dramatisch ist, habe ich eine Weg gesucht und gefunden, es zu vereinfachen.
Das Hauptproblem ist die fehlende Installation der Hyper-V Treiber.

Das notwendige Paket windows6.2-hypervintegrationservices-x64.cab kann man bei Microsoft herunterladen. Die ursprüngliche existierende vmguest.iso wird nicht mehr ausgeliefert.
Für den Rest habe ich ein paar Powershell Scripts erstellt.
Zunächst brauchen wir die entpackten Dateien in einem temporären Pfad.
# cab Datei entpacken und in allen inf Dateien eine Zeile ergaenzen
$cabFile="E:\support\amd64\Windows6.2-HyperVIntegrationServices-x64.cab"
# Zielpfad frisch machen
$DestDir = (split-path $cabFile -leaf) -replace '.cab'
if (Test-Path -Path $DestDir) {rm $DestDir}
md $DestDir
# cab datei auspacken
cmd.exe /c "C:\Windows\System32\expand.exe -F:* $cabFile $DestDir"
Damit die Treiber später installiert werden können, muss die inf Datei um die eine Zeile ($rString) ergänzt werden. Zusätzlich muss "neben" der inf Datei die Datei update.cat liegen.
# replace in den inf Dateien
$fString=[regex]::Escape('[Version]') # escapen wegen der Klammer []
$rString="$&`nCatalogFile=update.cat" # Der String der gefunden wurde + NL + Text
gci -Recurse $DestDir |where {$_.name -like "*.inf"}|% {(Get-Content $_.fullname) -replace $fString, $rString| Set-Content $_.fullname;copy-item "$DestDir\update.cat"  (split-path $_.fullname)}
Die vorbereitete virtuelle Disk (VHD datei) kann man per Doppelklick einfach einbinden. Die Treiber werden dann ins Offline Image integriert.
# Treiber in offline Image integrieren
$offDir="F:"
$driverDir="\\omv1\Shares\Software\vmguest"
Add-WindowsDriver -Path $offDir -Driver $driverDir -Recurse -ForceUnsigned
Sollte was schiefgegangen sein, kann man auch alles wieder entfernen, oder sich nur vergewissern das die Treiber vorhanden sind.
# Alle Treiber wieder entfernen 
$dArray=gci -Recurse $driverDir |where {$_.name -like "*.inf"}|% {$_.name}
Get-WindowsDriver -path $offDir|% {if ($dArray -match (split-path $_.OriginalFileName -leaf)){Remove-WindowsDriver -path $offDir -Driver $_.driver}}
Zum Abschluss die VHD Datei auswerfen und die virtuelle Maschine starten. Es sind keine weiteren Arbeiten erforderlich.

Für die Virtualisierung einer produktiven Server 2012 Foundation Maschine hat man damit folgenden simplen Weg:
  1. Image ziehen, entweder offline mit dem USB Stick von hier, oder online mit disk2vhd.
  2. Das Image auf eine neue VHD anwenden, oder die VHD Datei von disk2vhd verwenden.
  3. VHD Datei als Laufwerk mounten und die Hyper-V Treiber integrieren. 
  4. VHD Datei Auswerfen und in Hyper-V verwenden.
Damit funktioniert:

  • Gen 2 Virtuelle Maschine
  • EFI Boot
  • SCSI Disk, Netzkarte usw.

Was leider bleibt:
  • Die Hyper-V Dienste (vmic...) laufen nicht. 
ToDo?
Code Block

Code Block

Mittwoch, 5. Februar 2020

Windows Core Server verwalten

Eigentlich gibt es ein simples Dokument vom Hersteller, aber das hat so viele Lücken und Fehler, ich schreibe einfach mal auf wie es kurz und knapp geht.

Verwaltung eines Core Servers (Hyper-V 2019) ohne Domäne

Um ohne lokale Konsole arbeiten zu können braucht man RDP. Das aktiviert man schnell:
  • entweder im Dialog der blauen Box von %windir%\System32\sconfig.cmd (bzw. %windir%\System32\%language%\sconfig.vbs) 
    • Dialog: 7 e 1
  • oder über ein vorhandenes Script:
cscript %WinDir%\System32\Scregedit.wsf /ar 0
REM Dieser Befehl noch für alte RDP Clients
Cscript %WinDir%\System32\Scregedit.wsf /cs 0
Man sollte den Server noch umbenennen, entweder im Dialog (2) oder
netdom renamecomputer %computername% /force /NewName:ComputerName
Danach muss man den Server neu starten!

Ab hier geht es auch Remote

Das "Netzwerkprofile" steht per default auf public, das stellt man um auf private und ermöglicht die Reaktion auf Ping. Dazu eine Powershell im "schwarzen Fenster" starten:
start Powershell
Ping funktioniert mit dem Regelset -DisplayGroup "File and Printer Sharing" (Sprachabhängig: "Datei- und Druckerfreigabe") oder "codiert" in Group.
Set-NetConnectionProfile -InterfaceIndex (Get-NetConnectionProfile).InterfaceIndex -NetworkCategory Private
Enable-NetFirewallRule -Group "@FirewallAPI.dll,-28502"

Am Client

Eine "Remote Verwaltung" funktioniert nur mit etwas Vorbereitung.

  • Der Zielcomputer muss als TrustedHost eingetragen und 
  • das Konto vom Zielcomputer muss hinterlegt werden. 

Verwirrend: Für den Hyper-V Manager muss der TrustedHost mit FQDN hinterlegt werden! Man kann sich entscheiden oder beides hinterlegen.
$server = "ComputerName"
$user = "administrator"
$pwd = Read-Host "Enter Password"
$fqdn=[System.Net.Dns]::GetHostByName($server).Hostname
Start-Service -Name winrm
Set-Item WSMan:\localhost\Client\TrustedHosts -Concatenate -Value $server
Set-Item WSMan:\localhost\Client\TrustedHosts -Concatenate -Value $fqdn
Stop-Service -Name winrm
cmdkey /add:$server /user:$user /pass:$pwd
cmdkey /add:$fqdn /user:$user /pass:$pwd

Ist alles ordentlich eingerichtet kann man eine Powershell Remotesitzung aufbauen.
Enter-PSSession -ComputerName $server

Neben Powershell und dem Hyper-V Manager funktionieren auch andere "lokale" Snap-Ins in der mmc, mir ist aber noch nicht klar nach welchem Schema was funktioniert und was nicht.
Die Hyper-V Verwaltungstools kann man besser über die grafische Schnittstelle installieren, die Powershell Schnittstelle funktioniert nur Hyper-V komplett oder gar nicht.
Mann sollte dafür die RSat Tools verwenden, oder eben alles über RDP und Powershell machen.

Informationen

Es gibt ein Tool für die Kommandozeile, welches knapp und übersichtlich die System Informationen darstellt:
systeminfo.exe
Auf dem Windows Server ist PSRemoting von Haus aus aktiviert, auf anderen Ziel Systemen kann man sie mit Enable-PSRemoting aktivieren. Ob aktiviert oder nicht lässt sich leicht von jeder Maschine aus testen:
Test-WSMan -ComputerName ComputerName
Die schon existierenden Zielsysteme kann man abfragen
Start-Service -Name winrm
(Get-Item WSMan:\localhost\Client\TrustedHosts).value
Stop-Service -Name winrm
Die existierenden Konten kann man anzeigen lassen
cmdkey /list

Auf dem Server kann man sich Profil und die aktivierten Firewall Regeln anschauen:
Get-NetConnectionProfile
Get-NetFirewallRule -DisplayGroup "Windows Remote Management"|select Name,enabled
Get-NetFirewallRule -Group "@FirewallAPI.dll,-28502"|select name,enabled
Mit der Tastenkombination Ctrl+Alt+Ende öffnet sich ein Fenster von wo aus man z.B. den Taskmanager starten kann.

ToDo Ist da noch was?
Code Block
System Volume nach der Installation auf 60GB schrumpfen und den Rest als Volume V einrichten.
$disk=Get-Partition -DriveLetter C
Resize-Partition -DiskNumber $disk.DiskNumber -PartitionNumber $disk.PartitionNumber -Size 60GB
New-Partition -DiskNumber $disk.DiskNumber -UseMaximumSize -DriveLetter v|Format-Volume

Weiteres

Insgesamt zu diesem Thema gibt es auch schon ein paar Artikel hier im Blog
Link