I simply want to list all of the directories under my current working directory, using PowerShell. This is easy from a Bash shell:
ls -d */
or cmd.exe in Windows:
dir /a:d
Using PowerShell however I cannot seem to be able to do it with a single command. Instead the only the I've found that works is:
ls | ? {$_Mode -like "d*"}
That seems way too wordy and involved, and I suspect that I don't need a separate Where clause there. The help for Get-ChildItem doesn't make it clear how to filter on Mode though. Can anyone enlighten me?
This works too:
ls | ?{$_.PsIsContainer}
There is no doubt that it is a little more wordy than bash or cmd.exe. You could certainly put a function and an alias in your profile if you wanted to reduce the verbosity. I'll see if I can find a way to use -filter too.
On further investigation, I don't believe there is a more terse way to do this short of creating your own function and alias. You could put this in your profile:
function Get-ChildContainer
{
param(
$root = "."
)
Get-ChildItem -path $root | Where-Object{$_.PsIsContainer}
}
New-Alias -Name gcc -value Get-ChildContainer -force
Then to ls the directories in a folder:
gcc C:\
This solution would be a little limited since it would not handle any fanciness like -Include, -Exclude, -Filter, -Recurse, etc. but you could easily add that to the function.
Actually, this is a rather naive solution, but hopefully it will head you in the right direction if you decide to pursue it. To be honest with you though I wouldn't bother. The extra verbosity in this one case is more than overcome by the overall greater flexibility of powershell in general in my personal opinion.
Try:
ls | ? {$_.PsIsContainer}
dir -Exclude *.*
I find this easier to remember than
dir | ? {$_.PsIsContainer}
Plus, it is faster to type, as you can do -ex instead of -exclude or use tab to expand it.
You can now use Get-ChildItem -Directory or ls -dir for short. This has existed at least since PowerShell 3.0 according to Microsoft's documentation.
You can check old post on PowerShell team blog: http://blogs.msdn.com/powershell/archive/2009/03/13/dir-a-d.aspx
I came to this thread because I'm trying to figure out how "FOR /D" works. Well actually how to use the batch-command escape(%) with the /D option.
I read the above items with hope, to be honest they're all a lot more complex than the FOR command option -- If it worked of course.
Using additional forms of for
If command extensions are enabled (that is, the default), the following additional forms of for are supported:
Directories only
If set contains wildcards (* and ?), the specified command executes for each directory (instead of a set of files in a specified directory) that matches set. The syntax is:
for /D {%% | %}variable in (set) do command [CommandLineOptions]
Well, soon we will have to a make a class to simplify things and be typing commands like
dir -options {122b312aa3132-1313-131112f8111111} just so we can do the same as
dir/ad/od
Related
I'm trying to translate a Linux command to be easily usable for Windows user for a project, but I am not having any luck finding comparable commands in Powershell.
I have two paths with some SQL and CSV files. What I need is this command:
cat ./* ../path/* > new_file.sql
This takes all content from all files in path1 and then all content from all files in path2 and writes it to a file.
I assumed I could do something similar in Powershell, but apparently the behaviour is wildly different.
What I have tried are:
cat ./*, ../path/* > new_file.sql
Get-Content ./*, ../path2/* | Out-File new_file.sql
They both do the same which seems to... I'm not sure, take the entirety of path2/* for every file in path1? The output quickly balloons to tens of megabytes. The combined content of both directories is a perhaps 40 kilobytes.
Anyone know? I cannot find a proper answer to this. Thanks!
EDIT: I think I figured out what the problem is. I guess I should've just used the actual paths for the example. First path is ./* and it seems like it keeps looping over the Out-File it makes itself. I have updated the title and examples to reflect this.
Enumerate the files as a separate step before concatenating their contents (this way Get-Content won't accidentally discover the new file halfway through):
$files = Get-ChildItem ./,../path2/ -File
$files |Get-Content |Out-File newfile.txt
You can combine these statements in a single pipeline if you wish:
(Get-ChildItem ./,../path2/ -File) |Get-Content |Out-File newfile.txt
I am trying to configure my dotnet core project (in Windows) as "case sensitive", so it behaves as in my production server (linux).
I have found this way of doing it:
fsutil.exe file setCaseSensitiveInfo "C:\my folder" enable
The problem is that this function is not recursive:
The case sensitivity flag only affects the specific folder to which you apply it. It isn’t automatically inherited by that folder’s subfolders.
So I am trying to build a powershell script that applies this to all folders and subfolders, recursively.
I have tried googling something similar and just modifying the command line, but I don't seem to find the corrent keywords. This is the closest that I've gotten to this sort of example.
Correct code:
(Get-ChildItem -Recurse -Directory).FullName | ForEach-Object {fsutil.exe file setCaseSensitiveInfo $_ enable}
Explanation:
NOTE: The code in the answer assumes you're in the root of the directory tree and you want to run fsutil.exe against all the folders inside, as it's been pointed out in the comments (thanks #Abhishek Anand!)
Get-ChildItem -Recurse -Directory will give you list of all folders (recursively).
As you want to pass their full path, you can access it by using .FullName[1] (or more self-explanatory | Select-Object -ExpandProperty FullName ).
Then you use ForEach-Object to run fsutil.exe multiple times. Current file's FullName can be accessed using $_ (this represents current object in ForEach-Object)[2].
Hint:
If you want more tracking of what's currently being processed you can add the following to write the path of currently processed file to the console: ; Write-Host $_ (semicolon ; is to separate from fsutil invocation) as it was pointed out in the comments (thanks Fund Monica's Lawsuit !)
[1] .FullName notation works for PowerShell 3.0 and greater, Select-Object -ExpandProperty FullName is preferred if there's a chance that lower version will be used.
[2] $_ is an alias for $PSItem
(Get-ChildItem -Recurse -Directory).FullName | ForEach-Object {if (-Not ($_ -like '*node_modules*')) { fsutil.exe file setCaseSensitiveInfo $_ enable } }
I modified #robdy's code to allow excluding node_modules. You can replace the "node_modules" bit in the above with anything to exclude filepaths containing it.
If you're working with npm, you probably want to exclude node_modules. #robdy's answer is great, but was taking minutes at a time iterating over every single node package folder even if I didn't have the package installed; given that this is something one might want to run fairly often since directories might be added all the time, and since you probably aren't modifying anything in node_modules, excluding it seems reasonable.
With Cygwin and bash shell, you can do this:
$ find $THEDIR -type d -exec fsutil file setCaseSensitiveInfo "{}" enable \;
It appears that Windows handles the '/' characters output by the find command just fine.
In my case I had to first enable the Linux subsystem before using the fsutil tool. So my steps were:
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
then restart, and then #robdy 's solution:
(Get-ChildItem -Recurse -Directory).FullName | ForEach-Object {fsutil.exe file setCaseSensitiveInfo $_ enable}
On windows 11, the other answers are not correct, as fsutil requires that the directory is not empty. To overcome this, I created a NEW empty directory, used fsutil file setCaseSensitiveInfo to set the case sensitive flag on the new directory, then MOVED the files from the other directory inside the new one. This works, as the directories are re-created when moved, and new directories inherit the case sensitive flag.
With Unix cp you can use the --link option. When used with a folder, it will
hard link the files involved instead of
copying, example
cp --recursive --link foo bar
This can be ideal in certain situations because it is faster than regular
copying. Can anything like this be done with PowerShell?
PowerShell doesn't have support for Symbolic/Hard Links currently. There are improvements on this front coming in PowerShell 5.0. The latest preview (September 2014) includes some of this functionality. You may want to peruse the release notes (docx):
To support symbolic links, *-Item and a few related cmdlets have been extended. Now you can create symbolic links in a single, simple line with New-Item.
An example:
New-Item -ItemType HardLink -Path C:\Temp -Name MyHardLinkFile.txt -Value $pshome\profile.ps1
There isn't an example for Copy-Item, but I assume it would be simple to use this with a recursive Get-ChildItem and pipe the results to New-Item, but you would have to try it yourself.
In the meantime, the PowerShell Community Extensions project has a New-Hardlink cmdlet. From the looks of it, you would have to do as I described above and pipe the results of Get-ChildItem into this cmdlet to create a hardlink for each file.
I know that I can use DIR to list the directory and MKDIR to create a new one. However, I learned today that one can (should?) use New-Item -ItemType Directory "c:\pip" instead, which, indeed, looks much more PowerShellish.
I'm not getting any hits when googling for the equivalent of DIR, though. Is DIR just DIR?
dir | ls == get-childitem.
You can figure out aliases using the get-alias command: get-alias dir. Aliases are used fairly frequently, for example, gci is an alias for get-childitem as well.
I have a bunch of folders with similar prefixes in the name, and I'd like to make symbolick links to these folders so that I can remove the prefix while respecting the original folder naming convention. Here are some example folder names:
2013.Folder1
2013.Folder2
2014.Folder1
in the folder:
C:\Users\madeupname\Documents
In linux, I'd just do
ln -s /home/madeupname/Documents/201* /home/madeupname/Documents/links/
(this code may not exactly right as I don't have a linux box handy right now)
In Windows PowerShell, I could do it manually for these 3 files:
cmd /c mklink C:\Users\madeupname\Documents\links\2013.Folder1 C:\Users\madeupname\Documents\2013.Folder1
but that is no good because the real directory has a lot of files!
if I understood correctly this can work for you:
$path = "C:\Users\madeupname\Documents"
dir $path -Directory |
% { cmd /c mklink C:\Users\madeupname\Documents\links\$_.name $_.fullname /d}
I found a GUI to do this, but that's cheating so I won't mark this as the answer:
http://schinagl.priv.at/nt/hardlinkshellext/hardlinkshellext.html