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
| Command | CMD | PowerShell 7.4+ | Notes |
|---|---|---|---|
cat | ✅ | ⚠️ | |
cp | ✅ | ⚠️ | |
date | ⚠️ | ⚠️ | |
dir | 🛑 | 🛑 | Conflicts with the built-in DOS command |
echo | ⚠️ | ⚠️ | |
expand | 🛑 | 🛑 | Conflicts with the built-in DOS command |
find | ✅ | ✅ | Integrated port of the original DOS command |
hostname | ✅ | ✅ | Superset 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
| Difference | Detail |
|---|---|
| CRLF line endings | Windows 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/null | Use NUL instead, for example find . -name "*.log" > NUL |
| No POSIX signals | Signals such as SIGHUP, SIGPIPE, and SIGUSR aren’t available. Ctrl+C (SIGINT) works as expected. |
| Path separators | Both / and \ are accepted. Some utilities produce \-separated output, which can affect downstream piping. |
| File permissions | Windows uses ACLs, not POSIX permission bits. Permission-based predicates (for example find -perm) may behave differently or be unavailable. |
| Symbolic links | Reading 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 writefind . \( -foo -bar \)With Bash, you still need to writefind . `( -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.dircolors,shred,sync,uname: Not particularly useful 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!