get the latest created folder from a path using powershell - powershell

How to get the latest created folder from a path using Windows PowerShell?
I have the path C:\temp and I want to find the most recently created folder in this path.

PowerShell works mainly with the pipeline, so most of what you'd write will consist of creating objects representing some information, and filtering and manipulating them. In this case, the objects are a bunch of folders.
Get all items in the folder. This will get files and folders, that's why step 2 is necessary. The | at the end of the line signals that the pipeline will continue in the next line – objects created by Get-ChildItem will then be passed one by one to another command.
Get-ChildItem c:\temp |
Filter for folders. There is no really elegant way, sadly. Don't worry about that it says “container”, not “folder” – Those commands work with many different things, not only files and folders, so a more general concept was used in naming.
Where { $_.PSIsContainer } |
Sort by date, descending, so the newest folder is the first one.
Sort CreationTime -Descending |
Select the first (newest) folder.
Select -First 1
So in short:
gci c:\temp | ? { $_.PSIsContainer } | sort CreationTime -desc | select -f 1
or
(gci c:\temp | ? { $_.PSIsContainer } | sort CreationTime)[-1]
Both of those lines make heavy use of default aliases for commands in PowerShell, such as ? for Where-Object. You should use the full names in scripts, though, as you'll never know what the aliases will look like on other machines the code might run on.
EDIT: PowerShell 3 has additional parameters for Get-ChildItem that allow you to do filtering for files or folders directly, so you don't need the Where:
Get-ChildItem -Directory C:\temp | ...
Generally you will work with objects and their properties in PowerShell. Two very helpful commands are Get-Member and its alias gm and Get-Command or just gcm. Get-Member will tell you what properties and methods an object has; you just pipe something else into it for that:
Get-ChildItem | gm
will tell you what properties files and directories have.
Get-Command will list all commands there are or those that match a particular pattern. PowerShell commands try to be very consistent in their use of verbs and nouns. To find all commands that end in Object you can try gcm *-Object – those are general commands working with pretty much everything. Get-Help ForEach-Object then would tell you about a particular command, ForEach-Object in this case.

Related

Compiling CSV's dependent on Date

this is my first post so sorry about any mistakes.
I'm currently trying to use Powershell to combine folders of csv files based on date. I'm trying to go a week back, compile them, and export to another folder. I've only been using Powershell a few days and have an ok knowledge on coding in general.
I'm trying to use this fuction:
(Get-ChildItem C:\Folder | Group-Object -AsHashTable {$_.CreationTime -ge (Get-Date).AddDays(-2)})
That outputs a name(true or false) and a value(folder title). What I want to do is use another function to then export those CSV files in several folders all to one folder.
Is this possible? Am I going in the right direction? I have very little experience with this.
Thanks.
Luke
You're looking to filter by instead of group by, hence you would be using Where-Object instead of Group-Object. To copy files you can use the built-in cmdlet Copy-Item.
Do note, the path\to\destinationfolder in the example below must be an existing folder, you should create it before running the code.
# NOTE: If you want to filter only for files with .CSV Extension,
# `-Filter *.csv` should be included
Get-ChildItem C:\Folder -Recurse |
Where-Object { $_.CreationTime -ge (Get-Date).AddDays(-2) } |
Copy-Item -Destination path\to\destinationfolder

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!

Using Powershell to export the NTFS security permissions

Using Powershell, how can I get the list of Folders in D: drive with Everyone access explicitly defined?
I've installed the module below, but not sure how to arrange the command and export it to .CSV file.
https://ntfssecurity.readthedocs.io/en/latest/
https://devblogs.microsoft.com/scripting/weekend-scripter-use-powershell-to-get-add-and-remove-ntfs-permissions/
It somewhat depends on what you want the export to look like. However, the below example is a starting point:
$StartPath = "C:\temp\08-28-19"
Get-ChildItem $StartPath |
Get-NTFSAccess -Account Everyone |
Select-Object FullName,Account,AccessRights,Type |
Export-Csv c:\temp\PermExport.csv -NoTypeInformation
So you/we may have to work on the Select-Object command. Please update the question with an example of desired output and we'll workshop this more.
Note: there are some complications if there's a risk of paths longer than 260 characters. The NTFSSecurity module includes commands like Get-ChildItem2 which are based on the AlphaFS .Net libraries. However, there are some bugs around naming, which are documented in this GitHub issue I briefly reported into.
However, you can use an alternate syntax with good-old Get-ChildItem to list long paths. That might look something like this:
For UNC's:
Get-ChildItem '\\?\UNC\<ServerName>\Share\RemainingPath' -Recurse |
...
For Local Drives:
Get-ChildItem '\\?\c:\temp' -Recurse |
...

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.

Get Directories Names Only

I have a directoy X that has say 500 subdirectories. What I need is a quick way to just get only my directory and the names of these 500 subdirectories in my X directory (so, no Mode, no LastWriteTime or anything else, just the name) and pipe it to a file.
So, for example, I have this:
-X
|+Dir1
|+Dir2
|+Dir3
|
...
|+Dir500
What I want to get piped to a txt file is this
X/Dir1
X/Dir2
X/Dir3
...
X/Dir500
How can I do this using PowerShell or CommandLine?
I am using Windows 7 and PowerShell 4.0
Thanks,
Get-ChildItem will do the same thing as dir in command-line: it gets whatever is in your directory. You're looking only for directories. PS v3 and up has this built-in by using the flag of -directory. In older PowerShell versions, you can pipe your Get-ChildItem to a Where{$_.PSIsContainer to get directories and then pipe that to select Name to just get the names of the directories, not their full paths (e.g. "Dir1" vs. "X:\Dir1"). If you want the full path, use select FullName. Assuming you want that as a CSV, pipe that to Export-Csv followed by the name of the CSV you're creating, such as DirectoriesInX.csv and if you don't want the type information, add the flag of -NoTypeInformation.
PowerShell v3 and up:
Get-ChildItem "X:\" -directory | Select FullName | Export-Csv "DirectoriesInX.csv" -NoTypeInformation
PowerShell v2 and below:
Get-ChildItem "X:\" | Where{$_.PSIsContainer} | Select FullName | Export-Csv "DirectoriesInX.csv" -NoTypeInformation
I would have not used -Recurse based on requirement.
Moreover, OP wants to pipe output to a file :
(Get-ChildItem "X" -Directory).FullName | Out-File c:\myList.txt
The -Directory switch is only available from PS3.
The -Recurse switch would go as deep as possible in the tree and list all folders