Feststellen welches Programm das Entfernen eines USB-Gerätes unter Windows verhindert

30 August 2017

Wenn man unter Windows USB Geräte abmeldet bzw. auswirft, kann es passieren, dass man mit dieser schönen Meldung beglückt wird:

—————————
Fehler beim Abdocken von "USB-Massenspeichergerät"
—————————
Das Gerät "USB-Massenspeichergerät" kann aufgrund eines unbekannten Fehlers nicht beendet werden. Entfernen Sie das Gerät nicht, solange es noch verwendet wird. Schließen Sie alle Programme, von denen das Gerät verwendet wird, und entfernen Sie es anschließend.
—————————
OK  
—————————

Unter Windows 7 sieht die Meldung etwas anders aus, ist aber genauso sinnlos:

—————————
Fehler beim Abdocken von "USB-Massenspeichergerät"
—————————
Dieses Gerät wird gerade verwendet. Schließen Sie alle Programme oder Fenster, die möglicherweise das Gerät verwenden, und wiederholen Sie den Vorgang.
—————————
OK  
—————————

Tja, “Unbekannte Fehler” sind des Benutzers liebste Fehler! Selbst heute in Zeiten von Windows 10 hat es Microsoft noch nicht geschafft diese Meldung mit mehr sinnvollen Informationen zu versehen und kommt immer noch so kryptisch wie zu Windows XP-Zeiten daher.

Aber dank Powershell kann der gequälte Anwender sich etwas mehr Informationen beschaffen. Zumindest bei Windows 7 bis Windows 10.

Get-WinEvent -ProviderName Microsoft-Windows-Kernel-PnP -MaxEvents 5 | where {$_.TimeCreated.Date -eq (Get-Date).Date -and $_.id -eq 225} | ft TimeCreated, Message –Wrap

Denn es werden in der Ereignisanzeige in Windows tiefergehende Informationen zum Vorgang gespeichert und damit kann man in der Regel den Grund für obige Fehlermeldung herausfinden. Man muss nur beim Microsoft-Windows-Kernel-PNP Provider nach der EventID 225 suchen.

In diesem Fall bekommt man z. B.:

TimeCreated         Message
———–         ——-
30.08.2017 17:33:47 Die Anwendung \Device\HarddiskVolume4\Windows\System32\cmd.exe mit der Prozess-ID                     21832 hat das Entfernen oder Auswerfen für das Gerät                     USB\VID_1E68&PID_0035\BB00000XXXXXXX beendet.

angezeigt. D. h. cmd.exe, also die Eingabeaufforderung, mit der ProzessID 21832 hatte Zugriff auf den USB-Stick und verhinderte dadurch das Auswerfen.

Advertisements

Konvertieren von virtuellen Festplattenimages in VHD oder VHDX zur Verwendung in Hyper-V oder Azure

25 August 2017

Man bekommt immer wieder Images von anderen virtuellen Maschinen die man in Hyper-V einbinden möchte. Ich hatte hier schon mal auf ein Utility von Microsoft verlinkt: https://newyear2006.wordpress.com/2012/09/04/konvertieren-von-virtuellen-vmware-maschinen-in-virtuelle-hyper-v-maschinen/. Leider klappt der Link nicht mehr. Auf der Suche nach einer Alternative bin ich auf ein Image-Utility von Qemu gestoßen, welches im Prinzip alle gängigen Formate konvertieren kann. Ein weiterer Vorteil ist, dass es als Open Source vorliegt.

Hier die Binary: https://cloudbase.it/qemu-img-windows/ und hier der Source in github: https://github.com/cloudbase/qemu/. Hier gibt es die ausführliche Hilfe: https://qemu.weilnetz.de/doc/qemu-doc.html#qemu_005fimg_005finvocation.

Es werden alle gängigen Formate unterstützt:

Image-Format (schreibbar) qemu-img Parameter
QCOW2 (KVM, Xen) qcow2
QEMU qcow
QED (KVM) qed
raw raw
VDI (VirtualBox) vdi
VHD (Hyper-V) vpc
VMDK (VMware) vmdk
Linux dm-crypt/cryptsetup luks

Neben obigen Formaten, welche gelesen und geschrieben werden können, gibt es noch ein paar, welche nur gelesen werden können:

Image-Format (nur lesbar) qemu-img Parameter
Bochs x86 PC emulator bochs
Linux Compressed Loop image cloop
Apple disk image dmg
Parallels disk image format parallels

Zu jedem Format gibt es noch spezielle Parameter, eine Beschreibung dazu findet man hier: https://qemu.weilnetz.de/doc/qemu-doc.html#disk_005fimages_005fformats.

Zur Anwendung kann man z. B.

qemu-img.exe convert source.img -O vhdx -o subformat=dynamic dest.vhdx

aufrufen.

Man kann auch den Parameter info verwenden um Informationen über ein Image zu erfahren.

C:\>qemu-img info test.img
image: test.img
file format: vhdx
virtual size: 127G (136365211648 bytes)
disk size: 4.0M
cluster_size: 33554432

Aber Vorsicht, man kann sich nicht immer voll auf die Infos verlassen, denn in Fällen wo unsinnige Daten verwendet werden, werden trotzdem Daten ausgegeben:

C:>echo "Nix da" > test.txt
C:>qemu-img info test.txt
image: test.txt
file format: raw
virtual size: 512 (512 bytes)
disk size: 11

Dabei muss der Hinweis auf das Dateiformat RAW nicht immer heißen, dass es kein gültiges Dateisystem ist! Es bedeutet vielmehr, dass qemu-img das Format nicht zuordnen kann.

Obwohl das Tool ziemlich mächtig ist, fehlt noch die Möglichkeit .GHO-Dateien von Symantec Ghost konvertieren zu können. Dazu gibt es über einen Umweg die Möglichkeit mittels Ghost in VMDK-Dateien und dann mittels qemu-img in VHDX zu konvertieren:

ghost64 -clone,mode=restore,src=source.gho,dst=image.vmdk -batch –sure
qemu-img.exe convert image.vmdk -O vhdx -o subformat=dynamic dest.vhdx

Damit wird Source.GHO in Dest.VHDX konvertiert.

Hier sind noch weitere Parameter für die Konvertierung bei Ghost beschrieben: https://www.symantec.com/connect/articles/converting-image-file-format-gho-vmdk-and-vmdk-gho.

Dank qemu-img hat man nun ein mächtiges Tool für Festplattenimages an der Hand.

REST Api Guidelines und OpenAPI

23 August 2017

Da heutzutage immer mehr Dienste direkt per HTTP-Aufrufe ansprechbar sind, haben alle großen Hersteller von Webdiensten mittlerweile API-Guidelines zur Erstellung dieser Dienste. Dies kann manchmal hilfreich sein, wenn es um kryptische Fehlermeldungen in Log-Dateien geht.

Hier der Verweis auf die API-Guidelines von Microsoft: https://github.com/Microsoft/api-guidelines/blob/vNext/Guidelines.md und von Google: https://cloud.google.com/apis/design/. Guidelines von Amazon konnte ich noch keine ausfindig machen, daher nur ein Link auf die aktuelle API: https://docs.aws.amazon.com/apigateway/api-reference/. Es gibt auch bereits Seiten, welche sich den Guidelines annehmen und diese wieder auf bestimmte Kriterien untersuchen zum besseren Vergleichen: http://apistylebook.com/design/guidelines/.

Ein Punkt der beim Datenaustausch zwischen verschiedenen APIs für Verwirrung sorgen könnte, sind Datumsfelder. Bei Google ist die Rede von RFC3339 (http://tools.ietf.org/html/rfc3339), bei Microsoft von ISO8601. Beide sind sich ähnlich allerdings unterscheiden sie sich in ein paar Kleinigkeiten, die im Zweifel wie immer alles durcheinander bringen können: https://stackoverflow.com/questions/522251/whats-the-difference-between-iso-8601-and-rfc-3339-date-formats.

Wo findet man nun diese Guidelines angewendet? Z. B. hier: https://cloud.google.com/apis/docs/overview oder beim Microsoft Graph: https://developer.microsoft.com/de-de/graph/docs/concepts/overview.

Wenn wir schon dabei sind, muss ich noch OpenAPI nennen, welches in Zukunft auch größere Bedeutung bekommen dürfte: https://www.openapis.org/specification/repo bzw. https://swagger.io/specification/. Als alter Powersheller sollte ich dabei noch gleich auf PSSwagger verweisen: https://github.com/PowerShell/PSSwagger. Mit PSSwagger lassen sich aus bestehenden OpenAPI-Definitionen automatisch Cmdlets erstellen. Wer es allgemeiner benötigt kann auch AutoRest von MS verwenden: https://github.com/Azure/autorest.

Wer wendet nun OpenAPIs bereits an? Na z. B. Google: https://cloud.google.com/endpoints/docs/openapi/. Auch Microsoft ist bei seinen Azure-Bemühungen mit dabei und hat sich klar zu OpenAPI bekannt: https://blogs.msdn.microsoft.com/apimanagement/2016/10/24/swaggers-success-gives-birth-to-openapi/.

Mit der aktuellen OpenAPI Spezifikation 3.0 dürfte nun der API-Zug endgültig den Bahnhof verlassen und schnell Fahrt aufnehmen…

Wenn ich irgendetwas zum Thema vergessen habe sollte, findet man es sicher hier. https://design.apievangelist.com/.

Systemrechte unter Windows erlangen

17 August 2017

Schon seit Ewigkeiten ist bekannt wie man Systemrechte unter Windows erlangen kann. Aber das Ziel ist es – wie immer – es mit möglichst wenig Aufwand und am besten mit Bordmitteln zu erlangen. Zwar bringt jedes aktuelle Windows mittlerweile ein Recoverypartition mit aber man hat nicht immer unbedingt Zugriff im Bootvorgang darauf (z. B. bei gehosteten Webservern).

Der übliche Vorgang ist das Kopieren von CMD.EXE auf UTILMAN.EXE, OSK.EXE oder SETHC.EXE. Dies gelingt normalerweise nur, wenn man von einer Recoverypartition oder von WinPE bzw. eben WinRE-CD gebootet hat. Aus diesem Grund verwenden viele Sysinternals PSExec: https://docs.microsoft.com/en-us/sysinternals/downloads/psexec.

Mit Adminrechten und etwas Gefummel in der Registry, bekommt man es auch mit Bordmitteln hin. Da es komfortabler ist dies per Script zu erledigen hier die nötigen Powershell-Anweisungen. Zuerst kopieren wir Utilman.exe und cmd.exe:

copy "C:\Windows\System32\utilman.exe" "C:\Windows\System32\utilman.exe.bak"
copy "C:\Windows\System32\cmd.exe" "C:\Windows\System32\cmd.exe.bak"

Nun benötigen wir den Zugriff auf den Registryschlüssel HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\ um dort die Werte PeningFileRenameOperations und AllowProtectedRenames zu setzen.

$smreg = "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\"

AllowProtectedRenames ist wichtig, sonst klappt der Vorgang nicht. Dies ist mal wieder einer von so vielen Registrywerten die nicht klar dokumentiert sind. Er wird im MSDN nur einmal im Zusammenhang mit VSS und der Wiederherstellung von Dateien der Windows File Protection genannt: https://msdn.microsoft.com/en-us/library/windows/desktop/aa381498(v=vs.85).aspx.

set-ItemProperty -Path $smreg -Type DWORD  -Name AllowProtectedRenames -Value 1

Jetzt muss man die zu kopierenden Dateien angeben. Da es aber kein klassischer Copy-Befehl sondern ein Move-Befehl ist, wo die Quelldatei nach dem Vorgang weg ist, verwenden wir die vorher erstellte Kopie von CMD.EXE. Dabei ist darauf zu achten, dass vor den Dateinamen noch eine spezielle Notation \??\ nötig ist. Leider gibt es keine Informationen darüber wann !\??! verwendet wird. Aber damit hat es immer funktioniert. Wichtig ist noch, dass es ein String-Array sein muss, damit die Werte in der Registry korrekt als REG_Multi_Sz gespeichert wird.

[string[]]$moveFiles= @("\??\C:\Windows\System32\cmd.exe.bak", "!\??\C:\Windows\System32\Utilman.exe")
set-ItemProperty -Path $smreg -Type MultiString -Name PendingFileRenameOperations -Value $moveFiles

Nun muss nur noch der Rechner neu gestartet werden und schon steht einem eine Eingabeaufforderung mit Systemrechten zur Verfügung. Bei Verwendung von UTILMAN.EXE klickt man am Anmeldebildschirm einfach auf den Kreis mit den zwei Pfeilen und der Einblendung “Erleichterte Bedienung”.

Um die Änderung rückgängig zu machen, könnte man nun dieses Script verwenden, welche einfach die Kopie von Utilman.exe zurückkopiert:

$smreg = "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\"
set-ItemProperty -Path $smreg -Type DWORD  -Name AllowProtectedRenames -Value 1
[string[]]$moveFiles= @("\??\C:\Windows\System32\Utilman.exe.bak", "!\??\C:\Windows\System32\Utilman.exe")
set-ItemProperty -Path $smreg -Type MultiString -Name PendingFileRenameOperations -Value $moveFiles

Es geht aber noch einfacher, auch im Falle eines Fehlers zwischendrin, bemüht man einfach die Windows File Protection und beauftragt diese mit der Wiederherstellung der betreffenden Dateien:

# Falls was schiefgeht:
SFC /SCANFILE=C:\Windows\System32\cmd.exe
SFC /SCANFILE=C:\Windows\System32\utilman.exe

Jetzt nochmal das ganze Script um oben beschriebene Funktionalität zu erreichen:

copy "C:\Windows\System32\utilman.exe" "C:\Windows\System32\utilman.exe.bak"
copy "C:\Windows\System32\cmd.exe" "C:\Windows\System32\cmd.exe.bak"
$smreg = "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\"
set-ItemProperty -Path $smreg -Type DWORD  -Name AllowProtectedRenames -Value 1
[string[]]$moveFiles= @("\??\C:\Windows\System32\cmd.exe.bak", "!\??\C:\Windows\System32\Utilman.exe")
set-ItemProperty -Path $smreg -Type MultiString -Name PendingFileRenameOperations -Value $moveFiles

Hier noch ein guter Blogartikel mit Registrybildern, wer es von Hand machen möchte: https://blog.cscholz.io/windows-72008-movefileex/. Eine weitere Methode anstatt PendingFileRenameOperations:
https://guyrleech.wordpress.com/2014/07/16/reasons-for-reboots-part-2-2/, einfachere Beschreibung: https://superuser.com/questions/1204878/how-can-i-tell-windows-to-overwrite-a-system-file-on-the-next-reboot.

Eine weitere Variante an Systemrechte zu gelangen ist hier beschrieben: https://newyear2006.wordpress.com/2013/01/01/eingabeaufforderung-mit-lokalen-systemdienst-rechten-unter-windows-8-und-windows-server-2012/.

Fehlermeldungen bei Exchange Postfachverschiebungen vermeiden

8 Juli 2017

Es kann Sinn machen beim Verschieben von Postfächern bei einer Exchange Server Migration größere Werte für Mailgrößen anzugeben, damit der Vorgang möglichst reibungslos läuft.

Hier sind die wesentlichen Punkte beschrieben: https://blogs.technet.microsoft.com/sbs/2008/10/28/how-do-i-change-message-size-limits-in-sbs-20082011-standard/

Die wichtigsten Aufrufe hier am Beispiel einer SBS Migration sind:

Set-TransportConfig -MaxReceiveSize 30MB -MaxSendSize 30MB

Set-Sendconnector "Windows SBS Internet Send yourservername" -MaxMessageSize 30MB

Set-ReceiveConnector -Identity "Windows SBS Internet Receive yourservername" -MaxMessageSize 30MB

Um die aktuellen Werte abzufragen verwendet man:

Get-TransportConfig| select max*size

Get-Receiveconnector  | fl Name,MaxMessagesize

Get-Sendconnector  | fl Name,MaxMessageSize

E-Mails mit SSL/TLS-Unterstützung mittels Powershell versenden

6 Juli 2017

Die Powershell Funktion Send-MailMessage https://msdn.microsoft.com/de-de/powershell/reference/5.1/microsoft.powershell.utility/send-mailmessage hat so ihre Tücken und hilft leider nicht, wenn es Probleme beim E-Mailversand gibt. Teilweise reagiert sie auch nicht wie erwartet. In der heutigen Zeit, vor allem wegen der TLS-Pflicht reagiert sie oft zickig in Bezug auf den UseSSL Parameter. Aus diesem Grund hier eine einfache Methode E-Mails mittels TLS per Powershell versenden zu können.

Wer Probleme beim E-Mailversand hat, der schaue sich https://newyear2006.wordpress.com/2015/08/23/probleme-mit-transportverschlsselung-zertifikaten-oder-passwrtern-bei-smtp-servern-mittels-powershell-berprfen/ an, dort wird im Detail beschrieben, wie dieses Skript funktioniert.

Gleichzeitig benutzt diese Routine nicht mehr die Test-NetConnection Funktion, da diese komischerweise nicht mehr den Socket öffnet. Statt dessen wird der benötigte TCP-Socket zu beginn manuell geöffnet. Der Rest sind nur Anpassungen für diese Änderung.

Man muss nur die im ersten Block aufgeführten Parameter eintragen und schon kann die Spammerei losgehen…

Hier der ganze Code:

$smtp = "smtp.web.de"
$smtpPort = 587
$user = "meinewebdeadresse@web.de"
# $userPass kann auch leer gesetzt werden, dann wird nachgefragt
$userPass = "meinPasswort"
$Subject = "Test Betreff"
$Body = "Test Body"
$from = "meinewebdeadresse@web.de"
$to = "meinewebdeadresse@web.de"
$xmailer = "Powershell v1"

$c=New-Object System.Net.Sockets.TcpClient
$c.Connect($smtp, $smtpPort)

# Antwort vom SMTP-Server holen und ausgeben
[byte[]]$buffer= @(0) * $c.Client.Available
$c.Client.Receive($buffer)
[System.Text.Encoding]::ASCII.GetString($buffer)

# Begrüßung durchführen
$buffer=[System.Text.Encoding]::ASCII.GetBytes("EHLO $Env:Computername`r`n")
$c.Client.Send($buffer)
Sleep -Seconds 1

# Antwort vom SMTP-Server holen
[byte[]]$buffer= @(0) * $c.Client.Available
$c.Client.Receive($buffer)
[System.Text.Encoding]::ASCII.GetString($buffer)

# STARTTLS-Anfrage starten
$buffer=[System.Text.Encoding]::ASCII.GetBytes("STARTTLS`r`n")
$c.Client.Send($buffer)
Sleep -Seconds 1

# Bei dieser Antwort sollte 220 rauskommen,
# sonst gibt es ein Problem
[byte[]]$buffer= @(0) * $c.Client.Available
$c.Client.Receive($buffer)
[System.Text.Encoding]::ASCII.GetString($buffer)

# für den weiteren Gang ist entscheidend, dass man einen Stream braucht
# vom Socket erhält man einen Stream, durch Weitergabe an NetworkStream-Klasse
$n=New-Object System.Net.Sockets.NetworkStream $c.Client

# über den Networkstream kann man nun SslStream aktivieren:
$ssl = New-Object System.Net.Security.SslStream $n, $true

# nun kann man den eigentlichen TLS Handshake starten, dazu muss nochmal der Host angegeben werden
$ssl.AuthenticateAsClient($smtp)

# für die weitere Kommunikation richtet man sich am besten zusätzliche Streams ein:
$reader = New-Object System.IO.StreamReader $ssl
$writer = New-Object System.IO.StreamWriter $ssl
$writer.AutoFlush = $true

# damit wird die weitere Kommunikation einfacher und das Spiel beginnt von vorne:
$writer.WriteLine("EHLO $Env:Computername")
while ($reader.Peek() -gt -1) {
    $reader.ReadLine()
}

$writer.WriteLine("AUTH LOGIN")
$reader.ReadLine()

[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("VXNlcm5hbWU6"))

If ($UserPass) {
  $Spass = ConvertTo-SecureString -String $UserPass -AsPlainText -Force
  $cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $User, $SPass } else {
  $cred = Get-Credential –UserName $User –Message "Bitte Passwort eingeben"
}
$pass = $cred.GetNetworkCredential().Password
$userBytes = [System.Text.Encoding]::ASCII.GetBytes($user)
$userBase64 = [System.Convert]::ToBase64String($userBytes)
$writer.WriteLine($userBase64)
$reader.ReadLine()

$passBytes = [System.Text.Encoding]::ASCII.GetBytes($pass)
$passBase64 = [System.Convert]::ToBase64String($passBytes)
$writer.WriteLine($passBase64)
$reader.ReadLine()

$writer.WriteLine("MAIL FROM:$from")
$writer.WriteLine("RCPT TO:$to")
$writer.WriteLine("DATA")
#$writer.WriteLine("")
$writer.WriteLine("From: $from")
$writer.WriteLine("To: $to")
$writer.WriteLine("Date: {0}", (Get-Date).ToString("ddd, d M y H:m:s z"))
$writer.WriteLine("Subject: $Subject")
$writer.WriteLine("X-Mailer: $xmailer")
$writer.WriteLine("")
$writer.WriteLine("$Body")
$writer.WriteLine(".")
$writer.WriteLine("")
$writer.WriteLine("")
$reader.ReadLine()

# Streams und Sockets schließen
$ssl.Close()
$n.Close()
$c.Close()

Powershell Get-Credential aus Script heraus setzen

5 Juli 2017

In Powershell verwendet man häufiger Get-Credential um vom Benutzer Passwörter zu erhalten. Nun ist es beim Testen allerdings blöd immer ein Script zu haben, in dem man jedes mal etwas eintragen muss.

Anstatt nun Get-Credential zu verwenden, wäre es für den Workflow besser, man könnte Benutzernamen und Passwort direkt setzen. Dies geht, z. B. so:

$user = "Benutzer"
$pass = "Passwort"
$Spass = ConvertTo-SecureString –String $pass -AsPlainText -Force
$cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $User, $SPass
$cred.GetNetworkCredential().Password

dies entspricht:

$cred = Get-Credential –Message "Bitte Password eingeben" –Username "Benutzer"

Am Ende ist $cred immer vom Typ PSCredential und kann im weiteren Script gleich verwendet werden, wie z. B.

$cred.GetNetworkCredential().Password

Weitere Infos zu SecureString hier: https://newyear2006.wordpress.com/2012/12/30/in-den-niederungen-von-securestring-mittels-powershell/ und hier: https://newyear2006.wordpress.com/2012/12/30/spa-mit-net-securestring-und-powershell-oder-sicheres-speichern-und-einlesen-von-passwrtern/

Wiederherstellungsumgebung WinRE.WIM aus Windows ISO-Datei extrahieren

2 Juli 2017

Für bestimmte Zwecke benötigt man die WinRE.WIM-Datei. WinRE ist die Wiederherstellungsumgebung für Windows. WinRE gibt es quasi seit Windows Vista und wurde Version um Version weiter ausgebaut. WinRE.WIM findet vor allem bei aktuellen Windows 10 und Windows Server 2016 Systemen Anwendung.

Um WinRE.WIM zu erhalten gibt es verschiedene Wege. Der einfachste ist auf einem bestehenden System die versteckte Wiederherstellungspartition mit einem Laufwerksbuchstaben zu versehen und dann unter X:\Recovery\WindowsRE mittels

attrib –s –h winre.wim

die WinRE.WIM-Datei sichtbar zu machen. Danach kann man sie wegkopieren.

Allerdings kann es Fälle geben, da möchte man sicher sein, dass die WinRE.WIM-Datei vom Original stammt. In diesem Fall kann man die WinRE.WIM-Datei aus bestehenden ISO-Dateien herauskopieren. Allerdings ist dieser Weg nicht sofort offensichtlich, denn es muss zunächst die ISO-Datei und zusätzlich die INSTALL.WIM-Datei eingehängt werden.

Auf einem aktuellen Windows 10 System mit Powershell-Unterstützung sieht der Vorgang z. B. so aus:

#Requires –RunAsAdministrator
# ISO-Datei sollte als absoluter Pfad angegeben werden, keine Remotelaufwerke, sonst klappt es manchmal nicht:
$iso=’D:\ISOs\de_windows_10_multiple_editions_
version_1703_updated_march_2017_x86_dvd_
10191741.iso‘
$im=Mount-DiskImage -ImagePath $iso -PassThru
If ($im.Attached) {
  $isoDrive=(Get-DiskImage –DevicePath $im.DevicePath | Get-Volume).DriveLetter
}

So nun sollte $isoDrive den Laufwerksbuchstaben des eingehängten ISO-Images haben. Mit diesem kann man dann weiterarbeiten und die Install.Wim einhängen:

# Verzeichnis zum Einhängen von Install.WIM anlegen
md $env:TEMP\WinRE
Mount-WindowsImage -ImagePath "$($isoDrive):\sources\install.wim" -Index 1 -path "$env:Temp\WinRE" -ReadOnly

Nach dem Kopiervorgang kann man nun auf die WinRE.WIM zugreifen:

dir $env:Temp\WinRE\windows\System32\Recovery\Winre.wim

Man könnte sie z. B. in das ADK für WinPE kopieren, damit man eine individuelle RettungsCD erstellen kann:

# bei x86:
copy $env:Temp\WinRE\windows\System32\Recovery\Winre.wim "${env:ProgramFiles(x86)}\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\en-us"

# oder bei x64:
copy $env:Temp\WinRE\windows\System32\Recovery\Winre.wim "${env:ProgramFiles(x86)}\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\x64\en-us"

Hat man die Datei dann wegkopiert, sollte man die Umgebung noch wieder aufräumen, damit alles seine Ordnung hat:

Dismount-WindowsImage  -path $Env:Temp\WinRE  -Discard
DisMount-DiskImage -ImagePath $iso

Wer braucht noch SMB1?

2 Juni 2017

Durch die letzte Vorfälle mit Erpressungstrojanern kam das SMB-Protokoll mal wieder in die Schlagzeilen. Betroffen waren vor allem Rechner mit SMB Protokoll mit Version 1. Seit Jahren gibt es Version 2 und 3.

Hier findet man eine Übersicht welches Betriebssystem welche Version benutzt: https://blogs.technet.microsoft.com/josebda/2015/05/05/whats-new-in-smb-3-1-1-in-the-windows-server-2016-technical-preview-2/

Microsoft hat letztes Jahr einen Blogartikel gebracht, wo darauf aus ist, SMB1 loszuwerden: https://blogs.technet.microsoft.com/filecab/2016/09/16/stop-using-smb1/. Darin werden verschiedene Methoden gezeigt, wie man das SMB1 Protokoll deinstallieren kann. Selbst ein aktueller Windows Server 2016 hat aber das SMB1 Protokoll von Hause aus installiert. Man kann den aktuellen Zustand ganz einfach mittels

Get-Windowsfeature -Name FS-SMB1

abfragen. Oder auf einem Client:

Get-WindowsOptionalFeature -Online -FeatureName smb1protocol

Zum Loswerden kann man unter Powershell beim Server dies verwenden:

Remove-WindowsFeature -Name FS-SMB1

oder auf einem Client diesen Befehl:

Disable-WindowsOptionalFeature -Online -FeatureName smb1protocol

Neben Microsoft gibt es aber noch viele andere Hersteller, welche noch SMB1 einsetzen, dazu gibt es einen aktuellen Blogeintrag: https://blogs.technet.microsoft.com/filecab/2017/06/01/smb1-product-clearinghouse/.

Warum USB 3.0 bzw. USB 3.1 nicht so schnell ist wie es sein könnte – oder die Geschichte um UASP USB Attached SCSI Protocol

28 April 2017

Ein Kunde fragte warum seine USB 3.0 Festplatte nicht schneller wäre. Eine einfache Frage aber um diese richtig beantworten zu können sind verschiedene Aspekte und Begriffe zu klären. Dabei ist wichtig zu wissen, dass bei der Anbindung eines externen Speichers per USB verschiedene Protokolle zum Einsatz kommen können. Es gibt einmal die Anbindung über das BOT-Protokoll (Bulk-Only Transport) und einmal über das UAS-Protokoll (USB Attached SCSI).

UASP ist deshalb besonders interessant weil es Command Queuing, Asynchrone Verarbeitung und erweiterte Aufgaben und Verwaltungsmöglichkeiten mitbringt. Der Protokolloverhead im Vergleich zur Datenübertragung mittels BOT sinkt signifikant. So sind bei einem USB 3.0 Anschluss mittels BOT-Protokoll 250MB/Sekunde möglich. Mittels UASP erreicht man mit der gleichen Hardware fast 400MB/Sekunde dabei sinkt gleichzeitig noch die Prozessorbelastung. Damit aber alles reibungslos funktioniert müssen Hardware und Treiber optimal aufeinander abgestimmt sein und sich im richtigen Modus befinden. Bei USB 3.0 oder 3.1 ist vor allem auf die Länge und Qualität der Kabel zu achten, sonst wird es nix mit der Highspeed-Übertragung der Daten. Da viele herkömmliche Festplatten für diese hohe Übertragungsraten eh zu langsam sind, macht eigentlich nur die Verwendung von SSDs sinn. Allerdings können herkömmlich Festplatten einen erheblichen Geschwindigkeitszugewinn verzeichnen, wenn mehrere Prozesse gleichzeitig auf die Festplatte zugreifen, dann hilft das Command Queuing und die asynchrone Verarbeitung.

Es gab schon früh Bestrebungen UASP unter Windows zu nutzen. Es war sogar bereits für Windows XP und Server 2003 vorgesehen: https://msdn.microsoft.com/en-us/library/windows/hardware/dn642103%28v=vs.85%29.aspx. Jedoch war jeder Hersteller gezwungen eigene Treiber zu entwickeln. Erst später mit Einführung von Windows 8 wurde ein generischer Treiber UASPStor.SYS von Microsoft direkt ausgeliefert: https://msdn.microsoft.com/en-us/library/windows/hardware/ff538820%28v=vs.85%29.aspx.

Die UAS-Spezifikation ist hier zu finden: Die aktuelle Fassung ist von 2016 und läuft unter INCITS 471-2010[R2015]: https://standards.incits.org/apps/group_public/project/details.php?project_id=30. Eine ältere, aber frei einsehbare Version gibt es hier: http://www.usb.org/developers/docs/devclass_docs/uasp_1_0.zip.

In der Microsoft USB FAQ finden sich auch Hinweise: https://msdn.microsoft.com/en-us/library/windows/hardware/dn423379%28v=vs.85%29.aspx#loadeddriver

Hardware
Es gibt nur wenig Geräte, die extra mit UASP-Unterstützung werben. Dies liegt sicher daran, dass bei den meisten externen Festplatten die Festplatten einfach zu langsam sind. Wer jedoch SSDs in externen Laufwerken einsetzt, der wird um UASP-Unterstützung nicht herum kommen.

Ein Hersteller der die Bedeutung von UASP erkannt hat ist Startech, dort finden sich alle möglichen USB-Kabel und externe Gehäuse wo explizit auf UASP hingewiesen wird. Der Hersteller preist die Vorteile in einem eigenen Blog-Beitrag an: https://blog.startech.com/post/all-you-need-to-know-about-uasp/

Wie kann man die Unterstützung von UASP prüfen?
So siehts im Gerätemanager aus: http://winaero.com/blog/check-if-your-usb-3-0-device-supports-usb-attached-scsi-uas-protocol/. Aber spannend wird es wie immer erst in der Commandline. Wenn man ein UASP-Gerät einsteckt, so erkennt Windows automatisch ob es den UASP-Treiber und den Dienst UASPSTOR starten muss. Klappt beides, so kann man mittels Powershell den aktuellen Status ermitteln:

Get-PnpDevice |where name -match mass

Status     Class           FriendlyName
——     —–           ————
OK         USB             USB-Massenspeichergerät
OK         SCSIAdapter     Per USB angeschlossenes SCSI (UAS)-Massenspeichergerät

Hier müsste das Gerät als “USB Attached SCSI (UAS) Mass Storage Device” bzw. “Per USB angeschlossenes SCSI (UAS)-Massenspeichergerät” auftauchen.

Zum Prüfen, ob der UASP-Dienst läuft und der Treiber geladen ist:

get-service uaspstor

Status   Name               DisplayName
——   —-               ———–
Stopped  uaspstor           USB Attached SCSI (UAS) Driver

Wenn also der Dienst nicht läuft oder keine UAS bei den Massenspeichern auftaucht, dann hat man keine UAS-fähige Hardware.

Linux
Wie kann man unter Linux feststellen, ob sein Gerät als UASP-Gerät erkannt wurde? Man ruft dmesg auf und findet dort einen Eintrag wie

[15655.952172] scsi host 14: uas

[15667.952172] sd 14:0:0:0: [sdk] Attached SCSI disk

Mögliche Probleme mit UAS
Nicht direkt ein Problem von UAS, sondern eher eine Definitionslücke bei Microsoft. Beim normalen USB-Treiber kann man einen Schreibschutz aktivieren, dieser wird beim UAS-Treiber noch nicht unterstützt.

http://forensenellanebbia.blogspot.de/2015/08/usb-write-blocking-with-registry-beware.html, Lösung: http://forensenellanebbia.blogspot.de/2015/08/usb-write-blocking-with-registry-beware_13.html aber Wegfall der Geschwindigkeit!

Der schnelle UAS-Übertragungsmodus steht nur an XHCI-USB-Controllern zur Verfügung, siehe https://msdn.microsoft.com/en-us/library/windows/hardware/dn423379%28v=vs.85%29.aspx#loadeddriver.

Hier noch weitere Infos zum Thema UASP, USB 3.0 und USB 3.1: https://www.elektronik-kompendium.de/sites/com/1310061.htm.

Was noch aufgefallen ist, etwas für die Forensiker
Eine über UASP angeschlossene Festplatte taucht, wenn diese entfernt wurde, später immer noch bei den Massenspeichern auf, allerdings mit dem Status Unknown. Schließt man eine andere Festplatte mit demselben Controller am gleichen Port an, so erhält diese einen neuen “Mass Storage”-Treibereintrag. So dass darüber später jederzeit nachvollziehbar wird, wann welche Festplatte per UAS angeschlossen war.

Wie kann man diese Zuordnung im Nachhinein feststellen?

Dazu benötigt man die InstanceID und muss die Seriennummer der Festplatte kennen.

$uas=Get-PnpDevice -class scsiadapter |where name -match uas
($uas).DeviceID
USB\VID_174C&PID_55AA\MSFT30____________W400BBX4

Die Seriennummer ist nämlich in der InstanceID enthalten und zwar sind es immer die letzten 20 Zeichen nach MSFT30. Allerdings in umgekehrter Reihenfolge, d. h. obige ID gehört zu der Festplatte mit der Seriennummer 4XBB004W.

Damit ist die Zuordnung zur Platte eindeutig gegeben. Nun noch die Frage, wann wurde zuerst am System benutzt?

$uas|Get-PnpDeviceProperty -KeyName DEVPKEY_Device_FirstInstallDAte

InstanceId KeyName                                   Type       Data
———- ——-                                   —-       —-
USB\VID… DEVPKEY_Device_FirstInstallDAte           FileTime   28.04.2017 13:00:03

Ebenso kann man mit DEVPKEY_Device_LastRemovalDate feststellen, wann sie das letzte Mal am System angemeldet war.