.NET Core Cross-platform Scanner

This post is over a year old, the information may no longer be up to date.

I’ve been wanting to move over to .NET Core for quite a while now, but up until recently I’ve not really had much reason to do so. I started working on a tool for scanning an entire system for everything installed on it, to be released open-source, but .NET Framework didn’t have the Cross-platform benefits that I needed to support not only Windows, but Linux and MacOS under a single project - I’m one man, I’ve only got so much time.

Something I’ve noticed during this learning period is that the documentation (and Stack Overflow answers) still aren’t quite there yet like it is for .NET Framework, but obviously, Framework is a lot older and has years of questions and answers over the internet. It’s been a bit of a blind-eyed experience trying to work things out, but I’ve managed to get to a point where I’ve got a prototype working of what I’m wanting to create. I’m also going to be nice and explain how I’ve done it, in case someone else needs to in the future.

I’d like to first point out though, that my Linux knowledge is that of a five-year-old. So I apologise in advance if someone looks at this and goes “good lord”, it’s not the prettiest but it is the good base for something.

When you’re working with Cross-platform, you unfortunately can’t just use the same methods of extracting data on both systems. In some cases you can but in most cases you cannot, for instance on Windows you can use WMI or the Registry to get the Operating System ‘friendly name’, such as “Windows 10 Pro”. This won’t work on Linux because Linux has neither WMI or a registry that is readable in this method, so you have to go around it a different way.

1
2
3
4
5
// Get the Operating System in C# for Windows
var name = (from x in new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem").Get().Cast<ManagementObject>()
            select x.GetPropertyValue("Caption")).FirstOrDefault();

Console.WriteLine($"Operating System: {name.ToString()}");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Get the Operating System in C# for Linux
internal string RunShell(string cmd)
{
    var process = new Process()
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = "/bin/sh",
            Arguments = $"-c \"{cmd}\"",
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true,
        }
    };

    process.Start();
    string result = process.StandardOutput.ReadToEnd();
    process.WaitForExit();

    return result;
}

Console.WriteLine($"Operating System: {RunShell(". /etc/os-release; echo \"$PRETTY_NAME\"")}");

So it does beg the question of how do you build for each platform under the same project, without needing to worry about Linux somehow running Windows Code and vice versa? Ah well, Microsoft (or something) thought about that and created a handy little class called RuntimeInformation which includes IsOsPlatform() which lets you do a boolean check on whether you are running Windows, Linux, Unix etc. So all you need to do is wrap your above code in this to allow the application to know what to run on which operating system, example below.

1
2
3
4
5
6
7
8
9
using System.Runtime.InteropServices;

If(RuntimeInformation.IsOsPlatform(OSPlatform.Windows)) {
    // Run your Windows Method here...
}

If(RuntimeInformation.IsOsPlatform(OSPlatform.Linux)) {
    // Run your Linux Method here...
}

Pulling Software Information is equally painful, when working with Linux you ideally want to work on an exclusion basis of file extensions, whereas with Windows you want to work on an inclusion basis. Windows is simple, if it’s an .exe file it’s a runnable application in some form or another, MacOS is simple, if it’s an .app file it’s a runnable application in some form or another, with some slight variance. Linux on the other hand is nomans land, everything is technically an executable but you don’t care about maybe 90% of files on it from an Application Gathering perspective, so you can’t really refuse the same method across both Operating Systems.

The source code to what I’m working on is currently available on GitHub, although I’d only recommend looking at it to get an idea of how it works rather than using it for anything as it’s similar to that of an old fashioned banks online system, horrific spaghetti.

GitHub: Laim/SystemScanner

//

Song Addiction at he moment: Bring Me The Horizon - sTraNgeRs (Explicit)

Catch. 😊x