Visual Studio

How to debug NuGet package scripts

You can step by step debug your Init.ps1, Install.ps1, or Uninstall.ps1 using NuGetDebugTools. It won’t be the best debugging experience you’ll ever have in your life, but it will surely get the job done!

At first you need to open the Package Manager Console in Visual Studio and:

  1. install the NuGetDebugTools package
  2. add the debugger
  3. set breakpoints for the scripts  you want to debug

Now you’re all set and you can begin installing your own package. Depending on which breakpoints you’ve set with the Set-PSBreakpoint command, when a break point gets hit you will be prompted with a dialog. This is where you will be entering your commands debugging commands (e.g. s for step into, v for step over)

 

NuGetDebugTools_cmdprompt

Dialog for entering debugging commands

The basic commands that you can enter are

  • s – StepInto (Step to the next statement into functions, scripts, etc)
  • v – StepOver (Step to the next statement over functions, scripts, etc)
  • o – StepOut (Step out of the current function, script, etc)
  • c – Continue (Continue operation, also on Cancel or empty)
  • q – Quit (Stop operation and exit the debugger)
  • ?, h – Help (Write this help message)
  • k – CallStack (Write call stack, aka Get-PSCallStack)
  • K – CallStackDetailed (Write detailed call stack using Format-List)

And you will be receiving feedback and additional information in the Package Manager Console

NuGetDebugTools_output
You can find an exhaustive list of commands and more detailed information on the NuGetDebugTools github page

Modifying the project during NuGet package installation and removal

By default NuGet does a great job installing and referencing all the assemblies present in the ‘lib‘ directory of the NuGet package. Furthermore, if you have other files which need to be added to the solution, you can simply add them to the ‘content‘ directory of the package. The files added to the ‘content‘ directory will be added to the solution with the following properties:

  • BuildAction – Content
  • CopyToOutputDirectory – Do not copy

This is extremely nice if you have images, unmanaged dlls, or other things that just need to be added to the solution, and not referenced.

However, there are times when the default behavior is not enough, and you need control over how your items get added to the project (e.g. if you need to have CopyToOutputDirectory=CopyIfNewer).

Running scripts when installing the package

You will need to add a Install.ps1 script to your package. You can read more on how to do that here.

Now that you added Install.ps1 to your package, it’s time to change some values here and there. Of course, there are several ways this behavior can be achieved, I will start with how NOT to do it, and continue with how to do it.

How NOT to do it

While trying to figure out myself how to achieve this, I found this answer on stackoverflow.com. Unfortunately, I was hasty enough to take that solution as “good enough”, and didn’t scrolled down a few more answers (spoiler alert: one of them contains the correct way of doing it).

I adjusted the PowerShell code with a more “mean” xquery and got this bad boy

The above script loads the project file from the disk, performs some changes to it, and then flushes it back to the disk. Mission accomplished, however, you are actually changing the project “behind the scenes”, and big surprise, Visual Studio is not entirely happy about it:

Project modified outside Visual Studio

Project modified outside Visual Studio

Q: Should I Save, Discard, Overwrite, Ignore?

A: Can I chose more than one option?

If you saved all your changes before running the package installation, in most of the cases you would be able to click Discard
and get away with it, but not all the times. What’s left, is Save As and later on performing a merge of the two project files (highly uncool). Moreover, I wonder how this will work if there are errors while installing the package and a rollback is needed.

How to do it

The parameters that your Install.ps1 script is receiving are:

You can review the details of each parameter here.

The $project is a reference to the EnvDTE project the package is being installed into. This means that you get complete control over the project file in a standard way.

Here are a few examples on how to use it:

CopyToOutputDirectory

Given the following project structure

RoccatSolutionDLL

Changing the CopyToOutputDirectory property of the talkfx-c.dll can be done with the following construct

Note: You need to work your way down the project structure hierarchy until you reach the item you are after (in this case CroccatTalkWrapper/win32-x86/talkfx-c.dll)

The possible values for CopyToOutputDirectory are

  • 0 = Do not copy
  • 1 = Copy always
  • 2 = Copy if newer

BuildAction

Keeping the same project structure as above

Standard BuildAction values are:

  • 0 = None
  • 1 = Compile
  • 2 = Content
  • 3 = EmbeddedResource

Testing

If you need to test your $project manipulations, you can do it in the Visual Studio Package Manager Console

Now you can test all your manipulations in the console.

Compatibility

Starting with Visual Studio 2017 install.ps1 and uninstall.ps1 are no longer supported (read more).

Visual Studio – Conditional breakpoints and IntelliSense

I was a bit puzzled to find out how many people overlook the conditional breakpoints in Visual Studio. They usually settle with just setting a regular breakpoint, and then F5-ing their way until the program enters a specific state they are after. Sure, it gets the job done, but it makes your debugging experience worse, and since Visual Studio has so many tools that you can use when debugging, you have no excuse for having a miserable debugging experience (except when you debug distributed systems, then you just suffer :) – well, not really, I am stretching it a bit)

However, this is how you set a conditional breakpoint:

  • add a breakpoint as you usually do
  • then right click the breakpoint indicator and select Condition
  • Voila!
Visual Studio Conditional Breakpoint

Visual Studio Conditional Breakpoint

  • Most of the few people who reach this point will stop here, having the same question in their mind, why no intellisense?
  • The answer: Ctrl + Space, if you press the magic key combination when you type your condition, you will bring up intellisense
  • Voila!
Visual Studio - Intellisense in conditional breakpoint

Visual Studio – Intellisense in conditional breakpoint

  • These features have been in place since forever, however people seem to have overlooked them, even though they greatly improve the debugging experience