Montag, 7. Januar 2019

Kalender in FHEM - auf bestimmte Termine reagieren

Die Grundlage schaffen - ein Calendar Device

Für dieses Beispiel: ein Google Kalender. Als Grundlage brauchen wir die "Privatadresse" im iCal Format (Google Kalender Einstellungen/<Kalendername>/Kalendereinstellungen).
Diese URL wird einfach in die Calendar Definition eingesetzt, das Aktualisierungsintervall setze ich auf einen Tag. Man kann jederzeit ein reload des Kalenders durchführen. Man muss bedenken, dass vor allem viele Serientermine, eine nicht unerheblich Zeit beim reload beanspruchen. Das kann schnell mal mehrere Minuten dauern. In der Grundeinstellung erfolgt das blockierend. Je nach Kalender, kann also nach dem define die Oberfläche für ein paar Minuten "stehen"!
define TestKalender Calendar ical url https://calendar.google.com/calendar/ical/xxx/basic.ics 86400
Um zu testen, ob der Kalender richtig gelesen wird, kann man ihn jetzt einfach abfragen. Eine direkte Anzeige der Termine in Readings erfolgt nämlich nicht.

Abfragen machen

Die Abfrage der Termine ist nicht offensichtlich, es gibt aber einige Beispiele in der englischen Doku. Als Ausgangspunkt für mein Beispiel nehme ich mal die Weboberfläche. In der zweiten Auswahlbox in der get Zeile wählt man einfach events aus.
Als Ergebnis bekommt man in einer Box eine Liste der Kalendereinträge (events), ich habe heute (6.1.) drei Einträge drin. Wie man sieht, auch vergangene.
04.01.2019 08:00 4h Sprechstunde
06.01.2019 08:00 14h Heute frei
07.01.2019 08:00 11h Sprechstunde
In der leeren Box kann man weiter format und filter Angaben machen.

Das Ziel in diesem Beispiel soll sein, auf einen ganz bestimmten Eintrag im Kalender zur Startzeit des Termins etwas auszulösen: z.B. den Server an den Tagen wo Sprechstunde ist, kurz vor Arbeitsbeginn zu starten.

Event auswählen

Dazu erzeugt man am Besten einen Termin in naher Zukunft und schaut sich mit dem Eventmonitor die Events an:
2019-01-06 20:00:00 Calendar TestKalender changed: 79vs3fq7siulo1hskdn4gtht7kgooglecom start
2019-01-06 20:00:00 Calendar TestKalender start: 79vs3fq7siulo1hskdn4gtht7kgooglecom 
2019-01-06 20:00:00 Calendar TestKalender modeUpcoming: 7fcbh4r7snu7iqovask7l8oq9qgooglecom
2019-01-06 20:00:00 Calendar TestKalender modeAlarmOrStart: 44318rlssm81janveuga0olanpgooglecom;79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:00:00 Calendar TestKalender modeChanged: 79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:00:00 Calendar TestKalender modeStart: 44318rlssm81janveuga0olanpgooglecom;79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:00:00 Calendar TestKalender modeStarted: 79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:00:00 Calendar TestKalender triggered
2019-01-06 20:00:00 Calendar TestKalender nextWakeup: 2019-01-06 20:05:00
2019-01-06 20:05:00 Calendar TestKalender changed: 79vs3fq7siulo1hskdn4gtht7kgooglecom end
2019-01-06 20:05:00 Calendar TestKalender end: 79vs3fq7siulo1hskdn4gtht7kgooglecom 
2019-01-06 20:05:00 Calendar TestKalender modeAlarmOrStart: 44318rlssm81janveuga0olanpgooglecom
2019-01-06 20:05:00 Calendar TestKalender modeStart: 44318rlssm81janveuga0olanpgooglecom
2019-01-06 20:05:00 Calendar TestKalender modeStarted: 
2019-01-06 20:05:00 Calendar TestKalender modeEnd: 26aq76ljdgjfmo444466faml09googlecom;79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:05:00 Calendar TestKalender modeEnded: 79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:05:00 Calendar TestKalender triggered
2019-01-06 20:05:00 Calendar TestKalender nextWakeup: 2019-01-06 22:00:00
Man sieht jeweils 9 Events beim Start des Termines und 9 Events beim Ende. Allerdings keine Information über den "Lesbaren" Inhalt des Termines, diese kann man mittels der uid ($EVTPART1) auslesen. Es gibt zwei Events, jeweils den ersten und zweiten, die für einen trigger interessant sind.
TestKalender:changed:.*
TestKalender:changed:.*start
TestKalender:start:.*
Beim ersten regExp müsste/könnte man mit $EVTPART2 im Code abfragen ob es start oder end war. Bei den beiden anderen wird eindeutig auf start|end|alarm getriggert.

Exakte Abfrage auf einen Termin

Jetzt kann man im Code noch exakt abfragen, ob es sich um den richtigen Kalendereintrag handelt.
fhem('get '.$NAME.' events filter:uid=="'.$EVTPART1.'",field(summary)=~"(?i)sprechstunde" limit:count=1,from=+0d',1)
Die eigentliche Aktion ist damit recht simpel. Wenn die Abfrage des Events exakt genug ist, liefert sie nur bei Übereinstimmung ein Ergebnis. Damit sind alle notwendigen Komponenten komplett.
{fhem("set Server on") if defined fhem('get '.$NAME.' events filter:uid=="'.$EVTPART1.'",field(summary)=~"(?i)sprechstunde|notdienst" limit:count=1,from=+0d',1)}

Starte das Gerät zum Zeitpunkt

Ein notify, welches zu Beginn eines Kalenderevents, der den Begriff "Sprechstunde" in der Terminbeschreibung enthält, den Server startet:
define n_TestKalender notify TestKalender:changed:.*start {\
fhem("set Server on") if defined fhem('get '.$NAME.' events filter:uid=="'.$EVTPART1.'",field(summary)=~"(?i)sprechstunde" limit:count=1,from=+0d',1)\
}
Die Sache hat noch einen Schönheitsfehler: Die Sprechstunde beginnt zwar um 8:00 Uhr aber es wäre gut, wenn der Server  schon gestartet ist, wenn alle Mitarbeiter den Dienst beginnen. Dazu brauchen wir den Event nicht exakt zum Termin sondern vorher. Das kann das Calendar Modul erledigen. Mit diesem Attribute wird ein zusätzlicher alarm Event eine Stunde (3600 sec) vorm Termin in Abhängigkeit der Terminbeschreibung erzeugt.
attr TestKalender onCreateEvent { $e->{alarm}= $e->{start}-3600 if($e->{summary} =~ m/Sprechstunde/i)}

Starte das Gerät vor dem Zeitpunkt

Der Trigger im notify muss lediglich von start auf alarm geändert werden, der Ausführungsteil bleibt  identisch.
defmod n_TestKalender notify TestKalender:changed:.*alarm {}
Der Event für start und end bleibt erhalten, zu diesem Zeitpunkt kann man andere Aktionen ausführen.

Noch ein paar zusätzliche Tipps und Infos

Serientermine einer Serie (z.B. jeden Mittwoch 8:00) haben alle die gleiche UID. Bei einem Einzeltermin hätte man im notify über die uid den konkreten Zugriff auf genau den Termin, beim Serientermin erscheinen alle Termine der Serie, auch vergangene! Diese uid bleibt auch erhalten wenn man mal einen Termin der Serie modifiziert (Beschreibung, Zeit usw.)
Die Modi (alarm|start|end|upcoming) sind transient und geben quasi Auskunft über den aktuellen Status eines Termins (get <Kalender> events filter:mode=="<modus>").
  • upcoming - der Termin liegt in der Zukunft
  • end - der Termin ist abgelaufen und liegt in der Vergangenheit
  • start - der Termin ist gerade aktiv
  • alarm - die Alarmphase ist aktiv, also der Event alarm ist vorüber, der Event start noch nicht erreicht.

Noch ein paar Codebeispiele

toDo
Code Block

Code Block

Dienstag, 4. Dezember 2018

Diskpart vs Powershell

Um Festplattenpartitionen zu behandeln - was sollte man nehmen - Diskpart oder Powershell?

Achtung beim Probieren! der clean Befehl innerhalb diskpart wird ohne Nachfrage ausgeführt und löscht die aktive disk!
Die Powershell Befehle fragen zwar nach, Standardantwort ist aber Yes. Also auch hier Vorsicht!

Diskpart lässt sich zwar auch scripten, aber etwas ungewöhnlich. Mit Powershell lässt sich viel mehr machen. Aber die Befehle sind auch zum Teil komplexer.

Ich fange hier einfach mal eine Tabelle, die ich vervollständigen kann:

list disk get-disk|sort number
sel disk 0
list part
Get-Partition -disknumber 0
sel disk 1
clean
Clear-Disk -Number 1 -RemoveData -RemoveOEM
list volume Get-Volume
sel disk 1
(clean)
convert gpt
Initialize-Disk -Number 1
sel disk 1
(clean)
convert mbr
Initialize-Disk -Number 1 -PartitionStyle MBR
sel disk 5
attributes disk clear readonly
Set-Disk -Number 5 -IsReadonly $False






Das geht so richtig gut nur in Powershell

Wo liegt das Laufwerk E?
Get-Partition -DriveLetter E|select DiskNumber,PartitionNumber,DriveLetter,Offset,Size,Type|format-table

Welche Festplatte hat welche Laufwerke?
Get-Volume|Get-Partition |select DiskNumber,PartitionNumber,DriveLetter,Offset,Size,Type|sort DiskNumber,DriveLetter|Format-Table

Erzeuge neues Volume auf Disk 1 mit definiertem DriveLetter
New-Partition -Disknumber 1 -DriveLetter W -UseMaximumSize |Format-Volume

Ein Volume umbenennen
Set-Volume -DriveLetter W -NewFileSystemLabel "Data1"

Sonntag, 18. November 2018

Windows Image

Die Windows Installation (so wie ist) auf eine neue Festplatte ziehen - geht auch mit Boardmitteln.

Achtung! Diese Anleitung enthält Befehle, die bei falscher Anwendung Daten löschen können! Bitte unbedingt zwischen Copy & Paste auch den Kopf verwenden!

Was wird benötigt?
  • Ein Startmedium mit Windows PE: USB Stick oder CD (ISO)
  • Einen genügend großen Zwischenspeicher: USB Festplatte oder Netzlaufwerk,
  • ein paar Tools von Windows und
  • gewusst wie.

Ablauf

  1. Den Computer mit Windows PE starten (Man kann Quell und Ziel Laufwerk anschließen)
  2. Die Quell Laufwerk mit dism in ein image "aufzeichnen".
  3. Optional: Umbauen und wieder mit WinPE starten.
  4. Das Ziel Laufwerk partitionieren.
  5. Das Image auf das Ziel Laufwerk "anwenden".
  6. Startsystem wieder herstellen
Es ist also ziemlich simpel, die Befehle und Schritte sind im Prinzip im zweiten Link beschrieben. Ich will dies hier aber mit etwas Erfahrungen und Tipps ausbauen.

Windows PE

Es gibt Windows PE in 32 und 64 bit Version. Obwohl WinPE mit einem einfachen CMD Fenster startet, kann man von dort die meisten (portablen) Programme und Tools einfach starten. Aber - die 64 bit Version hat kein 32 bit Subsystem, mann kann also immer nur Programme der gleichen Architektur starten!
Ich habe darauf verzichtet WinPE aufwendig anzupassen. Ich habe einfach ein paar Scripte erstellt, einen Teil habe ich auf dem USB Stick bereitgestellt und Andere einfach auf einem zentralen Netzwerklaufwerk abgelegt.
Es genügt ein kleiner USB2 Stick, WinPE ist nicht groß (ca. 300 MB ohne Anpassung, ca 450 MB mit Powershell) und die Ladezeiten sind nicht sehr lang.
An meinem System lagen die Zeiten zwischen 25 und 30 sec, der Unterschied USB2 und USB3 sowie Powershell ging quasi in der "Nachdenkzeit" des Reset und BIOS unter.

Damit man mit der Tastatur klar kommt braucht man ein Startscript.
wpeutil SetKeyboardLayout 0407:00000407
start cmd
Die Tastatur ist sonst mit englischem Layout und die Änderung mit SetKeyboardLayout wirkt erst im neuen Fenster.
Um eine Netzwerkverbindung herzustellen ist dies sinnvoll. Dieses Zeile enthält auch einen Trick:
Hat man ein Linux SMB Share, welches mit anonymen Zugriff konfiguriert ist, kann sich WinPE nicht ohne Konto verbinden (anonymer Zugriff ist auch in Windows seit Version 10 1709 abgeschaltet).
Bei WinPE hilft es einfach einen Benutzer anzugeben den es nicht gibt: net use ist zufrieden und Linux ignoriert es.
net use * \\server1\Shares /user:willi password 
net use * \\server1\Sicherung  
Natürlich kann man die paar Zeilen auch in ein CMD Script packen und auf dem USB Stick bereitstellen.
Die beiden net use Befehle erzeugen ein Laufwerk z: und y: - das Laufwerk x: ist das Systemlaufwerk von WinPE.

Image aufzeichnen

Zunächst  muss man ermitteln, welche Laufwerksbuchstaben WinPE für die eingehängten Festplatten vergeben hat. Dazu gibt es viele Möglichkeiten, ziemlich eindeutig und gezielt funktioniert es mit diskpart. Am Prompt: DISKPART> gibt man folgende Reihenfolge ein:
list disk
sel disk 0
detail disk
Der erste Befehl zeigt alle eingebauten Festplatten.
Der zweite Befehl selektiert die Quellfestplatte, die Ziffer ist also entsprechend anzupassen.
Der dritte Befehl zeigt alle Details der gewählten Disk inklusive der dort enthaltenen Volumes und Laufwerks Buchstaben.
Tipp: Auch gleich die Nummer für das Zielaufwerk merken, die wird im nächsten Abschnitt benötigt.
Ein Beispiel zum Aufzeichnen des Images von Laufwerk C
dism /capture-image /imagefile:y:\wim\backup.wim /capturedir:c: /name:C-WinOS
Man kann recht einfach ein Beispielscript im Laufwerk z: vorbereiten und mit notepad (läuft unter WinPE) anpassen und dann ausführen. So spart man sich viel Tipparbeit. Die meiste Zeit wird die Bandbreite zum Ziellaufwerk sehr gut genutzt, die Geschwindigkeit für die Aufzeichnung hängt also vom Umfang, Geschwindigkeit Quelle und Netzlaufwerk (oder USB Laufwerk) ab.

Ziel Laufwerk partitionieren

Das Ziellaufwerk wird in der Regel neu partitioniert und kann dabei auch völlig neu strukturiert werden! Beispiel:
War das Quellsystem eine MBR Partition kann die Ziel Platte ein GPT System werden (falls der PC UEFI unterstützt).
Achtung! Wird jetzt die falsche Disk verwendet, werden ohne Nachfrage Daten gelöscht!
Die Empfehlung von Microsoft (man findet Unterschiedliche) für eine GPT Partitionsstruktur aus meinem zweiten Link sieht als diskpart Script wie folgt aus:
rem == CreatePartitions-UEFI.txt ==
rem == These commands are used with DiskPart to
rem    create four partitions
rem    for a UEFI/GPT-based PC.
rem    Adjust the partition sizes to fill the drive
rem    as necessary. ==
select disk 0
clean
convert gpt
rem == 1. System partition =========================
create partition efi size=100
rem    ** NOTE: For Advanced Format 4Kn drives,
rem               change this value to size = 260 ** 
format quick fs=fat32 label="System"
assign letter="S"
rem == 2. Microsoft Reserved (MSR) partition =======
create partition msr size=16
rem == 3. Windows partition ========================
rem ==    a. Create the Windows partition ==========
create partition primary 
rem ==    b. Create space for the recovery tools ===
shrink minimum=500
rem       ** NOTE: Update this size to match the
rem                size of the recovery tools 
rem                (winre.wim)                    **
rem ==    c. Prepare the Windows partition ========= 
format quick fs=ntfs label="Windows"
assign letter="W"
rem === 4. Recovery tools partition ================
create partition primary
format quick fs=ntfs label="Recovery tools"
assign letter="R"
set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"
gpt attributes=0x8000000000000001
list volume
exit
Bevor jetzt das Script mit dieser Befehlszeile angewendet wird, ist wie im vorherigen Abschnitt bitte genau zu prüfen auf welche Disk mit welcher Nummer das Ziel geschrieben werden soll! Das Script kann man einfach mit Notepad ändern und speichern.
DiskPart /s Z:\Scripts\CreatePartitions-UEFI.txt

Image anwenden

Für den jetzigen Schritt sind eigentlich alle Vorbereitungen getroffen und man kann direkt loslegen. Ich habe hier das Script zur Anwendung mal etwas vor dem "Doppelklick" entschärft.
@if "%1" == "" goto usage 
dism /Apply-Image /ImageFile:%1 /Index:1 /ApplyDir:%2
goto end
:usage
@echo Nichts passiert: Parameter fehlen, bitte so verwenden
@echo apply y:\wim\backup.wim W:\
:end

Startsystem erzeugen

Jetzt muss man mindestens noch die neue Platte "start-fähig" machen. Dazu genügt in der Regel ein Befehl. Wieder als ungefährliches Script:
@if "%1" == "" goto usage 
bcdboot %1 /s %2
goto end
:usage
@echo Nichts passiert: Parameter fehlen, bitte so verwenden
@echo makeboot W:\Windows S:
:end
Jetzt kann man mit dem Befehl
wpeutil shutdown
das System herunterfahren, den USB Stick und die Quellplatte entfernen und das System sollte sich mit der neuen Platte einfach starten lassen.

Recovery System erzeugen

Eigentlich fehlt noch etwas, das Recovery System. Vielleicht war es auf der Quellplatte schon nicht vorhanden, aber bei einer Windows Installation gehört es dazu. Solange die Laufwerke aus Schritt 4 noch vorhanden sind, sollte dieses Script das Recovery System einrichten.
@if "%1" == "" goto usage 
md %1
copy %2\System32\Recovery\winre.wim %1\winre.wim
%2\System32\reagentc /setreimage /path %1 /target %2
goto end
:usage
@echo MakeRecovery R:\Recovery\WindowsRE W:\Windows
:end
Man kann das Recovery System auch später im laufenden System einrichten.

Windows PE bekommen

Windows PE kann man aus unterschiedlichsten Quellen verwenden und "bauen". Ich habe einfach das aktuelle Windows ADK heruntergeladen, man braucht die Deployment Tools und das Windows PE AddOn (Details im ersten Link)
Das "Kommandocenter" für die Umgebung öffnet man nach der Installation mit "Windows + Bereit (tippen)" + rechte Maustaste "Als Administrator ausführen".
Hier braucht man nur zwei Befehle, Laufwerk mit 600-800 MB freiem Platz und einen freien USB Stick. Die Laufwerksbuchstaben und Pfade müssen angepasst  werden.
Achtung, der USB Stick wird (nach Nachfrage) neu formatiert!
copype amd64 D:\WinPE_amd64
MakeWinPEMedia /UFD D:\WinPE_amd64 Q:
Man kann natürlich auch ein ISO File erstellen, z.B. für Test in Hyper-V.
MakeWinPEMedia /ISO D:\WinPE_amd64 D:\ISO\WinPE_amd64.iso

Anmerkung für Dual Boot x86 und amd64:
Ich hatte hier schon mal einen dualen Windows Setup Stick gebaut. Ob die Anleitung mit aktuellem ADK funktioniert habe ich nicht getestet.

Probleme lösen

Ich hatte unklare, nicht reproduzierbare Probleme mit der 32 bit Version von WinPE und dism /Capture-Image. Ich habe daraufhin konsequent alles mit der 64 bit Version getestet. Ob die 32 bit Version ein generelles Problem hat kann ich nicht sagen.
Abbruch von dism
Beim Prozess "Aufzeichnen" hatte ich neben zu wenig Platz auf dem Netzlaufwerk Probleme die mit spartanischen Fehlermeldungen von dism abgebrochen wurden. dism schreibt aber normal eine Logdatei nach \Windows\Logs\DISM.
War der Vorgang erfolgreich sollte man die übrigens löschen, sonst ist sie beim nächsten Mal und einer Fehlersuche unnötig groß.
Durch die Hinweise im Log konnte ich die Fälle lösen.
  • chkdsk /f half beim Fehler mit dem Volumebit auf dem Laufwerk.
  • Löschen einer Datei im User Ordner \OneDrive half, weil dism offenbar eine "kaputte" Datei erst aus der Cloud komplett synchronisieren wollte.
  • Ein kleine verdächtige Datei im Browsercache des Users wurde vom Virenscanner erkannt. Ich hatte zu dem Zeitpunkt nicht WinPE gestartet sondern das normale System laufen und die Platte zusätzlich angesteckt.
Ich war durchaus froh über diese "Fehler" die sonst mit auf die neue Platte gewandert wären.
Der Virenscanner im laufenden System wird den Aufzeichnungsprozess verlangsamen! Aber man sollte durchaus erstmal das System auf der originalen Platte gründlich scannen!

Neue Platte startet nicht
Trotz identischem Vorgehen, hatte ich ein UEFI System, welches zunächst nicht starten wollte. Nachdem ich etwas konfus probiert und untersucht habe, war die Lösung ziemlich einfach:
  • Einfach solange in den Fehler starten (3 mal) bis Windows von sich aus in die Startoptionen startet. 
  • Dort einmal die Option: "Abgesichert mit Kommando Fenster" auswählen, anmelden und dann neu starten. Windows repariert so offenbar sein Startsystem automatisch.

Recovery System funktioniert nicht
Die obigen Befehle funktionieren scheinbar alle einwandfrei, aber im fertigen System meldet der Befehl
reagentc /info
das Recovery System als nicht verfügbar.
Der Befehl zum Aktivieren bringt eine Fehlermeldung
reagentc /enable
REAGENTC.EXE: Startkonfigurationsdaten können nicht aktualisiert werden.
Nach langer erfolgloser Suche habe ich einfach das probiert:
del c:\Windows\System32\Recovery\ReAgent.xml
Danach funktionierte /enable einwandfrei.

Zum Schluss

Ich bin oft für spartanische Lösungen, mit dem was gerade da ist. Windows hat seit langem schon alles an Board um eine Systeminstallation (die Systempartition) zu sichern und auf eine neue Festplatte zu bringen. Man braucht keine "bunten" Tools, die im Zweifelsfall auch bloß Dinge machen die man nicht versteht und die Fehlerhaft sein können.
Was ich hier aufgeschrieben habe funktioniert Schritt für Schritt "zu Fuß" und wenn man will mit Batch- oder Powershellscripts. Die c't hat vor Jahren schon mal ein Script für dism & Co vorgestellt welches noch weiter geht. Es erstellt eine Sicherung, die sich mit Setup wieder installieren lässt. (WIMage)
Diese Methode hat gegenüber dem üblicherweise verwendeten sektorbasiertem 1:1 Image durchaus Vorteile:
  • Dateisystem wird quasi auf Fehler überprüft
  • Quell und Zielsystem können unterschiedlich sein:
    • BIOS / UEFI
    • Partitionsgröße - man muss z.B. nicht vorher zeitaufwendig defragmentieren und verkleinern um ein System von einer großen Partition auf eine kleiner SSD zu migrieren
    • Partitionsanordnung
  • man könnte Ordner aus dem Aufzeichnungsprozess ausschließen (WimScript.ini - [ExclusionList])
  • unterschiedliches Dateisystem - muss ich noch untersuchen?
  • Zielsystem ist anschließend erstmal defragmentiert.

Nützliche Tools für WinPE

Die Anleitung zur Integration von Powershell findet man im dritten Link. Die Startzeit vergrößert sich dadurch etwas. 
Ein aktueller OpenSource Dateimanager mit 32 und 64 bit: DoubleCommander  
Ansonsten laufen relativ viele OpenSource Programme ohne Probleme.

Wichtige Quellen

Microsoft: Boot to Windows PE
Microsoft Aufzeichnen und Anwenden von wim Images
Microsoft WinPE mit Powershell

Dienstag, 30. Oktober 2018

Dateiversionsverlauf oder?

... FileHistory - die Übersetzung von eindeutigen und meist kurzen englischen Begriffen endet oft in sehr kunstvollen Umschreibungen.

Windows Sicherung

Windows bietet dem Anwender eine Absicherung seines Systems in zwei Stufen:
Die eigene Dateien -> Mit Dateiversionsverlauf sichern - zu finden in Menü Einstellung/Sicherung.
Das System -> kann man "Wiederbeleben" durch Reset, Recovery, neues Setup.
Die beiden Dinge sind vom normalen Anwender halbwegs beherrschbar, zumindest die Einrichtung und dann braucht er sich eigentlich nicht mehr kümmern.
Der Insider kann auch noch mit dism ein Image seines gesamten Systemes ziehen.

Wiederherstellung

Allzu oft ist die Sicherung eine Einbahnstraße im Kopf: Meine Daten werden ja gesichert...
Aber was muss ich im Fehlerfall machen: Wie gehe ich mit einer Sicherung um? Wie komme ich an meine (alten) Daten?

Alte Version einer Datei wiederherstellen

Per Standard wird stündlich eine Sicherung der Benutzerdaten durchgeführt. Hat man eine Datei versehentlich geändert und sie wurde vor dieser Änderung gesichert (kann man auch manuell triggern) kann man sie einfach über rechte Maustaste und dem Kontextmenü  "Vorgängerversionen wiederherstellen" zurück holen.

Dateiversionsverlauf auf einem neuen PC / nach einer Neuinstallation wieder herstellen

Sich durch die Menüs von Windows 10 derzeit hindurchzufitzen ist echt nicht einfach: Neue Menüs und alte (Systemsteuerung) geben sich scheinbar die Hand und existieren unter unterschiedlichen Begriffen scheinbar auch parallel.

Bildlich gesprochen passiert folgendes:
  • Die Sicherung erfolgt auf einem Extra Laufwerk, anders lässt es Windows nicht zu!
    • zweite interne Festplatte
    • USB Festplatte
    • Netzlaufwerk
    • Virtuelle Platte auf einem anderen Laufwerk
  • Man hat nach einer Neuinstallation das alte Sicherungslaufwerk zur Hand und macht es im System einfach als Laufwerk verfügbar - einstecken oder wie auch immer.
    • Jetzt wird es echt spannend, aktuell in der Version Windows 10 1803 findet man den notwendigen Punkt unter Systemsteuerung\System und Sicherheit\Dateiversionsverlauf -  ein "altes" Systemsteuerungsfenster und dort dann Laufwerk auswählen. Man kommt irgendwie auch über die neuen Menüs und Sicherungseinstellung\weiter Sicherungsoptionen und dann ganz unten "Siehe erweiterte Einstellungen" dorthin. 
    • In dem Moment wo man das Laufwerk markiert, öffnet sich eine Auswahlbox mit den vorhanden Dateiversionsverläufen (mit Benutzer- und Computername)
    • Durch Auswahl des Benutzers wird das Laufwerk aktiviert.
    • Nach kurzer Zeit ist die alte Sicherung analysiert und man kann seine alten Dateien wiederherstellen (Menüpunkt links persönliche Dateien wiederherstellen).
    • Ob sich der neuen Benutzername und der Alte unterscheiden spielt keine Rolle, Windows stellt den/die alten Benutzernamen in der Sicherung fest und fragt diese ab. Der alte Benutzer- und Computername wird danach durch den Neuen ersetzt.
Ich habe versucht den aktuellen Stand in Bildern zu dokumentieren.
Will man das alte Laufwerk so als Sicherungslaufwerk beibehalten ist alles in Ordnung. Ist es nur ein temporäres Laufwerk gewesen, kann man die alten Dateien nicht nur einmalig wieder herstellen, man kann auch die Historie auf das neue Sicherungslaufwerk kopieren.

  • Im letzten Menü noch einmal auf Laufwerk auswählen klicken.
  • In dem Moment wo man ein neues Laufwerk auswählt, wird man gefragt ob man die vorhandenen Dateien ebenfalls verschieben will.
  • Ein Datei verschieben Dialog öffnet sich automatisch nach kurzer Zeit.

Umzug von Benutzerdaten

Der Umzug von Benutzerdaten bei einer Neuinstallation (z.B. alten PC von 32 bit Version auf 64 bit Umstellen) erscheint mir mit dieser Methode relativ leicht, auf alle Fälle besser als in alten Benutzerverzeichnissen mit Rechte Problemen zu kämpfen.
  • USB Laufwerk anstecken
  • Sicherung einrichten und mit dem Benutzer kontrollieren ob alle notwendigen Pfade einbezogen sind! 
  • Vorhandene Sicherung bei Bedarf auf das neue Laufwerk umstellen (wird automatisch kopiert)
  • Sicherung manuell triggern und kontrollieren, USB Laufwerk danach auswerfen.
  • PC neu installieren
  • USB Laufwerk anstecken und wie oben beschrieben die Daten wiederherstellen.

Montag, 15. Oktober 2018

Powershell und Windows Update

Der Hyper-V Server hat ein Management Interface welches aus mehreren Scripts besteht:
Auszug

  • sconfig.cmd
    • sconfig.vbs
    • WUA_SearchDownloadInstall.vbs
    • ...
Die VBS-Scripts liegen %systemroot%\system32\en-us\ (bzw. anderen Sprachen).
Gesteuert wird das Windows Update über die Windows Update API. Die Doku ist schwerer Stoff, ich habe mir von verschiedenen Seiten und aus dem oben erwähnten Script ein paar Dinge zusammen gelesen und will es hier kurz notieren.
Meine Scripts in dem Artikel sind alle nicht perfekt, sondern eher als Lösungsansatz gedacht. Damit kann man z.B. beim Hyper-V Server etwas mehr tun als nur mit der sconfig "Oberfläche".

Die Schritte etwas im Detail

Zuerst muss man festlegen welche Updates man suchen will (ein paar Details):
$Criteria = "IsInstalled=0 and Type='Software'"
$Criteria = "IsInstalled=0 and Type='Driver'"
Dann werden verschiedene Com Objecte eingerichtet und z.B. die Titel der verfügbaren Updates angezeigt.
$Searcher = New-Object -ComObject Microsoft.Update.Searcher
$SearchResult = $Searcher.Search($Criteria).Updates
# Titel anzeigen
$SearchResult|select Title
Powershell bietet an der Stelle etwas mehr Komfort zur Suche und Auswahl als die eigentliche API. Deshalb füge ich hier bewusst den Neubau der Update Collection ein. Eigentlich ist diese jetzt schon in $SearchResult enthalten.
$updatesToDownload = New-Object -ComObject Microsoft.Update.UpdateColl
$SearchResult|%{ if($_.Title -match "KB2267602") {$updatesToDownload.Add($_)}}
$updatesToDownload|select Title
Danach werden die gewünschten Updates heruntergeladen.
$Session = New-Object -ComObject Microsoft.Update.Session
$Downloader = $Session.CreateUpdateDownloader()
$Downloader.Updates = $updatesToDownload
$Downloader.Download()
Um es ganz korrekt zu machen, kann man noch eine Collection der wirklich heruntergeladenen Updates erstellen ...
$updatesToInstall = New-Object -ComObject Microsoft.Update.UpdateColl
$SearchResult|%{ if($_.isDownloaded) {$updatesToInstall.Add($_)}}
... um dann die Updates zu installieren.
$Installer = New-Object -ComObject Microsoft.Update.Installer
$Installer.Updates = $updatesToInstall
$Result = $Installer.Install()
Als Abschluss wird bei Bedarf ein Neustart ausgeführt.
If ($Result.rebootRequired) { shutdown.exe /t 0 /r }

Komplett in einem Script

Das Ganze als ein Script mit zwei Parametern am Anfang:
Den Type entweder weglassen (Alle suchen) oder auf Software oder Driver setzen.
Bei $compare kann man entweder nur einen "*" für "Alles" setzen oder wie im Beispiel den Begriff mit Wildcards für ein bestimmtes Update.
# Parameter
$Criteria = "IsInstalled=0 and Type='Software'"
$compare= "*" # "*KB2267602*"
# Suche notwendige Updates 
$Searcher = New-Object -ComObject Microsoft.Update.Searcher
$SearchResult = $Searcher.Search($Criteria).Updates
# Zusammenstellung Download Collection
$updatesToDownload = New-Object -ComObject Microsoft.Update.UpdateColl
$SearchResult|%{ if( $_.Title -like $compare ) {$updatesToDownload.Add($_)}}
#$updatesToDownload|select Title
#$updatesToDownload.Count
# Download Updates 
$Session = New-Object -ComObject Microsoft.Update.Session
$Downloader = $Session.CreateUpdateDownloader()
$Downloader.Updates = $updatesToDownload
if ($updatesToDownload.Count -gt 0) {$Downloader.Download()}
# Zusammenstellung Install Collection
$updatesToInstall = New-Object -ComObject Microsoft.Update.UpdateColl
$SearchResult|%{ if($_.isDownloaded) {$updatesToInstall.Add($_)}}
# Install Updates 
$Installer = New-Object -ComObject Microsoft.Update.Installer
$Installer.Updates = $updatesToInstall
$Result = $Installer.Install()
# Neustart wenn gefordert
If ($Result.rebootRequired) { shutdown.exe /t 0 /r }

Was lief bisher?

Man kann sich auch die gesamte Historie anzeigen lassen:
Wann wurde welches Update installiert? Die Zeiten werden in UTC angezeigt!
# Historie abfragen
$session = new-object -comobject Microsoft.Update.Session
$searcher = $session.CreateUpdateSearcher()
$history = $searcher.QueryHistory(0, $searcher.GetTotalHistoryCount())
$history |select Date,Title |more
Leider liefert das Ergebnis am Ende immer viele Leerzeilen.

Mehr Komfort

Die Powershell Gallery halt ein umfangreiches Scriptmodul "PSWindowsUpdate" bereit mit dem der Windows Update Service wohl sehr komfortabel behandelt werden kann. Ich habe mir das zunächst nur kurz angeschaut. Um das Script aus der PSGallery zuinstallieren muss man ein paar Vorbereitungen treffen, das ist hier ganz gut beschrieben.

Noch ein Special

In $SearchResult stehen auf den zweiten Blick noch mehr Informationen!
So erzeugt man eine Liste mit Detailinformationen, z.B. mit der UpdateID oder dem Download Link.
#$Criteria = “IsInstalled=0 and Type=’Software'”
$Searcher = New-Object -ComObject Microsoft.Update.Searcher
$SearchResult = $Searcher.Search($Criteria).Updates

foreach ($update in $SearchResult) {
  $title = $update.Title
  $guid = $update.Identity.UpdateId
  $title
  $guid
  $bundles = $update.BundledUpdates
     foreach($bundledUpdate in $bundles) {
        foreach($content in $bundledUpdate.DownloadContents) {
           if (!$content.IsDeltaCompressedContent) {
              $url = $content.DownloadUrl
              $url
            }
        }
    }
}

Mit der so ermittelten UpdateID wäre es auch möglich die Suche nach speziellen Paketen auszuführen:
$Criteria = "IsInstalled=0 and UpdateID='a3fafd03-b687-49e6-9df9-3963057ce376'"

Es gibt mit CIM und "PowerShell remoting session" auch einen Ansatz die VMs zentral zu patchen.

Sonntag, 16. September 2018

Virtuelle Maschinen erzeugen und administrieren mit Powershell

Kennt Ihr das? Hilfe Texte stimmen nicht, Beschreibungen funktionieren nicht? Das Thema Powershell und VM ist auch damit ganz schlimm gebeutelt.

VM anlegen

Man kann eine leere VM anlegen, das ergibt ein relativ mageres Ergebnis:
1GB RAM, Generation 1, keine Disk.
New-VM –Name 'Test1'
Will man in etwa das Ergebnis, was der Hyper-V Manager Wizard nur mit der Eingabe "Name" erzeugt, muss man es so machen:
$vm = 'Test2'
New-VM –Name $vm –NewVHDPath "$vm.vhdx" -NewVHDSizeBytes 127GB
Bisher haben wir VMs der Generation 1 erzeugt.
Viel mehr als im nächsten Befehl, kann man bei New-VM gar nicht angeben.
$vm = 'Test3'
New-VM –Name $vm -Generation 2 –MemoryStartupBytes 4GB –NewVHDPath "$vm.vhdx" -NewVHDSizeBytes 32GB
Alles weitere muss man mit Set-VM* Befehlen machen.

Startmedien - DVD Laufwerk

Das wichtigste dabei (und nicht ganz einfach wie man denkt) wäre ja die Angabe von Start- bzw. Installationsmedien. Kaum noch existieren wirklich optische Laufwerke, das Handling am Hyper-V Server wäre extrem unpraktisch. Man kann ohne weiteres ISO oder VHD Images einbinden, aber nur wenn sie lokal auf dem Hyper-V Server liegen. Microsoft hat eine sehr eigenartige Sicherheit eingebaut, wenn es um den Zugriff auf ein Image geht, welches auf einem Server liegt.
Auch die hier beschriebenen Wege funktionieren bei mir nur in der manuellen Art für VMs der Generation 1!

Mein Resumé: Startmedien gehen nur lokal

Mag sein es funktioniert in AD Umgebungen, ich habe es in einer Workgroup versucht, und wirklich viel experimentiert, ich bekomme es nicht hin! Man kann auf dem Hyper-V Host ein Image mounten und sich einen Überblick von den Laufwerksbuchstaben ausgeben lassen.
Mount-DiskImage -ImagePath \\omv1\shares\ISO\de_windows_7_All_with_sp1_x64_.iso
Get-Volume|? DriveType -eq CD-ROM

Für VMs der Generation 1 kann man nun im Hyper-V Manager das physische Laufwerk auswählen und zuweisen. (Mit Set-VMDvdDrive kann man nur echte DVD Laufwerke zuweisen)

Bei VMs der Generation 2 kann man nur mit lokalen ISO Images arbeiten!
Mann muss zunächst ein DVD Laufwerk hinzufügen.
Add-VMDvdDrive -VMName $vm -Path D:\ISO\Name.iso
Mit Set-VMDvdDrive kann man lokale ISO Images zuweisen und ändern.

Konfiguration Netzwerk, Bootreihenfolge und Prozessor

Damit der Startvorgang nicht am PXE Boot "verhungert" sollte man noch die Boot Reihenfolge festlegen
$VMDVD=Get-VMDvdDrive -VMName $vm
Set-VMFirmware -VMName $vm -FirstBootDevice $VMDVD
Oder man legt die Reihenfolge neu fest, die neue vhdx Datei kann sowieso nicht booten, er sollte in dem Fall beim ersten Mal von der DVD starten
$VMHDD=Get-VMHardDiskDrive -VMName $vm
Set-VMFirmware -VMName $vm -BootOrder $VMHDD, $VMDVD
Will man den (einzigen) Netzwerk Adapter noch mit dem (einzigen) virtuellen, externen Switch verbinden, kann man das so machen
Connect-VMNetworkAdapter -VMName $vm -SwitchName (Get-VMSwitch|? Switchtype -eq External).Name
Während wir den mindest RAM bei der Einrichtung festgelegt haben, hat die VM bisher nur einen Prozessor. Man kann so alle verfügbaren Prozessoren zuweisen
Set-VMProcessor -VMName $vm -Count (Get-VMHost).LogicalProcessorCount

Zusammenfassung

Hier ein Template/Script für eine neue VM, Der VM Name kann als Parameter übergeben werden oder wird abgefragt (Mandatory=$true).
In der ersten und zweiten Zeile werden alle Parameter gesetzt. Ich habe deshalb auf übermäßig viele Variablen verzichtet.
<#
.SYNOPSIS 
    Das Script erstellt eine neue virtuelle Maschine
.DESCRIPTION 
    Das Script erstellt eine neue virtuelle Maschine
.EXAMPLE 
    CreateVM Name 
.NOTES 
    Generation 2, 32 GB HDD, 4 GB RAM, alle Prozessoren
#>
#region Params
param(
    [Parameter(Position=0, Mandatory=$true,HelpMessage="Name der VM",ValueFromPipeline=$false)]
    [System.String]
    $vm=""
)
#endregion 

New-VM –Name $vm -Generation 2 –MemoryStartupBytes 4GB –NewVHDPath "$vm.vhdx" -NewVHDSizeBytes 32GB
Add-VMDvdDrive -VMName $vm 
$VMDVD=Get-VMDvdDrive -VMName $vm
$VMHDD=Get-VMHardDiskDrive -VMName $vm
Set-VMFirmware -VMName $vm -BootOrder $VMHDD, $VMDVD
Connect-VMNetworkAdapter -VMName $vm -SwitchName (Get-VMSwitch|? Switchtype -eq External).Name
Set-VMProcessor -VMName $vm -Count (Get-VMHost).LogicalProcessorCount

Für die DVD habe ich mal noch einen "Würgaround" gefunden.
Dieser Mehrzeiler schaut nach, ob die ISO Datei im lokalen Pfad schon existiert und kopiert diese ansonsten dahin.
$DVD = "name.iso"
$Ziel = 'D:\ISO\'
$Quelle = '\\omv1\shares\iso\'
$Diff = Compare-Object -ReferenceObject (gci -Path $Ziel) -DifferenceObject (gci -Path $Quelle)
Copy-Item -Path (($Diff|? InputObject -like $DVD).InputObject).FullName -Destination $Ziel
# DVD einlegen
Set-VMDvdDrive -VMName $vm -Path $Ziel$DVD

Damit das lokale Verzeichnis nicht vermüllt, kann man ja von Zeit zu Zeit die ISOs entfernen, die nicht mehr eingebunden sind.
$Ziel = 'D:\ISO\'
$InUse = (Get-VMDvdDrive -VMName *|? Path -like $Ziel*).Path
$Exist = (gci -Path $Ziel).Fullname
$Diff = Compare-Object -ReferenceObject $Exist -DifferenceObject $InUse
Remove-Item ($Diff|? SideIndicator -eq '<=').InputObject -confirm

Aufräumen

Dieser Einzeiler löscht alle VMs und deren virtuelle HDDs, deren Name mit Test beginnt.
Jeder Löschvorgang verlangt nach Bestätigung! Bitte genau hinschauen, ich übernehme keine Verantwortung!
Ich hoffe, dass ich in einem Jahr noch weiß, wie dieser Einzeiler funktioniert.
% ist das Kürzel für ForEach, $_ Ist das aktuelle Element der Schleife
-process enthält den Ausführungsteil(, beide Befehlsteile werden in getrennten Schleifen abgearbeitet.)
-InputObject die Eingabe
% -process {Remove-Item (Get-VMHardDiskDrive -VMName $_.name).Path -Confirm ; Remove-VM -VMName $_.name} -inputobject (Get-VM -VMName Test*)

Informationen

Man kann sich relativ schnell einen Überblick über die Cmdlets verschaffen und detaillierte Hilfe abrufen. (Leider stimmt auch in den Hilfetexten nicht alles)
Get-Help Hyper-V
Get-Help Set-VM*

Mittwoch, 5. September 2018

Storage Pool auf dem Hyper-V Server verwalten

Wie bekommt man einen gespiegeltes HDD System, welches unter Windows Server 2012 als Storage Pool eingerichtet war, wieder online?

Ein paar Befehle für die  Analyse des Storage mit Powershell 

So bekommt man ein Bild der vorhandenen Disks:
get-disk

Number Friendly Name Serial Number                    HealthStatus         OperationalStatus      Total Size Partition
                                                                                                             Style
------ ------------- -------------                    ------------         -----------------      ---------- ----------
1      Samsung SS... S1DBNSAF878015M                  Healthy              Online                  232.89 GB GPT
0      Samsung SS... S21PNSAG155972R                  Healthy              Online                  232.89 GB GPT
6      VD1           {05bf1a4e-44d2-11e5-80d3-7824... Healthy              Offline                   1.82 TB GPT
5      VD2           {dcdf1498-41bd-11e5-80cf-7824... Healthy              Offline                    930 GB GPT
7      TOSHIBA Ex...            92N5P3KXT             Healthy              Online                  931.51 GB MBR
Zwei Platten sind Offline, die Disks 2,3 und 4 "fehlen".

Die Abfrage der Virtuellen Disk ergibt folgendes Bild:
get-virtualdisk

FriendlyName ResiliencySettingName OperationalStatus HealthStatus IsManualAttach    Size
------------ --------------------- ----------------- ------------ --------------    ----
VD1          Mirror                OK                Healthy      False          1.82 TB
VD2          Simple                OK                Healthy      False           930 GB
Obwohl die eigentlichen Laufwerke im Storage Pool ausgeblendet werden, kann man sich die echten Laufwerke anzeigen lassen:
Get-physicaldisk

FriendlyName              SerialNumber    CanPool OperationalStatus HealthStatus Usage            Size
------------              ------------    ------- ----------------- ------------ -----            ----
Samsung SSD 840 EVO 250GB S1DBNSAF878015M True    OK                Healthy      Auto-Select 232.89 GB
WDC WD2003FYPS-27Y2B0     WD-WCAVY7115101 False   OK                Healthy      Auto-Select   1.82 TB
TOSHIBA External USB 3.0  92N5P3KXT       False   OK                Healthy      Auto-Select 931.51 GB
Samsung SSD 850 EVO 250GB S21PNSAG155972R False   OK                Healthy      Auto-Select 232.89 GB
ST31000333AS              9TE24JDS        False   OK                Healthy      Auto-Select  931.5 GB
WDC WD2003FYPS-27Y2B0     WD-WCAVY5334150 False   OK                Healthy      Auto-Select   1.82 TB

Get-PhysicalDisk kann aber mehr, mit Hilfe von Format-List habe ich mal eine Ausgabe der Zuordnung zu den Hardware Ports gebastelt
Get-PhysicalDisk| Select-Object -Property DeviceId,PhysicalLocation,BusType,MediaType,FriendlyName,SerialNumber| Sort-Object -Property DeviceId |Format-Table

DeviceId PhysicalLocation                BusType MediaType   FriendlyName              SerialNumber
-------- ----------------                ------- ---------   ------------              ------------
0        Integrated : Adapter 0 : Port 1 SATA    SSD         Samsung SSD 850 EVO 250GB S21PNSAG155972R
1        Integrated : Adapter 1 : Port 0 SATA    SSD         Samsung SSD 840 EVO 250GB S1DBNSAF878015M
2        Integrated : Adapter 1 : Port 1 SATA    HDD         ST31000333AS              9TE24JDS
3        Integrated : Adapter 1 : Port 4 SATA    HDD         WDC WD2003FYPS-27Y2B0     WD-WCAVY5334150
4        Integrated : Adapter 1 : Port 5 SATA    HDD         WDC WD2003FYPS-27Y2B0     WD-WCAVY7115101
6        Integrated : Adapter 0 : Port 0 USB     Unspecified TOSHIBA External USB 3.0  92N5P3KXT

Den Zusammenhang zwischen Storage Pool, VirtualDisk und PhysicalDisk kann man auch anzeigen lassen. Dazu braucht man zunächst ein Object auf den Storage Pool
$stpool = (Get-StoragePool -FriendlyName "SP1")
Get-VirtualDisk -StoragePool $stpool

FriendlyName ResiliencySettingName OperationalStatus HealthStatus IsManualAttach    Size
------------ --------------------- ----------------- ------------ --------------    ----
VD1          Mirror                Degraded          Warning      False          1.82 TB

Get-PhysicalDisk -StoragePool $stpool

FriendlyName          SerialNumber    CanPool OperationalStatus HealthStatus Usage          Size
------------          ------------    ------- ----------------- ------------ -----          ----
WDC WD2003FYPS-27Y2B0 WD-WCAVY7115101 False   OK                Healthy      Retired     1.82 TB
WDC WD2003FYPS-27Y2B0 WD-WCAVY5334150 False   OK                Healthy      Auto-Select 1.82 TB
Für die Information auf welcher Disk das Volume des Systemlaufwerkes ist, habe ich diese Befehlskette gefunden.
Get-Disk (Get-Partition | ? isboot).DiskNumber

Storage Pool Disk wieder aktivieren

Ich möchte das VD1 wieder online ist, dies wird nämlich nicht automatisch getan, wenn der Storagepool an einen andere Maschine gehangen wird. Da VD1 eine (virtuelle) Disk ist, geht das mit dem set-disk Cmdlet
Set-Disk -Number 6 -IsOffline $False
Es gab bei mir die Situation, dass eine Disk nach dem Import von einer Physical Disk in eine vhdx Datei mit dem Hyper-V Manager sowohl offline als auch readonly war. Auch readonly lässt sich mit Set-Disk beheben.
Set-Disk -Number 5 -IsReadonly $False

Storage Pool Disk Fehler behandeln

Es gibt hier eine detaillierte Beschreibung wie man Fehler im Storage Pool behandeln kann. Hinbekommen habe ich das so aber noch nicht.
Versucht man in einem StoragePool, der 2 HDD enthält und darin eine Mirror VirtualDisk - eine HDD geordnet zu entfernen und diese danach durch eine Andere zu ersetzen, funktioniert das praktisch nicht. Obwohl man eine Platte als Retired markiert, lässt sie sich nicht entfernen. Man muss erst einen neue HDD zum StoragePool hinzufügen. Aber selbst das ist mir nicht richtig gelungen.
Dies habe ich versucht:
Set-PhysicalDisk -FriendlyName "WDC WD2003FYPS-27Y2B0" -SerialNumber WD-WCAVY7115101 -Usage Retired
Repair-VirtualDisk -FriendlyName "VD1"
# Zwei Varianten um das Objekt der richtigen PhysicalDisk zu bekommen
$PDToRemove = Get-PhysicalDisk | Where-Object { $_.Usage -eq 'Retired'}
$PDToRemove = Get-PhysicalDisk -FriendlyName "WDC WD2003FYPS-27Y2B0" -SerialNumber WD-WCAVY7115101
Remove-PhysicalDisk -PhysicalDisks $PDToRemove -StoragePoolFriendlyName "SP1"
Aber diese Aktion endet mit einem Fehler:
StorageWMI 48011,Remove-PhysicalDisk

Storage Pool entfernen

Erkenntnis: Storage Pool sieht gut aus, ist mir aber so undurchsichtig! Nach der kompletten Sicherung der Daten, habe ich einfach alles entfernt:
Set-Disk -Number 6 -IsOffline $true
Remove-VirtualDisk -FriendlyName "VD1"
Remove-StoragePool -FriendlyName "SP1"
Jetzt tauchen die Platten 3 + 4 wieder normal in der Ansicht auf (get-disk) und können normal verwendet werden. Um sie völlig leer zu machen verwendet man Clear-Disk
Clear-Disk -Number 3
Clear-Disk -Number 4
Get-Disk |Where-Object PartitionStyle –Eq "RAW" |Initialize-Disk 

Um eine neue Partition anzulegen, einen bestimmten Laufwerksbuchstaben zu vergeben und es gleich zu formatieren, kann man so vorgehen.
New-Partition -DiskNumber 3 -UseMaximumSize -DriveLetter S |Format-Volume