diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,12 @@
 # Version history for simple-cmd
 
+## 0.2.7 (2022-06-20)
+- allow building on Windows without unix (no sudo*)
+- add 'newline' to output newline
+- rename 'sudo_' to 'sudoLog' ('sudo_' no longer outputs log)
+- export 'sudoInternal' helper
+- provide 'cmdLog_' to be used instead of 'cmdLog'
+
 ## 0.2.6 (2022-05-18)
 - timeIO: print the duration in hours and minutes, not just seconds
 
diff --git a/simple-cmd.cabal b/simple-cmd.cabal
--- a/simple-cmd.cabal
+++ b/simple-cmd.cabal
@@ -1,5 +1,5 @@
 name:                simple-cmd
-version:             0.2.6
+version:             0.2.7
 synopsis:            Simple String-based process commands
 description:
             Simple wrappers over System.Process
@@ -20,6 +20,7 @@
 extra-source-files:  README.md ChangeLog.md TODO
 tested-with:         GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4,
                      GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7, GHC == 9.0.2
+                     GHC == 9.2.3
 
 source-repository head
   type:     git
@@ -35,8 +36,9 @@
                        extra,
                        filepath,
                        process >= 1.4.3.0,
-                       time,
-                       unix
+                       time
+  if !os(windows)
+   build-depends:      unix
   default-language:    Haskell2010
   default-extensions:  CPP
   ghc-options:         -Wall
diff --git a/src/SimpleCmd.hs b/src/SimpleCmd.hs
--- a/src/SimpleCmd.hs
+++ b/src/SimpleCmd.hs
@@ -35,7 +35,7 @@
   cmdLines,
   cmdMaybe,
   cmdFull,
-  cmdLog, cmdlog {-TODO: remove for 0.3 -},
+  cmdLog_, cmdLog, cmdlog {-TODO: remove for 0.3 -},
   cmdN,
   cmdQuiet,
   cmdSilent,
@@ -47,13 +47,16 @@
   needProgram,
   error',
   warning,
+  newline,
   logMsg,
   (+-+),
   removePrefix, removeStrictPrefix, removeSuffix,
   egrep_, grep, grep_,
   shell, shell_,
   shellBool,
-  sudo, sudo_,
+#ifndef mingw32_HOST_OS
+  sudo, sudo_, sudoLog, sudoInternal,
+#endif
   PipeCommand,
   pipe, pipe_, pipeBool,
   pipe3, pipe3_, pipeFile_,
@@ -85,7 +88,9 @@
 import System.FilePath
 import System.IO (hGetContents, hPutStr, hPutStrLn, IOMode(ReadMode),
                   stderr, stdout, withFile, Handle)
+#ifndef mingw32_HOST_OS
 import System.Posix.User (getEffectiveUserID)
+#endif
 import System.Process (createProcess, CreateProcess (cmdspec), proc,
                        ProcessHandle,
                        rawSystem, readProcess,
@@ -171,18 +176,24 @@
 shellBool cs =
   boolWrapper (rawSystem "sh" ["-c", cs])
 
--- FIXME cmdLog_
--- | @cmdLog c args@ logs a command with a datestamp
+-- | @cmdLog_ c args@ logs a command with a datestamp
 --
--- @since 0.1.4
-cmdLog :: String -> [String] -> IO ()
-cmdLog c args = do
+-- @since 0.2.7
+cmdLog_ :: String -> [String] -> IO ()
+cmdLog_ c args = do
   logMsg $ unwords $ c:args
   cmd_ c args
 
--- | @cmdlog@ deprecated alias for 'cmdLog' (will be removed in 0.3)
+-- FIXME change in 0.3
+-- | deprecated, use @cmdLog_@ instead (will change type in 0.3)
+--
+-- @since 0.1.4
+cmdLog :: String -> [String] -> IO ()
+cmdLog = cmdLog_
+
+-- | @cmdlog@ deprecated alias for 'cmdLog_' (will be removed in 0.3)
 cmdlog :: String -> [String] -> IO ()
-cmdlog = cmdLog
+cmdlog = cmdLog_
 
 -- | @logMsg msg@ outputs message with a timestamp
 logMsg :: String -> IO ()
@@ -298,6 +309,7 @@
 egrep_ pat file =
   cmdBool "grep" ["-q", "-e", pat, file]
 
+#ifndef mingw32_HOST_OS
 -- | @sudo c args@ runs a command as sudo returning stdout
 --
 -- Result type changed from IO () to IO String in 0.2.0
@@ -309,11 +321,25 @@
 -- | @sudo_ c args@ runs a command as sudo
 --
 -- @since 0.2.0
+-- @since 0.2.7 no longer logs (use sudoLog)
 sudo_ :: String -- ^ command
      -> [String] -- ^ arguments
      -> IO ()
-sudo_ = sudoInternal cmdLog
+sudo_ = sudoInternal cmd_
 
+-- | @sudo_ c args@ runs a command as sudo
+--
+-- @since 0.2.7
+sudoLog :: String -- ^ command
+     -> [String] -- ^ arguments
+     -> IO ()
+sudoLog = sudoInternal cmdLog_
+
+-- | @sudoInternal@ converts a command runner to sudo
+--
+-- Uses sudo unless the effective uid is 0, otherwise errors if sudo not found.
+--
+-- @since 0.2.7
 sudoInternal :: (String -> [String] -> IO a) -> String -> [String] -> IO a
 sudoInternal exc c args = do
   uid <- getEffectiveUserID
@@ -324,6 +350,7 @@
   when (uid /= 0 && noSudo) $
     warning "'sudo' not found"
   exc (fromMaybe c sd) (if noSudo then args else c:args)
+#endif
 
 -- | Combine two strings with a single space
 infixr 4 +-+
@@ -361,6 +388,11 @@
 warning :: String -> IO ()
 warning s = hPutStrLn stderr $! s
 
+-- | output a newline
+--
+-- @since 0.2.7
+newline ::IO ()
+newline = putStrLn ""
 
 -- | Type alias for a command in a pipe
 --
