neonzero
Goto Top

Batch - Betriebssysteminformationen abfragen (auch ohne WSH) - NT, 200x, XP, Vista, ... - Name ink. Typ (Server, Home, etc.), Version, Product Suite (Terminal Server, etc.), Sprache und Windows Service Pack, 32 oder 64 Bit

Der Beitrag, inkl. Quelltext, ist Gemeinfrei (er darf ohne jegliche Einschränkung genutzt werden).

Tipp: Wird der Inhalt in den Quelltextfenstern chaotisch angezeigt, kann es hilfreich sein dort auf den Link "Quelltext" (oben rechts) zu klicken. Es öffnet sich dann ein separates Fenster, welches in der maximierten Darstellung, je nach Bildschirmauflösung, den unerwünschten Zeilenumbruch unterbindet.

In dieser Anleitung soll eine Batch-Funktion gebaut werden, die gebräuchliche Betriebssysteminformationen ermittelt kann und dabei auch in der Lage ist zu prüfen, ob bestimmte Eigenschaften für das aktuelle System zutreffen (also ob es sich z. B. um einen Terminal Server handelt, ob Service Pack 2 [oder womöglich höher] installiert wurde, ob die deutsche Sprachversion von Windows verwendet wird, etc.).

Die Batch soll ohne .vbs und anderen optionalen Skriptsprachen auskommen. Ziel ist es also, eine Batch-Funktion zu schreiben, die möglichst auf allen Computern ablauffähig ist, auf denen ein Windows-Betriebssysem läuft; also auch auf Computern, auf denen kein Windows Scripting Host (WSH) läuft.

Einschränkung: Da Batch-Funktionen erst seit NT3.51 unterstützt werden, ist der Ablauf unter älteren Betriebssystemen (Win3.x bis Win9x) nicht möglich.

Es wird zunächst gezeigt, wie man mit der Funktion umgeht. Dabei soll ein Überblick geschaffen werden, was sich mit der Funktion machen lässt. Der eigentliche Funktionscode ist recht lang, da er die Besonderheiten zahlreicher Betriebssystemversionen berücksichtigen muss. Der Code befindet sich am Ende des Beitrages.


back-to-topAufruf der Funktion

Die Funktion wird im Folgenden „FncWinVer“ genannt und per
    call :FncWinVer [Parameter]
aufgerufen.

back-to-topBetriebssysteminformationen ermitteln
Sobald die Funktion ohne Parameter aufgerufen wird, werden die Betriebssysteminformationen ein einem Format ausgegeben, das sich gut für die Verarbeitung in einer for-Schleife eignet:
@echo off
call :FncWinVer
goto :EOF

<an dieser Stelle muss noch die Funktion FncWinVer hineinkopiert werden, deren Sourcecode weiter unten zu finden ist>
Unter Windows XP könnte das die folgende Ausgabe bewirken:
    Windows XP Professional:5.1 Build 2600:NonSuite:German:SP2:32 bit

Zudem ist es möglich, die Ausgabezeile wie folgt einer Variablen (hier _x) zuzuweisen:
    call :FncWinVer -s _x
Eine Aufschlüsselung der Werte ist dann in folgender Weise denkbar:
@echo off
call :FncWinVer -s _x
for /F "tokens=1-6 delims=:" %%a in ("%_x%") do (  
  echo Operating System... %%a  &rem e.g. "Windows XP Professional"  
  echo Version............ %%b  &rem e.g. "5.1 Build 2600"  
  echo Product Suite...... %%c  &rem e.g. "Terminal Server, ..."  
  echo Localization....... %%d  &rem e.g. "German"  
  echo Service Pack....... %%e  &rem e.g. "SP2"  
  echo Architecture....... %%f  &rem e.g. "32 bit"  
)
goto :EOF

<an dieser Stelle muss noch die Funktion FncWinVer hineinkopiert werden, deren Sourcecode weiter unten zu finden ist>

back-to-topBetriebssysteminformationen abfragen
Für eine Abfrage, ob etwas zutrifft, oder nicht, bieten Batch-Funktionen ganz allgemein einen Rückgabewert an, der sich mit
    <call :Batch-Funktion> && echo Die Bedingung ist erfüllt
oder

Das lässt sich auch auf die hier gezeigte Batch-Funktion anwenden. Die denkbar einfachste Abfrage ist die nach dem verwendeten Betriebssystem-Namen. Sie kann wie folgt erfolgen:
    call :FncWinVer -e "NT4" "XP" && echo Das Betriebssystem ist entweder NT4 oder XP
bzw.

Es ist auch möglich, mehrere Anweisungen an die Funktion zu binden
    call :FncWinVer -e "2000" "2008" "XP" && (
        echo Das Betriebssystem ist entweder Windows 2000, 2008 oder XP
        echo ... hier eine zweite echo-Anweisung
    )

Mögliche Betriebssystem-Namen, die sich hier abfragen lassen, sind z.B.
    "NT3", "NT4", "2000", "2003", "2008", "XP", "Vista", ...
Grundsätzlich sollte die Funktion auf allen Windows-Versionen laufen, die auf NT basieren, von NT3 bis Vista und Nachfolgende, wobei die Namen nur bis zur maximal gewünschten Übereinstimmung angegeben werden müssen. Also wird hier z. B. „NT“ angegeben, so ist die Bedingung unter NT3 und NT4 erfüllt. Wird stattdessen „3“ angegeben, so passt 2003 und NT3 in das Suchmuster der Funktion.

Auf gleicher Weise lassen sich nicht nur die Betriebssystem-Namen abfragen, sondern auch sämtliche andere Felder, die die Funktion ohne Parameter ausgegeben hat.
call :FncWinVer -e "XP::::SP2"                    && echo Das ist Windows XP mit Service Pack 2  
call :FncWinVer -e "XP Professional::::SP2"       && echo Das ist Windows XP Profssional mit SP2  
call :FncWinVer -e "XP Professional:::German:SP2" && echo Das ist ein deutsches WinXP Prof mit SP2  
call :FncWinVer -e "XP Pro:::Ger:SP2"             && echo Das ist ein deutsches WinXP Prof mit SP2  
Bei einer "Windows XP Home"-Version würde nur die erste Zeile ausgegeben werden. Eine englische Variante von "Windows XP Professional" würden die beiden ersten Ausgaben hervorbringen. Bei einer deutschen Variante von "Windows XP Professional" würden alle vier Ausgabezeilen zu sehen sein. Die Anfrage wurde so formuliert, dass als weitere Bedingung genau das "Service Pack 2" (nicht höher oder niedriger) installiert sein muss, um eine Ausgabe zu erzeugen.

Hinweis: Seit Windows Vista wurde die Länderkennung von German in de geändert. Eine entsprechende Abfrage nach einer deutschen 32-Bit Variante von Windows Vista mit beispielsweise Service Pack 1 muss also wie folgt erfolgen:
    call :FncWinVer -e "Vista:::de:SP1:32" && echo Das ist ein deutsches Windows Vista, 32-Bit, mit Service Pack 1

Auch Abfragen ohne Angabe des Betriebssystem-Namens sind möglich:
call :FncWinVer -e "::Terminal Server:::" && echo Das Betriebssystem arbeitet als Terminal Server  
call :FncWinVer -e ":::::64"              && echo Das ist eine 64-Bit-Variante des Betriebssystems  
call :FncWinVer -e ":5.1::::"             && echo Das Betriebssystem hat die Version 5.1  
call :FncWinVer -e ":Build 2600::::"      && echo Das Betriebsystem hat das Build 2600  
call :FncWinVer -e ":5.1 Build 2600::::"  && echo Das Betriebssystem hat die Version 5.1 Build 2600  
call :FncWinVer -e ":5.1 Build 2600"      && echo Das Betriebssystem hat die Version 5.1 Build 2600  

Die folgende Abfrage zeigt, wie man ermitteln kann, ob es sich um Windows 2000 mit Service Pack 2 oder höher handelt. Das schließt Service Pack 3 genauso mit ein, wie neuere Versionen von Windows (2003, 2008, etc.). Das wird erreicht, indem die anderen bekannten Systeme ausgeschlossen werden (hier beispielhaft auch XP und Vista):
@echo off
call :FncWinVer -e "NT" "XP" "Vista" "2000::::SP0" "2000::::SP1" || (  
  echo Das ist Windows 2000 mit SP2 oder höher.
  echo Neben Windows 2000 mit SP3 könnte es also auch z.B. Windows 2003, 2008 oder höher sein.
)
goto :EOF

<an dieser Stelle muss noch die Funktion FncWinVer hineinkopiert werden, deren Sourcecode weiter unten zu finden ist>
Künftige Betriebssystem-Versionen führen in diesem Beispiel ebenfalls zur Abarbeitung des ()-Blocks, da sie ja nicht explizit ausgeschlossen wurden.

back-to-topDer Funktionscode

Um den Funktionscode zu kopieren, klicke auf "in den Speicher kopieren". Wenn nur ein Teil des Codes kopiert werden soll, klicke auf "Quelltext" und maximiere das sich dann öffnende Fenster, um den unerwünschten Zeilenumbruch zu unterbinden. Dort lassen sich die Zeilen wie gewohnt markieren und kopieren.
:FncWinVer      ::Version 2.0.1
::Parameters:   [-e | -s] [...]
::Options:      -e <Name> [Name2]   When the Operating System is one of the name, function returns true (0)
::                  Name can be "NT3", "NT4", "2000", "2003", "2008", "XP", "Vista"  
::                  For Detail-Information use e.g. "XP Professional:::German:SP2" (see Example)  
::              -s <VarNameToReturnOSString>
::Example:      if "%OS%" == "" echo The OS is DOS, Win3.x or Win9x  & goto :EOF  (you can not use batch-functions)  
::              call :FncWinVer        (print OS-Version, e.g. "Windows XP Professional:5.1 Build 2600:NonSuite:German:SP2:32 bit")  
::              call :FncWinVer -s _x  (set _x=OS-Version)
::              for /F "tokens=1-6 delims=:" %%a in ("%_x%") do (  
::                echo Operating System... %%a  &rem e.g. "Windows XP Professional"  
::                echo Version............ %%b  &rem e.g. "5.1 Build 2600"  
::                echo Product Suite...... %%c  &rem e.g. "Terminal Server, ..."  
::                echo Localization....... %%d  &rem e.g. "German"  
::                echo Service Pack....... %%e  &rem e.g. "SP2"  
::                echo Architecture....... %%f  &rem e.g. "32 bit"  
::              )
::              call :FncWinVer -e "NT" "XP" && (  
::                echo The Operating System is Windows NT3 or NT4 or XP
::                call :FncWinVer -e "XP::::SP2"                   && echo The OS is Windows XP with Service Pack 2  
::                call :FncWinVer -e "XP Professional:::SP2"       && echo The OS is Windows XP Profssional with SP2  
::                call :FncWinVer -e "XP Professional::German:SP2" && echo The OS is German Windows XP Prof with SP2  
::                call :FncWinVer -e "XP Pro::Ger:SP2"             && echo The OS is German Windows XP Prof with SP2  
::              )
::              call :FncWinVer -e "NT4" "XP" || echo The OS is not Windows NT4 or XP     (&&=is true; ||=is not true)  
::              call :FncWinVer -e "NT" "XP" "Vista" "2000" "2003::::SP0" "2003::::SP1" || (  
::                echo This is Windows 2003 with SP2 or higher - also can be Windows 2008, etc.
::              )
::              call :FncWinVer -e "::Terminal Server::" && echo This is a Terminal Server  
::              call :FncWinVer -e ":5.1:::"             && echo This is Version 5.1  
::              call :FncWinVer -e ":Build 2600:::"      && echo This is Build 2600  
::              call :FncWinVer -e ":5.1 Build 2600:::"  && echo This is Version 5.1 Build 2600  
::              call :FncWinVer -e ":5.1 Build 2600"     && echo This is Version 5.1 Build 2600  
::Return:       0=Operating System found; 1=Operating System not found; 2=syntax error
 setlocal EnableDelayedExpansion & set "_#SP=SP0" & set "_#OSEX1=NonSuite" & set "_#TMP=" & set "_#EL=0" & set "_#Prd=unknown system"  
  if exist "%systemroot%\system32\prodspec.ini" ( ::Name und Sprache ermitteln; NT3 bis Windows 2008  
    for /F "tokens=1* delims==" %%a in ('type "%systemroot%\system32\prodspec.ini"') do (  
      if /i "%%a" == "Product"      set _#Prd=%%b  
      if /i "%%a" == "Localization" set _#Lang=%%b  
    )
  ) else ( ::ab Vista
    set _#Lang=%LC_LANG%
    set _#TmpPrdFile=%TMP:"=%\%~n0_Prd%RANDOM%.tmp  &::Da der ProductName, z.B. "Vista (TM)", auch Klammern enthalten kann... 
    for /f "tokens=2,* delims=	 " %%a in ('%SYSTEMROOT%\system32\reg.exe query  
                                            "HKLM\Software\Microsoft\Windows NT\CurrentVersion"  
                                            /v "ProductName" 2^>NUL ^| find /i "ProductName"') do (echo."%%b") > "!_#TmpPrdFile!"  
    set /p "_#Prd=" < "!_#TmpPrdFile!" &::... wird die Variablen-Zuweisung ueber diesen Umweg vorgenommen.  
    set "_#Prd=!_#Prd:(=!" & set "_#Prd=!_#Prd:)=!" & set "_#Prd=!_#Prd:"=!"  
    del "!_#TmpPrdFile!"  
  )
  
  if exist "%windir%\SysWOW64" ( set "_#Bit=64 bit" ) else ( set "_#Bit=32 bit" )  

  set "_#Prd=%_#Prd:NT Workstation 4.=NT4 Workstation 4.%" & set "_#Prd=%_#Prd:NT Server 4.=NT4 Server 4.%"  
  set "_#Prd=%_#Prd:NT Workstation 3.=NT3 Workstation 3.%" & set "_#Prd=%_#Prd:NT Server 3.=NT3 Server 3.%"  
  
  if not exist "%SYSTEMROOT%\system32\reg.exe" ( ::NT3, NT4 und w2k kennen keine reg.exe, daher...  
    set _#TmpRegFile=%TMP:"=%\%~n0_RegExport%RANDOM%.tmp 
    %SYSTEMROOT%\regedit.exe /E "!_#TmpRegFile!" "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion"  
    type "!_#TmpRegFile!" > "!_#TmpRegFile!_ANSI-Format"  
    rem Von den ca. 60.000 rekursiv exportierten Registry-Zeilen die ersten 100 Zeilen extrahieren...
    (for /L %%i in (1,1,100) do set /p "_x=" & echo.!_x!) <"!_#TmpRegFile!_ANSI-Format" >"!_#TmpRegFile!"  
    rem ...damit die nun folgende for-Schleife wesentlich schneller abgearbeitet werden kann:
    for /f "tokens=1,2,4 delims==	 " %%a in ('type "!_#TmpRegFile!"') do (  
        if /i %%a == "CSDVersion"         set _#SP=SP%%c  
        if /i %%a == "CurrentVersion"     set _#Ver=%%b  
        if /i %%a == "CurrentBuildNumber" set _#Build=%%b  
    )
    del "!_#TmpRegFile!" "!_#TmpRegFile!_ANSI-Format"  
    set _#OSEX1=NT3_NT4_or_2000=Product Suite can not be identified
  ) else ( ::Windows XP, 2003 oder hoeher... (reg.exe ist schneller und kann MULTI_SZ "ProductSuite" auslesen)  
    for /f "tokens=1,3,5 delims=	 " %%a in ('%SYSTEMROOT%\system32\reg.exe query  
                                              "HKLM\Software\Microsoft\Windows NT\CurrentVersion" 2^>NUL') do (  
      if /i "%%a" == "CSDVersion"         set _#SP=SP%%c  
      if /i "%%a" == "CurrentVersion"     set _#Ver=%%b  
      if /i "%%a" == "CurrentBuildNumber" set _#Build=%%b  
    )
    for /f "tokens=2,* delims=	 " %%a in ('%SYSTEMROOT%\system32\reg.exe query  
                                            "HKLM\System\CurrentControlSet\Control\ProductOptions"  
                                            /v "ProductSuite" 2^>NUL ^| find /i "ProductSuite"') do set _#TMP=%%b  
    if defined _#TMP set _#TMP=!_#TMP:\0\0=!
    if defined _#TMP set _#TMP=!_#TMP:\0=, !
    if defined _#TMP if not "!_#TMP!" == ", " set _#OSEX1=!_#TMP! 
  )

  set _#TMP=%_#Prd:*Terminal Server Edition=Found_%
  if "%_#TMP:~0,6%" == "Found_" ( ::zur Vereinheitlichung: unter NT4 den Prd-TS-Eintrag nach ProductSuite verschieben  
    set _#Prd=%_#Prd: Terminal Server Edition=%
    set _#OSEX1=Terminal Server Edition, %_#OSEX1%
  )

  set "_#OS_Info=%_#Prd%:%_#Ver% Build %_#Build%:%_#OSEX1%:%_#Lang%:%_#SP%:%_#Bit%" & set "_#OS_Info=!_#OS_Info:"=!"  
  
  if "%~1" == "" (  
    echo %_#OS_Info%
    goto :LEB_FncWinVer_END
  ) else if "%~1" == "-s" (  
    endlocal & set "%~2=%_#OS_Info%" & exit /b %_#EL%  
  ) else if not "%~1" == "-e" (  
    set _#EL=2 & goto :LEB_FncWinVer_END
  ) 
  set _#EL=1
  :LOOP_FncWinVer_NextOS   ::Option -e gefunden (es soll gestestet werden, ob das aktuelle Betriebssystem bestimmte Bedingungen erfuellt)
    shift
    set "_#InfoLST=%_#OS_Info%:#END#" & set "_#ParLST=%~1:#END#"  
    :LOOP_FncWinVer_NextDetail
      set "_#InfoITM=%_#InfoLST%"                 &rem die OS-Info-Liste (z.B. "Windows XP Professional:5.1 Build 2600:...") auseinandernehmen...  
      set "_#InfoLST=%_#InfoLST:*:=%"             &rem "*:=" loescht alles bis zum Aufkommen des ersten ":"-Zeichens; uebrig bleibt der rechte Teilstring  
      if not "%_#InfoITM%" == "%_#InfoLST%" (  
        set "_#InfoITM=!_#InfoITM::%_#InfoLST%=!" &rem InfoITM=erster Eintrag (entspricht urspruengliche Liste abzueglich rechtem Teilstring)  
      )
      set "_#ParITM=%_#ParLST%"                   &rem Den Suchstring (z.B. "XP:::SP2:#END#") auseinandernehmen...  
      set "_#ParLST=%_#ParLST:*:=%"               &rem "*:=" loescht alles bis zum Aufkommen des ersten ":"-Zeichens; uebrig bleibt der rechte Teilstring  
      if not "%_#ParITM%" == "%_#ParLST%" (  
        set "_#ParITM=!_#ParITM::%_#ParLST%=!"    &rem ParITM=erster Eintrag (entspricht urspruengliche Liste abzueglich rechtem Teilstring)  
      )
      if defined _#InfoITM if defined _#ParITM if not "%_#ParITM%"  == "#END#" ( 
        set "_#TMP=!_#InfoITM:*%_#ParITM%=Found_!" &rem das ist _wesentlich_ schneller als find.exe, ignoriert aber Gross-/Kleinschreibung  
        if "!_#TMP:~0,6!" == "Found_" ( ::gefunden; nun muss die Ueberpruefung noch einmal case-sensitiv durchgefueht werden...  
          echo "!_#InfoITM!" | find "!_#ParITM!" >NUL && set "_#EL=0" && rem "ParITM kommt in InfoITM vor" ist fuer dieses Item erfuellt  
        ) else ( ::die erste Unstimmigkeit des Parameters wurde im aktuellen Item entdeckt
          set "_#EL=1"   
          set "_#ParITM=#END#"                   &rem Weitersuchen nicht erforderlich; auf zum naechsten Parameter  
        )
      )
    if not "%_#ParITM%"  == "#END#" if not "%_#InfoITM%" == "#END#" goto :LOOP_FncWinVer_NextDetail  
  if not "%~2" == "" if not "%_#EL%" == "0" goto LOOP_FncWinVer_NextOS  
  :LEB_FncWinVer_END
 endlocal & exit /b %_#EL%

Bedeutung der Versionsfelder:
    x.x.x
    |   |   '-->Änderungen in diesem Bereich zeigen an, dass ein Fehler beseitigt
    |   |         oder eine Optimierung vorgenommen wurde
    |   '---->Der Parameteraufbau zu einer Option oder der Funktionsumfang hat
    |             sich verändert (neue Optionen, etc.)
    '------->Es wurde eine grundlegende Änderung vorgenommen (allgemeiner
                   Parameteraufbau, Rückgabewert oder ähnliches)

Version 2.0.1: In der vorherigen Version schlug die Anweisung
    call :FncWinVer -e "NT" && echo Es wurde Windows NT gefunden.
leider auch bei z.B. "Windows 2003 Enterprise Edition" an. Der Fehler wurde behoben. Hintergrund: Die verwendete Suchmethode arbeitete nicht case-sensitive. -- NeonZero 22.07.2009

Version 2.0.0: Der Rückgabewert enthält nun ein zusätzliches Feld, welches angibt, ob es sich um eine 32-Bit- oder eine 64-Bit-Variante von Windows handelt. Die Abfrage kann wie folgt erfolgen:
    call :FncWinVer -e ":::::32" && echo Es handelt sich um eine 32 Bit Variante von Windows
    call :FncWinVer -e ":::::64" && echo Es handelt sich um eine 64 Bit Variante von Windows

Version 1.0.3: Windows Vista kennt keine prodspec.ini mehr. Die Länderkennung befindet sich jetzt in der Variablen %LC_LANG%, allerdings als en oder de und nicht als German. Damit muss man wohl leben. Die allgemeine Produktinformation findet sich jetzt in der Registry wieder. Der Code und die Anleitung wurden entsprechend angepaßt. -- NeonZero 29.01.2009

Version 1.0.2: Anders als unter Windows 2000 (und neuer) wird unter NT4 die Information über die Verfügbarkeit eines Terminal Servers nicht unter ProductSuite abgelegt. Vielmehr ist sie Bestandteil der allgemeinen Produktinformation ("Windows NT Server 4.0 Terminal Server Edition"). Zur Vereinheitlichung wurde der Eintrag "Terminal Server Edition" aus diesem (ersten) Feld entfernt und in das (dritte) Feld ProductSuite verschoben. Damit sollte nun auch unter NT4 der Terminal Server wie in der Anleitung beschrieben im dritten Feld abfragbar sein (call :FncWinVer -e "NT4::Terminal Server::" && echo Das Betriebssystem arbeitet als Terminal Server). Zusätzlich wurde die NT-Produktinformation (Feld1) für eine bessere Abfragemöglichkeit vereinheitlicht (eine Suche nach "NT3", "NT4" oder auch "NT4 Server", etc. ist nun möglich). -- NeonZero 13.01.2009

Version 1.0.1: Das Auslesen der Registry-Einträge wurde derart angepaßt, dass nun auch NT3, NT4 und Windows 2000 unterstützt werden. Einzige Einschränkung: Eine Auflistung der "ProductSuite" (unter "HKLM\System\CurrentControlSet\Control\ProductOptions") ist mir unter diesen alten Betriebssystemen noch nicht gelungen, da dies ein MULTI_SZ-Eintrag ist. Das bedeutet, dass die Funktion so tut, als ob auf dem System keine ProductSuite installiert wurde. Alle anderen Informationen sind ohne Einschränkung abfragbar. XP, Windows 2003 und neuer sind von dieser EInschränkung nicht betroffen. Wenn jemand eine Idee hat, wie sich unter Windows 2000 mit Standardmethoden (ohne WSH und ohne ein zusätzliches Tool installieren zu müssen) ein MULTI_SZ-Eintrag auswerten läßt, dann wäre ich für einen Hinweis dankbar. -- NeonZero 13.01.2009

Version 1.0.0: Erste Version, die lediglich unter XP, Windows 2003 und neueren Versionen von Windows funktioniert; sie nutzt reg.exe, die von NT3 bis w2k auf einer Standardinstallation noch nicht vorhanden ist (das wird erst ab Version 1.0.1 berücksichtigt - danke an @paulepank für den Hinweis). -- NeonZero 11.01.2009

Content-Key: 105641

Url: https://administrator.de/contentid/105641

Printed on: April 16, 2024 at 19:04 o'clock

Member: TuXHunt3R
TuXHunt3R Jan 10, 2009 at 23:16:54 (UTC)
Goto Top
Grundsätzlich mal nicht schlecht, allerdings benutze ich inzwischen bei solchen Scripts inzwischen immer die PowerShell in Kombination mit WMI (oder VBS, wenns denn vom Chef so bestimmt wurde). Batchcode ist meiner Meinung nach zu unleserlich und zu kryptisch für solch komplexe Scripts.
Member: NeonZero
NeonZero Jan 11, 2009 at 01:30:31 (UTC)
Goto Top
Hallo TuXHunt3R. Ich kann Deine Argumente gut nachvollziehen. Allerdings würde man bei der Verwendung der PowerShell oder einer alternativen Skriptsprache das maßgebliche Ziel aus den Augen verlieren. Die spezielle Anforderung war es, die Lauffähigkeit zu gewährleisten, ohne ein Zusatzprodukt installieren zu müssen und auch ohne auf einen aktivierten WSH angewiesen zu sein. Der Vorteil von Batch ist ja gerade der, dass der Code ohne weiteres Zutun auf jedem der genannten Systeme ausgeführt werden kann.

Bye, nz
Member: Biber
Biber Jan 11, 2009 at 11:22:10 (UTC)
Goto Top
Moin TuXHunt3R,
Batchcode ist meiner Meinung nach zu unleserlich und zu kryptisch für solch komplexe Scripts.
Genau diese Ansicht ist ja die große Herausforderung beim Erstellen von Batchscripts und erst recht von Tutorials zum Thema "Batchlösungen für komplexere Probleme".

Batchdateien sind wirklich nicht selbstdokumentierend und erzwingen syntaktisch nicht unbedingt eine strukturierte Herangehensweise.

Gerade deshalb finde ich NeonZeros Tutorial - mit sauberer Herleitung, Struktur und Dokumentation - im Bereich "Batch & Shell" sehr gelungen.

Und die von NeonZero formulierte Ausgangssituation "Wie kann ich verlässliche Ergebnisse erzielen, wenn ich als Werkzeuge nur ein Stück Bindfaden und zwei Streichhölzer zur Verfügung habe?" finde ich bezogen auf Windows-Standard-Client-Installationen durchaus begründet.

Natürlich geht es mit einem prall gefüllten Powershell-Werkzeugkasten eventuell "besser". aber ...
... ein C#-oder .NET-Coder würde auch sagen:
"Hey, da brat ich Dir in 10 Minuten was Besseres zusammen."

Von mir jedenfalls großes Lob für das mit Bindfaden und Streichhölzern erstellte Ergebnis.

Grüße
Biber
Member: paulepank
paulepank Jan 11, 2009 at 19:01:58 (UTC)
Goto Top
Hallo hier,

@Biber
...für das mit Bindfaden und Streichhölzern erstellte Ergebnis
naja, etwas Zauberpulver war auch dabei, weil ...

@NeonZero
...dass der Code ohne weiteres Zutun auf jedem...
Das stimmt so nicht.
Am Beispiel vom Windows 2000 - hier gibt es keine reg.exe.
Diese muß per Hand aus dem Supporttool entweder in den System32-Ordner kopiert werden.
Dann wäre der Aufruf %SYSTEMROOT%\system32\reg.exe doppelt gemoppelt.
oder die Supporttools werden installiert. Dann liegt reg.exe im Ordner %ProgramFiles%\Supporttools.
Dann ist der Aufruf %SYSTEMROOT%\system32\reg.exe sogar falsch.
Fazit:
Da %ProgramFiles%\Supporttools zur PATH-Variablen hinzugefügt wird genügt auf jeden Fall als Aufruf reg.exe query ....

Der Anspruch "ohne weiteres Zutun" kann durch Verwenden von reg.exe nicht erfüllt werden.

cu paulepank
Member: NeonZero
NeonZero Jan 11, 2009 at 21:47:25 (UTC)
Goto Top
Zitat von @paulepank:
... Windows 2000 - hier gibt es keine reg.exe.

Das ist ein guter Hinweis. Danke. Mann könnte das über die Export-Funktion von regedit.exe lösen, die auch unter Windows 2000 läuft. Allerdings wird diese Anpassung die Batch-Funktion um einiges aufblähen.

Bis dahin ist die Batch-Funktion, wie Du richtig festgestellt hast, nur für XP, Windows 2003 und Nachfolgende geeignet.

Nachtrag: Mit der aktuellen Anpassung sollte die Batch-Funktion (Verison 1.0.1) nun auch unter NT3, NT4 und w2k laufen. Allerdings mit einer Einschränkung: Der Eintrag "ProductSuite" unter "HKLM\System\CurrentControlSet\Control\ProductOptions" lässt sich nicht über den Weg der Export-Funktion von regedit.exe aufschlüsseln, da dies ein MULTI_SZ-Eintrag ist. Wenn jemand eine Idee hat, wie sich unter Windows 2000 mit Standardmethoden (ohne WSH und ohne ein zusätzliches Tool installieren zu müssen) ein MULTI_SZ-Eintrag auswerten läßt, dann wäre ich für einen Hinweis dankbar.

Bye, nz
Member: TuXHunt3R
TuXHunt3R Jan 13, 2009 at 23:21:01 (UTC)
Goto Top
@ Biber:
Und die von NeonZero formulierte Ausgangssituation "Wie kann ich verlässliche Ergebnisse erzielen, wenn ich als Werkzeuge nur ein Stück Bindfaden und zwei Streichhölzer zur Verfügung habe?" finde ich bezogen auf Windows-Standard-Client-Installationen durchaus begründet.

Bei Servern gehört die PowerShell ab 2008 standardmässig dazu, bei den Clientsystemen ab Windows 7. Das .NET Framework 2.0 ist seit Vista auch überall standardmässig drauf (ausser der Core-Installation von 2008 Server) und den WSH gibt es seit Windows 2000 auch überall standardmässig dazu. Aber ich verstehe deine Argumentation...


Am Beispiel vom Windows 2000 - hier gibt es keine reg.exe.
Richtig. Es gibt auch noch andere Dinge, die bei Windows 2000 anders sind, z.B. die Abfrage des Errorlevels (%errorlevel%).
Member: NeonZero
NeonZero Jan 14, 2009 at 11:39:09 (UTC)
Goto Top
TuXHunt3R, Du möchtest auf einem Windows 2008 lieber per PowerShell-Skript nach dem verwendeten Betriebssystem fragen. Unter Windows 2000 nutzt Du dafür lieber den WSH und unter NT4 vermutlich lieber eine Batch-Lösung. Um das zu tun, musst Du vorher schon wissen, um welches System es sich handelt. Dann ist die Abfrage nach dem verwendeten Betriebssystem allerdings überflüssig. Andernfalls brauchst Du etwas, das auf all diesen Systemen läuft. Die Batch-Funktion erfüllt diese Voraussetzung.

Zudem: Selbst wenn Du ein System hast, auf dem per Standardinstallation eine PowerShell installiert wurde, wird Dein PowerShell-Skript nicht laufen, da die Skript-Ausführung standardmäßig deaktiviert ist. Das ist Teil des Sicherheitskonzepts. Der Administrator muss die PowerShell erst entsprechend konfigurieren und dabei bewusst festlegen, welche Art von .ps1-Skripten zugelassen sind (z.B. nur Skripte von lokalen Laufwerken starten, ggf. nur signierte Skripte starten, etc.). Eine verlässliche einheitliche Einstellung, die Du z.B. außerhalb Deines Unternehmens vorfinden kannst, gibt es nicht.

Ähnlich sieht es mit dem WSH aus. Aus Sicherheitsgründen wird er gerne deaktiviert. Deshalb existiert ja die Aufgabenstellung aus der Einleitung, die explizit darauf hinweist, dass bei dieser Lösung nicht auf den WSH zugegriffen werden soll. Was Du mit dem .NET-Framework machen möchtest, ohne den WSH zu verwenden, ist mir unklar.

Zitat von @TuXHunt3R:
Es gibt auch noch andere Dinge, die bei Windows 2000 anders sind, z.B. die Abfrage des Errorlevels (%errorlevel%).

Könntest Du das bitte konkretisieren?

Bye, nz
Member: TuXHunt3R
TuXHunt3R Jan 15, 2009 at 20:43:36 (UTC)
Goto Top
Windows 2000:
ping -n 1 192.168.1.1 | find /i "TTL" >nul  
if "%errorlevel%"=="0" (  
echo Erreichbar
) else (
echo Nicht erreichbar
)

Windows Vista:
ping -n 1 192.168.1.1 | find /i "TTL" >nul  
if %errorlevel%==0 (
echo Erreichbar
) else (
echo Nicht erreichbar
)
(Aus dem Kopf, nicht getestet)

Des weiteren ändert bei den verschiedenen zusätzlichen Commandline-Tools (z.B. Resource Kit) manchmal die Syntax. Ich glaube, RMTSHARE ist so ein Beispiel. Bin mir allerdings nicht sicher.
Member: NeonZero
NeonZero Jan 16, 2009 at 08:50:18 (UTC)
Goto Top
Zitat von @TuXHunt3R:
Aus dem Kopf, nicht getestet

Es wäre nett, wenn Du den Test bitte nachholen könntest. Beide Abfragen sollten unter beiden Systemen funktionieren (wobei Du bitte zwischen dem Vergleichsoperator und den beiden Argumenten ein Leerzeichen setzen solltest).

Bye, nz
Mitglied: 36539
36539 Feb 02, 2009 at 21:37:07 (UTC)
Goto Top
Hallo NeonZero,

Erstmal Respekt. Wirklich Klasse gemacht.

Dazu noch eine Frage:

Kann man hier auch die Abfrage ob 32- oder 64-bit-System ebenfalls mit einbauen?

gruß
onegasee59
Member: NeonZero
NeonZero Feb 03, 2009 at 16:21:37 (UTC)
Goto Top
Ich habe die Funktion entsprechend angepasst. Sie hat jetzt die Version 2.0.0, da sich der Rückgabewert geändert hat (ein zusätzliches letztes Feld enthält die gefragte Information). Die Abfrage kann nun wie folgt erfolgen:
    call :FncWinVer -e ":::::32" && echo Es handelt sich um eine 32-Bit-Version von Windows

Es ist jedoch ein quick-and-dirty hack, da ich auf die Schnelle keine offizielle Aussage von MS finden konnte, die besagt, wie man aus einer Batch heraus diese Information ermitteln soll. Was soll’s. Sobald sich mir ein besserer Weg offenbart, um an diese Information zu gelangen, werde ich die Funktion entsprechend anpassen.

Allgemeine Abfragemöglichkeiten in einer DOS-Konsole wären:
  1. dxdiag /t benutzt APIs, um solche Informationen zu sammeln und in eine Textdatei abzuspeichern. Die Textdatei ließe sich in einer for-Schleife auswerten. Allerdings dauert es extrem lange, bis die Protokolldatei angelegt wird. Für die Batch-Funktion scheint mir dieser Weg ungeeignet zu sein.
  2. Alternativ dazu könnte man auch eine WMI-Anfrage starten (z.B. wmic path win32_operatingsystem get caption). Das funktioniert aber nur auf Windows 2003, XP Professional (nicht XP Home) und Vista. Auch muss der WMIC (Windows Management Instrumentation Commandline) auf dem PC installiert sein; dieser benötigt zudem den WSH. Für die Funktion ist diese Lösung deshalb nicht geeignet.
  3. Auf 64-Bit Windows-Systemen gibt es einen Registry-Schlüssel namens HKEY_LOCAL_MACHINE\Software\WOW6432. Das scheint ein virtueller Key zu sein, der die 32-Bit-Schlüssel zusammenfasst.
  4. Zudem gibt es auf 64-Bit-Systemen exklusiv das Verzeichnis %windir%\SysWOW64.

Daher benutze ich in der Funktion nun einfach die Abfrage, ob das Verzeichnis %windir%\SysWOW64 auf dem System vorhanden ist, in der Hoffnung, dass auch künftige 64-Bit-Systeme ein solches Verzeichnis anlegen.

Bye, nz
Mitglied: 36539
36539 Feb 03, 2009 at 17:01:24 (UTC)
Goto Top
Hallo NeonZero,

erstmal Danke für Deinen Antwort.

Ich habe inzwischen auch mal recherchiert.

Zu Punkt 4.
Ich frage das gleiche Verzeichnis "%windir%\SysWOW64" in meinem Tool XPandWMP-PermReset-Fix , damit es nicht auf 64bit-Systemen angewendet werden kann. Vor einigen Tagen erhielt ich Rückmeldung das bei einem User mein Tool das weiterarbeiten verweigert und ihm 64bit meldet, er aber angeblich nur ein 32bit-System hat.

Habe dann mal weiter recherchiert und jetzt die Abfrage über Systemvariable eingebaut:

if %PROCESSOR_ARCHITECTURE%==x86 (set osbit=32bit) else (set osbit=64bit)

Vielleicht ist das auch für Dich gegeignet.

Gruß
onegasee59
Member: NeonZero
NeonZero Feb 03, 2009 at 18:02:51 (UTC)
Goto Top
Hallo Matthias. Danke für Deinen Tipp. In einer .exe sollte die Abfrage kein Problem sein. Du kannst leicht auf eine entsprechende API zugreifen, die Dir u.a. die 32 oder 64-Bit-Variante zurückgibt (siehe msdn-Suche).

<ot>Sympathisch finde ich, dass Du Deine Tools als Freeware zur Verfügung stellst. Perfekt wäre es, wenn auch die Sourcen enthalten wären. Gibt es einen speziellen Grund dafür, sie nicht in die .zip zu packen?</ot>

Ich würde mich gerne selbst davon überzeugen, ob auf der fraglichen 32-Bit-Version tatsächlich dieses Verzeichnis existiert. Dabei ist es wichtig zu wissen, was genau unter „Systemsteuerung / System / Allgemein“ des betroffenen PCs ausgegeben wird. Kannst Du die Angaben des Anwenders bitte hier posten?

Bye, nz
Mitglied: 36539
36539 Feb 03, 2009 at 21:46:16 (UTC)
Goto Top
Hallo NeonZero,

Hallo Matthias. Danke für Deinen Tipp. In einer .exe sollte die Abfrage kein Problem sein. Du kannst leicht auf eine entsprechende API
zugreifen, die Dir u.a. die 32 oder 64-Bit-Variante zurückgibt (siehe msdn-Suche).

Ist Batch-to-EXE, d.h. nur als *.exe verpackt. face-wink

<ot>Sympathisch finde ich, dass Du Deine Tools als Freeware zur Verfügung stellst. Perfekt wäre es, wenn auch die
Sourcen enthalten wären. Gibt es einen speziellen Grund dafür, sie nicht in die .zip zu packen?</ot>


Klar könnte ich machen, aber dann müsste sich jeder Interressent den ganzen Kram runterladen.
Wollte ich vermeiden, weil wenn man die *.zip entpackt und die *.exe startet, findet man den gesamten Inhalt der *.exe im Ordner Temp.
"C:\Dokumente und Einstellungen\..username..\Lokale Einstellungen\Temp"

Ich würde mich gerne selbst davon überzeugen, ob auf der fraglichen 32-Bit-Version tatsächlich dieses Verzeichnis
existiert. Dabei ist es wichtig zu wissen, was genau unter „Systemsteuerung / System / Allgemein“ des betroffenen PCs
ausgegeben wird. Kannst Du die Angaben des Anwenders bitte hier posten?

Gerne, muss ich aber hoffen das von Ihm noch eine Reaktion auf mein Antwort an Ihn kommt.
Er hatte in der Newsgroup geantwortet und ist dabei über das Webinterface von MS gegangen, also keinen replayfähigen Emailaccount benutzt.
Thread "Installation fehlgeschlagen" in NG microsoft.public.de.inetexplorer.ie7

Gruß
onegasee59
Member: Batchler
Batchler Jan 28, 2011 at 20:58:27 (UTC)
Goto Top
Hallo Leute,

bin neu hier und bin schon durch einige Threads hier im Unterforum "Batch & Shell" inspiriert worden, komme aber momentan nicht weiter.

Habe mal vor längerer Zeit angefangen, das Betriebssystem bei Win2000 zu ermitteln, dann ist WinXP dazugekommen und mittlerweile bin ich bei Win7 / 64bit angekommen. Auf der Suche nach einer allgemeingültigen Abfrage bin ich auf diesen Thread gestoßen.

Super Sache, allerdings sind mir 2 Sachen aufgefallen.

Bei Windows 7 wird folgendes Ergebnis ausgespuckt:

Operating System... Windows 7 Professional
Version............ 6.1 Build 7600
Product Suite...... Terminal Server
Localization....... SP0
Service Pack....... 64 bit
Architecture.......

Ergebnisse von "ServicePack" und "Architecture" rutschen ein Feld nach oben. Nach dem ich unter die Zeile 42

set _#Lang=%LC_LANG%
noch folgende Zeile eingefügt habe
IF "%_#Lang%" == "" SET _#Lang=No Localization
klappt es mit der Abfrage. Ich denke, da Win7 mehrsprachig ist, wird auch keine direkte Sprache hinterlegt sein. Ist aber nur eine Vermutung von mir und es funktioniert.

Da, wo ich nicht weiterkomme, ist bei Windows 2000:
Operating System... Windows 2000 Professional
Version............ "5.0" Build "2195"  
Product Suite...... NT3_NT4_or_2000=Product Suite can not be identified
Localization....... German
Service Pack....... SP4"  
Architecture....... 32 bit" & set "_#OS_Info "=  

Wie man sieht, wird bei "Architecture" noch ein Rest vom nachfolgenden Befehl mit angehängt. Ich habe schon ein bisschen probiert, da ich aber, sagen wir mal, fortgeschrittener Anfänger bin, komme ich mit meinem Latein nicht weiter.

Hat jemand von Euch eine Idee, wo der Fehler in diesem Skript liegt ?

Ach ja, noch eine kleiner Schönheitsfehler meinerseits: Wollte bei "Architecture" folgende Ausgabe: "64bit (x64)" bzw. "32bit (x86)"
Bei den Klammern innerhalb des "SET"-Befehls für die Variablen-Deklaration "_#Bit" kommt das Skript ins Straucheln. Habe es mit dem Maskierungszeichen ^ versucht, klappt aber auch nicht. Wie gesagt nur ein kleiner Schönheitsfehler, sollte aber jemand eine Lösung dafür haben, immer her damit.

So das war es fürs erste Mal.
Gruß

Batchler

Nachtrag:

Habe es gerade nochmals probiert mit der "Architecture"-Ausgabe: "64bit (x64)" bzw. "32bit (x86)" und dem Maskieren von der Klammer.

wenn ich mir per ECHO die Variable direkt anzeigen lasse
echo Architecture....... %%f
habe ich folgende Ausgabe
Architecture....... 32bit ^(x86^)

wenn ich aber die Ausgabe wieder in einer Variable hinterlege
SET Architecture=%%f
und danach per ECHO aufrufe
ECHO Architecture....... %Architecture%
habe ich folgende Ausgabe
Architecture....... 32bit (x86)

also alles wieder im Lot.
Mitglied: 99045
99045 Sep 06, 2011 at 10:13:53 (UTC)
Goto Top
Ich hätte da einen 5-Zeiler im Angebot, bei dem die wesentlichen Informationen das Systemprogramm systeminfo.exe, dabei ab Windows XP ermittelt und eine Batchzeile für die Ausgabe sorgt:

@echo off & setlocal enabledelayedexpansion
set /a line=0
for /f "tokens=1,2* delims=:" %%a in ('systeminfo') do @echo %%a %%b & set /a line+=1 & if !line! gtr 15 goto :raus  
:raus
set /p blubb=fertig.

Funktioniert ab XP bis Win7 32/64 auf Workstations, Server habe ich nicht, kann es also nicht testen, sollte aber eigentlich ebenfalls funktionieren. Evtl. muss der Zähler von 15 auf einen etwas höheren Wert gesetzt werden.