Jack the intern was thrilled. He sat at his computer in front of a cmd prompt ready to learn.

“It’s your first day, and we need you to work out all this new dotnet command line stuff”. Jack recalled the words of his new Boss, Joe. “We are far too busy to figure this out, we have code to ship, but this should keep you busy for a few months while we ship the Widgets 2.0 interface.” She looked very serious whenever she talked about the Widgets thing. It must be a big deal. Jack hadn’t really understood the whole widgets thing at induction but was happy to have a job.

Luckily for Jack, he had just spent the last few months at Uni learning java and python on Linux and was a pro at the command line stuff. His personal machine ran Windows too so he felt pretty comfortable now staring at the cold black shell covering most of his windows desktop.

Joe had at least told him where to install dotnet from (www.microsoft.com/net/core) and it practically installed itself. It was no apt-get install, but hey, it’s for Windows people. He had also been told to start with the command ‘dotnet’ so he was all set.

Jack started typing and looked at the results. First, he typed dotnet to see what it would tell him.

C:\Users\jackr>dotnet

Usage: dotnet [options]
Usage: dotnet [path-to-application]

Options:
  -h|--help            Display help.
  --version         Display version.

path-to-application:
  The path to an application .dll file to execute.
  

“It looks like ‘dotnet –help’ is the right next instruction to find out more”, he thought to himself, “so…”:

C:\Users\jackr>dotnet --help
.NET Command Line Tools (2.0.0)
Usage: dotnet [runtime-options] [path-to-application]
Usage: dotnet [sdk-options] [command] [arguments] [command-options]

path-to-application:
  The path to an application .dll file to execute.

SDK commands:
  new              Initialize .NET projects.
  restore          Restore dependencies specified in the .NET project.
  run              Compiles and immediately executes a .NET project.
  build            Builds a .NET project.
  publish          Publishes a .NET project for deployment (including the runtime).
  test             Runs unit tests using the test runner specified in the project.
  pack             Creates a NuGet package.
  migrate          Migrates a project.json based project to a msbuild based project.
  clean            Clean build output(s).
  sln              Modify solution (SLN) files.
  add              Add reference to the project.
  remove           Remove reference from the project.
  list             List reference in the project.
  nuget            Provides additional NuGet commands.
  msbuild          Runs Microsoft Build Engine (MSBuild).
  vstest           Runs Microsoft Test Execution Command Line Tool.

Common options:
  -v|--verbosity        Set the verbosity level of the command. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].
  -h|--help             Show help.

Run 'dotnet COMMAND --help' for more information on a command.

sdk-options:
  --version        Display .NET Core SDK version.
  --info           Display .NET Core information.
  -d|--diagnostics Enable diagnostic output.

runtime-options:
  --additionalprobingpath <path>    Path containing probing policy and assemblies to probe for.
  --fx-version <version>            Version of the installed Shared Framework to use to run the application.
  --roll-forward-on-no-candidate-fx Roll forward on no candidate shared framework is enabled.
  --additional-deps <path>          Path to additonal deps.json file.

“Well, that is a lot of information, where to start?” The first instruction new seemed to jump out as a reasonable place to start. but first, somewhere to put the files:

C:\Users\jackr>mkdir internTest
C:\Users\jackr>cd internTest
C:\Users\jackr\internTest>dotnet new
Usage: new [options]

Options:
  -h, --help          Displays help for this command.
  -l, --list          Lists templates containing the specified name. If no name is specified, lists all templates.
  -n, --name          The name for the output being created. If no name is specified, the name of the current directory is used.
  -o, --output        Location to place the generated output.
  -i, --install       Installs a source or a template pack.
  -u, --uninstall     Uninstalls a source or a template pack.
  --type              Filters templates based on available types. Predefined values are "project", "item" or "other".
  --force             Forces content to be generated even if it would change existing files.
  -lang, --language   Specifies the language of the template to create.


Templates                                         Short Name       Language          Tags
--------------------------------------------------------------------------------------------------------
Console Application                               console          [C#], F#, VB      Common/Console
Class library                                     classlib         [C#], F#, VB      Common/Library
Unit Test Project                                 mstest           [C#], F#, VB      Test/MSTest
xUnit Test Project                                xunit            [C#], F#, VB      Test/xUnit
ASP.NET Core Empty                                web              [C#], F#          Web/Empty
ASP.NET Core Web App (Model-View-Controller)      mvc              [C#], F#          Web/MVC
ASP.NET Core Web App                              razor            [C#]              Web/MVC/Razor Pages
ASP.NET Core with Angular                         angular          [C#]              Web/MVC/SPA
ASP.NET Core with React.js                        react            [C#]              Web/MVC/SPA
ASP.NET Core with React.js and Redux              reactredux       [C#]              Web/MVC/SPA
ASP.NET Core Web API                              webapi           [C#], F#          Web/WebAPI
global.json file                                  globaljson                         Config
Nuget Config                                      nugetconfig                        Config
Web Config                                        webconfig                          Config
Solution File                                     sln                                Solution
Razor Page                                        page                               Web/ASP.NET
MVC ViewImports                                   viewimports                        Web/ASP.NET
MVC ViewStart                                     viewstart                          Web/ASP.NET


Examples:
    dotnet new mvc --auth Individual
    dotnet new xunit
    dotnet new --help

“Right, I have to tell it what template to use at least, and I can pick C#, F# or even VB. (what is VB?)” Jack had played around a bit with visual studio, so he knew that there were projects and solutions, and websites, console applications and tests. Figuring a website might be too complicated, he decided to give the Console Application option a go:

C:\Users\jackr\internTest>dotnet new console
The template "Console Application" was created successfully.

Processing post-creation actions...
Running 'dotnet restore' on C:\Users\jackr\internTest\internTest.csproj...
  Restoring packages for C:\Users\jackr\internTest\internTest.csproj...
  Generating MSBuild file C:\Users\jackr\internTest\obj\internTest.csproj.nuget.g.props.
  Generating MSBuild file C:\Users\jackr\internTest\obj\internTest.csproj.nuget.g.targets.
  Restore completed in 261.64 ms for C:\Users\jackr\internTest\internTest.csproj.


Restore succeeded.

“What’s it done, I wonder?”

C:\Users\jackr\internTest>tree /F /A
Folder PATH listing for volume Windows
Volume serial number is 000000D8 BC96:4BCD
C:.
|   internTest.csproj
|   Program.cs
|
\---obj
        internTest.csproj.nuget.cache
        internTest.csproj.nuget.g.props
        internTest.csproj.nuget.g.targets
        project.assets.json

Jack could see a Program.cs which must be the console application, an internTest.csproj (“which must have been named after the parent folder”, he thought) and an obj folder full of other files ("‘obj’ and ‘bin are build outputs, from memory").

The next instruction in the original list of commands was restore:

C:\Users\jack\internTest>dotnet restore
  Restore completed in 22.69 ms for C:\Users\jackr\internTest\internTest.csproj.

“‘Restore completed’, that’s what is said after I ran ‘dotnet new’, so it must have run that for me automatically.” The next two options were run and build. Since Jack was following the order given, he figured he might as well use run first and see what happens.

C:\Users\jackr\internTest>dotnet run
Hello World!

“Alright, maybe?” He figured it best to look at that Program.cs file to see what was what. Having not set up his machine with emacs for windows yet, the file was promptly opened in ’notepad’.

using System;

namespace internTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Guessing the program has worked as expected he moved onto the next command, build.

C:\Users\jackr\internTest>dotnet build
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  internTest -> C:\Users\jackr\internTest\bin\Debug\netcoreapp2.0\internTest.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:05.12

“So ‘build’ appears to do what you would think it does. Moving on to ‘publish’:”

C:\Users\jackr\internTest>dotnet publish
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  internTest -> C:\Users\jackr\internTest\bin\Debug\netcoreapp2.0\internTest.dll
  internTest -> C:\Users\jackr\internTest\bin\Debug\netcoreapp2.0\publish\
C:\Users\jackr\internTest>tree /F /A
Folder PATH listing for volume Windows
Volume serial number is 00000093 BC96:4BCD
C:.
|   internTest.csproj
|   Program.cs
|
+---bin
|   \---Debug
|       \---netcoreapp2.0
|           |   internTest.deps.json
|           |   internTest.dll
|           |   internTest.pdb
|           |   internTest.runtimeconfig.dev.json
|           |   internTest.runtimeconfig.json
|           |
|           \---publish
|                   internTest.deps.json
|                   internTest.dll
|                   internTest.pdb
|                   internTest.runtimeconfig.json
|
\---obj
    |   internTest.csproj.nuget.cache
    |   internTest.csproj.nuget.g.props
    |   internTest.csproj.nuget.g.targets
    |   project.assets.json
    |
    \---Debug
        \---netcoreapp2.0
                internTest.AssemblyInfo.cs
                internTest.AssemblyInfoInputs.cache
                internTest.csproj.CoreCompileInputs.cache
                internTest.csproj.FileListAbsolute.txt
                internTest.dll
                internTest.pdb

“That has made a publish folder with a ‘dll’ in it, but I expected an ’exe’. I wonder if I can find out more on publish…”. He tried dotnet help publish. For a reason totally unknown to Jack, this launched a web browser window to https://docs.microsoft.com/en-gb/dotnet/core/tools/dotnet-publish?tabs=netcore2x displaying help for the publish command, reminiscent of a MAN page. Trying again for something that didn’t take him away from the shell, he tried dotnet publish --help instead.

C:\Users\jackr\internTest>dotnet publish --help
Usage: dotnet publish [options]

Options:
  -h, --help                            Show help information.
  -o, --output <OUTPUT_DIR>             Output directory in which to place the published artifacts.
  -f, --framework <FRAMEWORK>           Target framework to publish for. The target framework has to be specified in the project file.
  -r, --runtime <RUNTIME_IDENTIFIER>    Publish the project for a given runtime. This is used when creating self-contained deployment. Default is to publish a framework-dependent app.
  -c, --configuration <CONFIGURATION>   Configuration to use for building the project.  Default for most projects is  "Debug".
  --version-suffix <VERSION_SUFFIX>     Defines the value for the $(VersionSuffix) property in the project.
  --manifest <manifest.xml>             The path to a target manifest file that contains the list of packages to be excluded from the publish step.
  --self-contained                      Publish the .NET Core runtime with your application so the runtime doesn't need to be installed on the target machine. Defaults to 'true' if a runtime identifier is specified.
  --no-restore                          Does not do an implicit restore when executing the command.
  -v, --verbosity                       Set the verbosity level of the command. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].
  --no-dependencies                     Set this flag to ignore project to project references and only restore the root project.
  --force                               Set this flag to force all dependencies to be resolved even if the last restore was successful. This is equivalent to deleting project.assets.json.

There were at least two useful finds in this bunch: --output or -o would let him choose a different location to publish to. --self-contained seemed like it might give him an exe, perhaps. Jack tried a few combinations, which resulted in some errors. He tried to correct them as he went.

C:\Users\jackr\internTest>dotnet publish -o C:\publish\interntestoutput --self-contained
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

C:\Program Files\dotnet\sdk\2.0.0\Sdks\Microsoft.NET.Sdk\build\Microsoft.NET.RuntimeIdentifierInference.targets(116,5): error : It is not supported to build or publish a self-contained application without specifying a RuntimeIdentifier.  Please either specify a RuntimeIdentifier or set SelfContained to false. [C:\Users\jackr\internTest\internTest.csproj]

C:\Users\jackr\internTest>dotnet publish -o C:\publish\interntestoutput --self-contained -r windows
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.0.0\build\netcoreapp2.0\Microsoft.NETCore.App.targets(19,5): error : Project is targeting runtime 'windows' but did not resolve any runtime-specific packages for the 'Microsoft.NETCore.App' package.  This runtime may not be supported by .NET Core. [C:\Users\mclea\internTest\internTest.csproj]

So firstly It is not supported to build or publish a self-contained application without specifying a RuntimeIdentifier seems to be a thing. and windows as a value results in Project is targeting runtime 'windows' but did not resolve any runtime-specific packages for the 'Microsoft.NETCore.App' package. After going back to that web page that launched when he typed in dotnet help publish he found more info on that option:

-r|–runtime <RUNTIME_IDENTIFIER>

Publishes the application for a given runtime. This is used when creating a self-contained deployment (SCD). For a list of Runtime Identifiers (RIDs), see the RID catalog. Default is to publish a framework-dependent deployment (FDD).

Clicking on the link for RID catalog found that he needed to use one of linux-x64, ubuntu.14.04-x64, win7-x64, or osx.10.12-x64 as the runtime value. Must be win7-x64, then. Trying again:

C:\Users\jackr\internTest>dotnet publish -o C:\publish\interntestoutput --self-contained -r win7-x64
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  internTest -> C:\Users\jackr\internTest\bin\Debug\netcoreapp2.0\win7-x64\internTest.dll
  internTest -> C:\publish\interntestoutput\
C:\Users\jackr\internTest>cd c:\publish\interntestoutput

c:\publish\interntestoutput>tree /F /A
Folder PATH listing for volume Windows
Volume serial number is 00000062 BC96:4BCD
C:.
    api-ms-win-*.dll  <-- truncated for your reading pleasure
    clrcompression.dll
    clretwrc.dll
    clrjit.dll
    coreclr.dll
    dbgshim.dll
    hostfxr.dll
    hostpolicy.dll
    internTest.deps.json
    internTest.dll
    internTest.exe
    internTest.pdb
    internTest.runtimeconfig.json
    Microsoft.CSharp.dll
    Microsoft.DiaSymReader.Native.amd64.dll
    Microsoft.VisualBasic.dll
    Microsoft.Win32.Primitives.dll
    Microsoft.Win32.Registry.dll
    mscordaccore.dll
    mscordaccore_amd64_amd64_4.6.00001.0.dll
    mscordbi.dll
    mscorlib.dll
    mscorrc.debug.dll
    mscorrc.dll
    netstandard.dll
    sos.dll
    SOS.NETCore.dll
    sos_amd64_amd64_4.6.00001.0.dll
    System.*.dll <-- also truncated for readability, phew!
    ucrtbase.dll
    WindowsBase.dll

Finally! An internTest.exe as expected. Jack makes a note that this folder is a whopping 61.7 MB in size, though! Let’s run it for complete satisfaction:

c:\publish\interntestoutput>internTest.exe
Hello World!

Jack remembered seeing Solution File (sln) back in the dotnet new help window. He went back to his original project to see how he might add a solution to it. Pretty quickly he has this sussed out, too.

c:\publish\interntestoutput>cd c:\Users\jackr\internTest

c:\Users\jackr\internTest>dotnet new sln
The template "Solution File" was created successfully.

c:\Users\jackr\internTest>dotnet sln
Required command was not provided.
Usage: dotnet sln [options] <SLN_FILE> [command]

Arguments:
  <SLN_FILE>   Solution file to operate on. If not specified, the command will search the current directory for one.

Options:
  -h, --help   Show help information.

Commands:
  add <args>      .NET Add project(s) to a solution file Command
  list            .NET List project(s) in a solution file Command
  remove <args>   .NET Remove project(s) from a solution file Command
c:\Users\jackr\internTest>dotnet sln add internTest.csproj
Project `internTest.csproj` added to the solution.
c:\Users\jackr\internTest>ls
'ls' is not recognized as an internal or external command,
operable program or batch file.
c:\Users\jackr\internTest>dir
 Volume in drive C is Windows
 Volume Serial Number is BC96-4BCD

 Directory of c:\Users\jackr\internTest

23/09/2017  18:20    <DIR>          .
23/09/2017  18:20    <DIR>          ..
23/09/2017  17:38    <DIR>          bin
23/09/2017  17:30               178 internTest.csproj
23/09/2017  18:20             1,691 internTest.sln
23/09/2017  18:12    <DIR>          obj
23/09/2017  17:30               192 Program.cs
               3 File(s)          2,061 bytes
               4 Dir(s)   2,718,973,952 bytes free

with two simple commands, dotnet new sln and dotnet sln add internTest.csproj Jack was able to create a Visual Studio sln file and add the project to it. Mint.

In total this had only taken Jack an hour (far less time than this Author took to write this whole farce up) and he took his findings back to Joe.

“What? Done already. Dammit, Intern! You’re not meant to be so productive! I’ll have to get you fetching coffees and making team flight suits. How are you at working a sewing machine? First things first though. Write up your findings and get ready to present to the entire department tomorrow, at the cross-team catchup!”

Jack left feeling a mix of achievement and pressure while wondering if she was serious about those jumpsuits…

The dotnet CLI in a nutshell. If an intern can do it so can you. Plenty was left unexplored, but the Author has left plenty of breadcrumbs for you to continue the journey from where Jack left off.

Stay tuned for more adventures of An Intern Named -Grack- Jack.

*Any resemblance to real people is purely intentional for comedic effect as part of an in-joke. The rest is just an interesting way to look a getting started with dotnet CLI.