This is not a question - I just need to get some frustration out. And as a warning to other people about the problem.
I have this utility generating a batch file for setting environment variable values. (The need arises because under the Bamboo build system, any environment setting is lost from one job step to the next; each job step must set the environment variables anew - but this is of minor importance to the problem). PATH and SET commands are written to a file named on the command line - I usually name it setenv.bat - and then executed in every job step.
Only that some users, running this utility on their desktop machines, ended up with crazy environment settings, not at all those that the utility shold have generated. But the debugger showed the correct commands to be written to the file. The .bat file appeared to, in mysterious ways, being modified between being written and being executed on the next command line.
The problem occured on PCs running cmd.exe in the default working directory, that of cmd.exe itself - C:\Windows\System32. (Most users change the CWD of cmd.exe to C:\ or some project directory, but those who rarely use CLI systems may not care to.) Running the utility from any other directory worked fine, but not from C:\Windows\System32. setenv.bat was not written to the directory; it never appeared.
I suspected access right problems, but creating the file caused no error/exception. Maybe the physical file was not accessed (causing the exception) until the file was flushed? So I flushed the file explicitly before closing it. Still no exception.
After closing I checked for File.Exists("C:\Windows\System32\setenv.bat"). True - file exists. I tried to open it: Once again - successful. I could read the correctly written contents. The file was completely absent from C:\Windows\System32\, yet I could create it, write to it, close it, open it again and read C:\Windows\System32\setenv.bat... What the... ???
So I searched the entire file system for the file setenv.bat. The first occurence explained how the crazy, incorrect settings could be made: Some completely unreated job had left a setenv.bat file in a directory on the path. Then there was a second setenv.bat occurence: In C:\Windows\SysWOW64, with a last written time stamp revealing that is was our guy.
I haven't yet sat down to learn the relationhship between System32 and SysWOW64 (but I sure will do now!). Appearently, System32 is interpreted as one core set of files, plus some extra - but the extras depend on who is asking. When a .net application (such as my utilitiy) asks, it gets the core+extras named SysWOW64, and new files are written to the extra part. When Explorer asks, it gets the core + another set of extras which do not overlap the extras of SysWOW64. When cmd.exe asks, in spite of being located in System32, does not get the SysWOW64 extras, but the same extras as Explorer. (Is it not a 32 bit program, in spite of its location?).
A simple workaround is to write to .\setenv.bat rather than setenv.bat. Even though CWD is identical in my utility and in cmd.exe, the .\setenv.bat generated is distinct from the .\setenv.bat executed on the next line. You then get an error message because C:\Windows\System32\setenv.bat, in the cmd.exe understanding, isn't there. But my utility cannot tell you in advance - to it, C:\Windows\System32\setenv.bat IS there!
Sure there are explanations, and frequently good ones. It can make sense to give a 64 bit application a different file than the one you give to a 32 bit application, especially if we talk about executable code. This logic may be the very best for the intended use.
My utility will write the file wherever the user tells it to write - it treats any file name as a plain string and does NOT have a list of directories given special treatment. I have no particular interest in writing to System32 - but if the user asks me to (in the command line parameter), I will do so. If the write fails, I'll report it. If it succeeds (which it does), and the file can be read back by the utility from System32, I would expect that the user's script could also read it back from System32. It can't. That's the frustrating point.
The user doesn't have an expressed wish to write to System32 - that's just were he ends up when starting cmd.exe. So he says: "Place the file here; it will be deleted in a second anyway". He doesn't want to know that he must specify ..\Sysnative to write them to his current working directory, named System32. The other alternative, that the next line in his script runs the file, which was written to System32, from ..\SysWOW64, is not significantly better. The user should not need to be concerned about the utility runing under dotNET! Trying to explain such things to users is not likely to make you a lot of new friends among them...
The end result is that if I want my utility to work (or even to give an error message / error return) for all users, even those running it from special directories, my utility will have to mess with the path, and be aware of all the paths that need to be messed with.
One funny detail I discovered after beginning to understand what happens: Start cmd.exe from \Windows\System32. Start cmd.exe from \Windwos\SysWOW64, and tell it to CD ..\System32. With the two command shells running from the same directory, give both a DIR command. The two directory lists, produced by the same command in the same current directory are neverhteless quite different.
The directory name might fool you to think that \Windows\System32\cmd.exe is a 32 bit program. It is not. It is a 64 bit program, while the one in SysWOW64 is a 32 bit program.
I guess that if we had a 64 bit implementation of dotNet, it would go to the same locations as e.g. Explorer does, so they would see the same set of files. As far as I know, dotNet is a 32 bit implementation (correct me if I am wrong). But I fear that the day we see a 64 bit dotNet, a number of applications will run into problems because the mapping of certain directories will be changed from the 32 bit version.
I suspect that lots of programmers are not aware of the issues this redirecting raises, and would run into the same problem as I did, without knowing why. Maybe the long term solution is to migrate dotNet to 64 bits.
Ok, I wasn't aware of the 64 bit dotNET. Thanks for the correction.
Obviously that isn't the default choice. Or at least was not under Windows7, which still is used on most of our machines.
I will be looking into the possibility of switching to 64-bit dotNet. My gut feeling is that it might require a little more work, for 100+ PCs, than you can accomplish before lunch. And that there may be more than one compatibility/porting issue to be solved.
Still, that is the way to go in the long run.
Of course I do not intentionally want to put files into \Windows\System32!
But my utility is agnostic with respect to the file name specified on the call line. If the user sits in \Windows\System32\ and specifies plain filename, with no path, the utility accepts that - it does not make any specific check for \Windows\System32 saying "I think you shouldn't write to this directory". That is the responsibility of the user.
There are other directories where I really don't want to leave .bat files, such as C:\
For all practical purposes it doesn't matter: The desktop user really calls a small script that generates the file, executes it, and deletes it. The problem with \Windows\System32 is that the file generated under \Windows\System32 cannot be deleted (from the script) under that name, because it isn't there, it is in a different place, under a different name from the name it was created with!
When the user sits in \Windows\System32 and explicitly asks for writing a .bat file there, and it is automatically deleted immediately after running, then I do not see the big problem: The user has write access, then I will do what he asks for. In locations where the user has no write privleges, the utility fails - I'd be happy to see that in \Windows\System32. The problem is that you can create the file, but you can't delete it without knowing all the inner workings and give special treatment to a bunch of directory names that appears to be quite normal.
There are a number of such virtual directories in Windows, essentially for accessing user profile data. In those cases, line 1 and line 2 in a given script file sees the same real file when using identical names. That is not the case here: A .net application sees a different file from what cmd.exe sees. That is what creates the problems.
Nobody says it's the user's fault. The user specifies a file name, my utility writes to the file named by the user, and successfully reads it back, under the name given by the user. Everything is OK so far. Then the user tries to read it (i.e. execute the script) using the file name he gave to the utility, and which worked fine within the utility. But then the file isn't there!
Even if the user specifies the fully rooted name, both when giving it to the utility, and when trying to execute the generated script, the file isn't there. But it was when the utility wrote it (and later read it back), under that very same name.
Whose fault is that? The user's fault? The utility's fault? They both use the same name, even fully rooted, but the file nevertheless "disappears".
This has nothing to do with where the utility is installed (that's in a completely different directory). The situation described solely depends on a data file written to C:\Windows\System32\. If the writing is done by a dotNet program, or any other 32 bit program, the data file is written to C:\Windows\SysWOW64, and is not seen in C:\Windows\System32\ by neither Explorer, cmd.exe nor any other 64 bit program, but appears to have disappeared. (Unless you fully understand what is going on - but even seasoned system programmers may be weak in that respect.)
If the user makes a "CD \" before running the utility, everything works fine. Or if he specifies a file name that is NOT in C:\Windows\System32. This is not easy to make users see as reasonable or "right". Plain users really shoudn't be messing around in C:\Windows\System32\ at all - but in an out-of-the box Windows installation, that is exactly where the user is sent when he opens a command window. That is really the one to blame! If the default working directory for cmd.exe had been C:\ rather than C:\Widows\System32, there wouldn't have been a problem.
Well, obviously: If some system guy really has work to do in \Windows\System32, the problem would still be the same for that guy. But if he has a reason to fiddle with System32, then he is most likely competent to understand why the system behaves that way. The ordinary user is not.
Like I said before, you should really not be writing into Windows\System32. There are plenty of locations which would save you all this aggravation, and indeed the estimable OrignalGriff has an article which may be of some use: Where should I store my data?[^], and yes I know it's about data.
So what do you suggest that I do, when the user opens a command window and asks the utility to genereate the file setenv.bat? Should I say: "Sorry, I can't do what you ask of me - even though you have write permission to that directory?"
I am not making the choice where to store the data. The user is. The user is, inadvertently because that is where cmd.exe by default sends him, in System32. The user has write access. The file is deleted after a second in any case, after the script is run.
You shouldn't store .bat files, not even for a second, in C:\ either. If the user nevertheless asks for it, it works, without. Should the utilty say, when the user says "Use C:\", in a similar manner say "Sorry, I am not willing to do that for you; you shouln't be puttng files there"?
It is so simple to say "You shouldn't do that". When the user says "Do it!" you may blame the user, or you may blame the utility doing what it is being asked to. Or you may say: OK, if the user asks to use that directory, and permissions are OK, then the user asked for it, the user got it!
You may go out on a mission to explain (or maybe "excuse") to all users of the world the underlaying reasons for why their files disappear into that black SysWOW64 hole, so that every user understands that where cnd.exe by default sends them, is to a place where they shouldn't be, and shouldn't touch anything unless they are computer experts. Then you have cleansed your hands and can say: We have told you not to be in that place where we sent you! So get out of there! This is logical, da*mit! Get out of there, now!
Arguing like that to users make you sound like a Unix guru...
Just make sure you generate your .bat file somewhere that is not going to cause problems, as suggested in OriginalGriff's Tip. It's no good saying the error is caused by the user's lack of knowledge, it is your responsibility to protect the user from him/herself.
I've been tasked with migrating my company's kiosk music system from Windows 7 to Windows 10. We currently have about 40 machines out on rental.
The machines are not internet-connected, and the kiosk launcher runs in a restricted "standard" user account, and uses Parental Controls and Group Policies to maintain its security. I'm currently rewriting the launcher shell in C#/.NET 4.6.2 following MS current security policy guidelines.
The main music player app and its registration plugin were written (not by me!) nearly 10 years ago for Windows Vista, and needs read/write access to several files in %programfiles% folder and to registry keys in both HKLM and HKCU. We no longer have the original source code, and the company will not authorise a complete rewrite (despite my protestations!).
In Windows 7, I simply disabled UAC across the entire system, and set the music player app and its registration plugin "Run As Administrator" for all accounts. That has worked for us for 7 years now, and caused us no security issues, due to the machines being "locked down" in so many other ways.
With the advent of Windows 10, "Run As Administrator" results in the user being prompted for an administrator password every time the music player is started. I've failed completely to disable UAC on the standard restricted user account. Here's all the suggestions which haven't worked:
1) Drop the UAC slider to the bottom in the main Administrator account. This disables UAC on all Admin accounts, but not on standard ones.
2) Change "EnableLUA" to zero in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System. Same result as 1)
3) Create a shortcut to the music player EXE including the administrator password... Basically Aaaaaaargh! That would risk exposing the machine's administrator password and break our other security.
4) Create a task in Task Scheduler to run the app with administrator permissions. This is impractical because the machine administrator password has to be written into the task. All 40 machines have unique passwords, and there is no "automatic" way of writing that into the task. The systems need to be upgradeable with a sysprep'd clone. It also risks exposing the admin password to "local hackers" same as 3).
5) Write the "Run As Administrator" along with the password into the kiosk launcher shell prior to compilation. Gets around the chance of exposing the password, but I'd need to recompile the launcher for each machine, because they all have unique passwords.
It has been suggested that there may be extra Group Policy settings available to disable UAC completely in the Enterprise edition of Windows 10, but nobody seems to be able to confirm that, and in any case I'd be unlikely to get my company to fork out for 40 copies of Enterprise!!!
I can't believe that no one has yet found a way to completely disable UAC in Windows 10, but googling the issue has produced no workaround which is usable for our systems.
PLEASE... Has anyone managed to crack this issue yet? I'm sure I'm not the only person in need of a "fix" for this.
Thanks for your reply, Richard, and apologies for taking so long to reply. Unfortunately I didn't get a notification.
Unfortunately, the "Do not store password" option probably won't work, because it will then request an admin password whenever the app is started.
I'll have a look through the other links you've supplied. It looks like quite a steep learning curve, but I guess nothing worth doing was ever "easy"!
It amazes me that no one has found a way to totally disable UAC in Windows 10 yet. It seems to be something that a lot of users need to do in order to provide backward compatibility for "badly written" old apps. It's all very well Microsoft trying to push us towards better security practices, and I agree that we need eventually to rewrite some of those dodgy old apps, but I don't know any company which can afford to ditch 15 years of R&D and go back to the drawing board in the few months we're being given, especially with the Intel gen7 processors refusing to install any older OS!
If you select the checkbox labeled Do not store password , Task Scheduler will not store the credentials supplied on the local computer, but will discard them after properly authenticating the user. When required to run the task, the Task Scheduler service will use the "Service-for-User" (S4U) extensions to the Kerberos authentication protocol to retrieve the user's token.
When using S4U the ability of the service to use the security context of the account is constrained. In particular, the service can only use the security context to access local resources.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
Specifying requestedExecutionLevel node will disable file and registry virtualization.
If you want to utilize File and Registry Virtualization for backward
compatibility then delete the requestedExecutionLevel node.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
Thank you for your response, but I was not able to use an app manifest as I had no access to the source code. I've now solved the problem. Please refer to my response to Richard Deeming's reply if you'd like to know how I did it. Thanks again.
Anyone out there with some experience on network file transfers with Windows?
On my Windows Xp, Windows 7, Windows 10 machines I have scripts that build release folders for Windows CE and Windows Embedded Compact 7. In the past, I stayed on my local VM - Windows Xp, and all was well. Due to progress, I have to push files from my Windows Xp VM to either a shared drive on the desktop (same machine), a network drive or a new Windows 10 laptop.
The folders are shared between machines, so I expect I could copy and paste, or run a DOS script. But every transfer drops important OS files - like hive files for the registry.
I have a work around - zip up the dir, copy to where it needs to go, and expand, but really?
Edit: so, thinking I would work around things, I zipped up my release folders on Xp, coped the zip file to my Win7 machine and then pulled it to my Windows 10 laptop that will do the final build. No registry files.
It's all on local machines
Is there a setting I don't know about?
<italic>Stuck in a dysfunctional matrix from which I must escape...
"Where liberty dwells, there is my country." B. Franklin, 1783
“They who can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety.” BF, 1759