There are a few reasons that we need to know if our program is running under the Windows Remote Desktop (RDP) session. For example, if it is running under RDP, we may disable animation and other fancy graphics effects. But how can we detect if our program is currently under RDP? Let's see.

Windows Forms

If you are developing Windows Forms Apps using .NET Core 3.x, there's a built-in API that can return if the current program is under RDP: SystemInformation.TerminalServerSession

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        if (IsRDP)
        {
            MessageBox.Show("Under RDP");
        }
    }

    public static Boolean IsRDP => SystemInformation.TerminalServerSession;
}

Very straight forward.

Other .NET Core Programs

For other .NET Core program types that we can't use Windows Forms classes. We need to use the old school way: P/Invoke.

According to a Microsoft document, User32.dll got a method to return if the current invoker program is running under RDP: GetSystemMetrics( SM_REMOTESESSION )

Here, the SM_REMOTESESSION is actually an integer value, which can be presented as 0x1000 in C#. So the example code would be:

static void Main(string[] args)
{
    bool isRDP = GetSystemMetrics(SM_REMOTESESSION);
    Console.WriteLine($"Running under RDP: {isRDP}");

    Console.ReadKey();
}

const int SM_REMOTESESSION = 0x1000;

[DllImport("user32")]
static extern bool GetSystemMetrics(int index);

Tip: The ".dll" behind "user32" can actually be left out because .NET Core is smart enough to look for .dll on Windows systems and .so on Linux. But in this example, the code won't work on Linux since it neither has RDP nor user32 API :)

However, you should be very careful when using P/Invoke to call unmanaged code from managed code, in fact, you should avoid this trick as much as possible in .NET programming because it will make your code couple with a specific platform unless you write a whole bunch of platform checking code. Anyway, it can get things complicated in seconds. 

For more information on P/Invoke, please see Microsoft document: https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke