Apply setCaseSensitiveInfo recursively to all folders and subfolders - powershell

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.

Related

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.

Need windows batch command one-liner to remove folders by name, not by date.time using powershell if applicable

Need help with command like, one-liner, powershell to remove folders
I'm trying to find an elegant way to remove folders by folder name which reflects the date but I cannot rely on the file/folder date meta-data attributes.
Here's the problem I'm trying to solve:
I have a folder in which there are archived call recordings for each day the recording system creates folders and fills them with call recordings, a folder for each day named like format MM_dd_yyyy.
I need to remove all but the last 7 folders. But, I cannot rely on the creation/modified date on the file. That would be much easier with just powershell. So I MUST, unfortunately, remove the folders by testing the file name against the dates of the folders that I need to retain with same format (MM_dd_yyyy).
I can get the list of folder names that are to be retained base on the previous 6 days with the following Windows command line:
c:\>powershell $d0=(Get-Date).ToString('MM-dd-yyyy'); $d1=(Get-Date).AddDays(-1).ToString('MM-dd-yyyy'); $d2=(Get-Date).AddDays(-2).ToString('MM-dd-yyyy'); $d3=(Get-Date).AddDays(-3).ToString('MM-dd-yyyy'); $d4=(Get-Date).AddDays(-4).ToString('MM-dd-yyyy'); $d5=(Get-Date).AddDays(-5).ToString('MM-dd-yyyy'); $d6=(Get-Date).AddDays(-6).ToString('MM-dd-yyyy'); $d0; $d1; $d2; $d3; $d4; $d5; $d6
NOTE: I need to keep this in a command one-liner and cannot use PS1 power shell script because of corporate and domain enforced security limitations
This produces the folder names to be retained as listed below (ran on 20 NOV 2021 to retain last 7 days).
11_20_2021
11_19_2021
11_18_2021
11_17_2021
11_16_2021
11_15_2021
11_14_2021
The intention would be to remove any folder names that were like 11_13_2021, 11_12_2021... etc.
I can get away with running nested FOR loops in a Windows bat file to try and hack this together but I'm trying to find a more simple, readable and elegant one-liner that will let me do something like the following:
powershell $d=(Get-Date).AddDays(-7).ToString('MM-dd-yyyy'); and then some magic powershell stuff to remove any folder that doesn't match any of those that are to be retained.
If I had a way to provide the folder name (MM_dd_yyyy) to the (get-date).AddDays(-6) powershell command and have it return a boolean yes or no, that would be something closer to what I'm looking for.
I've been reading and you tubing and pulling hairs out but so far I'm learning but mostly making a mess of it. Any ideas are most welcome.
I'm likely approaching this all wrong. The constraints are:
Given a list of folders with naming format MM_dd_yyyy, I need to remove/delete all that are not within the last week of days.
I cannot run powershell scripts .ps1
I can run windows bat or cmd files with for loops and such
I cannot rely on the folder of files date/time meta attributes, some data in the folders may have create/write/modified dates that are not in line with the folder name. I must rely on the folder name (MM_dd_yyyy) to remove the folders.
UPDATED with resolution:
powershell "($f=Get-ChildItem -Path 'D:\PosConvSav' -Filter '*_*_*' -Directory | Where-Object { $_.Name -match '\d{2}_\d{2}_\d{4}' } | sort-object -desc)[14..($_.count)] | remove-item -recurse"
The PowerShell code for this would be:
Get-ChildItem -Path 'RootPath\Where\The\Folders\To\Delete\Are\Found' -Filter '*_*_*' -Directory |
Where-Object { $_.Name -match '\d{2}_\d{2}_\d{4}' } | # filter some more using regex -match
Sort-Object { [datetime]::ParseExact($_.Name, 'MM_dd_yyyy', $null) } | # sort by date
Select-Object -SkipLast 7 | # skip the newest 7 folders
Remove-Item -Recurse -Force # remove the rest
To play it safe, add -WhatIf to the final Remove-Item command. By doing that, the code does not actually delete anything, but show in the console what would be deleted. If you are satisfied that is correct, then remove -WhatIf to actually remove those folders.
As Olaf already commented, don't think using one-line code would be best, because what you'll end up with is code that isn't readable anymore and where mistakes are extremely hard to find.
There is no penalty whatsoever for multiline code, in fact it is THE way to go!

Powershell: How to copy files from one Directory to another

I am looking to copy a series of files from one directory to another. Essentially the files are a series of zip folders that are simply changed versions of programs. The files will be named something like: test_1_092.zip in the source directory and test_1_091.zip in the target directory. I don't want the script to look at the numeric portion of the folder, simply the name.
Please forgive my lack of knowledge as this is my first foray into powershell scripting. Any thoughts or need more info?
Something to start with
(Get-ChildItem -Filter "*.zip").Name | where {$_ -like 'test_1_*'} | Move-Item -Destination .\1 -Force -WhatIf
Please confirm the output from –whatif , then remove it to perform the action.
For the relation between the new and old name, please provide some more information.

backing up certain files in a folder using powershell

I have a couple of questions. I have certain binaries in a folder...
F:\program files\application\Client\
I only want to copy the latest dll's that have a certain phrase in there names. Lets say "MVCsite". I know you can use Get-ChildItem -Filter with the filter parameters, to get just child items with a .dll extension, but is there a way to look for specific files with specific keywords, or am I going to have to literally copy a list of files out of the directory and move it to a back up folder? Is there a quick and dirty command to do that? As you can tell, I am new to powershell, but I am learning fast.
gci -path $path -filter "*.dll" | where {$_.Name -match "Keyword1|Keyword2|etc"}
Simply use wildcards in your -Path parameter:
Copy-Item F:\program files\application\Client\*MVCsite*.dll X:\DestinationDir
That will copy all files in F:\program files\application\Client\ whose names contain the string "MVCsite" and have the extension ".dll". Is that what you wanted to accomplish? If not, please clarify.

Get powershell to display all paths where a certain file can be found on a drive

I'm trying to build a function that will show me all path's where a certain filename is located. The function would take one parameter, that being the file name.
The result would be either a list of all paths, or a message saying there's no such file on the system.
I'm new to Powershell, and I'm not getting the syntax just yet.
I've tried this:
Get-ChildItem -Path -Include notepad.exe
But that threw an error message. I'm currently trying:
$i="notepad.exe"
Foreach ($i in Get-ChildItem c:\ -Recurse){echo -Path}
Started that now, it's still running, don't know what'll happen, really.
EDIT: echo'd an enormous amount of lines that just say "-Path"...
Can anybody help with this problem? I'm running Powershell 1.0 by the way.
So, to explain what I wish to see when executing this command, here is an example of what I expect after looking for *.txt:
C:/foo.txt
C:/A/foobar.txt
C:/A1/foo.txt
And so on, listing the path to all .txt files on my harddrive. Only the paths, one per line, no extra info needed.
EDIT2:
I've done it. I'm gonna leave this question up for those who make look for this in the future.
The function I used was this(this specific example will hand you a list of all .zip files on your harddrive, edit where needed):
Get-ChildItem -Path c:\ -Include "*.zip" -Recurse -Force -Name > c:\listOfPaths.txt
This created a file called listOfPaths.txt on my C:\ folder and this contained a list of all occurences of any file ending with .zip in all subfolders of my harddrive.
The "c:\" bit isn't mentioned, but I don't mind.
EDIT3:
thanks capar for a more complete version.
Here is capar's code(or how I got it to work, since Get-Children doesn't work in 1.0)
Get-ChildItem -Path c:\ -Recurse *.txt | Select-Object -Property FullName
Since it's Friday night, I decided to play with Power Shell to see if I can help :)
This comes pretty close to what you are asking for I think:
Get-ChildItem -Path c:\ -Recurse *.txt | Select-Object -Property FullName
If it helps, this command will list the properties of any object that will be returned by Get-ChildItem:
Get-ChildItem | Get-Member
ls c:\ -r | ? {$_.name -eq "notepad.exe"}
Get-Children is not recognized in Powershell V3 either. It would be great if someone removed that bad example.
As a warning to anyone searching for files: C:\ on today's hard drives will take a long time to run. You are well advised to narrow your search as much as you can. Since your folder structure might include spaces or special characters, use the typewriter quote (") or apostrophe (') delimeters.
$mylistoffiles = Get-ChildItem -Path 'C:\Windows\Setup\Scripts' -Recurse *.cmd | Select-Object -Property FullName
$mylistoffiles