Replace Powershell with C# scripts!

Replace Powershell with C# scripts!

I was mind blown when I first saw this tool. It let you use the C# language in all it's glory with the framework, classes and namespaces to make small apps compiled just in time like scripts. We will walk throught the pros and cons of using it.

The sources files from this article are available here.

Installation

Using the dotnet extensibility tool, the installation process is resumed to one line and will make dotnet-script accessible from anywhere.

dotnet tool install -g dotnet-script

You're first C# script

The next command will initialize the current folder with a hello-world like csx file and create the required configs to debug with Visual Studio Code.

dotnet script init

Making a script to backup an Azure File Share

This will be a port of our previously made powershell script.

Nugets

Nugets are supported through a special syntaxe. You can also specify Dlls.
Add thoses line to the main.csx.

#r "nuget: CliWrap, 3.2.3"

using System;
using CliWrap;
using CliWrap.Buffered;

When changing a Nuget with VS Code, you must restart OmniSharp.

Ctrl+Shit+P -> Restart OmniSharp

Add variables

var storageSubscription = "";
var storageAccountName = "";
var storageAccountKey = "";
var storageRessourceGroup = "";
var storageFileShareName = "";

var expiry = DateTime.Now.AddHours(12).ToString("yyyy-MM-ddTHH:mmZ");

Generate a SAS key

With CliWrap we can't call az directly but the full path of the bootraper.
In a Command Promt :

C:\Users\nfs12>where az
C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\az.cmd

Next, append the API call to the file.

const string AZ = @"C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\az.cmd";

var sasTokenCmdResult = await Cli.Wrap(AZ)
    .WithArguments($@"storage share generate-sas --subscription {storageSubscription} --account-key {storageAccountKey} --account-name {storageAccountName} --name {storageFileShareName} --expiry {expiry} --permissions lr")
    .ExecuteBufferedAsync();

Be aware that the StandardOutput returns a Windows new line so we remove it to grab only the token.

var sasToken = sasTokenCmdResult.StandardOutput.Replace("\r\n", "");

Delete the olds files

if(Directory.Exists(storageFileShareName))
    Directory.Delete(storageFileShareName, true);

Copy the files from the Cloud to a local folder

There is currently a bug with OmniSharp that breaks the coloration if we don't use the var keyword.

var a = await Cli.Wrap(@"azcopy.exe")
    .WithArguments($"copy https://{storageAccountName}.file.core.windows.net/{storageFileShareName}?{sasToken} ./ --recursive")
    .ExecuteAsync();

Delete the SAS key

Lastly we revoke the delegation key after it's use.

var b = await Cli.Wrap(AZ)
    .WithArguments($@"storage account revoke-delegation-keys --subscription {storageSubscription} --name {storageAccountName} --resource-group {storageRessourceGroup}")
    .ExecuteAsync();

Wrap it up

If you're a C# developper and you need a quick modifiable script but you don't have to call any other executables, I would recommand dotnet-script as experimental. The tool is backed by OmniSharp, who is part of the .Net Fondation.

If you need to call executables, it is a little more work and when a process crashes, it is not verbose. dotnet-script could and should implements a custom and simpliest way to call external executables. When that happens, goodbye Powershell!

Don't forget, the source code is in GitHub!