In PowerShell if you need to determine the process or OS architecture, you should theoretically be able to leverage the .NET APIs to find it out. And in fact this works in PowerShell Core:
> [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture
X64
> [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture
X64
But Windows PowerShell is inconsistent. The above syntax works on one of my two Windows machines, but the other acts as if the properties do not even exist:
> [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture
> [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture
> [System.Runtime.InteropServices.RuntimeInformation] | gm -static
TypeName: System.Runtime.InteropServices.RuntimeInformation
Name MemberType Definition
---- ---------- ----------
Equals Method static bool Equals(System.Object objA, System.Object objB)
IsOSPlatform Method static bool IsOSPlatform(System.Runtime.InteropServices.OSPlatform platform)
new Method System.Runtime.InteropServices.RuntimeInformation new()
ReferenceEquals Method static bool ReferenceEquals(System.Object objA, System.Object objB)
OSDescription Property static string OSDescription {get;}
So Windows PowerShell is hiding some of the properties on that type. I know it’s hiding it because [System.Runtime.InteropServices.RuntimeInformation].GetType().Assembly
reveals the path to the assembly the type comes from and it’s just standard mscorlib.dll, which if I open in ILSpy does indeed have the properties I need. I can even circumvent the filter that Windows PowerShell must have inside by being slightly fancier:
> [type]::gettype('System.Runtime.InteropServices.RuntimeInformation').getproperties() | select name
Name
----
FrameworkDescription
OSDescription
OSArchitecture
ProcessArchitecture
Well how about that! The properties are there in the Windows PowerShell process.
It turns out that I had two RuntimeInformation classes in my process. PSReadLine (a PowerShell plugin I use) defines one, with the same namespace, but an incomplete set of properties. Go figure. To make the script work reliably, you just have to add an assembly name qualifier:
> [System.Runtime.InteropServices.RuntimeInformation,mscorlib]::OSArchitecture.ToString().ToLower()
It turns out that this syntax works on both Windows machines, in both Windows PowerShell and PowerShell Core. It works in PowerShell Core on Mac and Linux as well.
Note that although PowerShell Core runs on .NET 6+, which doesn’t define RuntimeInformation in mscorlib any more, .NET 6 does include an mscorlib type forwarding assembly, so pretending like the type is in mscorlib actually makes it work everywhere.