views:

251

answers:

2

I've written a PowerShell script to build several .net solutions one after the other. It simply makes several calls to tfget (to get latest) followed by devenv.exe (to build the .sln files).

Here's the code:

tfget -item $SolutionPath -overwrite -recurse -ev +errors
...
$out = invoke-expression "devenv.com /rebuild debug $SolutionPath"

Almost every time I run the script one of the solutions fails to build I get an error from CSC.exe (?) saying:

error CS1606: Assembly signing failed; output may not be signed -- The process cannot access the file because it is being used by another process.

This happens even though I've closed all instances of Visual Studio holding these solutions and I've none of their exes running on mu machine.

A similar batch file that I've written works just fine. It's only PowerShell that complains about the file being used by another process.

How can avoid having this happen? Are there any better examples out there of building .net solutions through PowerShell?

+1  A: 

That's because devenv is running in the background. You have to run it and wait until it finishes.

This should work:

$p = Start-Process -FilePath devenv -ArgumentList $solutionPath,"/Rebuild Debug" -PassThru
$null = $p.WaitForExit(-1)

I use it to build my solutions as well.

stej
My PowerShell (v2.0) complains that I should use -File instead of -FilePath and -Arguments instead of -ArgumentList . Now I'm stuck because it tells me that $solutionPath is of type object[] and needs to be of type string :)
urig
Scratch that. It seems my PS is running the wrong Start-Process Cmdlet. I have PSCX installed and PS is running PSCX' version of Start-Process by default. I'll start a new SO question to find out how to make PS use the correct version.
urig
Ok, good luck. As I saw there are some solutions ;)
stej
`devenv.com` is a console application though. So it shouldn't run in background.
Joey
@Johannes I guess it's a typo - it should be `devenv.exe` (for me it is located at c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe)
stej
@stej: Nope, definitely not. `devenv.com` is a console executable that allows you to build projects (among other things). `devenv.exe` is the IDE itself and a Windows GUI application. PowerShell should wait for the `.com` but not for the `.exe`. In `cmd` `.com` files are executed preferred over `.exe` if a name clash happens; that's why you get the console application when just running `devenv` in the console.
Joey
@Johannes I checked that and: `devenv.exe` has itself the capability to rebuild solution (in the background) as stated in my code. And `devenv.com` itself calls `devenv.exe` and passes the same arguments. You can check it via ProcessExplorer - the parent-child hiearchy is very well observable. So, it doesn't matter if you call `devenv.com` or `devenv.exe`.
stej
`.com` has output, though :-)
Joey
@Johannes /Out works well in devenv.exe :)
stej
Aaah, I do those things too infrequently. I was quite happy already when I found out that there are both .com and .exe variants ... and dumpbin then told me about the different subsystems of both :-). Much to learn still ...
Joey
+4  A: 

Don't use invoke-expression. Just call devenv.exe directly on the SLN file (or for that matter just use MSBuild.exe unless you have setup or other unsupported project types). One of the beauties of using a shell scripting language is that they are designed to work with console exes rather seamlessly. We do this all the time in PowerShell scripts:

msbuild.exe "R:\Source\Foo.sln" /t:build /p:Configuration=Debug `
    /v:detailed 2>&1 | Out-String -stream -width 1024 > $DebugBuildLogFile

We run the output through Out-String so that the log file output doesn't wrap at 80 or 120 chars (default width of the console that runs the script).

Keith Hill
Works like a charm, thank you. I should only add that the msbuild.exe can be typical found in the .net framework folder, for example: C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe
urig