PowerShell and the new Coreutils for Windows

Microsoft released Coreutils for Windows at the beginning of this month, command-line tools that are native to Linux, macOS, and WSL. In this blog post, I will show you how they work and if you can use them with PowerShell, too 🙂

What are Coreutils?

“UNIX-style core utilities for Windows. The same commands and pipelines you use on Linux, macOS, and WSL – natively.”

Source: https://github.com/microsoft/coreutils#coreutils-for-windows

How do I install it for my current user?

You can install them using WinGet on Windows, both for x64 and ARM64, using either WinGet:

winget install Microsoft.Coreutils

or the installer executables from here. (Download/Save your type (x64 or ARM64) to your temporary folder and run)

How do I install it for all users?

When installing with WinGet, you will be prompted that it will install and modify the user’s PowerShell profile. Other users on that system should rerun the installation so it modifies their profiles, too.

Alternatively, you can run this so that you can add it to the system-wide PowerShell’s profile straight away using WinGet:

winget install Microsoft.Coreutils --interactive

It will also tell you that this might break batch scripts that depend on Find, and that it will prefer the Coreutils/GNU version of sort, which might break non-UTF8 scripts:

What does Coreutils contain?

After installation, these commands are available for you to use both in a Command or PowerShell terminal:

And yes, if you spotted the .txt file, it’s a strange one 😉

If you’re a Linux, macOS, or WSL user, you will recognize these executables and have probably used them already. Because you have installed Coreutils on your Windows system, you can now use them as you would on those systems, making it easier to transition to PowerShell and take advantage of their magic there.

Limitations

These are as listed below: (Source https://github.com/microsoft/coreutils#shell-conflicts)

Shell conflicts

There are shell conflicts between native Windows features and the executable from the Coreutils package.

Note

Any command not mentioned is included in this suite. The following only lists conflicts.

Warning

PowerShell 7.4 or later is required. PowerShell 7.6 or later is recommended for ~ support.

Several commands share names with built-ins in CMD and PowerShell. Whether the Coreutils version runs depends on the shell, the PATH order, and (for PowerShell) the alias table.

Legend: ✅ ships and works · ⚠️ ships but conflicts with a built-in · 🛑 not shipped

CommandCMDPowerShell 7.4+Notes
cat⚠️
cp⚠️
date⚠️⚠️
dir🛑🛑Conflicts with the built-in DOS command
echo⚠️⚠️
expand🛑🛑Conflicts with the built-in DOS command
findIntegrated port of the original DOS command
hostnameSuperset of the Windows built-in
kill🛑🛑Unavailable due to lack of signals on Windows; Implementing a form of SIGTERM/SIGKILL may be possible in the future however
ls⚠️
mkdir⚠️⚠️
more🛑🛑Conflicts with the built-in DOS command (consider edit as an alternative)
mv⚠️
pwd⚠️
rm⚠️
rmdir⚠️⚠️
sleep⚠️
sort⚠️Integrated port of the original DOS command
tee⚠️
timeout🛑🛑Relies on kill‘s functionality
uptime⚠️
whoami🛑🛑Conflicts with the built-in Windows command

Windows caveats

And some Windows caveats:

DifferenceDetail
CRLF line endingsWindows text files often use CRLF (\r\n). Most utilities handle this transparently, but byte-oriented behavior can still observe the \r; for example, uniq may treat the final line as different from a preceding duplicate if the input uses CRLF and the final line has no trailing newline.
No /dev/nullUse NUL instead, for example find . -name "*.log" > NUL
No POSIX signalsSignals such as SIGHUPSIGPIPE, and SIGUSR aren’t available. Ctrl+C (SIGINT) works as expected.
Path separatorsBoth / and \ are accepted. Some utilities produce \-separated output, which can affect downstream piping.
File permissionsWindows uses ACLs, not POSIX permission bits. Permission-based predicates (for example find -perm) may behave differently or be unavailable.
Symbolic linksReading existing symbolic links works without elevation. Creating new symbolic links requires Developer Mode (Settings > System > Advanced) or an elevated terminal.

PowerShell Command Parsing

Things like escape characters and aliases are an issue, too.

The installer integrates with interactive PowerShell sessions via PSReadLine. It ensures that quoted expressions behave somewhat as they do under UNIX shells or CMD: echo *.txt will then print a number of file names, while echo '*.txt' will print “*.txt” literally.

There are two shortcomings, however:

  • PowerShell’s escape character is still `, not \
    While you may write find . \( -foo -bar \) With Bash, you still need to write find . `( -foo -bar `) in PowerShell.
  • Get-Command ls, Get-Help ls, etc., will still show ls, etc., as built-in commands
    Due to limitations around PSNativeCommandPreserveBytePipe, we cannot integrate ourselves in a more robust way with PowerShell.

Dropped features

Commands that exist upstream but aren’t shipped here because they rely on POSIX-only concepts would break existing Windows scripts or simply aren’t useful on Windows.

  • dd: Perhaps useful in the future.
  • dircolorsshredsyncuname: Not particularly useful on Windows.
  • chconchgrpchmodchownchrootgroupshostididinstalllognamemkfifomknodnicenohuppinkyrunconstdbufsttyttyuserswho: POSIX-only concepts unavailable on Windows.

Using Coreutils

You can start them from a cmd.exe or Pwsh (v7.4 and higher) prompt by just running them as you would on Linux. For example, uptime:

Or LS:

But also DU:

The –help Parameter works just like Linux, too 🙂 So, using DU (Disk Usage) as an example, this now also works on Windows to determine the amount of space used for a folder, and its subfolders:

You can also use it in PowerShell to, for example, grep results from a Get-Process overview:

Nicely color-coded, even, but… PowerShell stores things differently, and you can query/see its Properties and values (in this case, it’s a System).ComponentModel.Component Process Property, but could be a normal Array with Objects)

Whereas Coreutils stores things in Arrays as a String per item, which makes scripting/looping items difficult because there are no Properties with values or Methods:

Should you use Coreutils?

Yes 🙂 It does have its benefits; some extra command-line tooling is always nice! However, using it in Scripts for processing large amounts of objects, etc., is not so versatile. But for me, as a command-line guy, this increases my workflow on Windows machines (When I’m not working on my MacBook Air) because I have these Coreutils executables available!

Wrapping up

And that’s it for now for the Coreutils release, nice to have and use, and especially for admins coming from Linux or macOS systems. But I do think that you shouldn’t use them in scripts because the output will only give you Strings… (As a general rule, don’t use executables in scripts because you are creating dependencies on those.) Have a lovely weekend!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.