Laden...

Wie per exe eine Umgebungsvariable setzen als hätte ich set x=y eingegeben?

Erstellt von Pedant vor 6 Jahren Letzter Beitrag vor 6 Jahren 3.250 Views
P
Pedant Themenstarter:in
12 Beiträge seit 2014
vor 6 Jahren
Wie per exe eine Umgebungsvariable setzen als hätte ich set x=y eingegeben?

Hallo,

ich versuche mit einer exe eine Umgebungsvariable zu setzen mit der Zielsetzung, dass diese (nur) in der Eingabeaufforderung gültig ist, in der ich auch die exe ausgeführe.

Mache ich es nur mit Batch

@echo off
set Test=123
echo %Test%

wird 123 ausgegeben und das ist gut so.

Was ich möchte ist das hier:

@echo off
REM set Test=123
meine-exe-die-set-Test-macht.exe
echo %Test%

Hier bekomme ich es nicht hin, dass auch 123 ausgegeben wird.

Das habe ich schon ausprobiert:

1.

Environment.SetEnvironmentVariable("Test", "123");
string ausgabe = System.Environment.GetEnvironmentVariable("Test");
Console.WriteLine(ausgabe);

Das funktioniert soweit, aber die gesetzte Variable ist verloren, sobald meine exe beendet ist.
Dann hätte ich auch gleich string ausgabe="123"; schreiben können und es hätte mir auch nichts genutzt.

2.

Environment.SetEnvironmentVariable("Test", "123", EnvironmentVariableTarget.User);

Das will ich nicht, da so die Variable dauerhaft in der Registry eingetragen wird und ich brauche sie nur temporär im aktuellen Kontext.
Außerdem steht die Variable so noch nicht in der Eingabeaufforderung zur Verfügung, in der sie gesetzt wurde, sondern erst in allen später geöffneten Eingabeaufforderung, wo sie aber nicht mehr benötigt wird.

3.

Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.Arguments = "/k set Test=123";
cmd.Start();

Das öffnet mir eine neue, zusätzliche Eingabeaufforderung in der zwar die Variable korrekt gesetzt ist, aber meine Ausgangseingabeaufforderung kennt die Variable trotzdem nicht.
Außerdem möchte ich keine neu Eingabeaufforderung öffnen, sondern bei der bleiben, bei der ich bin.

4.

Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.Arguments = "/c set Test=123";
cmd.Start();

Mit /c statt /k öffnet mir das zwar keine bleibende, neue Eingabeaufforderung, aber die gesetzte Variable ist sofort wieder verloren, sobald cmd sie erfolgreich gesetzt und sich anweisungsgemäß wieder geschlossen hat.
Die aufrufende Eingabeaufforderung hat, wie bei 1., davon nichts.

Mein aktueller Workaround
Im Moment lasse ich mir von meiner exe eine Batch-Datei erzeugen, in der der gewünscht set-Befahl enthalten ist und rufe dann diese Batch per call auf und lösche diese Datei wieder.
Das sieht dann so aus:

@echo off
meine-exe-die-eine-setTest.cmd-erzeugt.exe
REM Der Inhalt von setTest.cmd ist: set Test=123
call setTest.cmd
del setTest.cmd
echo %Test%

Es ist allerdings nicht sonderlich elegant eine Variable über die Festplatte zu übergeben.

Wozu das Ganze?
Der Wert, den ich der Umgebungsvariablen zuweisen möchte ist nicht statisch, sondern das Ergebnis einer Auswertung, die die exe ausführt.
Diese Auswertung von der Batch selbst erledigen zu lassen ist zu komplex.
Andersherum wäre es mir zu unflexibel, alles von der exe erledigen zu lassen und somit ohne Batch auszukommen.

Meine Fragen
Gibt es eine Möglichkeit eine Umgebungsvariable so setzen zu lassen, dass sie (nur) im gewünschten Kontext gültig ist?
Hat jemand einen alternativen Ansatz für eine Variabenübergabe von exe zu Batch?
Dazu noch eine Anmerkung: Es geht nicht nur um eine Variable, die übergeben werden soll, sondern um 42 Stück.

Gruß Frank

16.825 Beiträge seit 2008
vor 6 Jahren

Schau Dir mal die Dokumentation von Environment.SetEnvironmentVariable an, dann siehst Du, dass es einen dritten Parameter gibt, mit dem man den MachineScope angeben kann, womit ein permanentes Setzen des Wertes erreicht wird.
Ansonsten, siehe Doku, ist es an den Prozess gekoppelt.

P
Pedant Themenstarter:in
12 Beiträge seit 2014
vor 6 Jahren

Hallo Abt,

danke für Deine Antwort, aber scheinbar hast Du übersehen, was ich bei "Das habe ich schon ausprobiert" unter 2. geschrieben habe.
Das permanente Setzen ist einerseits nicht erwünscht und andererseits in meinem Fall leider auch nutzlos und es (wie bei 1.) nur an den Prozess zu koppeln ist ja leider auch nicht zielführend.

Gruß Frank

16.825 Beiträge seit 2008
vor 6 Jahren

Es gibt aber nur die beiden Varianten: Prozess oder Maschine.

Dann musst Dir ein anderes Austauschmedium als Umgebungsvariablen suchen.

D
985 Beiträge seit 2014
vor 6 Jahren

Jeder Prozess der gestartet wird erhält eine Kopie der aktuellen Umgebungsvariablen. Dort kann sich der Prozess dann daran austoben und andere Prozesse werden davon nicht beeinflusst (es sei denn diese Prozesse werden von dort gestartet, dann bekommen die allerdings ein Kopie von dort).

Du musst also dein Konzept überdenken, denn so geht das nicht.

T
2.221 Beiträge seit 2008
vor 6 Jahren

@Pedant
Wäre es nicht zielführender mit der Powershell zu arbeiten?
Spätestens mit dem Creators Update wird die cmd von der Powershell abgelöst.
Gerade jetzt wäre es eine gute Idee sich von der Leiche Batch zu verabschieden.

Mit der Powershell wärst du um Dimensionen flexibler und könntest eigentlich deine Auswertungen auch damit fahren.
Dies würde deine exe überflüssig machen und dürfte das Problem mit der Umgebungsvariable lösen.
Dann kannst du das Ergebnis in einer einfachen Variable speichern und auswerten!
Ein Arbeitungszeit ist an sich relativ kurz.

Hab dafür folgendes Buch genommen:
https://www.amazon.de/Windows-PowerShell-5-0-Das-Praxisbuch/dp/3446446435/ref=sr_1_3?ie=UTF8&qid=1492525954&sr=8-3&keywords=Powershell

Ist sehr ausführlich, bietet auch sehr gute Einblicke in die Abläufe der Powershell.
Auch einige Interessante Commandlets werden dort schon angeschnitten.

Nachtrag:
@Sir Rufo
Da ich bisher die Finger von den Umgebungsvariablen gelassen habe, wusste ich nicht dass es pro Prozess nur Kopieen gibt.
Dacht eigentlich, diese würden von allen geteilt.
Gut zu wissen, falls ich damit mal arbeiten muss 😃

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

P
Pedant Themenstarter:in
12 Beiträge seit 2014
vor 6 Jahren

Hallo,

danke für Eure Antworten.
Wie es aussieht muss ich vorerst bei meinem beschriebenen Workaroud belieben.
Ich finde es allerdings überraschend, dass es anscheinend keinen vorgesehenen Weg der Interaktion zwischen Batch und C# gibt und wie es sich hier anhört auch nicht zwischen Powershell und C#.
Das könnte ja auch in vielen anderen Situationen hilfreich sein und nicht nur bei meinem konkreten Anliegen.

Es gibt aber nur die beiden Varianten: Prozess oder Maschine.

Genaugenommen sind es drei: Machine, Process und User, aber alle drei nicht zielführend.

Spätestens mit dem Creators Update wird die cmd von der Powershell abgelöst.

Das "Ablösen", habe ich dem schon installierten Creators Updates schon wieder ausgetrieben.

Gerade jetzt wäre es eine gute Idee sich von der Leiche Batch zu verabschieden.

Batch sehe ich zwar nicht als "Leiche", aber vielleicht ist es tatsächlich an der Zeit sich mit Powershell zu befassen.
Dank für den Buchtipp.

...wusste ich nicht dass es pro Prozess nur Kopien gibt.

Eine Anmerkung dazu: mit dem Befehl setx statt mit set, kann man die Originale setzen und/oder ändern (was mir aber auch nicht helfen würde).

Gruß Frank

16.825 Beiträge seit 2008
vor 6 Jahren

Der vorgesehene Weg sind Übergabeparameter.

PS: ich sehe Batch ebenfalls nicht als Leiche.
Microsoft geht in vielen Bereichen auch wieder zurück zur CLI, denn im Gegensatz zu PowerShell nutzen auch viele andere Technologien die CLI.
Daher sieht man zB. im Bereich Azure die CLI wieder vorne (zB Azure CLI).

Ich zB verzichte bewusst auf PowerShell und nutze die PowerShell Shell nur weil sie hübscher ist 😉

P
Pedant Themenstarter:in
12 Beiträge seit 2014
vor 6 Jahren

Hallo Abt,

meinst Du mit "Übergabeparameter"
dings.exe /Parameter
einerseits und
cmd.StartInfo.Arguments = "Parameter"; andererseits oder etwas anderes?

Gruß Frank

16.825 Beiträge seit 2008
vor 6 Jahren

Si.

ja, es gibt drei Modi wobei User und Maschine (fast, in Deinem Szenario vom verhalten sogar identischen) den gleichen Scope haben.
Process ist da schon was ganz anderes.

P
Pedant Themenstarter:in
12 Beiträge seit 2014
vor 6 Jahren

Hallo Abt,

ob "User" oder "Machine" macht für mich tatsächlich keinen Unterschied.

Wenn ich jetzt aber so über "Process" nachdenke, bin ich etwas irritiert.
Man kann damit aus einem C#-Programm heraus Umgebungsvariablen setzen, die aber nur für den Prozess gültig und sichbar sind, der sie gesetzt hat, also nur für das Programm selbst und auch nur für die Dauer seiner Laufzeit.
Gibt es in C# nicht genug Möglichkeiten und Platz Variablen zu setzen?
Muss man noch welche ins Betriebssystem auslagern?

Wahrscheinlich fehlt es mir an Phantasie, aber mir fällt nichts ein wozu man das gebrauchen könnte?

Gruß Frank

D
152 Beiträge seit 2013
vor 6 Jahren

Das C#-Programm das die Umgebungsvariable setzt, startet selbst ein weiteres Programm, das diese dann erbt.

P
Pedant Themenstarter:in
12 Beiträge seit 2014
vor 6 Jahren

Hallo david.m,

...na dann hatte ich ja recht mit "zuwenig Phantasie".

Gruß und Dank
Frank

U
1.688 Beiträge seit 2007
vor 6 Jahren

Aber genau das wäre doch die Lösung für Dein Problem:

Die exe setzt die Variable(n) und ruft dann per cmd die Batch-Datei auf, die alle geänderten Umgebungsvariablen erbt.

P
Pedant Themenstarter:in
12 Beiträge seit 2014
vor 6 Jahren

Hallo ujr,

ja danke, das war eine Überlegung wert.
Es ist zwar nicht exakt die Lösung für mein Problem, aber durchaus ein alternativer Workaroud.
Ich habe das jetzt als optionalen, zweiten Workaroud eingebaut.
Gibt man der exe jetzt eine Batchdatei als Parameter an, dann werden die "Process"-Variablen gesetzt und per cmd die angegebene Batch gestartet.
Das Working-Directory wird dabei entsprechend gesetzt.

Beispiel:
meine.exe /b "C:\Mein Ordner\irgendeine.cmd"
=> meine.exe ermittelt die Werte und setzt die Variabeln entsprechend
=> irgendeine.cmd wird im Ordner "C:\Mein Ordner" gestartet
=> meine.exe beendet sich
=> irgendeine.cmd läuft weiter und kann die Variablen verwenden

Gruß Frank