What is DIR command a substitute of in PowerShell - powershell

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.

Related

Powershell Script: Search for BATs with specific name and run them

back with another request to try and make my life a little easier. The problem: one of the programs I use deposits BMPs (yes, bitmaps, this is an ancient app, and no, I can't configure it not to make BMPs) where I don't need them. I've got a BAT file that can sweep a folder and remove them, but what I'd really like to do is put a copy of said BAT file in each folder where it leaves them, and then every time I run a backup cycle, have it search for those BAT files, and wherever it finds one, run it. (I'd also need to know how to tell it "look in the same folder you're in"--I think I can do that by something like $searchfolder = "." but please correct me if I'm wrong)
I'm guessing this is a Get-Childitem and ForEach, but I've taken a few stabs at it and it won't work. Does anyone have an idea how to go about it?
This is what I've got so far for the parent script to find all instances of "Clear_BMPs.bat":
Get-ChildItem $sourceDir -Include Clear_BMPs.bat -Recurse | ForEach-Object { call "Clear_BMPs.bat" }
And this is what I've got in the child script, to get rid of the BMPs themselves (the filename for it is "Clear_BMPs.bat":
$searchfile = "*.bmp"
$targetdir = ".\"
Get-ChildItem $targetdir -Include $searchfile | foreach{ "Removing file $($_.FullName)"; Remove-Item -force $_}
I'm still trying to get the Clear_BMPs.bat files to work properly but in my vision it will only search the root of the folder it's in, and not recurse through subdirectories.
Since you're calling from PowerShell, there's no reason to involve batch files, given that the code is under your control.
Indeed, what you show as the content of a Clear_BMPs.bat batch file is PowerShell code, which means you need to store it in a .ps1 file, not a .bat file.
Therefore, your recursive invocation that executes all .ps1 files should look like this:
# Find all 'Clear_BMPs.ps1' scripts in the subdir. tree of $sourceDir
# and invoke them.
Get-ChildItem -Recurse -LiteralPath $sourceDir -Filter Clear_BMPs.ps1 |
ForEach-Object { & $_.FullName }
And the Clear_BMPs.ps1 files in the various directories should contain:
# Remove all *.bmp files from the same dir. in which this .ps1 script is located.
Remove-Item -Path "$PSScriptRoot/*.bmp"
Note the use of the automatic $PSScriptRoot variable, which refers to the directory in which the enclosing .ps1 file is located.

Add files from selected directories to 7-zip archive while keeping relative directory structure in archive

I am trying to zip files that are in directories that have subdirectories and I can't figure out how to zip the files and not the subdirectories.
Here is the current setup:
C:\users\user\appdata\local\folder\
Inside of this folder, I need 3 out of the 20 or so folders that are in there so I used the Get-Childitem to accomplish this:
GCI C:\users\user\appdata\local\folder | ? {$_.name -like "*folder*}
Now that I have that, I don't want the subdirectories and just want the files that are sitting in the folder itself. I have not found a way to do this, but I have gotten close with using this:
& "C:\program files\7-zip\7z.exe" "a" "D:\TestBackup\Zipfile.7z" (GCI C:\users\user\appdata\local\folder | ? {$_.name -like "*folder*} | select -expandproperty FullName)
But this gives me the entire contents of the folder. I want to keep the structure so that it looks like this:
folder 1\files
folder 2\files
folder 3\files
I hope I am explaining myself well. The files are all different types of extensions so I was wanting a blanket way to do this or to exclude the subdirectories when zipping.
I had to consult the FAQ to get this right:
7-Zip stores only relative paths of files (without drive letter
prefix). You can change current folder to folder that is common for
all files that you want to compress and then you can use relative
paths:
cd /D C:\dir1\
7z.exe a c:\a.7z file1.txt dir2\file2.txt
Solution:
# Set base directory that is common for all files
Push-Location 'C:\users\user\appdata\local\folder'
# Get names of directories that match filter
$folderNames = (Get-ChildItem -Directory -Filter '*folder*').Name
# Call 7-zip, passing the list of directory names.
& 'C:\Program Files\7-Zip\7z.exe' a 'D:\TestBackup\Zipfile.7z' $folderNames
# Restore current directory
Pop-Location
Remarks:
Push-Location sets the current directory, while Pop-Location restores the previous current directory. Changing the current directory is crucial for this solution, as explained by the 7-zip FAQ. It is also the only way to set the base directory for Resolve-Path -Relative.
Pass -Directory or -File to Get-ChildItem if you are only interested in either directories or files.
Use -Filter instead of Where-Object (alias ?) if you only need simple wildcard filtering. -Filter is faster because it uses the FileSystem provider which filters at a lower API level, which avoids PowerShell overhead.

Apply setCaseSensitiveInfo recursively to all folders and subfolders

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.

PowerShell mklink on multiple files with regular expressions

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

PowerShell analog to "dir /a:d" (Win) or "ls -d */" (Bash)

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