I cannot get my .NET Core 3.1 console application to recognize my custom system environment variables. I can pull and print other system variables such as username just fine. But if I set a custom one like 'TestKey' in the example below, they are always null within the application.
Here is my code:
static void Main()
{
var config = new ConfigurationBuilder().AddEnvironmentVariables().Build();
var value = config.GetValue<string>("TestKey");
var envValue = Environment.GetEnvironmentVariable("TestKey");
Console.WriteLine($"Config Variable is: {value}");
Console.WriteLine($"Environment Variable: {envValue}");
}
This is the output:
and system variables clearly show the variable has been set:
Likewise, when I do an echo from the command prompt for the TestKey variable, it correctly returns the associated value.
This is a Windows 10 Pro computer and it is not part of a domain. This behavior is truly puzzling. I have rebooted the computer and the system variable persist but still will not appear in the application.
There are two major points here. First, according to Configuration in ASP.NET Core, environment variables are retrieved only for current process
Are only set in processes launched from the command window they were
set in
So, you should set them in the same command window before launch the app or add to the launchsettings.json file
"environmentVariables": {
"Test": "Test",
"ASPNETCORE_ENVIRONMENT": "Development"
}
and restart Visual Studio for that. Or just change it in Debug properties of your project
Second, to be able to get a system environment variable in GetEnvironmentVariable method, you should specify the EnvironmentVariableTarget.Machine parameter
var envValue = Environment.GetEnvironmentVariable("Test", EnvironmentVariableTarget.Machine);
By default
The GetEnvironmentVariable(String) method retrieves an environment
variable from the environment block of the current process only
Or, if you'll add the variable to launchsettings.json in previous point, setting the target isn't needed.
However, if you will run your project in command line via dotnet run, you should be able to access the system environment variable as well, because
On Windows systems, the environment block of the current process
includes:
All environment variables that are provided to it by the parent process that created it. For example, a .NET application launched from
a console window inherits all of the console window's environment
variables.
If there is no parent process, per-machine and per-user environment variables are used instead. For example, a new console
window has all per-machine and per-user environment variables defined
at the time it was launched.
Bottom Line: I had to reboot my web server.
I had this very same problem, in a razor view i had this...
#inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment env
.
.
<div>
Environment is #env.EnvironmentName
</div>
<environment include="Development">
<strong>You are in the Development environment</strong>
</environment>
and in ASPNETCORE_ENVIRONMENT variable i had 'Development'
The page never saw 'Development' it always defaulted to 'Production' (which it's supposed to). Rebooting the web server 'fixed' it for me. I'm not sure if it was the reboot or I just could have recycled the app pool. I'm using .net core 3.1
use the following command to set the environment variable permanently setx key value /M
If you use set command then it will accessible in that cmd.exe itself.
Event after using setx command if the env variable gets null, do a quick restart and it will work.
Related
I´m trying to run a PowerShell script with C# on .netCore.
I have tried many different solutions for now, but none of them seem to work. I just want to execute a PowerShell script and set ExecutionPolicies and Scope to make it work.
But I always got the exception that the ExecutionPolicies don´t allow me to run the script that way.
Despite that with the actual configuration and code, you find below, I don´t get any feedback from the Debugger after reaching the point where .Invoke(); is executed. And waiting for response and letting the software doing its stuff in background leads always to a stackoverflow exception.
commandParameters is a simple Dictionary<string, string>
Any thoughts on this?
Cheers.
var iss = InitialSessionState.CreateDefault2();
// Set its script-file execution policy.
iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;
iss.ExecutionPolicy = (ExecutionPolicy)Microsoft.PowerShell.ExecutionPolicyScope.CurrentUser;
// Create a PowerShell instance with a runspace based on the
// initial session state.
PowerShell ps = PowerShell.Create(iss);
ps.AddCommand(path + "\\" + fileName);
ps.AddParameters(commandParameters);
var results = ps.InvokeAsync().GetAwaiter().GetResult();
Assigning to iss.ExecutionPolicy only ever controls the execution policy for the current process.
Do not assign a Microsoft.PowerShell.ExecutionPolicyScope value, as it is an unrelated enumeration that defines the execution-policy scope, relevant only to the Set-ExecutionPolicy and Get-ExecutionPolicy cmdlets. The numeric values of this unrelated enumeration just so happen to overlap with the appropriate [Microsoft.PowerShell.ExecutionPolicy] enumeration values, so that policy scope CurrentUser maps onto policy RemoteSigned (value 0x1).
In effect, your second iss.ExecutionPolicy = ... assignment overrides the first one and sets the process-scope execution policy to RemoteSigned.
The process-scope execution policy, i.e. for the current process only, is the only one you can set via an initial session state; see the next section for how to change policies for persistent scopes.
Therefore, iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted; alone is enough to invoke *.ps1 files in the session at hand - remove the second iss.ExecutionPolicy = ... assignment.
If you want to modify the execution policy persistently, you must use .AddCommand('Set-ExecutionPolicy') with the appropriate arguments and invoke that command. Caveat:
Changing the persistent current-user configuration also takes effect for regular PowerShell sessions (interactive ones / CLI calls) in the respective PowerShell edition.
By contrast, if you change the persistent machine configuration - which requires running with elevation (as admin):
With the Windows PowerShell SDK, the change also takes effect for regular PowerShell sessions.
With the PowerShell (Core) SDK, it only takes effect for the SDK project at hand.[1]
See this answer for sample code.
Caveat:
If the current user's / machine's execution policy is controlled via GPOs (Group Policy Objects), you fundamentally cannot override it programmatically (except via GPO changes).
To check if a GPO-based policy is in effect:
Run Get-ExecutionPolicy -List to list policies defined for each available scope, in descending order of precedence.
If either the MachinePolicy or the UserPolicy scope have a value other than Undefined, then a GPO policy is in effect (run Get-ExecutionPolicy without arguments to see the effective policy for the current session).
Limited workaround for when a GPO-based policy prevents script-file execution:
Assuming all of the following; script file refers to *.ps1 files:
Your script file calls no other script files.
It (directly or indirectly) loads no modules that on import happen to call script files.
Your script file doesn't rely on knowing its own location (directory) or name on disk.
You can load your script file's content into a string and pass that string to the SDK's .AddScript() method, as the following simplified example shows:
using (var ps = PowerShell.Create()) {
var results =
ps.AddScript(File.ReadAllText(path + "\\" + fileName))
.AddParameters(commandParameters)
.Invoke();
}
[1] Windows PowerShell stores the execution policies in the registry, which both regular sessions and the SDK consult. By contrast, PowerShell (Core) stores them in powershell.config.json files, and in the case of the machine policy alongside the PowerShell executable (DLL). Since SDK projects have their own executable, its attendant JSON file is not seen by the executable of a regular PowerShell (Core) installation.
In Startup.cs file I have
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
There is appsettings.json file with configurations. Like :
{
"Log" : {
"Type" : "value from appsettings.json"
}
}
reloadOnChange set to true, so, when I change appsettings.json then I get immediately a new value of log type in my program.
But I'm using Docker with docker-compose and pass a value of setting by env variables. My docker-compose.override.yml file is:
version: '3.7'
services:
myservice:
environment:
ASPNETCORE_ENVIRONMENT: Development
Log__Type: "value from docker-compose"
To run I use `docker-compose up. Now my app has value "value from docker-compose" for log type.
Question: Are there any ways to change a value of env variable (Log__Type) at runtime (without restarting docker container) and reload configuration in my app as it has done with reloadOnChange and appsettings.json?
I tried to connect to the container (docker exec) and set a new value of env variable
printenv Log__Type // -> value from docker-compose
export Log__Type=new value
printenv Log__Type // -> new value
but my app didn't reload configuration and still shows log type "value from docker-compose".
Could you please advise how to change settings at runtime using docker? Or explain why there is only reload when the file has changed but not env variable.
Are there any ways to change a value of env variable at runtime (without restarting docker container)
No. (And even a restart isn't enough: you need to delete and recreate the container.)
This follows the ordinary Unix model. A process can set the initial environment for its child process, but once it's exec'd the child, it has no more control over the environment any more. docker exec launches a new process in the container namespace and so if you change an environment variable there it will only affect that process and not the main container process.
There are a significant number of options that can only be set during the initial docker run command. This includes environment variables, and also includes volume mounts and published ports. Critically, it also includes the underlying image: if you ever have a new build of your application, or need to update the underlying OS distribution for a security issue, you will be forced to delete and recreate your container. In my experience docker rm is extremely routine, and you should plan for it to happen regularly.
so what you want to do is read weather a file has changed or not during runtime? you can use a FileSystemWatcher to detect when the file has been changed or edited, so in a sense you can, but detecting weather or not a specific variable has changed is a bit more messy, because you'd only be able to detect when the entire file has had a change to it, and then check if the wanted var has changed yourself.
FileSystemWatcher MSD
but if we're talking about the app reciving a new environment change during runtime, you can use a hacky solution, using a NamedPipeStream you could send environment changes by either starting another process to tell the main one to update Var X to Y or by like mentioning earlier but instead having a sub process detecting it and sending it back up the chute.
NamedPipeStream Server MSD
NamedPipeStream Client MSD
I thought the variables set in the Variables tab in a release pipeline were set as environment variables?
On my TestCase Project I've got some settings stored as environment variables which are accessed during setup process of my tests, but in azure release pipeline it just comes back as null(this is using a hosted agent).
How can I access the Variables set in Variables tab of a release pipeline from my C# code?
My code to access Environment variables at the moment is
Environment.GetEnvironmentVariable("DevOpsUserName", EnvironmentVariableTarget.Machine)
This doesn't pull back the variables data.
They are set as environment variables (excepting secret variables, which are not automatically converted to environment variables for security reasons).
However, they're not machine-level environment variables. They are process-level.
Use EnvironmentVariableTarget.Process.
You can use Environment.GetEnvironmentVariable("DevOpsUserName", EnvironmentVariableTarget.Process), as Daniel mentioned.
Or you can directly use Environment.GetEnvironmentVariable("DevOpsUserName"), which is equivalent to the previous statement and targets the process-level environment variables.
I have a VB6 executable which is accessing some system environment variables. I have implemented a .NET console application which checks if those environment variables exist, creates them if needed, and then runs the VB6 application by calling Process.Start.
Doing this, the VB6 application cannot find the environment variables and it says they don't exist.
If I run the VB6 application from Windows Explorer it works fine and can find the variables.
So it seems the VB6 app is running under the context of .NET console app and cannot access the system environment variables!
Code to set the environment vars .NET Cosnole app:
foreach(var varObject in Variables)
{
var envVar = Envrionment.GetEnvironmentVariable(varObject.Name ,
EnvironmentVariableTarget.Machine);
if(string.IsNullOrEmpty(envVar)
{
Environment.SetEnvironmentVariable(varObject.Name,varObject.Value,
EnvironmentVariableTarget.Machine);
}
}
Code to run the VB6 app from .NET Cosnole app:
var processInfo = new ProcessStartInfo(VB6ApplicationFilePath);
processInfo.UseShellExecute = true
processInfo.WindwoStyle= ProcessWindowStyle.Hidden;
Process.Start(processInfo);
A copy of a program's environment is passed to a program that it starts. As it is a copy the second program only sees the state it was in when given it (and changes it made). No other program can change another program's environment.
When using ShellExecute (which you tell ProcessStart to) you are asking Explorer to start the program for you. The program will get a copy of Explorer's environment.
When changing the system environment, programs can send a message to all windows open saying environment has changed (as setx does - see setx /?). But ONLY Explorer.exe pays attention to this message. So only programs started by explorer after explorer receives this message will see the changes.
These are the API calls that .NET calls. In Windows all programs are started by CreateProcessEx (or older programs CreateProcess). Shellexecute and ShellexecuteEx process the command like you typed it in Explorer's Start - Run dialog (Winkey + R) then changes it and calls CreateProcessEx.
At the command prompt. Type
set MyCat=PewResearch
cmd /k echo %MyCat%
We set an environment variable, start a new command prompt that prints that variable.
This is the message that notifies
WM_SETTINGCHANGE
The system sends the WM_SETTINGCHANGE message to all
top-level windows when the SystemParametersInfo function changes a
system-wide setting or when policy settings have changed.
Applications should send WM_SETTINGCHANGE to all top-level windows
when they make changes to system parameters. (This message cannot be
sent directly to a window.) To send the WM_SETTINGCHANGE message to
all top-level windows, use the SendMessageTimeout function with the
hwnd parameter set to HWND_BROADCAST.
I have a ClickOnce application and a simple c# launcher that starts the ClickOnce application by launching IE with the URL of the app. I would like to set an environment variable that can be read by the ClickOnce application. Is this possible? This is my code for the launcher app:
ProcessStartInfo pInfo =
new ProcessStartInfo("iexplore.exe", "http://svr:8080/cotest.application");
Process appProc = new Process();
appProc.StartInfo = pInfo;
appProc.StartInfo.EnvironmentVariables.Add("some_var", "some_val");
appProc.StartInfo.UseShellExecute = false;
appProc.Start();
I realise that I'm setting the variable for iexplore, but I thought (hoped) the environment might be inherited by the ClickOnce app. What happens is that the ClickOnce app starts but if I list its environment, the variable "some_var" is not present.
Any ideas?
Probably you are going to face some security limitation by using ClickOnce when you are changing environmental variables for non user variables.
Please see below:
Edit environment variable in registry
I think you may need to either consider using other setup package methods (i.e. InstallShield) or change the way that you intract with Internet Explorer and pass parameters to your site.
If you provide your full requirements people might be able to help you with
alternative solutions.