How to store environment variables - python

To set an environment variable using Windows Command Processor ( cmd) :
SET MY_VARIABLE=c:\path\to\filename.txt
MY_VARIABLE now can be accessed by Python application started by same cmd window:
import os
variable = os.getenv('MY_VARIABLE')
I wonder if there is a way to set an environment variable from inside of Python so it becomes available to other processes running on the same machine?
To set a new environment variable:
os.environ['NEW_VARIABLE'] = 'NEW VALUE'
But this NEW_VARIABLE is lost as soon Python process and exited.

You can store environment variables persistently in the Windows registry. Variables can be stored for the current user, or for the system:
Code to persistently set an environment variable on Windows:
import win32con
import win32gui
try:
import _winreg as winreg
except ImportError:
# this has been renamed in python 3
import winreg
def set_environment_variable(variable, value, user_env=True):
if user_env:
# This is for the user's environment variables
reg_key = winreg.OpenKey(
winreg.HKEY_CURRENT_USER,
'Environment', 0, winreg.KEY_SET_VALUE)
else:
# This is for the system environment variables
reg_key = winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE,
r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
0, winreg.KEY_SET_VALUE)
if '%' in value:
var_type = winreg.REG_EXPAND_SZ
else:
var_type = winreg.REG_SZ
with reg_key:
winreg.SetValueEx(reg_key, variable, 0, var_type, value)
# notify about environment change
win32gui.SendMessageTimeout(
win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0,
'Environment', win32con.SMTO_ABORTIFHUNG, 1000)
Test code to invoke above:
set_environment_variable('NEW_VARIABLE', 'NEW VALUE')

Would a simple if not perhaps slightly crude way of doing this be simply to use os.system and pass the command through that as if you were running it in CMD?
An example being os.system("SET MY_VARIABLE=c:\path\to\filename.txt")
Hope that helps.`

Related

How to set windows environment variable from python

I am writing a python program that needs to store a value in a persistent user environment variable. I believe these values are stored in the registry. I have tried something like this using the winreg python module.
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Environment', access=winreg.KEY_WRITE)
winreg.SetValueEx(key, envVarName, 0, winreg.REG_SZ, envVarValue)
winreg.Close(key)
I can see from using Registry Editor that this value is successfully set. But if I try and read the value from another python script or from a new powershell instance, I don't see the new value until the machine is rebooted.
What else do I need to do to make this value available to other processes without rebooting?
Looking at this answer gives a possible answer:
https://stackoverflow.com/a/61757725/18300067
os.system("SETX {0} {1} /M".format("start", "test"))
This is how we do it in production on one of Windows servers (code is simplified):
import winreg
regdir = "Environment-test"
keyname = "Name-test"
keyvalue = "Value-test"
def setRegistry(regdir, keyname, keyvalue):
with winreg.CreateKey(winreg.HKEY_CURRENT_USER, regdir) as _:
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, regdir, 0, winreg.KEY_WRITE) as writeRegistryDir:
winreg.SetValueEx(writeRegistryDir, keyname, 0, winreg.REG_SZ, keyvalue)
def getRegistry(regdir, keyname):
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, regdir) as accessRegistryDir:
value, _ = winreg.QueryValueEx(accessRegistryDir, keyname)
return(value)
If I firstly set the value using:
setRegistry(regdir, keyname, keyvalue)
Then check if it's created:
Now I use the getRegistry and open a PS in admin mode to run it:
print(getRegistry(regdir, keyname))

How to define all environment variables as global variables?

I am looking to port a bash script that makes heavy use of environment variables to a python script. For a quick sanity check, I would like to follow a similar approach and define all environment variables (or a selection of them) as python global variables.
Is there a better way of doing this besides defining each variable one by one using VAR = os.getenv('VAR').
Update: I think this will do it. Contents of def_vars.py
#!/usr/bin/env python3
import os
def define_env_vars(env_vars=None):
""" Define all (select few) environment variables as python global variables
Args:
env_vars: list of selected environement variables to import, or None,
in which case all environment variables are imported
Returns:
None
"""
if env_vars == None:
env_vars = os.environ
else:
env_vars = { k: os.environ[k] for k in env_vars }
for k,v in env_vars.items():
globals()[k] = v
# Test
import_env_vars = ["PWD"]
define_env_vars(import_env_vars)
print(PWD)
But using this from another python module doesn't seem to work ??
Update 2 It does work now but only if the variables are prepended with the package path. I want to avoid this too. Contents of test.py
#!/usr/bin/env python3
import def_vars
# from def_vars import * #This doesn't work
env_vars = ["PWD"]
def_vars.define_env_vars(env_vars)
print(def_vars.PWD)
Update 3 This does what I needed it, and puts the variables on the caller module's globals()
#!/usr/bin/env python3
import os
import inspect
def define_env_vars(env_vars=None):
""" Define all (select few) environment variables as python global variables
of the caller module
Args:
env_vars: list of selected environement variables to import, or None,
in which case all environment variables are imported
Returns:
None
"""
if env_vars == None:
env_vars = os.environ
else:
env_vars = { k: os.environ[k] for k in env_vars }
for k,v in env_vars.items():
inspect.stack()[1][0].f_globals[k] = v
Use operator.itemgetter to fetch the values from os.environ.
from operator import itemgetter
import os
import_vars = ['FOO', 'BAR', 'BAZ']
pairs = zip(import_vars, itemgetter(*import_vars)(os.environ))
globals().update(pairs)
It won't work if import_vars is empty, but then, if it were empty, you wouldn't be worried about bulk creation of global variables.

How to get default browser name using python?

Following solutions (actually it is only one) doesn't work to me :
How to get a name of default browser using python
How to get name of the default browser in windows using python?
Solution was:
from _winreg import HKEY_CURRENT_USER, OpenKey, QueryValue
# In Py3, this module is called winreg without the underscore
with OpenKey(HKEY_CURRENT_USER,
r"Software\Classes\http\shell\open\command") as key:
cmd = QueryValue(key, None)
But unfortunately, in Windows 10 Pro I don't have targeted registry value. I've tried to find alternative keys in Regedit, but no luck.
Please take a look, what my registry virtually contains:
The following works for me on Windows 10 pro:
from winreg import HKEY_CURRENT_USER, OpenKey, QueryValueEx
reg_path = r'Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice'
with OpenKey(HKEY_CURRENT_USER, reg_path) as key:
print(QueryValueEx(key, 'ProgId'))
Result (first with Chrome set as default, then with IE):
$ python test.py
('ChromeHTML', 1)
$ python test.py
('IE.HTTPS', 1)
Please check for the key in windows 10
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\Shell\Associations\URLAssociations(http|https)\UserChoice
def get_windows_default_browser_launch():
""" On windows, return the default browser for 'https' urls
returns: example '"C:\Program Files\Mozilla Firefox\firefox.exe" -osint -url "%1"'
"""
import winreg
key = winreg.OpenKey(winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER), r"Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice")
prog_id, _ = winreg.QueryValueEx(key, "ProgId")
key = winreg.OpenKey(winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE), r"SOFTWARE\Classes\{}\shell\open\command".format(prog_id))
launch_string, _ = winreg.QueryValueEx(key, "") # read the default value
return launch_string
Windows 10 Python3 , may want to change the key for 'http' not https, but this is my code verbatim as my context is of a secured server. I wanted the browser binary name and path, which is just one more line.

Using CreateProcessAsUser in python does not pass the user's environment to the created process

First thank you for your time reading this question.
I start an app executable (lets call it MyApp.exe) successfully from my windows service under the Interactive user using the following code:
#MyWindowsService.py
console_session_id = win32ts.WTSGetActiveConsoleSessionId()
console_user_token = win32ts.WTSQueryUserToken(console_session_id)
my_app_path= os.path.normpath(r"/Path\to\MyApp.exe")
startup = win32process.STARTUPINFO()
priority = win32con.NORMAL_PRIORITY_CLASS
handle, thread_id ,pid, tid = win32process.CreateProcessAsUser(console_user_token, my_app_path, None, None, None, True, priority, None, None, startup)
From inside MyApp I need to get the environment paths that belong to the interactive user. For example I use the following code to get the path for user's %appdata%:
#MyApp.py
user_app_data_path = os.getenv('APPDATA')
It should return:
C:\Users\ Interactive-user-name \AppData\Roaming
However the returned value is:
C:\Windows\System32\config\systemprofile\AppData\Roaming
Which means although MyApp.exe is started under interactive user's name, it gets the environment for SYSTEM user that the windows service is running under.
My question is how I can get the environment paths that belong to the user not system.
Many thank,
P.S. I am using py2exe to convert MyApp and Windows service into executables.
I found the answer, in case any one is interested:
According to this if the environment is not explicitly specified, the process inherits the environment of the parent. Using this one can get the environment and pass it on to CreateProcessAsUser.
Simply follow the environment word in the following code.
#MyWindowsService.py
console_session_id = win32ts.WTSGetActiveConsoleSessionId()
console_user_token = win32ts.WTSQueryUserToken(console_session_id)
my_app_path= os.path.normpath(r"/Path\to\MyApp.exe")
startup = win32process.STARTUPINFO()
priority = win32con.NORMAL_PRIORITY_CLASS
environment = win32profile.CreateEnvironmentBlock(console_user_token, False)
handle, thread_id ,pid, tid = win32process.CreateProcessAsUser(console_user_token, my_app_path, None, None, None, True, priority, environment, None, startup)

WLST execute stored variable "connect()" statement

So, I am passing a environment variable from bash to python;
#!/usr/bin/env python2
import os
#connect("weblogic", "weblogic", url=xxx.xxx.xxx.xxx:xxxx)
os.environ['bash_variable']
via wlst.sh I can print exported bash_variable, but how do I execute stored variable? Basically, I am trying to remove the original connect statement and pass a variable that has said information. Thanks
Question though, why wouldn't you called the script with the variable as an argument and use sys.argv[] ?
By example something like this.
import os
import sys
import traceback
from java.io import *
from java.lang import *
wlDomain = sys.argv[1]
wlDomPath = sys.argv[2]
wlNMHost = sys.argv[3]
wlNMPort = sys.argv[4]
wlDPath="%s/%s" %(wlDomPath,wlDomain)
wlNMprop="/apps/bea/wls/scripts/.shadow/NM.prop"
try:
print "Connection to Node Manager"
print ""
loadProperties(wlNMprop)
nmConnect(username=NMuser,password=NMpass,host=wlNMHost,port=wlNMPort,domainName=wlDomain,domainDir=wlDPath,mType='ssl',verbose='true')
except:
print "Fatal Error : No Connection to Node Manager"
exit()
print "Connected to Node Manager"
The NM.prop file is a 600 file with the username/password for the NM.
EDIT :
So from what I understand you want to do something like this :
URLS = ['t3s://Host1:Port1','t3s://Host2:Port2','t3s://Host3:Port3']
for urls in URLS:
connect('somebody','password',urls)
{bunch of commands}
disconnect()
And the values of the list URLS would be define by the environment.
The way I see it you have 3 choices :
Have 1 script per environment, more or less identical save for the URLS list
Have 1 script but with a conditionnal branching on sys.argv[1] (the environment as a parameter) and create the list there.
Have 1 script which use a parameter file for each environment according to the environment. Each parameter file containing the list in question.
Something like that :
propENV = sys.argv[1]
propPath = "/path1/path2"
propFile = "%s/%s" %(propPath,propENV)
loadProperties(propFile)
I would probably use the properties file option myself as it is more flexible from an operational standpoint...at least IMHO.

Categories

Resources