Set environment variable for ClickOnce Application? - c#

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.

Related

.NET Core 3.1 application not finding environment variable

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.

Process.Start won't work

I am trying to launch a process from a web page's back-end code/app pool. This process will launch an App that i built myself.
For some reason, the process only works / runs when i start it from VS2013... it never works when i launch it from IIS(7.5) itself.
I am on a Windows 7 machine (both IIS host, and App location), and I've setup my web site to only be accessible via internal network.
Here's the code, followed by the config / attempts to fix the issue:
protected void btn_DoIt_Click(object sender, EventArgs e)
{
string file_text = this.txt_Urls.Text;
if (!String.IsNullOrWhiteSpace(file_text))
File.WriteAllText(ConfigurationManager.AppSettings["filePath"], file_text);
ProcessStartInfo inf = new ProcessStartInfo();
SecureString ss = GetSecureString("SomePassword");
inf.FileName = #"........\bin\Release\SomeExecutable.exe";
inf.Arguments = ConfigurationManager.AppSettings["filePath"];
inf.UserName = "SomeUserName";
inf.Password = ss;
inf.UseShellExecute = false;
//launch desktop app, but don't close it in case we want to see the results!
try
{
Process.Start(inf);
}
catch(Exception ex)
{
this.txt_Urls.Text = ex.Message;
}
this.txt_Urls.Enabled = false;
this.btn_DoIt.Enabled = false;
this.txt_Urls.Text = "Entries received and process started. Check local machine for status update, or use refresh below.";
}
Here are the things I've tried to resolve the issue:
Made sure the executing assembly was built with AnyCPU instead of
x86
Ensured that the AppPool that runs the app, also runs under the same account (SomeUsername) as the ProcessStartInfo specified.
Ensured that the specific user account has full access to the executable's folder.
Ensured that IIS_USR has full access to the executable's folder.
Restarted both the app pool and IIS itself many times over implementing these fixes
I am now at a loss as to why this simply will not launch the app... when i first looked into the event log, i saw that the app would die immediately with code 1000:KERNELBASE.dll, which got me on the AnyCPU config instead of X86 fix... that fixed the event log entries but the app still doesn't start (nothing comes up in task manager), and i get no errors in the event log...
if someone could help me fix this problem i would really appreciate it. This would allow me to perform specific tasks on my main computer from any device on my network (phone, tablet, laptop, etc etc) without having to be in front of my main PC...
UPDATE
The comment to my OP, and ultimate answer from #Bradley Uffner actually nailed the problem on the head: My "app" is actually a desktop application with a UI, and in order to run that application, IIS would need to be able to get access to the desktop and the UI, just like if it were a person sitting down in front of the PC. This of course is not the case since IIS is running only as a service account and it makes sense that it shouldn't be launching UI programs in the background. Also see his answer for one way of getting around this.
Your best bet might be to try writing this as 2 parts. A web site that posts commands to a text file (or database, or some other persistent storage), and a desktop application that periodically polls that file (database, etc) for changes and executes those commands. You could write out the entire command line, including exe path command arguments, and switches.
This is the only way I can really think of to allow a service application like IIS to execute applications that require a desktop context with a logged in user.
You should assign a technical user with enough high priviliges to the running application pool. By default the application pool is running with ApplicationPoolIdentity identy which has a very low priviliges.

Changing virtual path and enabling/disabling sites in code

I am working on a web project that contains three web services and a website. My source code is stored in TFS for version control and I regularly have to work in several different branches on the same code. These branches are merged regularly and are all set up in the same way. They all use WebDev.WebServer as default host. Which is fine because it saves other teammembers from having to continuously alter settings in IIS to switch to the proper folder.
Well, guess what?
I want to move to IIS and still be able to use the same config for every branch. This will results in conflicts since I Need to change the virtual folders for these projects every time when I switch branches. I also need to be able to turn off these IIS sites to enable the use of WebDev. Manually, that's a bit of work and I'm a programmer. This needs to be automated...
My idea is to create a small web application running on my local host, which I can use to change the virtual folder and/or to turn on/off the IIS site. Sounds simple enough so all I need are two things:
How do I change the virtual folder of an IIS site from one location to another in code?
How to turn on and off a site in IIS?
Simple, right? So, point three: do you have any other suggestions that I could use?
Oh, other developers are also working on the same project. Not all of them will use IIS to run it. Thus I cannot alter the config files for these projects. I must manage it all through IIS.
Personally, I would use Powershell in this instance.
$websitePath = "IIS:\\Sites\Path to your website in iis"
$fullWebSiteFilePath = "file path to your content"
if(-not (test-path $websitePath))
{
new-item $websitePath -physicalPath $fullWebSiteFilePath -type Application
}
else
{
Set-ItemProperty $websitePath -name physicalPath -value $fullWebSiteFilePath
}
with a little jigerry pokery you could read the different configurations from an xml file and then call the shell script passing the xml file name as a parameter.
To manage IIS7 programmatically, you can start with the ServerManager class.

Disable "The publisher could not be verified" while tarting .NET console app from share folder

I am trying to run a .NET console app from a shared network folder using method Process.Start.
Everytime the console app starts I get the message "The publisher could not be verified" and Windows asks for user confirmation. How can I disable this dialog? I do not want to buy a digital certificate.
within your .net application when you use "Process.Start"
use the feature Process.StartInfo.UseShellExecute = false.
so ...
Process proc = new Process();
proc.StartInfo.UseShellExecute = false;
what this does is it allows you to launch EXES (and only exes) directly without using the Explorer(shell).
This will bypass any IE Security Zone checks. The Explorer by default includes the IEZone check and thus will
give you a security warning if the application you are running is not 'trusted' (specifically in a trusted zone).
Now you cannot use 'false' if you want to launch a 'PDF' for example. This only works for Exes.
Last bit of information:
http://technet.microsoft.com/en-us/library/bb457006.aspx
http://technet.microsoft.com/en-us/library/dd349795(WS.10).aspx
these bits of info, which a MS rep just provided me, may provide a way to trust the publisher of a signed application by using Software Restriction Policies. I haven't looked into this yet, but for those that need to continue with this further... this looks like another way to address part (1) .

Why can't my ASP.NET web service kick off a process, but my .NET console app can?

This is code from a class library:
proc.StartInfo = new ProcessStartInfo(CmdPath, "+an -b");
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
proc.WaitForExit();
This works perfectly as I would expect when called from a console test app. When I take the same library and call the method from an ASP .NET web service it just hangs.
Is there something I am missing here, perhaps permissions? The ASPNET service has access to the folder where the EXE is, and I see it running in Task Manager, though it isn't doing anything.
If anyone could tell me what I'm doing wrong, I would appreciate it. Thanks.
EDIT: Sorry for the lack of information. CmdPath goes to the command line interface for our scheduling software. I'm passing in commands based on the documentation they provided. I have one method to get a list of jobs, and another method to run a job. ...hmm idea. The client normally uses Active Directory to login, I think impersonation is going to be necessary. Going to test now.
EDIT 2: Ok, now the client is blowing up with AccessViolation issues. This is obviously a permissions thing. If the software uses integrated AD authorization, and I impersonate my AD account, will that be sufficient? I'm doing impersonation using the tag in web.config.
I think you will face a lot of problems launching an executable server side using the ASPNET identity, have you tried impersonating an identity with appropriate priveleges (this does work btw), but again launching an executable on the server side is probably not a good idea to begin with.
The ASP.Net user account probably doesn't have permissions to execute. Can you give a bit more information as to why you are trying to do this as there may be a better way of doing it.
It could be a permissions issue. The ASPNET service may have permissions to the executable, but does it have permissions for everything the executable does.
For example, if the executable copies files, does the ASPNET account have full rights to the source and destination paths of those files? The same questions need to be asked of everything the executable does.
If you need to get around this, you can use impersonation, or assign the web site to run under a different account in IIS, but those are not recommended practices, and more trouble than they're worth in most cases.
By default the ASP.NET worker process has less security than most local account (certainly an account that a developer uses or the logged in account on a server.)
There are two main ways to move forward:
Give the asp.net process more priviledges. See This Link for a good explanation of how to do that.
Have asp.net run under an account with more priviledges. See This Link for a good explanation and how to get that process running under a different account.
Either will work for you.
When you redirect standard output don't you need to use ReadToEnd to read the response from StandardOutput?
You probably should check what is your executable performs, cos ASP.NET works under user with limited rights (NETWORK SERVICE on IIS 6.0) and you executable also gets this rights and runs under same user. As far as you waiting on until it finishes its work, probably something wrong in the executable you are trying to run. I suggest you to make a simple experiment - switch your WebApplication to build-in in VS web server, called "Casini" and check your code behavior. By means of this you can prove yourself that it's not ASP.NET's fault. If I am right the only thing you will need to do is to investigate problems of you executable and determine what rights it needs.
Instead of Impersonation or giving Asp.net more privileges, how about launching the process under different credentials.
In the sample below, UserWithVeryLimitedRights would be a new account that you create with just enought rights to run the app.
Doing so may minimize the security risks.
ProcessStartInfo StartInfo = new ProcessStartInfo();
SecureString ss = new SecureString();
string insecurePassword = "SomePassword";
foreach(char passChar in insecurePassword.ToCharArray()) {
ss.AppendChar(passChar);
}
StartInfo.RedirectStandardInput = true;
StartInfo.RedirectStandardError = true;
StartInfo.RedirectStandardOutput = true;
StartInfo.CreateNoWindow = true;
StartInfo.UseShellExecute = false;
StartInfo.Password = ss;
StartInfo.UserName = #"UserWithVeryLimitedRights";
StartInfo.FileName = #"c:\winnt\notepad.exe";
Process.Start(StartInfo);

Categories