PowerShell in .NET Core and Docker
Since the beginning of time .NET Core there has been one continuous annoyance about developing cross-platform solutions, including build scripts for windows and non-windows platforms.
We have at least fallen into a standard pattern, most repositories will contain both a build.cmd
and build.sh
that will build the project in whichever platform we're currently using.
Sometimes though there's only one or one is neglected in favour of the other. If we're using a build tool like Cake or Fake then we have a simple setup, our build files can just trigger the build logic which is stored in a single file. In fact, both tools will give you default build files that do just that.
So what if we're just doing a relatively plain build task? Something like
dotnet clean
dotnet tool restore
dotnet build ./src/*.csproj
dotnet build ./tests/*.csproj
dotnet test ./tests/*.csproj
dotnet package ./src/*.csproj
Over time changes will be made to this and human error is inevitable, a change will be made to build.cmd
but not to build.sh
, or vice versa.
Enter PowerShell Core, now available as a dotnet tool
! Presuming you have the .NET Core SDK installed, you can simply run
dotnet tool install --global PowerShell
It will now be available with the pwsh
command. But this still presumes that other developers will have it installed globally.
Let's add it on a project level.
# add a tool manifest if there isn't one already
dotnet new tool-manifest
dotnet tool install PowerShell
Now PowerShell becomes a tool available in the project. Instead of pwsh
, you will have to specify dotnet pwsh
but now we can create a build.ps1
file that can contain all our build logic and replace our build.cmd
and build.sh
files with a one-liner.
dotnet pwsh build.ps1
Now all our build logic is cross-platform without external dependencies!
Where this really comes into its own is that PowerShell has been included as a global tool in .NET Core SDK docker images.
Combined with Visual Studio Code's new Remote Development functionality, this means you can build a truly cross-platform development environment in a docker image. Simply set it up for your project, write one build script in PowerShell and rest secure in the knowledge that you're providing everything needed for another developer to be able to grab your project, open it up and build it immediately without having to worry about setting up dependencies or even what platform they're using!