MSBuild creates BAT file, call it and delete it immediately, how can I see BAT content? - msbuild

I'm diagnosing a Visual Studio project building problem, and I want to see what MSBuild.exe actually does. However, from Procmon, I see MSBuild creates BAT file, call it and delete it immediately, then how can I see that BAT's content?
For example, real BAT command is hidden inside tmpd60d571fd9d549e5b2b31bb1f2ba51a7.exec.cmd.
"C:\Windows\system32\cmd.exe" /Q /C C:\Users\win7evn\AppData\Local\Temp\tmpd60d571fd9d549e5b2b31bb1f2ba51a7.exec.cmd
MSBuild.exe writes cl.exe, link.exe, Prebuild/Postbuild custom commands etc into those temporary bat files. Specifically, I want to see how exactly MSBuild is calling my custom commands and how does he pass parameters to me from within a bat file.
The ideal way, I think, may be some tools that can intercept file deleting operation, and make a backup(copy) of that file, so we can investigate the "deleted" files later. Procmon only records ReadFile and WriteFile byte count, but not their byte content, so I think Procmon is not enough.
==== Update ====
According to stijn's answer(env-var MSBUILDPRESERVETOOLTEMPFILES=1), I tried it on VS2019 with success. The content in the xxx.exec.cmd is like this:
Two things to note:
We don't need to pass /verbosity:d parameter.
On VS2010, the MSBuild version may be too old, no effect.
Final comment: I think this feature of "seeing true .bat content" is critical, because, I may use many macros in my Custom-build/Prebuild/Postbuild commands, like $(ProjectDir), $(Configuration), or even my own defined macros of any name, so I need a global view of the macro expansion result, instead of checking each macro from VSIDE UI one by one(so many mouse clicking and time consuming) . The .bat content is the exact global view I need.

Msbuid creates .cmd files when it runs the Exec task, depending on what problem you are diagnosing it might be enough to just know what statements are added in those files, which can be found here: https://github.com/dotnet/msbuild/blob/main/src/Tasks/Exec.cs.
Otherwise set the MSBUILDPRESERVETOOLTEMPFILES environment variable to 1 so the files do not get deleted, then run with /v:D to see which files were created.

Related

Is it possible to have .net console application that embed another executable file?

I have a single command line windows executable that has many options built into this exe file.
Eg:
(It can take screenshot)
ToolGo.exe printscreen c:\temp\filename.jpg yyyymmdd
(It can show up)
ToolGo.exe showIP machineA
I want to write another command line application, possibly in .net , where it can embed/build a wrapper around this ToolGo.exe file into my application without the user be able to use the ToolGo.exe, and also users can only access one function of this main exe file.
In the example I want this other tool to access only the print screen function in this new exe file.
The new application will have this:
Tool2go.exe printscreen c:\temp\filename.jpg yyyymmdd
But if someone types the following, it will not work:
Tool2go.exe showIP machineA
Or
ToolGo.exe showIP machineA
Any ideas how I can write this code to do this in a .net command line application?
This is a multi-part question, so I'll just give the main part of the issue as the answer with suggestions on handling the rest.
You can embed a .exe into your program by clicking on Properties and navigating the the Resources section, and adding that .exe to it.
After that, it's just a matter of extracting it locally so you can pass your commands to it, and handle it's responses. (I'm not really aware of any way to do so w/out first extracting the. exe; the .exe itself needs to run somehow after all).
To extract the embedded .exe, you do this:
' Extract the MyProgram resource (i.e. your .exe)
Dim b() As Byte = My.Resources.MyProgram
' Write it to the user's Temp folder
File.WriteAllBytes(Environment.ExpandEnvironmentVariables("%TEMP%\MyProgram.exe"), b)
By extracting it to the user's Temp folder, you can pass it your commands, and since it's 'out of sight' the user probably won't even know it's there to directly use it themselves, unless they're a bit more advanced and visit their Temp folder often. You can slightly help to avoid this, but extracting the .exe when your program starts, and then deleting it when it exits, so it only exists on the user's system while your program is running.
As far as what the user can and cannot type in order to pass to the program, you can simply handle the filtering with your program; since your program is the one passing the commands to the .exe, just don't pass any commands that you don't allowed, and pass the ones you do want allowed.

PhpStorm minify multiple JavaScript files in 1

I wanted to minify my JavaScript files using PhpStorm's file watcher but I can't get it working the way I would like it to.
I have installed uglify-js. In the file watcher I tried the following:
Arguments: $FileName$ -o $FileDir$.min.js --style compressed
Output paths to refresh: $FileDir$.min.js
The problem is that there is just 1 file being minified each time not all in one.
The other problem is that I would like to output a sourcemap but I don't know how to do this nor where to put it (arguments or output paths).
I hope someone could help me with these settings.
Few notes on File Watchers:
File watchers were designed primarily to perform some external actions on file on save.
File watcher gets called for each modified file.
If you want to process multiple files in one go (for example: merge 2+ files into 1) using File Watcher then you need to hard code all participating files (as opposed to using current file macro $FileName$ for that), unless, of course, uglify supports file masks (e.g. /path/to/folder/*.js).
If you modify 2 files from the target list then File Watcher will be called for each of them so even with hard coded file names it will be performed twice (same job done twice).
Considering the above I suggest using Grunt or Gulp task for that instead -- they're more suitable for such requirements.
P.S.
If you wish you could actually use such grunt/gulp task inside File Watcher (same as calling it in terminal/console manually) but because of point #3 above the better solution would be using Grunt's/Gulp's watch module/functionality if you need automatic execution of task.

How to read/execute NSIS script from memory in VB program

I have a VB.NET application that is essentially a front end for a NSIS script. The script is called with all of the files and variables given on the commandline. The purpose of the application is to search and find these files on a persons computer, then format the commandline and call the NSIS script to create the installer.
I want to be able to distribute this program and protect NSIS script source code. What I was looking for is a way to "read" the script from memory within the application. My idea is that the contents of the script would be saved inside of the application, then whenever it is needed the script could be loaded and called without ever having to actually write it to the users computer.
Is this possible? If so what should I look for to accomplish it. I don't need step by step (not that you could provide one with such a skeletal outline) just what is the major concept or functions inside VB that would allow me to do this.
I assume you are using the official NSIS compiler and not a custom .dll version? If that is the case then someone can just replace makensis.exe with something that writes stdin to a file. NSIS 3 also supports dumping the preprocessed script to stdout or a file so if you allow your users to modify the switches passed to makensis then this would be a easy way to recover most of your script.
Even if we take NSIS out of the equation you are stuck with a problem that is hard to solve. I would suggest that you just encrypt the script with a simple XOR cipher, this should stop most people just looking at your .exe in a hex-editor. You can of course use stronger encryption if you want.
When you are about to call makensis you would retrieve the encrypted script resource as a memory stream or array, decrypt it and then pass it as the stdin for makensis by using ProcessStartInfo.RedirectStandardInput...

WIX: Files not copied over on new installs

So, I have a WIX project which is to install either fresh installations or over previous installations of a product. This product, if it was already installed, has several files inside of 3 different folders which need to be preserved. This project also needs to copy the contents of those 3 different folders into another set of folders (same content in two different locations). In order to accomplish this I have set up my project to first attempt to write into the original folders if the files don't already exist, then copy the contents of those folders. On an upgrade where those files already exist this works fine. On a fresh install the second set of folders do not get created, but all the files do.
My assumption, and I may be incorrect, is that the msi is attempting to copy the folders over before they have even been created. This would cause folders to not exist in the area they were supposed to be copied to as there would be nothing to copy from. Is there a way I can ensure the files have been generated before trying to copy them? Is there a better way of going about this that I'm not seeing?
EDIT:
I'm going to try to clear this up a little. What I'm trying to do is the following (pseudo):
1) See if an option file (hi.opt) exists in c:\options, if not create it.
2) Copy that file to c:\options\opt2015.
I'm doing this 3 times for 3 different folders. I am creating the initial files with Wix in the c:\options folder using the NeverOverwrite parameter. This part works great; the files are created without issue and none are overwritten if they already exist. Where the problem lies is step two where I'm using the CopyFile Wix command. This will only copy some of the files from the c:\options folder to the c:\options\opt2015 folder. Depending on the initial setup of the system (if the files at c:\options exist or not) some files will copy over and others won't. It's not random, the results are repeatable every time, but there seems to be no reason why some files copy and others don't depending on the initial setup of the system.
I hope this makes sense and is a little more clear, though I think it makes things worse! It is strange behavior because to me it looks like everything should just work, but it doesn't (isn't that every bug though).
Edit2:
After more work and creating a vb script which runs perfectly outside of WIX my team and I have determined that the files just are not being seen by WIX during the installation even though they do exist. We haven't found any permissions issues and the installation is running as admin on an admin account. Doing the copy via a VBS or through the Wix CopyFile command results in, well the same results; files that already exist on the system are not being copied. Any more ideas? Should we find a solution I'll be sure to post it because this is just getting weird.
I believe your installer design should work as long as you're attempting to copy the files after the InstallFiles action runs. You should be copying the files from the first set of folders to the second set of folders by doing one of the following:
Running a deferred custom action that executes after InstallFiles
Using the MoveFiles action
This is too long for a comment, but may not be an answer either....
There isn't really such a thing as "over previous installations of a product", especially if you end up with multiple instances in Programs/Features, and files that may or may not have the same component ids replacing each other - that's going to be a mess. If you need to upgrade the installed product, use a major upgrade, that seems to be where you're going with this. If you are already writing custom actions to do some of this "first attempt to write into the original folders" then I've no idea what's going on or where you doing this in the install. In general, if you need those files in the new install then add them to the new major upgrade MSI. If you need to copy the older existing files from the older product, then do a major upgrade with afterInstallExecute and write custom action code to copy them before the InstallFiles action. Or the CopyFile WiX element could do it, see the part about the element under a component with no fileid.
http://wixtoolset.org/documentation/manual/v3/xsd/wix/copyfile.html
Well, as sometimes happens, the error was entirely elsewhere. It turns out that an uninstaller for another program which was in the chain of programs which are installed at the same time was destroying the folder. Unfortunately this is what happens when a product isn't touched for 10 years. Thank you for your contributions, they were very helpful. Even though I was going down the wrong path the whole time I still made use of them in my tests and am more adamant about checking the installation order.

"File Not Found" in MSBuild Community Tasks -- Which File?

I'm trying to use the VssGet task of the MSBuild Community Tasks, and the error message "File or project not found" is beating me with a stick. I can't figure out what in particular the error message is referring to. Here's the task:
<LocalFilePath Include="C:\Documents and Settings\michaelc\My Documents\Visual Studio 2005\Projects\Astronom\Astronom.sln" />
<VssGet DatabasePath="\\ofmapoly003\Individual\michaelc\VSS\Astronom_VSS\srcsafe.ini"
Path="$/Astronom_VSS"
LocalPath="#(LocalFilePath)"
UserName="build" Password="build"
Recursive="True" />
If I write a Streamreader to read to either the database path or the local path, it succeeds fine. So the path to everything appears to be accessible. Any ideas?
Two thoughts. One, sometimes a type load exception manifests as a FNF - let's hope that's not it. But if the code is actually being honest, you can track the problem using Procmon or Filemon. Start one of those utilities and then run your task again. You should be able to track down a record of a file that couldn't be located.
#famoushamsandwich that's a great response -- I had not previously heard of procmon or filemon. Tried procmon on the problem, but even after sifting through the relevant output (my gosh the machine does a lot more stuff behind the screen than I was aware of) I couldn't find where a file I'm referencing wasn't being found.
Procmon and Filemon are good suggestions - just make sure you filter the results to only show errors. Otherwise the success messages will bury the problem entries. Also, you can filter out processes that are not at fault (either through the filter dialog or by right-clicking the entry and choosing "Exclude Process".)
A couple other thoughts:
In the LocalFilePath, you are specifying a single file as opposed to a folder. The task, on the other hand, specifies to get files recursively. Perhaps you need to remove "\Astronom.sln" from the LocalFilePath?
Is the build task being run under your account or another? It's possible you have a permissions issue
Do you already have a copy of the code pulled down in the same location? Perhaps there is a failure to overwrite an existing file/folder?