Top-Themen

AppleEntwicklungHardwareInternetLinuxMicrosoftMultimediaNetzwerkeOff TopicSicherheitSonstige SystemeVirtualisierungWeiterbildungZusammenarbeit

Aktuelle Themen

Administrator.de FeedbackApache ServerAppleAssemblerAudioAusbildungAuslandBackupBasicBatch & ShellBenchmarksBibliotheken & ToolkitsBlogsCloud-DiensteClusterCMSCPU, RAM, MainboardsCSSC und C++DatenbankenDatenschutzDebianDigitiales FernsehenDNSDrucker und ScannerDSL, VDSLE-BooksE-BusinessE-MailEntwicklungErkennung und -AbwehrExchange ServerFestplatten, SSD, RaidFirewallFlatratesGoogle AndroidGrafikGrafikkarten & MonitoreGroupwareHardwareHosting & HousingHTMLHumor (lol)Hyper-VIconsIDE & EditorenInformationsdiensteInstallationInstant MessagingInternetInternet DomäneniOSISDN & AnaloganschlüsseiTunesJavaJavaScriptKiXtartKVMLAN, WAN, WirelessLinuxLinux DesktopLinux NetzwerkLinux ToolsLinux UserverwaltungLizenzierungMac OS XMicrosoftMicrosoft OfficeMikroTik RouterOSMonitoringMultimediaMultimedia & ZubehörNetzwerkeNetzwerkgrundlagenNetzwerkmanagementNetzwerkprotokolleNotebook & ZubehörNovell NetwareOff TopicOpenOffice, LibreOfficeOutlook & MailPapierkorbPascal und DelphiPeripheriegerätePerlPHPPythonRechtliche FragenRedHat, CentOS, FedoraRouter & RoutingSambaSAN, NAS, DASSchriftartenSchulung & TrainingSEOServerServer-HardwareSicherheitSicherheits-ToolsSicherheitsgrundlagenSolarisSonstige SystemeSoziale NetzwerkeSpeicherkartenStudentenjobs & PraktikumSuche ProjektpartnerSuseSwitche und HubsTipps & TricksTK-Netze & GeräteUbuntuUMTS, EDGE & GPRSUtilitiesVB for ApplicationsVerschlüsselung & ZertifikateVideo & StreamingViren und TrojanerVirtualisierungVisual StudioVmwareVoice over IPWebbrowserWebentwicklungWeiterbildungWindows 7Windows 8Windows 10Windows InstallationWindows MobileWindows NetzwerkWindows ServerWindows SystemdateienWindows ToolsWindows UpdateWindows UserverwaltungWindows VistaWindows XPXenserverXMLZusammenarbeit
GELÖST

VBScript setzt Umgebungsvariable - Verarbeitung im Batch funktioniert nur bedingt

Frage Entwicklung Batch & Shell

Mitglied: rubberman

rubberman (Level 2) - Jetzt verbinden

11.08.2009, aktualisiert 03:43 Uhr, 6719 Aufrufe, 6 Kommentare

Hallo Forum,
ich versuche mich gerade an einem VBS-Tool, das die Zeit vom Start des Tools in Sekunden hochzählt und in eine Umgebungsvariable schreibt. Das ganze hat den Sinn, die Laufzeit von einzelnen (langwierigeren) Batchsteps anzuzeigen.

Grundsätzlich funktioniert das ganze auch hervorragend. Beim ersten Start wird ein temporäres VBScript in Temp geschrieben, das die Arbeit übernimmt. Beim erneuten Aufruf wird dieses Script geschlossen, gelöscht und die Umgebungsvariablen gelöscht.

Hier erst einmal die Datei secdiff.vbs:
01.
timev = Now 
02.
Dim oSh, oEnv 
03.
Set oSh = CreateObject("WScript.Shell") 
04.
Set oEnv = oSh.Environment("volatile") 
05.
temp = osh.ExpandEnvironmentStrings("%temp%") 
06.
FileName = temp & "\secdifftemp.vbs" 
07.
If oEnv("secdiff") = "" Then 
08.
  oEnv("secdiff") = 0 
09.
  vbsContents = "Dim oSh, oEnv" & vbCrLf 
10.
  vbsContents = vbsContents & "Set oSh = CreateObject(""WScript.Shell"")" & vbCrLf 
11.
  vbsContents = vbsContents & "Set oEnv = oSh.Environment(""volatile"")" & vbCrLf 
12.
  vbsContents = vbsContents & "Set oSh = Nothing" & vbCrLf 
13.
  vbsContents = vbsContents & "Do" & vbCrLf 
14.
  vbsContents = vbsContents & "stimediff = DateDiff(""s"", WScript.Arguments(0), Now)" & vbCrLf 
15.
  vbsContents = vbsContents & "oEnv(""secdiff"") = stimediff" & vbCrLf 
16.
  vbsContents = vbsContents & "WScript.Sleep 500" & vbCrLf 
17.
  vbsContents = vbsContents & "Loop" 
18.
  Set oFile = CreateObject("Scripting.FileSystemObject").OpenTextFile(FileName, 2, True) 
19.
  oFile.Write vbsContents 
20.
  Set oFile = Nothing 
21.
  Dim oExec 
22.
  Set oExec = oSh.Exec("wscript.exe" & " """ & FileName & """ " & """" & timev & """") 
23.
  secdifftempID = oExec.ProcessID 
24.
  Set oExec = Nothing 
25.
  oEnv("secdifftempID") = secdifftempID 
26.
Else 
27.
  secdifftempID = oEnv("secdifftempID") 
28.
  Dim results 
29.
  Set results = GetObject("winmgmts:\\.\root\cimv2").ExecQuery("Select * from Win32_Process where ProcessId = '" & secdifftempID & "'") 
30.
  For Each obj In results 
31.
    obj.Terminate() 
32.
  Next 
33.
  Set results = Nothing   
34.
  WScript.Sleep 200 
35.
  oEnv.Remove "secdiff" 
36.
  oEnv.Remove "secdifftempID" 
37.
  Dim oFs 
38.
  Set oFs = CreateObject("Scripting.FileSystemObject") 
39.
  oFs.GetFile(FileName).Delete 
40.
  Set oFs = Nothing 
41.
End If 
42.
Set oEnv = Nothing 
43.
Set oSh = Nothing
Wie gesagt, das Script macht seine Arbeit gut. Wenn ich es händisch starte und anschließend die Variable %secdiff% in einem Batch abfrage, erhalte ich die verstrichene Zeit in Sekunden.

Das Problem liegt darin, dass bei mehrmaligem Aufruf der Variablen %secdiff% zu Laufzeit des Batch, keine Änderung des Werts zu beobachten ist. Es scheint als würde die Variable nur einmal expandiert.

Beispiel *.bat:
01.
@echo off &setlocal 
02.
echo %secdiff% 
03.
secdiff 
04.
echo %secdiff% 
05.
ping -n 6 localhost>nul 
06.
echo %secdiff% 
07.
secdiff 
08.
echo %secdiff% 
09.
pause
Erwarten würde ich jetzt:
01.
ECHO ist ausgeschaltet (OFF). 
02.
03.
04.
ECHO ist ausgeschaltet (OFF). 
05.
Drücken Sie eine beliebige Taste . . . 
Leider bleibt es durchgängig bei "ECHO ist ausgeschaltet (OFF).", obwohl das VBScript ordnungsgemäß läuft.
Was kann ich tun?

Vielen Dank im Voraus.
Grüße
rubberman
Mitglied: Biber
11.08.2009 um 07:19 Uhr
Moin rubberman,

mit dem Befehl 'Set oSh = CreateObject("WScript.Shell") ' erzeugst Du ja zwangsweise nur eine vom Parent-Prozess abgeleitete Tochter-Instanz der laufenden CMD-Session.
Bedeutet, dass für die neue instanz alle Umgebungsvariablen gelten, die auch der ober-Instanz bekannt sind.
Genau dieses nutzt Du ja auch beim Auslesen/Expandieren der %temp%-Variablen.
Dennoch steht Dir "nur" eine Kopie des gesamten Environments zur verfügung, nicht etwa das Original.
Und die Kopie kannst Du natürlich ändern, erweitern oder anpassen wiedewutt, aber Du nimmst diese geänderte Kopie mit ins virtuelle Grab, wenn der Tochterprozess beendet wird.
Ob nun mit ' Set oEnv = Nothing:.Set oSh = Nothing' oder ohne diese beiden Zeilen ist unerheblich.

Umgehungsmöglichkeit: Übergib die %secdiff%-Werte nicht als Umgebungsvariable, sondern transportiere diese Info via Wscript.echo raus aus dem VBS-Schnipsel und rein in den Batch mit einer FOR/F-Anweisung.
Dafür haben wir ein oder zwei Beispiele im Bereich "Batch & Shell".

Grüße
Biber
Bitte warten ..
Mitglied: rubberman
11.08.2009 um 14:21 Uhr
Hallo Biber,

vielen Dank für die schnelle Antwort. So ganz kann ich das ganze zwar noch nicht nachvollzierhen, da der Wert für die Environmentvariable in die Registry geschrieben wird und (dem leichten Bildschirmflackern zu Folge) auch übernommen wird.

Aber gut. Bin deinem Ratschlag nachgekommen (falls ich es nicht fasch verstanden habe) und habe den Beispielbatch entsprechend umgebaut:
Beispiel *.bat:
01.
@echo off &setlocal 
02.
 
03.
set tmpScript=%temp%\tmp.vbs 
04.
echo Set oSh = CreateObject("WScript.Shell")>"%tmpScript%" 
05.
echo WScript.Echo osh.ExpandEnvironmentStrings("%secdiff%")>>"%tmpScript%" 
06.
echo Set oSh = Nothing>>"%tmpScript%" 
07.
 
08.
for /f "tokens=*" %%i in ('cscript //nologo "%tmpScript%"') do echo %%i 
09.
secdiff.vbs 
10.
for /f "tokens=*" %%i in ('cscript //nologo "%tmpScript%"') do echo %%i 
11.
ping -n 6 localhost>nul 
12.
for /f "tokens=*" %%i in ('cscript //nologo "%tmpScript%"') do echo %%i 
13.
secdiff.vbs 
14.
for /f "tokens=*" %%i in ('cscript //nologo "%tmpScript%"') do echo %%i 
15.
 
16.
del %tmpScript% 
17.
pause
Leider auch hier keinerlei Ausgabe.

Zur Gegenprobe:
das tmpScript in eine separate Datei gepackt:
*.vbs:
01.
Set oSh = CreateObject("WScript.Shell") 
02.
WScript.Echo osh.ExpandEnvironmentStrings("%secdiff%") 
03.
Set oSh = Nothing
und anschließend die secdiff.vbs und den obigen Schnipsel händisch gestartet, ergibt eine Ausgabe. So hat es auch schon bei Versuchen mit separat gestarteten Batch-Schnipseln funktioniert, denn einnmal lässt sich auch da %secdiff% expandieren. Nur mehrfaches Erweiternen (nach Warte-Ping) ergibt keine Änderung des Wertes in der Ausgabe.

Wie ich noch anders den Wert dynamisch (irgendwann im laufenden Batch) abgreifen kann, fällt mir nicht ein.

Grüße
rubberman
Bitte warten ..
Mitglied: bastla
12.08.2009 um 01:16 Uhr
Hallo rubberman und Biber!

Was spricht eigentlich gegen die Verwendung einer Datei, um den Start-Timestamp festzuhalten (eine Temporärdatei mehr sollte ja keinen großen Unterschied machen)?

Dann würde eigentlich etwas in der Art genügen:
01.
@echo off & setlocal 
02.
set "T=%temp%\Timestamp.txt" 
03.
set "S=%temp%\Secdiff.vbs" 
04.
>%S% echo WScript.Echo DateDiff("s",CreateObject("Scripting.FileSystemObject").OpenTextFile(WScript.Arguments(0)).ReadAll,Now) 
05.
 
06.
::Start 
07.
>%T% echo %date%%time:~,8% 
08.
 
09.
ping -n 6 localhost>nul 
10.
for /f %%i in ('cscript //nologo %S% %T%') do set "secdiff=%%i" 
11.
echo %secdiff% 
12.
 
13.
ping -n 10 localhost>nul 
14.
for /f %%i in ('cscript //nologo %S% %T%') do set "secdiff=%%i" 
15.
echo %secdiff% 
16.
 
17.
::Ende 
18.
del %S% 
19.
del %T%
Soferne die hier nur durch "ping"-Pausen angedeuteten Aktionen weitere Batches sind, übernehmen diese bei einem Aufruf mit "call" ja die Variablen %S% und %T% (der Inhalt Letzterer könnte als zusätzliche Vereinfachung gleich in das VBScript als Konstante eingetragen werden), und es "kostet" also jeweils nur die eine "for /f"-Zeile im aufgerufenen Batch, um die (aktualisierte) Variable %secdiff% auch dort zu erhalten ...

Grüße
bastla
Bitte warten ..
Mitglied: rubberman
12.08.2009 um 01:47 Uhr
Hallo bastla,

perfekt. Und ich habe (Asche aufs Köpfchen) wieder mal viel zu kompliziert gedacht.
Bin wieder mal überrascht, was man so alles in eine VBS-Zeile packen kann.

Vielen Dank!

Falls doch noch jemand weiß, wie mit selbstgebauten Umgebungsvariablen umzugehen ist, oder was das OS mit dynamischen Variablen wie %date%, %time% oder %random% veranstaltet und ob man das per Script nachstellen kann, würde mich das nach der ganzen Probiererei schon interessieren.

Nochmals danke und Grüße
rubberman

EDIT:
@Biber,

habe mir natürlich auch Dein Posting noch mal intensiv zu Gemüte geführt.
Nach meinen Versuchen scheint es mir eher so, dass ich das "Original" des Environments ändere, sich aber die "Kopie" in der geöffneten CMD-Instanz nicht aktualisiert wird. Um so interessanter, wie das etwa bei %time% trotzdem funktioniert... [ Man(n) will ja was lernen ]
Bitte warten ..
Mitglied: 76109
12.08.2009 um 21:52 Uhr
Hallo rubberman!

Was die Umgebungsvariablen angeht, liegst Du falsch.

Das Master-Environ (1.Instanz) kannst Du z.B. auf der Console nur mit einem direkten SET-Befehl ändern. Sobald eine Batch, ein Programm etc. aufgerufen wird, steht immer nur eine Environ-Kopie des Aufrufers zur Verfügung. D.h. im Grunde wird das Environ von Instanz zu Instanz vererbt und wenn eine Instanz beendet wird, existiert die jeweilige Environ-Kopie nicht mehr.

Das kannst Du ganz einfach testen, indem Du z.B. auf der Console Command oder Cmd eingibst und eine SET-Variable definierst und diesen Vorgang mehrmals wiederholst und am Ende wieder mit dem Befehl Exit von der jeweils letzten Instanz in die vorige Instanz wechselst.

Den Grund dafür ist, dass das Environ pro Instanz maximal 32KB groß sein darf, aber nur einen Speicherblock mit der aktuellen Größe belegt. Das wurde mal in DOS so festgelegt und wurde zwecks Kompatibilität so aufrecht erhalten.

Beim setzen einer oder mehreren Variablen mit SET, muss im Prinzip ein neuer Speicherblock angelegt werden und hier fangen die Probleme an. Wenn ein Programm geladen wird, dann benötigt es bestimmte Informationen. D.h. einem Programm wird eine sogenannte Programm-Segemnt-Präfix (PSP) vorangestellt. Bei einer *.COM währen das z.B. die ersten 256 Byte zusätzlich zum eigentlichen Programmcode. In der PSP befindet sich dann u.a. die Adresse des Environ-Speicherblocks.

Wenn jetzt z.B. ein Programm geladen wird, das wiederum ein anderes Programm oder eine Command-Funktion aufruft, müsste die PSP aller bereits geladenen Programme neu initialisiert werden und das währe wiederum schwierig, da z.B. eine *.EXE noch einen unterschiedlich großen Header mit Adressen für die Speichermodell-Initialisierung enthält....

Command/Cmd-Beispiel:
Set Instanz_1=1
Command
Set Instanz_2=2
Command
Set Instanz_3=3

Ergebnis:
Set -> Instanz_1=1 + Instanz_2=2 + Instanz_3=3
Exit
Set -> Instanz_1=1 + Instanz_2=2
Exit
Set -> Instanz_1=1

Die Variablen %Date% und %Time% und %Random% werden von der Cmd direkt erzeugt und haben mit dem Environ nix am Hut

Gruß Dieter
Bitte warten ..
Mitglied: rubberman
12.08.2009 um 22:29 Uhr
Hallo didi1954,

stimme völlig Deiner Erklärung zu.
Die Sache ist nur, dass ich mit einem autark laufenden VBScript das Environment geändert habe (also den entsprechenden Registry-Eintrag). Dass sich diese Änderungen auch wirksam auf das Masterenvironment ausgewirkt haben, haben Tests mit separat aufgerufenen Batches oder auch VBScripts bewiesen. Da in der entsprechenden Instanz aber nur ein zum Zeitpunkt des Aufrufs geltendes Abbild des Environs gilt, hatte ich gehofft dieses Abbild zur Laufzeit aktualisieren zu können. Scheint offensichtlich nicht möglich zu sein.
Da ich nun auch weiß, wie %date%, %time% und %random% zustande kommen, bin ich wieder ein gutes Stück klüger, und weiß dass ich ähnliche Konzepte zukünftig gleich knüllen kann

Vielen Dank und Grüße
rubberman
Bitte warten ..
Neuester Wissensbeitrag
Windows 10

Powershell 5 BSOD

(8)

Tipp von agowa338 zum Thema Windows 10 ...

Ähnliche Inhalte
LAN, WAN, Wireless
Internetverbindung funktioniert erst nach ipconfig renew (6)

Frage von Joshh1 zum Thema LAN, WAN, Wireless ...

Windows Server
gelöst W2008 R2 msiinstaller funktioniert nicht mehr (5)

Frage von Alix zum Thema Windows Server ...

C und C++
gelöst IF Abfrage funktioniert nicht mehr (2)

Frage von pablovic zum Thema C und C ...

Heiß diskutierte Inhalte
Microsoft
Ordner mit LW-Buchstaben versehen und benennen (21)

Frage von Xaero1982 zum Thema Microsoft ...

Netzwerkmanagement
gelöst Anregungen, kleiner Betrieb, IT-Umgebung (18)

Frage von Unwichtig zum Thema Netzwerkmanagement ...

Windows Update
Treiberinstallation durch Windows Update läßt sich nicht verhindern (14)

Frage von liquidbase zum Thema Windows Update ...

DSL, VDSL
Problem mit variernder Internetgeschwindigkeit (12)

Frage von schaurian zum Thema DSL, VDSL ...