rm binary in Windows $PATH but Powershell still prefers Remove-Item - windows

I have the GNU core utils installed on Windows and have added the bin folder to my user PATH variable in Windows.
I have found that Powershell prefers Windows native commands over commands with the same name in PATH.
For example, when running get-command rm, powershell informs me that it's mapped to the internal
CommandType Name Version Source
----------- ---- ------- ------
Alias rm -> Remove-Item
Same with any commands where there is a Windows version - find, mkdir, etc.
Checking commands that I know Windows does not have an alternative for gives me the correct binay location
get-command md5sum
CommandType Name Version Source
----------- ---- ------- ------
Application md5sum.exe 5.3.0.1936 C:\Users\alshd\bin\coreutils\bin\md5sum.exe
Is there a way to tell PowerShell to prefer the versions I have specified in my PATH over the native Windows commands (without manually aliasing them)?

Building on Lee Dailey's helpful comments:
PowerShell aliases have higher precedence than external programs with the same (base) name.
Note that the precedence rules imply that in the absence of an rm alias a (hypothetical) rm function would take precedence too (and even a cmdlet, though the verb-noun naming convention of cmdlets makes this highly unlikely).
To see all command forms that exist for a given name, use Get-Command with the -All switch: Get-Command rm -All
To bypass naming conflicts, invoke the external program with its filename extension, namely rm.exe in this case; using the program's (full) path works too.
While it is advisable for scripts and modules to not use aliases - to put it differently: it is advisable to use aliases only as an interactive convenience - in practice they do, so there's a risk of breaking code if you remove built-in aliases such as rm.
If you're willing to assume this risk, see below for how to remove the rm alias; if you want the removal to apply to all future PowerShell sessions too, add the call to your $PROFILE file.
To remove the rm alias, using Remove-Item with the standard Alias: drive provided by the alias provider:
Remove-Item Alias:rm -Force
Note:
In PowerShell (Core) 6+, you can more simply use Remove-Alias rm -Force.
Not all aliases require -Force for removal, but many built-in ones do (though not rm, specifically).

Related

Unable to delete a folder on Windows with a .git in it

If I start a PowerShell as a regular user (not admin) and run
cd Desktop
mkdir test
cd test
git init
cd ..
I then cant delete the folder via PowerShell. I have tried the following commands as admin and as the current user.
rm -r test # -> no access permission
rmdir test # -> no access permission
del -r test # -> no access permission
del test # -> no access permission
It prints
+ CategoryInfo : PermissionDenied: (.git:DirectoryInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemUnAuthorizedAccess,Microsoft.PowerShell.Commands.RemoveItemCommand
But I don't understand why I can't remove folders with a .git folder in them.
In order to remove [a directory that contains] hidden items, PowerShell's Remove-Item cmdlet requires passing the -Force switch:
Remove-Item -Recurse -Force test
The shortest form of this command (for interactive rather than scripting use), using the platform-neutral ri alias and PowerShell's so-called elastic syntax, where it is sufficient to specify a prefix of a parameter name (such as -r for -Recurse), as long as that prefix is unambiguous):
ri -r -fo test
Note how a two-letter prefix is required for -Force, because -f alone is ambiguous: it could also refer to the -Filter parameter.
git init creates a .git subdirectory that is assigned the Hidden attribute on Windows (on Unix-like platforms, the fact that the name starts with . alone makes the directory a hidden one).
On Windows, rm, del, rmdir are simply built-in aliases of Remove-Item, the single cmdlet used to remove both files and directories (removal of the latter requiring -Recurse if the directory is not empty).
(On Unix-like platforms, only del is defined as an aliases, so as not to shadow the platform-native rm and rmdir utilities.)
ri is a platform-neutral alias derived from the name Remove-Item, and therefore preferable.
To see all aliases defined for a given command use Get-Alias -Definition $name; e.g.:
Get-Alias -Definition Remove-Item
Note: While it is arguably beneficial for PowerShell to require explicit opt-in via -Force in order to delete hidden items - so that you don't accidentally delete items whose existence you may not be aware of - the error message is suboptimal, in that the problem isn't one of permissions.

Analog of $PWD in Windows

I run windows command in particular directory and I need to pass files and subdirectories in this directory with full path. How to retrieve full path of current directory? What is analog of bash $PWD?
$pwd is indeed a valid command in PowerShell as well (if you're using PowerShell). $pwd in PowerShell is basically an alias for Get-Location - both of them will give you the full path of current directory.
In case you are using cmd, use cd (just cd without any parameters)

How to expand ZIP archive using PowerShell (UTF-8 filenames)

My zip archive has a single file:
Père-Noël.txt
The zip expands nicely with Windows File Explorer, 7-Zip or any other tool I've tried. But I cannot figure out how to do it from PowerShell. Obviously I've tried Expand-Archive but it cannot handle the file name and garbles it into PŠre-N”el.txt. Note: The problem isn't specifically with this example, but indeed with any file name which uses characters outside of the ASCII-127 range. Or so it seems.
Any solution which uses PowerShell and which doesn't rely on an external tool - whose presence cannot be guaranteed - will be accepted. Windows 10 is the platform. I cannot do system-level changes and cannot rely on users of the script having any specific global setting on their system. It has to be a solution within the script.
Is there another way, besides Expand-Archive ? Or is there a setting in PowerShell which will magically do the trick?
Steps to reproduce:
On your Windows 10 host:
Create an empty file named Père-Noël.txt.
ZIP the file using Windows Explorer ("Compressed Folders" feature) into an ZIP archive of your choice, say myarchive.zip.
Delete the Père-Noël.txt file.
Now try to unpack the myarchive.zip using PowerShell. This operation should create the file Père-Noël.txt again.
Compressing using PowerShell Compress-Archive cmdlet
True, if the ZIP was originally created using Compress-Archive cmdlet then it actually works as intended when decompressing using Expand-Archive. So you can say that PowerShell is compatible with itself. It is just not compatible with Windows Explorer ZIPs.
You'll likely need to check the encoding [System.Text.Encoding]::GetEncodings() but the below works with your example Père-Noël
$zipfile = 'C:\test\Père-Noël.zip' #Contains Père-Noël.txt
$outpath = 'C:\test\out'
$enc = [System.Text.Encoding]::GetEncoding(29001) #29001, x-Europa, Europa
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath, $enc)
Hope this helps,
Although we arrived in 2021 I stumbled upon the same problem.
Like the accepted answer my solution is based on the System.IO.Compression namespace.
The expand-archive command accepts pipeline-input and a -Force switch.
I had the same goals for my implementation - still in work and not thoroughly tested.
$encoding = [System.Text.Encoding]::GetEncoding(437)
Write-Output $encoding
Get-ChildItem -Path ".\*.zip" | Unzip -target "C:\unzipped" -f -encoding $encoding -v
Find unzip function here
It's similar to the accepted answer but I like this answer better:
[System.IO.Compression.ZipFile]::ExtractToDirectory("$pwd/test.zip", "$pwd", [System.Text.Encoding]::GetEncoding((Get-Culture).TextInfo.OEMCodePage)
source

Getting home directory?

I'm trying to get a directory off of the user's home directory in a script. This is what I'm trying, but the ~ is interperated as a literal instead of expanding to the home directory. Is there anyway to get it to expand? If not, can I get the home directory another way?
$mySourceDir = "~/Projects/svn/myProject/trunk" # Single quote also does not expand
cd $mySourceDir
This is using the PS 6 beta on OSX.
In PowerShell, the most robust way to refer to the current user's home directory is to use automatic variable $HOME, inside "..." if it is part of a larger path:
$mySourceDir = "$HOME/Projects/svn/myProject/trunk"; Set-Location $mySourceDir
(Set-Location is PowerShell's cd equivalent; thanks to a built-in alias definition, you can use cd too, however.)
If you're passing a path as an argument to a command, you may be able to get away without the enclosing "...", depending on what characters the path contains; e.g.,
Set-Location $HOME/Desktop
Works on both Windows and Unix platforms, whereas if you tried to use environment variables such as $env:HOME, platform differences would surface.
To learn about all automatic variables (built-in variables) that PowerShell defines, see the conceptual about_Automatic_Variables help topic (as of this writing, the description of $HOME reflects just the Windows perspective, but $HOME does work analogously on Unix platforms).
Use ~ only if you're certain that the current location is a filesystem location:
The current location is PowerShell's generalized concept of the current directory: PowerShell generalizes the concept of a drive to include other (typically) hierarchical data stores, such as the Windows registry, a directory of all defined functions (drive Function:), variables (Variable), or environment variables (Env:).
Each such drive is provided by a drive provider, of which the filesystem [drive provider] is just one instance.
~ is a drive-provider-specific concept, so using just ~, without an explicit reference to a drive provider, refers to the home location as defined by the provider underlying the current location.
Some providers provide no default for what ~ represents, causing attempts to use it to fail; for instance, that is the case for the Environment drive provider and its Env: drive:
Set-Location Env:; Set-Location ~ results in error
Home location for this provider is not set. To set the home location, call "(get-psprovider 'Environment').Home = 'path'
It is the drive provider that interprets ~, so ~ also works inside '...' and "..."
From a filesystem location, the following commands all work the same:
Set-Location ~/Desktop
Set-Location "~/Desktop"
Set-Location '~/Desktop'
Contrast this with POSIX-like shells such as bash, where it is the shell that expands ~, up front, before the target command sees it, but only if it is unquoted.
Try
$mySourceDir = "$env:HOME/Projects/svn/myProject/trunk"

Renaming a file and remove 'dot' and replace it with' _'

I have set of files in a folder with name like abcd.15678
I want to remove the . and replace it with _
Pls suggest the windows command to do this
This solution is reposted from How to Batch Rename Files in Windows: 4 Ways to Rename Multiple Files by Chris Hoffman
PowerShell offers much more flexibility for renaming files in a command-line environment. Using PowerShell, you can pipe the output of one command – known as a “commandlet” in PowerShell terms — to another command, just like you can on Linux and other UNIX-like systems.
First of all, open Powershell ISE and then navigate to the directory (folder) that has the files and folders you'd like to rename by using this command:
cd "C:\your\directory\"
The two important commands you’ll need are Dir, which lists the files in the current directory, and Rename-Item, which renames an item (a file, in this case). Pipe the output of Dir to Rename-Item and you’re in business.
After you launch PowerShell ISE, use the cd command to enter the directory containing your files. You should put the files in their own directory so you don’t accidentally rename other files.
For example, let’s say we don’t want the dot character in our file names – we’d rather have an underscore instead.
The following command lists the files in the current directory and pipes the list to Rename-Item. Rename-Item replaces each dot character with an underscore.
Dir | Rename-Item –NewName { $_.name –replace ".","_" }
Consult Microsoft’s documentation on the Rename-Item commandlet if you want help performing other, more advanced operations.
There isn't a windows command to do this. You should consider writing a script of some sort that obtains a directory listing and enumerates through each entry: changes the dot to an underscore, and calls the windows rename command appropriately.
Actually this should work :
Dir | Rename-Item –NewName { $_.Name.Replace(".","_") }

Resources