Arp für IPv6 bzw. wie kann ich zu einer IPv6-Adresse die zugehörige IPv4-Adresse unter Windows ermitteln?

20 März 2017

Wenn man unter aktuellen Windowsversionen z. B. Get-SmbOpenFile verwendet, um z. B. sehen zu können, welcher Benutzer auf welchem Rechner gerade welche Dateien geöffnet hat, so bekommt man dort einen ClientComputername angegeben. Leider wird dieser ClientComputername oft als IPv6-Adresse und nicht als IPv4-Adresse angegeben. Im Grunde ist es ja korrekt alles über IPv6 zu machen aber wir Menschen tun uns halt schwer mit den IPv6-Adressen.

Wie kann man nun aber zu einer IPv6-Adresse die zugehörige IPv4-Adresse im lokalen Netz ermitteln? Ein Aufruf von ARP.EXE zeigt gähnende Leere, denn es zeigt nur IPv4-Adressen an. Einen Parameter –6 oder ARP6.EXE gibt es nicht.

Nun könnte man NETSH.EXE das alte Universaltool rauskramen und mittels

netsh int ipv6 show neigh

die MAC-Adressen zu den MAC-Adressen von der ARP.EXE-Ausgabe in Beziehung setzen. Aber das artet schnell in Arbeit aus.

Hier hilft wie immer Powershell, denn dort gibt es das Get-NetNeighbor-Cmdlet und damit kommt man bei richtiger Anwendung ganz schnell zum Ziel:

PS> Get-NetNeighbor| Group-Object linklayeraddress | where count -eq 2 | select -ExpandProperty group

ifIndex IPAddress                 LinkLayerAddress 
——- ———                 —————- 
3       fe80::41dc:1d58:7d3b:c57b EC-A8-6B-D1-F5-46
3       192.168.100.72            EC-A8-6B-D1-F5-46
3       fe80::1e74:dff:feac:c8d0  1C-74-0D-AC-C8-D0
3       192.168.100.1             1C-74-0D-AC-C8-D0

Hier sieht man schön, dass die passenden IP-Adressen immer durch die MAC-Adresse beieinander gruppiert sind und so schön von der einen auf die andere geschlossen werden kann.

Da wir uns schon wieder bei Powershell befinden, ist es sicher sinnvoll daraus gleich eine Funktion zu machen, welche in Skripten verwendet werden kann.

Function Convert-IPAddress {
[CmdletBinding()]
Param(
  [IPAddress]$IPAdresse
)

$n=Get-NetNeighbor

# Alle IP-Adressen mit MAC-Adressen ermitteln:
$nip = $n|where linklayeraddress -ne ""| sort linklayeraddress

# MAC-Adresse zur gesuchten IP-Adresse ermitteln: 
$nMAC = $nip | where ipaddress -eq $IPAdresse.IPAddressToString
# alle IP-Adressen zur ermittelten MAC holen:
$rip = $nip | where linklayeraddress -eq $nmac.LinkLayerAddress

$rip = $rip| where ipaddress -ne $IPAdresse.IPAddressToString

If ([System.Net.Sockets.AddressFamily]::InterNetworkV6 -eq $IPAdresse.AddressFamily) {
  # von IPv6 nach IPv4, also nur IPv4 zurückgeben
  ($rip | where {([IPAddress]$_.IPAddress).AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork}).IPAddress
} else {
  If ([System.Net.Sockets.AddressFamily]::InterNetwork -eq $IPAdresse.AddressFamily) {
   # von IPv4 nach IPv6, also nur IPv6 zurückgeben
   ($rip | where {([IPAddress]$_.IPAddress).AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetworkV6}).IPAddress
  } 
}
}

Damit kann man nun ganz einfach die IP-Adresse konvertieren:

PS> Convert-IPAddress fe80::1e74:dff:feac:c8d0
192.168.100.1
PS> Convert-IPAddress 192.168.100.1
fe80::1e74:dff:feac:c8d0

Gibt man eine Adresse an, zu der es keine Entsprechung gibt, bekommt man einfach $Null zurück.

Einfacher SNMP Walker in Powershell

15 März 2017

Ein Uraltprotokoll das Simple Network Management Protokoll kurz SNMP gibt es heute immer noch. Teilweise hilft es sogar ganz schnell Informationen zu erhalten, die sonst nur mühsam aus anderen Geräten, z. B. Druckern zu erhalten sind.

Auch im Server 2016 und Windows 10 gibt es standardmäßig eine COM-Bibliothek welche die Kommunikation mit SNMP-Geräten ermöglicht. Die Bibliothek bringt eine Funktion mit Namen GetTree mit. Mittels dieser Funktion kann man auf einen Schlag alle relevanten Informationen erhalten. Dies hilft oft schon einen ersten Eindruck von einem Gerät zu erhalten, man muss lediglich die IP-Adresse kennen. Wichtig zu wissen, die OIDs müssen mit einem führenden Punkt angegeben werden:

$IP = "192.168.1.87"
$SNMP = New-Object -ComObject olePrn.OleSNMP
$SNMP.Open($IP, "public")
$SNMP.GetTree(".1.3.6.1")
$SNMP.Close()

Die Zahl 1.3.6.1 ist quasi eine Art Adresse. Bei einem aktuellen HP-Drucker funktioniert diese 1.3.6.1 die Adresse 1.3.6 allerdings nicht. Interessiert man sich speziell für Managementdaten dann wird man unter 1.3.6.1.2 fündig. Hier eine schöne Auflistung mit RFC-Verweisen, was wo gefunden werden kann: http://www.multinet.de/fileadmin/mib2/. Drucker werden speziell über die OID 1.3.6.1.2.1.43 abgefragt. Auf der Internetseite http://www.alvestrand.no/objectid/ ist die Hierarchie schön erklärt. Darüber kann man dann den Sinn der Zahlen verstehen.

Was kann man mit diesen OIDs und SNMP anstellen? Z. B. kann man einen Reboot eines Druckers im Netz auslösen: https://newyear2006.wordpress.com/2016/07/10/hp-netzwerkdrucker-per-remote-und-reboot-txt-neu-starten-nix-klappt-aber-snmp-bringt-die-lsung/. Man findet z. B. für die OID 1.3.6.1.2.1.43.5.1.1.3 folgenden Eintrag:

{iso(1) identified-organization(3) dod(6) internet(1) mgmt(2) mib-2(1) printmib(43) prtGeneral(5) prtGeneralTable(1) prtGeneralEntry(1) prtGeneralReset(3)}

prtGeneralReset OBJECT-TYPE
-- This value is a type 3 enumeration
SYNTAX INTEGER {
notResetting(3),
powerCycleReset(4), -- Cold Start
resetToNVRAM(5), -- Warm Start
resetToFactoryDefaults(6) -- Reset contents of
-- NVRAM to factory defaults
}
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"Setting this value to `powerCycleReset, `resetToNVRAM, or `resetToFactoryDefaults will result in the resetting of the printer. When read, this object will always have the value `notResetting(3), and a SET of the value `notResetting shall have no effect on the printer. Some of the defined values are optional. However, every implementation must support at least the values `notResetting and resetToNVRAM."

Quelle: http://oid-info.com/get/1.3.6.1.2.1.43.5.1.1.3

Die tatsächliche Quelle in diesem Fall ist aber eine RFC, die RFC 1759, https://tools.ietf.org/html/rfc1759.html. Dadurch, dass es eine RFC ist, wird es natürlich klar, dass es bei dem Script für den Druckreboot nicht um eine HP spezifische OID handelt sondern um eine allgemein gültige OID, welche auch von anderen Druckerherstellern verwendet werden kann. Damit funktioniert der Neustart auch bei anderen Netzwerkdruckern.

Noch ein Hinweise zum Artikel mit dem Druckerreset. Die Angabe des Parameters 4 ist nun auch klar, denn die steht für powerCycleReset, siehe oben die Parameter.

Um einfache Infos zu einem Gerät zu erhalten fragt mein einfach den sysDescr ab. Der sysDescr stellt eine Gerätebeschreibung dar. http://www.alvestrand.no/objectid/1.3.6.1.2.1.1.1.html. Der Aufruf sieht dann so aus:

$snmp.get(".1.3.6.1.2.1.1.1.0")
HP ETHERNET MULTI-ENVIRONMENT

oder noch besser, man fragt mittels Tree nach:

$snmp.GetTree(".1.3.6.1.2.1.1.1")
system.sysDescr.0
HP ETHERNET MULTI-ENVIRONMENT

Dabei ist offensichtlich, dass sich HP nicht an die Vorgabe hält und Versionsinformationen unterdrückt. Das Beispiel zeigt aber auch, dass man einen einzelnen Wert mittels Get() und .0 erhalten kann und bei GetTree() automatisch alles dazugehörige erhält, sogar den Typ.

Mit dieser Information können wir nun auch folgendes schreiben:

$snmp.get("system.sysDescr.0")
HP ETHERNET MULTI-ENVIRONMENT

D. h. man kann nun sprechendere Namen verwenden. Für unser Druckerreset wäre dies:

$snmp.gettree(".1.3.6.1.2.1.43.5.1.1.3")
printmib.prtGeneral.prtGeneralTable.prtGeneralEntry.prtGeneralReset.1
3
$snmp.get("printmib.prtGeneral.prtGeneralTable.prtGeneralEntry.prtGeneralReset.1")
3

Beides mal wird die 3 für notResetting geliefert.

Noch ein Punkt der wichtig ist, um die Rückgaben von GetTree() besser zu verstehen. Es werden immer zwei Arrays zurückgegeben, d. h. zuerst ein Array mit den Namen der OIDs und danach ein Array mit den eigentlichen Werten zu den OIDs. Dies wird deutlich wenn man die verfügbaren Sprachen des Druckers abfragt:

$snmp.gettree("printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage")
printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage.1.1
printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage.1.2
printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage.1.3
printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage.1.4
printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage.1.5
printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage.1.6
printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage.1.7
printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage.1.8
en
es
de
fr
ar
it
pt
nl

In Wahrheit ist es jedoch ein verschachteltes bzw. zweidimensionales Array:

($snmp.gettree(".1.3.6.1.2.1.43.7.1.1.2"))[0]
Der Index [0] ist für einen Zugriff auf ein 2-dimensionales Array unzulässig.
In Zeile:1 Zeichen:1
+ ($snmp.gettree(".1.3.6.1.2.1.43.7.1.1.2"))[0]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NeedMultidimensionalIndex

($snmp.gettree(".1.3.6.1.2.1.43.7.1.1.2"))[0,0]
printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage.1.1
($snmp.gettree(".1.3.6.1.2.1.43.7.1.1.2"))[1,0]
en

Man erhält zuerst die Namen und in der zweiten Dimension die Werte. Also [0,*] enthält alle Namen und [1,*] enthält alle Werte.

Achso, wie bin ich jetzt von “printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage” auf 1.3.6.1.2.1.43.7.1.1.2 gekommen? Auch dazu gibt es eine Funktion:

$snmp.OIDFromString("printmib.prtLocalization.prtLocalizationTable.prtLocalizationEntry.
prtLocalizationLanguage") -join "."
1.3.6.1.2.1.43.7.1.1.2

Jetzt hab ich soviel von den ganzen Zusammenhängen geschwafelt, warum nun nicht am Schluss noch etwas sinnvolles zusammenbauen, z. B. eine Tabelle mit allen sinnvollen Werten?

$e=$SNMP.GetTree(".1.3.6.1")
$d=@()
# umsortieren der Arraystruktur
for($i=0;$i-lt $e.length/2;$i++){$d+=@($e[0,$i], $e[1,$i]) }
$d | out-gridView

Oder noch besser alles mehr powershelllike mit Objekten:

$e=$SNMP.GetTree(".1.3.6.1")
$d=@()
# umsortieren der Arraystruktur
for($i=0;$i-lt $e.length/2;$i++){$d+=[pscustomobject]@{ID=$e[0,$i];Value=$e[1,$i];OID=($snmp.OIDFromString(($e[0,$i])) -join ".")} }
$d | out-gridView

Damit steht dem Erkunden der SNMP-Welt nichts mehr im Wege!

“Wie soll diese Website geöffnet werden?”-Dialog wegbekommen

10 März 2017

In bestimmten Situationen, vor allem nach einer Installation oder Deinstallation eines Programms, kann es bei einem neu eingerichteten Windows 10 dazu kommen, dass ein Dialog geöffnet wird mit dem Text:

Wie soll diese Website geöffnet werden?

App verwenden
—–
Standardbrowser verwenden

[  ]  Immer diese App zum Öffnen von <Website> verwenden

OK

Da die Installationen oder Deinstallationen meistens mit Adminrechten durchgeführt werden, kann es zu einer Situation kommen, wenn man die Meldung nicht beachtet und der eigentliche administrative Vorgang bereits abgeschlossen ist, dass die Meldung weiterhin am Bildschirm stehen bleibt und nicht mehr wegzubekommen ist. Das hat mit den fehlenden Rechten des Standardbenutzers nach der Installation zu tun.

Was also tun?

Entweder Rechnerneustart oder im Taskmanager die Datei OpenWith.EXE beenden.

WLAN bzw. Wireless unter Windows Server 2016 aktivieren, Meldung “Ein Dienstinstallationsabschnitt dieser INF-Datei ist ungültig.” beheben

8 März 2017

Die Windowsserver können auch an WLAN-Netze angebunden werden. Dazu ist allerdings etwas mehr Aufwand nötig. GUI-Menschen haben vielleicht schon mal bei einem Windows Server die Meldung “Ein Dienstinstallationsabschnitt dieser INF-Datei ist ungültig.”, wenn man im Gerätemanager Treiber aktualisiert, gesehen. Dies ist z. B. auf die standardmäßig nicht verfügbare Wireless Unterstützung zurückzuführen.

WirelessNetworking Feature aktivieren bzw. prüfen
Zunächst benötigt man das WirelessNetworking Feature. Man kann dies mittels Powershell so abfragen:

Get-WindowsOptionalFeature -Online| where featurename -match wireless

FeatureName : WirelessNetworking
State       : Disabled

Wenn Disabled gemeldet wird, dann muss das Feature zuerst einmal installiert werden:

Enable-WindowsOptionalFeature -Online -featurename WirelessNetworking

Meistens ist danach ein Neustart des Rechners notwendig.

Restart-Computer

WLAN Dienst aktivieren
Damit nun mit WLAN gearbeitet werden kann, muss auch der WLAN Dienst geprüft werden:

Get-Service WLanSvc

Status   Name               DisplayName
——   —-               ———–
Stopped  WlanSvc            Automatische WLAN-Konfiguration

Sollte hier Stopped stehen, muss er mit

Start-Service WLanSvc

gestartet werden. Sollte der Dienst gar nicht aufgelistet werden, dann ist oben bei der Featureinstallation was schief gelaufen oder der Rechner wurde noch nicht neu gestartet.

WLAN Treiber laden
Damit man tatsächlich mit dem WLAN arbeiten kann, sollte man nun noch im Gerätemanager prüfen, ob man noch einen Treiber für das WLAN laden muss.

Gängige Intel-WLAN-Treiber findet man hier https://downloadcenter.intel.com/de/download/ unter dem Stichwort ProSetWireless.

Treiber von Windows 10 erhalten
Wenn es mal keine Treiber direkt für den Windows Server 2016 geben sollte, dann kann man doch meist die Treiber von Windows 10 verwenden. Hier wird das Verfahren anhand einer LAN-Karte dargestellt: https://newyear2006.wordpress.com/2017/03/07/treiber-von-windows-10-im-windows-server-2016-installieren-wenn-es-keine-offiziellen-treiber-gibt-am-beispiel-einer-intel-netzwerkkarte/.

Würde man dieses Verfahren auf z. B. auf eine aktuelle Intel WLAN-Karte anwenden, dann wären die Hardware-ID VEN_8086&DEV_24F3 und die Datei NETwtw04.INF im Spiel, welche geändert werden müsste.

Falls man Probleme haben sollte die Wireless-Treiber zu entpacken, ohne sie zu installieren, dann muss man wissen, dass die Treiberinstallation mittels den WIX-Toolset erstellt wurden. Zum Entpacken benötigt man Dark.exe für Bundle WIX : https://github.com/wixtoolset/issues/issues/3645/. Die Angabe von /Layout führte bei der bisherigen Version leider nicht zum Entpacken.

Treiber von Windows 10 im Windows Server 2016 installieren wenn es keine offiziellen Treiber gibt, am Beispiel einer Intel-Netzwerkkarte

7 März 2017

Eigentlich sind sich Windows 10 und Windows Server 2016 recht nahe, je nach Versionsstand von Windows 10. Dennoch gibt es manchmal bei der verwendeten Hardware Einschränkungen in Bezug auf Treiber. In einem aktuellen Fall war in einem Rechner eine Intel I219-V Netzwerkkarte verbaut. Dieser Karte genügt natürlich heutigen Managementansprüchen in Servern nicht unbedingt und deshalb wurde in Server 2016 die Treiberunterstützung für diese Karte unterlassen. Was an dieser Karte aber komisch ist, ist dass es eine Zertifizierung im Windows Server Katalog dafür gibt: https://www.windowsservercatalog.com/item.aspx?idItem=985d89e0-d6d1-b9e0-654c-0209df71a8c7&bCatID=1468.

Was kann man machen um die Karte trotzdem nutzen zu können? Früher ging man her und änderte die zugehörige Treiber-INF-Datei und aktivierte die Windows 10 Treiber für Server 2016. Diese Methode wurde seit Windows Vista Zeiten immer schwieriger. Man benötigt nun passende Zertifikate, damit Änderungen an INF-Dateien autorisiert sind. Man kann aber in Server 2016 noch die bewährte Methode gehen, die Überprüfung der Treibersignatur auszuschalten, dann installiert man einmal die Treiber, ladet und segnet sie ab. Danach aktiviert man wieder die Prüfung der Treibersignaturen. Nun kann man die Geräte mit Windows 10 Treibern unter Windows Server 2016 nutzen.

Für obiges Beispiel beschreibt dieser Blogartikel den Vorgang sehr schön: http://blog.citrix24.com/install-windows-server-2016-core-intel-nuc/.

Hier mache ich aber eine komplette Beschreibung wegen ein paar Besonderheiten und weil oft Blogs im Internet auch verschwinden.

Ermittlung der HardwareID
Fangen wir an die betreffenden Geräte ausfindig zu machen. Normalerweise würden erkannte Netzwerkadapter mittels Get-NetAdapter auftauchen. Aber die Intel I219-V ist nicht dabei. Nun kann man wie im Blogartikel beschrieben mittels

GetWMIObject win32_PNPEntity |select name,deviceid |where {$_.Name match "Ethernet"}

die HardwareID ermitteln, welche

name     : Intel(R) Ethernet Connection I219-V
deviceid : PCI\VEN_8086&DEV_1570&SUBSYS_20638086&REV_21\3&11583659&0&FE

ergibt. Von dieser Info ist die VEN_8086&DEV_1570 von Bedeutung. Im Blogartikel wird noch eine zweite Variante genannt, die bezieht sich auf die WLAN-Karte, welche nicht unter Ethernet zu finden ist, sondern unter Network. Wenn man allerdings unter einem deutschsprachigen Windows diesen Befehl ausführt

GetWMIObject win32_PNPEntity |select name,deviceid |where {$_.Name match "Network"}

dann erscheint nicht die gesuchte Info, sondern

name                                   deviceid
—-                                   ——–
Microsoft Kernel Debug Network Adapter ROOT\KDNIC\0000

weil es Network nicht gibt. Man muss statt dessen nach

GetWMIObject win32_PNPEntity |select name,deviceid |where {$_.Name match "Netzwerkcontroller"}

suchen, um z. B. dieses Ergebnis zu bekommen:

name     : Netzwerkcontroller
deviceid : PCI\VEN_8086&DEV_24F3&SUBSYS_90108086&REV_3A
\4&A711841&0&00E0

Blöd und umständlich so was. Aber wir sind ja auf Server 2016, da gibt es neuere Möglichkeiten Hardwaredinge abzufragen:

Get-PnpDevice -Class Net| select status, friendlyname, instanceid|fl *

status       : OK
FriendlyName : Intel(R) Ethernet Connection I219-V
InstanceId   : PCI\VEN_8086&DEV_1570&SUBSYS_20638086&REV_21\3&11583659&0&FE

status       : Error
FriendlyName : Netzwerkcontroller
InstanceId   : PCI\VEN_8086&DEV_24F3&SUBSYS_90108086&REV_3A
\4&A711841&0&00E0

Prima. Hier sehen wir auch gleich, dass es beim Wirelesscontroller ebenso Probleme gibt, weil dort der Status Error steht. Dies war beim I219-V am Anfang natürlich auch, allerdings sind hier im Beispiel bereits die LAN-Treiber geladen.

Wir müssen uns also nur merken, dass wir anstatt der WMI-Abfrage von Win32_PNPEntity auch direkt Get-PnPDevice –Class Net verwenden können.

Treiber herunterladen und entpacken
Neben der HardwareID benötigen wir auch die passenden Treiber von Windows 10. In diesem Fall waren diese unter https://downloadcenter.intel.com/de/download/ unter dem Stichwort ProWin und ProsetWireless zu finden. Damit man aber mit den Dateien etwas anfangen kann, müssen diese aber entpackt werden. Leider wird es immer mehr zur Unsitte nicht mehr hinzuzuschreiben, wie man Treiber nur entpacken aber nicht installieren kann. Im Zweifel verwendet man 7zip um die Treiber aus den .EXE-Dateien zu extrahieren.

INF-Datei modifizieren
So nun muss man zu den IDs den passenden Treiber finden. Dazu ruft man

Get-ChildItem –Recurse | Select-String –Pattern "VEN_8086&DEV_1570" | group Path | select name

Name
—-
D:\IntelTreiber\PRO1000\Winx64\NDIS62\e1d62x64.inf
D:\IntelTreiber\PRO1000\Winx64\NDIS63\e1d63x64.inf
D:\IntelTreiber\PRO1000\Winx64\NDIS64\e1d64x64.inf
D:\IntelTreiber\PRO1000\Winx64\NDIS65\e1d65x64.inf

auf. Dabei sollte man bereits im Pfad stehen, wo man die Treiber entpackt liegen hat.

Eine Frage ergibt sich, welche Datei man nun bearbeitet? Im konkreten Fall die e1d65x64.inf. Mit den kryptischen Versionen 62, 63, 64 und 65 ist die NDIS-Version gemeint. Windows Server 2016 beherrscht zwar bereits NDIS 6.60 aber ist abwärtskompatibel, deshalb die 65 für Version 6.50. Hier findet man ein paar Infos zu den verschiedenen NDIS-Versionen bei Windowsversionen: https://en.wikipedia.org/wiki/Network_Driver_Interface_Specification.

Man ladet nun die INF-Datei einfach in Notepad, im obigen Beispiel so:

Notepad D:\IntelTreiber\PRO1000\Winx64\NDIS65\e1d65x64.inf

Nun müssen wir uns die Sektionen [Intel.NTamd64.10.0.1] und [Intel.NTamd64.10.0] genauer ansehen. Kurz die 10.0.1 steht für Windows Clientversionen, und 10.0 für Server.

Die Sektionen haben bei INF-Dateien eine besondere Bedeutung. Das lustige ist, dass in der betreffenden INF-Datei nicht nur Windows 10 sondern auch Server 2016 Informationen stehen, ja sogar explizit für die I219-V Netzwerkkarte. Allerdings wurde im für Server entscheidenden Abschnitt die I219-V ausgelassen!

Mehr Infos zu den Herstellerangaben bei INF-Dateien findet man hier, da wird auch der genaue Aufbau der Sektionsnamen beschrieben: https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-manufacturer-section.

Man fügt also unter [Intel.NTamd64.10.0] diesen Eintrag hinzu

%E1570NC.DeviceDesc%            = E1570.10.0.1,       PCI\VEN_8086&DEV_1570
%E1570NC.DeviceDesc%            = E1570.10.0.1,       PCI\VEN_8086&DEV_1570&SUBSYS_00008086
%E1570NC.DeviceDesc%            = E1570.10.0.1,       PCI\VEN_8086&DEV_1570&SUBSYS_00011179

dabei müsste auch

%E1570NC.DeviceDesc%            = E1570,       PCI\VEN_8086&DEV_1570
%E1570NC.DeviceDesc%            = E1570,       PCI\VEN_8086&DEV_1570&SUBSYS_00008086
%E1570NC.DeviceDesc%            = E1570,       PCI\VEN_8086&DEV_1570&SUBSYS_00011179

funktionieren und stellt sogar die sicherere Variante dar.

Treibersignaturprüfung ausschalten
Jetzt kommt der eigentlich wichtigste Punkt. Ohne diesen bekommt man die Sache nicht zum Laufen.

bcdedit /set LOADOPTIONS DISABLE_INTEGRITY_CHECKS
bcdedit /set TESTSIGNING ON
bcdedit /set NOINTEGRITYCHECKS ON

Für diese Änderung muss allerdings der Rechner neu gestartet werden, also

Restart-Computer

Treiber installieren
Nun kommt der spannende Moment, wenn man die Treiber lädt, ob es klappt.

pnputil.exe -i -a D:\IntelTreiber\PRO1000\Winx64\NDIS65\e1d65x64.inf

Wenn dann so was ausgegeben wird, hat alles geklappt:

Microsoft-PnP-Hilfsprogramm

Verarbeitungsinf.:            e1d65x64.inf
Der Treiber konnte auf einem Gerät dieses Systems installiert werden.
Das Treiberpaket wurde erfolgreich hinzugefügt.
Veröffentlichter Name:            oem2.inf

Versuche gesamt:              1
Anzahl erfolgreicher Importe: 1

Abschlussarbeit
Natürlich muss man nun die Treibersignaturprüfung wieder aktivieren.

bcdedit /set LOADOPTIONS ENABLE_INTEGRITY_CHECKS
bcdedit /set TESTSIGNING OFF
bcdedit /set NOINTEGRITYCHECKS OFF

 

USB-Bootstick von einer Windows-ISO erstellen, MasterbootRecord (MBR)-Variante

6 März 2017

In Bezug zu diesem Artikel https://newyear2006.wordpress.com/2009/09/19/windows-vista-windows-7-usb-boot-stick-erstellen/, hier ein Update um die einzelnen Dinge per Powershell hinzubekommen. Dadurch wird es möglich eine beliebige aktuelle Microsoft ISO-Datei (von Vista bis Server 2016) zu verwenden und deren Inhalt auf einem bootbaren USB-Stick zu erhalten. Damit die unten stehenden Powershellbefehle verfügbar sind, braucht man mindestens Windows 8.1, getestet habe ich es mit Windows 10.

Diese Methode könnte man auch mit leichter Variation verwenden, um eine bootbare VHD oder VHDX für einen Hyper-V zu bekommen. Aber dies vielleicht ein anderes Mal.

Ein weiterer Vorteil bei diesem Weg kann man auch Modifikationen der zu installierenden Dateien vornehmen. So kann man z. B. die EI.CFG bearbeiten, bevor man die eigentliche Installation beginnt. https://newyear2006.wordpress.com/2009/12/13/windows-7-versionsauswahl-bei-installation/. Oder man könnte die Eingabe des Produktschlüssels umgehen: https://newyear2006.wordpress.com/2012/08/30/windows-8-eingabe-des-produktschlssels-bei-der-installation-umgehen/. Noch eine Variante: https://newyear2006.wordpress.com/2013/09/13/windows-8-1-mit-product-key-von-windows-8-installieren/.

Damit die folgenden Befehle auch funktionieren, braucht man eine Powershell-Eingabeaufforderung mit Administratorrechten.

Auswahl des USB-Sticks
Da wir hier gezielt die Daten auf einen USB-Stick schreiben wollen und bei den Aktionen auch mal schnell die falsche Platte gelöscht werden kann, lassen wir uns nur Geräte die als Wechseldatenträger (Removable Storage) auftauchen anzeigen.

$diskObj = Get-Volume | Where DriveType –eq Removable | Get-Partition | Get-Disk | Out-GridView –Title "USB-Stick auswählen" –PassThru

Um auf vom Volume zur Disk zu kommen, muss man den Umweg über die Partition machen. Am Ende sorgt Out-GridView, dass nur ein Stick ausgewählt werden kann.

Wer hier nichts angezeigt bekommt, der hat womöglich einen Stick der als interne Festplatte erkannt wird. Vor allem USB-Sticks die “Windows to Go” geeignet sind, werden so also nicht erkannt. Wer möchte, kann dazu diese Variante wählen:

$diskObj = Get-Disk | Out-GridView –Title "USB-Stick auswählen" –PassThru

Wer auf einem Hyper-V oder Nano-Server arbeitet, der hat Out-GridView nicht zur Verfügung, der kann auch diese Variante verwenden:

Get-Disk | select Number, FriendlyName, @{Name="Total Size"; Expression={"{0:N2} GB" –f ($_.Size/1GB)}}

Es werden alle Laufwerke aufgelistet und man wählt eines aus:

$diskObj = Get-Disk –Number X

Egal welche Methode man gewählt hat, man sollte nun in $diskObj ein Objekt vom Typ MSFT_Disk haben.

USB-Stick löschen und formatieren
Nun geht es ans eingemachte. Für alle, die nicht wissen, was sie tun, hier kann man schnell seine Platte löschen, wenn man oben nicht das richtige Laufwerk ausgewählt hat!

$diskNr = $diskObj.Number

Get-Disk –Number $diskNr | Clear-Disk –RemoveData

muss mit Ja bestätigt werden.

$part=New-Partition –DiskNumber $diskNr –UseMaximumSize –IsActive

$part | Format-Volume –FileSystem NTFS –NewFileSystemLabel "BootDisk"

hier darf kein –Full angegeben werden, dann ist es automatisch eine Quick-Formatierung.

Add-PartitionAccessPath –Disknumber $diskNr –PartitionNumber $part.PartitionNumber –AssignDriveletter

Laufwerksbuchstaben holen:

$drive = (Get-Partition –DiskNumber $diskNr –PartitionNumber $part.PartitionNumber).DriveLetter

ISO-Datei auswählen
So, nun muss das ISO-Image geladen werden, hier wieder komfortabel per Auswahl die ISO-Datei ausgewählt:

$isoFile = Get-Item .\myIsoPath\*.ISO | Out-GridView –Title "ISO auswählen" –PassThru

Möchte man eine ISO-Datei direkt angeben oder liegt die ISO-Datei im aktuellen Pfad, dann kann auch der direkte Weg benutzt werden:

$isoFile = Get-Item (Resolve-Path .\myIsoFile.ISO)

Nun muss die ISO-Datei eingehängt werden und der zugeordnete Laufwerksbuchstabe ermittelt werden. Allerdings gibt es hier mal wieder ein kleines Problem! Die ISO-Datei darf nicht mittels UNC-Pfad angegeben werden bzw. darf nicht auf einem Remotelaufwerk liegen, sonst wird sie nicht richtig eingehängt, bzw. es wird kein Laufwerksbuchstabe zugeordnet. Nachdem ich ewig lang gezweifelt habe, habe ich jemand anderes gefunden, der genau das gleiche Problem entdeckt hat: https://github.com/VirtualEngine/Lability/issues/28#issuecomment-159657191. Kurz gesagt, Get-Volume liefert nicht den Laufwerksbuchstaben der ISO-Datei, allerdings liefern PS-Drive, Win32_Volume den Laufwerksbuchstaben! Mal wieder ein krasser Bug. Also Vorsicht!

$image=Mount-DiskImage –ImagePath $isoFile.Fullname –PassThru
$imageDrive=($image|Get-Volume).DriveLetter

Bootsector schreiben
Damit von dem USB-Stick auch gebootet werden kann, muss natürlich ein Boot-Sektor geschrieben werden.

Start-Process –Wait "$($ImageDrive):\Boot\BootSect.Exe" –ArgumentList "/NT60","$($drive)"

Dateien der ISO auf den Stick kopieren:

xcopy.exe "$($ImageDrive):\*.*" "$($drive):\" /s /h

So nun sollte alles auf dem Stick sein, so dass von diesem gebootet werden kann.

Noch wichtig: Was tun, wenn der Stick beim Bootvorgang nicht auftaucht? Im UEFI BIOS sollte dann die SecureBoot-Einstellung überprüft werden, ob beliebige Betriebssysteme gebootet werden können oder nur SecureBoot-fähige.

Ein späterer Artikel soll die SecureBoot- also UEFI-fähige Variante nachliefern.

Exchange Server 2010 Postfachweiterleitung und automatischen Abwesenheitstext setzen

5 März 2017

Die Vorgehensweise ist grundsätzlich hier https://support.microsoft.com/de-de/help/2667296/how-to-set-out-of-office-messages-by-using-exchange-2010-powershell beschrieben, allerdings fehlt die Möglichkeit auf eine externe SMTP-Adresse weiterzuleiten. Dieser Punkt wird ausführlich hier beschrieben: http://www.msxfaq.de/exchange/migration/forwardingsmtpaddress.htm.

Wir definieren zuerst eine Variable mit dem Namen des Benutzers:

$identity = "Benutzer"

Zunächst die Abfrage zu den aktuellen Einstellungen eines Benutzers:

Get-MailboxAutoReplyConfiguration -Identity $identity

RunspaceId       : 5531bcbd-6be3-4dad-80c3-dbd1ca1a97d3
AutoReplyState   : Disabled
EndTime          : 06.03.2017 08:00:00
ExternalAudience : All
ExternalMessage  :
InternalMessage  :
StartTime        : 05.03.2017 08:00:00
MailboxOwnerId   : mydomain.local/MyBusiness/Users/SBSUsers/benutzer
Identity         : mydomain.local/MyBusiness/Users/SBSUsers/benutzer
IsValid          : True

und noch die Einstellungen für die Weiterleitung der E-Mails abfragen:

Get-Mailbox –Identity $identity | fl *forw*, name

DeliverToMailboxAndForward : False
ForwardingAddress          :
ForwardingSmtpAddress      :
Name                       : Benutzer

Um die Weiterleitung nun zu aktivieren, verwendet man:

Set-Mailbox –Identity $identity –ForwardingSmtpAddress NeueAdresse@Irgendwo.de –DeliverToMailboxAndForward $true

Um die Weiterleitung wieder zu deaktivieren:

Set-Mailbox –Identity $identity –ForwardingSmtpAddress $null –DeliverToMailboxAndForward $false

Um nun dem ursprünglichen Absender eine Nachricht zukommen zu lassen, verwendet man Set-MailboxAutoReplyConfiguration:

$nachricht = "Guten Tag! Diese Adresse wird zum 30.4.20
17 abgeschaltet. Die E-Mail wird aber an meine neue Adresse weitergeleitet. Bei relevanten E-Mails antworte ich mit mein
er neuen E-Mail-Adresse."
Set-MailboxAutoReplyConfiguration –Identity $identity –AutoReplyState Enabled –InternalMessage $nachricht –ExternalMessage $nachricht

Hier wird für die interne, wie für externe Adressen die Nachricht aus $nachricht zurückgeschickt.

Fragt man die aktuelle Einstellung ab, dann sieht es so aus:

Get-MailboxAutoReplyConfiguration -Identity $identity

RunspaceId       : 5531bcbd-6be3-4dad-80c3-dbd1ca1a97d3
AutoReplyState   : Enabled
EndTime          : 06.03.2017 09:00:00
ExternalAudience : All
ExternalMessage  : <html>
                   <body>
                   Guten Tag! Diese Adresse wird zum 30.4.2017 abgeschaltet. Die E-Mail wird aber an meine neue Adresse
                    weitergeleitet. Bei relevanten E-Mails antworte ich mit meiner neuen E-Mail-Adresse.
                   </body>
                   </html>

InternalMessage  : <html>
                   <body>
                   Guten Tag! Diese Adresse wird zum 30.4.2017 abgeschaltet. Die E-Mail wird aber an meine neue Adresse
                    weitergeleitet. Bei relevanten E-Mails antworte ich mit meiner neuen E-Mail-Adresse.
                   </body>
                   </html>

StartTime        : 05.03.2017 09:00:00
MailboxOwnerId   : mydomain.local/MyBusiness/Users/SBSUsers/Benutzer
Identity         : mydomain.local/MyBusiness/Users/SBSUsers/Benutzer
IsValid          : True

Hier sieht man auch, dass man für Internal- und Externalmessage auch etwas HTML setzen könnte, wenn man sich beim Text künstlerisch betätigen wollte.

Verknüpfung auf Powershellbefehl mit Adminrechten

31 Januar 2017

Möchte man einem Benutzer erlauben z. B. die Druckerwarteschlange neu zu starten so benötigt dieser meist Adminrechte dafür. Man kann zwar die Rechte anders zuordnen aber bei Standardeinstellungen werden diese benötigt. Man kann zwar dem Benutzer eine einfache Verknüpfung zur Ausführung des Powershellbefehls einrichten aber das Anfordern der Adminrechte wird schon etwas komplizierter. Damit man nicht immer solange überlegen muss hier der passende Aufruf:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command "& {Start-Process powershell.exe -Verb runas -ArgumentList ‚-Command ""& {restart-service spooler -force -verbose; “Druckerdienst wurde neu gestartet.“; Start-Sleep -Seconds 5}"" ‚}"

Man kann die Zeile direkt bei der Angabe des Speicherorts einfügen und weiter klicken, den Namen der Verknüpfung noch nennen und schon ist man fertig. Der Befehl startet einfache eine zweite Powershellinstanz welche die Adminrechte anfordert und dann den Neustart der Druckwarteschlange ausführt.

Diese Konzept kann man natürlich noch weiter ausbauen um direkt jegliche Scripte mit Adminrechten ausführen zu können.

The power of commandline and batch files

12 Dezember 2016

Manchmal gibt es echte Perlen im Netz. Gerade per Zufall entdeckt: www.dostips.com. Hier geht jedem Hardcorecommandliner das Herz auf. Powershell kann jeder aber manchmal hat man nicht die Zeit oder Ressourcen Powershell zu laden. Dann kommt einem die gewöhnliche Eingabeaufforderung CMD.EXE zuhilfe. Schon seit NT-Zeiten gibt es die erweiterte Shell. Viele Befehle haben nützliche Parameter erhalten. Aber ein oft übersehener Befehl ist SET. Denn was da alles mit machbar ist!

Da gibt es so geile Funktionen wie Trim, Len, Lower, Upper, Unique, MakeAbsolute usw. usf. Der Oberhammer sind dann aber Unit-Tests!!! Voll geil, das hätte mal einer zu früheren DOS-Zeiten sagen sollen.

Aber nicht nur das. In Powershell nutze ich häufiger Get-History um meine früheren Befehle sehen zu können. CMD.EXE kennt sowas auch mittels DOSKEY /History!

Aber seht selber: http://www.dostips.com/

Es gibt sogar ein Buch dazu, mit dem passenden Untertitel: The Art of Batch Files Programming. Leider momentan nur als eBook: https://www.amazon.de/Batchography-Batch-Files-Programming-English-ebook.

Warum schaltet sich dieser verdammte DHCP-Dienst am Windows Server ständig ab? Was hat das mit IPv6 zu tun?

5 Dezember 2016

Irgendwie stand ich gerade auf dem Schlauch und hab mich mit einem Problem länger als nötig beschäftigt um am Ende festzustellen, die Lösung ist logisch und ganz einfach. Es ging los, dass bei einem Kunden der Speedport gegen eine Fritzbox ausgetauscht werden sollte.

Zu Beginn war alles ganz einfach, Internetverbindung war schnell da. Aber dann gab es Probleme im Netz mit den Client-Rechnern nach einem Neustart. Dazu muss man wissen, dass bei der Fritzbox der IPv4-DHCP ausgeschaltet wurde. Egal wie oft man nun am Windows Server den DHCP-Server neu gestartet hat, er funktionierte immer kurz und war dann wieder ausgeschaltet. Sowas kennt man wenn ein zweiter DHCP-Server im Netz ist. Also nochmal auf der Fritzbox versichert, dass der Ipv4-DHCP ausgeschaltet war. Am Ende war nur noch der Server mit dem Client mit der Fritzbox verbunden. Klappte aber immer noch nicht!

Wo schaut man nach, wenn man solche Probleme hat? Richtig, in der Ereignisanzeige. Also kurz nach den DHCP-Server Logs geschaut:

Get-WinEvent -ListLog *dhcp*|select logname

LogName
——-
Microsoft-Windows-Dhcp-Client/Admin
Microsoft-Windows-Dhcp-Client/Operational
Microsoft-Windows-Dhcp-Server/FilterNotifications
Microsoft-Windows-Dhcp-Server/Operational
Microsoft-Windows-DhcpNap/Admin
Microsoft-Windows-DhcpNap/Operational
Microsoft-Windows-Dhcpv6-Client/Admin
Microsoft-Windows-Dhcpv6-Client/Operational

Ah alles klar:

Get-WinEvent -LogName Microsoft-Windows-Dhcp-Server/Operational -MaxEvents 10

TimeCreated                   ProviderName                                             Id Message
———–                   ————                                             — ——-
17.12.2015 12:52:43           Microsoft-Windows-DHCP-Server                           106 Die Rese
17.12.2015 12:52:43           Microsoft-Windows-DHCP-Server                           107 Die Rese
17.12.2015 12:49:25           Microsoft-Windows-DHCP-Server                           106 Die Rese
17.12.2015 12:48:23           Microsoft-Windows-DHCP-Server                           107 Die Rese
25.11.2015 09:12:51           Microsoft-Windows-DHCP-Server                           106 Die Rese
25.11.2015 09:12:24           Microsoft-Windows-DHCP-Server                           107 Die Rese
21.05.2014 14:25:11           Microsoft-Windows-DHCP-Server                           106 Die Rese

Wie 2015? Ich hab aktuell Problem und nicht 2015! Hä? Was geht hier. Auf jeden Fall ist es wie immer man sucht überall aber nicht an der richtigen Stelle!!!!

Irgendwann dachte ich, dass kann nicht sein und klar es war so. Denn man sollte ja auch wegen DHCP-Server Meldungen nicht bei Microsoft-Windows-DHCP-Server schauen sondern unter SYSTEM!!!! Ich könnte so kotzen…

Also mittels

Get-WinEvent -LogName system -MaxEvents 20

TimeCreated                   ProviderName                                             Id Message
———–                   ————                                             — ——-
05.12.2016 14:52:32           Service Control Manager                                7040 Der Starttyp des Diensts "…
05.12.2016 14:50:02           Microsoft-Windows-GroupPolicy                          1500 Die Gruppenrichtlinieneins…
05.12.2016 14:50:01           Microsoft-Windows-GroupPolicy                          1500 Die Gruppenrichtlinieneins…
05.12.2016 14:49:56           Service Control Manager                                7036 Dienst "Windows Modules In…
05.12.2016 14:49:25           Microsoft-Windows-DHCP-Server                          1043 Es wurde festgestellt, das…
05.12.2016 14:49:05           Service Control Manager                                7036 Dienst "DHCP-Server" befin…
05.12.2016 14:49:01           Microsoft-Windows-DHCP-Server                          1056 Der DHCP-Dienst wird auf e…
05.12.2016 14:45:31           Service Control Manager                                7036 Dienst "DHCP-Server" befin…
05.12.2016 14:45:31           Microsoft-Windows-DHCP-Server                          1054 Der DHCP/BINL-Dienst auf d…
05.12.2016 14:45:31           Microsoft-Windows-DHCP-Server                          1053 Der DHCP/BINL-Dienst hat e…
05.12.2016 14:45:19           Service Control Manager                                7036 Dienst "DHCP-Server" befin…
05.12.2016 14:45:15           Microsoft-Windows-DHCP-Server                          1056 Der DHCP-Dienst wird auf e…
05.12.2016 14:45:03           Microsoft-Windows-GroupPolicy                          1500 Die Gruppenrichtlinieneins…

geschaut und hier tauchen dann auch die üblichen Verdächtigen DHCP/BINL-Meldungen auf! Wenn man nun genauer nachschaut, wird es auch offensichtlich:

Get-WinEvent -LogName system -MaxEvents 20| where {$_.id -eq 1053}| ft message -Wrap

Message
——-
Der DHCP/BINL-Dienst hat einen anderen Server mit der IP-Adresse fe80::3a10:d5ff:fe89:bb02 in diesem Netzwerk ermittelt
, der zu der folgenden Domäne gehört: .

Also wo liegt nun das Problem? Warum hab ich oben immer geschrieben, dass ich den IPv4DHCP ausgeschaltet habe? Na klar, weil die Fritzbox auch noch einen IPv6DHCP hat und dieser munter weiter aktiv war. Und da im Netz nunmal unabhängig von IPv4 und IPv6 nur ein DHCP aktiv sein war, hat sich der Windows DHCP-Server immer schneller verabschiedet!

Also Lösung: Entweder IPv6 ganz abschalten oder den IPv6DHCP abschalten! Besser ist natürlich die zweite Variante.

Mal abgesehen davon, dass ich hätte schneller drauf kommen können. ist mir erst durch diese Geschichte wieder aufgefallen, wie inkonsistent die DHCP-Dienst-Sache unter Windowsservern ist. Einfach nur traurig…