Powershell Folder List Filter - powershell

I have a folder and inside has a list of subfolders/files
Folders
2022
20221101
20221103
20221107
20221108
test123
results
test.txt
Using Powershell
How do get the list of folders that are dates.
How do I get the second latest folder (20221107).
This is what I was able to come with so far:
Get-ChildItem "C:\code\Test" -Filter "2022*" | Sort-Object Name -Descending

You can use TryParseExact method from DateTime to parse the folders names and avoid any type of error, this can be combined with Sort-Object and Select-Object to get the 2nd latest. I have added -Directory to output only folders. Also changed your filter to -Filter "2022????" to ensure you're matching folders that start with 2022 and are followed by 4 characters.
$ref = [ref] [datetime]::new(0)
Get-ChildItem "C:\code\Test" -Filter "2022????" -Directory | Sort-Object {
$result = [datetime]::TryParseExact(
$_.Name,
'yyyyMMdd',
[cultureinfo]::InvariantCulture,
[Globalization.DateTimeStyles]::AssumeLocal,
$ref
)
if($result) { $ref.Value }
} -Descending | Select-Object -Index 1
If you want to ensure you're matching folders with a date format (because -Filter may be too permissive), you can pipe to Where-Object for additional filtering via regex:
$ref = [ref] [datetime]::new(0)
Get-ChildItem "C:\code\Test" -Filter "2022????" -Directory |
Where-Object Name -Match '^2022\d{4}$' | Sort-Object {
# rest of the code here
} -Descending | Select-Object -Index 1

To provide an alternative to Santiago's helpful answer:
Since the timestamps that your folder names represent sort lexically in a way that is equivalent to their chronological sorting, you may not need to convert them to [datetime] instances, and can sort them as-is.
Get-Item C:\code\Test\* -Include 2022???? |
Sort-Object Name -Descending |
Select-Object -Index 1
Note the use of -Include instead of -Filter (which in turn necessitates ending the -Path argument with \* and using Get-Item instead of Get-ChildItem), because the -Filter parameter has legacy quirks that prevent character-exact matching with multiple ? wildcards - see this answer for background information.
Unfortunately, as this solution and the linked answer shows, making -Include (and -Exclude) work as intended is tricky as of PowerShell 7.2.x, and requires memorizing non-intuitive rules.
On the plus side, -Include, which (unlike -Filter) uses PowerShell's wildcard expressions, would also allow you to create a more specific pattern, such as -Include 2020[0-1][0-9][0-3][0-9] (which still isn't strict enough to rule out invalid digit combinations, however).

Related

Counting .csv files based on their first n number of characters

I need to write a script that checks the first 3 to say 5 characters of a .csv file, then count those files and report the characters with the corresponding count.
I already have a few methods to do the simpler tasks. I've used a filter before to only select certain .csvs, using this:
Get-ChildItem C:\path -Recurse -Filter *.csv | Where {$_.Name -match 'NNN'}
I also use this to count the number of csvs in that corresponding location:
(Get-ChildItem C:\path -Recurse -Filter *.csv | Measure-Object).Count
How can I run a scan through a folder with say 3 random titles for the csv? Say they're RUNxxxxxxxx.csv, FUNxxxxxxx.csv, and TUNxxxxxxx.csv.
Edit: Let me explain more; basically, the example csvs I have above would be completely random, so it'd need to recognize those first 3 are different and only count those.
I'm not sure if a prompt inputting these would do any. The values are known, just different week to week (which is when this would be run;every week)
Thanks!
You can accomplish that using the where-object filter combining three or statements which finds anything starting with the three letters you want and a wild card after.
Get-ChildItem C:\path -Recurse -Filter *.csv | Where {$_.Name -like "RUN*" -or $_.Name -like "Fun*" -or $_.Name -like "TUN*"}
You could also use the get-childitem -filter to accomplish this instead of searching for all .csv files and then use where-object.
Get-ChildItem C:\path -Recurse -Include "fUN*.csv","RUN*.csv","Tun*.csv"
How about using a calculated property to add the desired part as additional property to be able to work with it?
$PatternList =
'run',
'fun',
'tun'
Get-ChildItem -Recurse -Filter *.csv |
Select-Object -Property #{Name = 'Part'; Expression={($_.Name).substring(0,3)}},* |
Where-Object -Property Part -In -Value $PatternList |
Group-Object -Property Part

Powershell - GetChilditem grab first result

I have an issue with a powershell script i have made. The purpose of the script is to gather information from various ressources, CMDB og and other systems and gather them in a combined report and send it.
I have everything working just fine, except one single ting that keeps bothering me. In my script, i do a lot of parsing and trimming in the information i get, at in some functions i need to get some XML files. Example:
$filter = "D:\WEC\Script\Rapportering\BigFixData\"
$xmlfiles = Get-ChildItem -path $filter -Filter "Bigfix_trimmed_JN.xml" -Recurse -Force |where {$_.psIsContainer -eq $false }
$xmlfile = $xmlfiles | ogv -OutputMode Single
There will always be only one file to grab, and thats why i use the Filter option and give the specific name. The code above will trigger a pop-up, asking me to select the file. It works fine except for the file picker popup. I want to get rid of that.
I then changed the code to this:
$filter = "D:\WEC\Script\Rapportering\BigFixData\"
$xmlfiles = Get-ChildItem -path $filter -Filter "Bigfix_trimmed_JN.xml" | Select-Object -First 1 |where {$_.psIsContainer -eq $false }
This no longer shows the popup, but it does not seem to select the file. Resulting in a referenceObject error later in the script, because it is null.
the script is about 1000 lines and i have narrowed the error down to the command aboove.
Can anyone help me figuring out what i do wrong?
Thanks in advance
Your 2nd command is missing the -Recurse switch, which may explain why you're not getting any result.
While it is unlikely that directories match with a filter pattern as specific as "Bigfix_trimmed_JN.xml", the more concise and faster way to limit matching to files only in PSv3+ is to use the -File switch (complementarily, there's also a -Directory switch).
$xmlfile = Get-ChildItem $filter -Filter Bigfix_trimmed_JN.xml -Recurse -File |
Select-Object -First 1
You should add a check to see if no file was returned.
If you want the first file, you'll need to filter out the directories before piping to Select-Object -First 1 - otherwise you run the risk of the first input element being a directory and your pipeline therefore evaluates to $null:
$xmlfiles = Get-ChildItem -path $filter -Filter "Bigfix_trimmed_JN.xml" | Where-Object {-not $_.PsIsContainer} | Select-Object -First 1

Count Files by Name

I am looking for a way to count files from many sub-folders but the tricky part is that i want to filter them by part of their names. To be more specific, all files have a date at the middle of their names. If I want to just count the files within a specific folder I use this:
dir * |%{$_.Name.SubString(7,8)} | group |select name,count|ft -auto
And works like a charm. The problem lies that it cannot see more than one folder. Also a second problem is that in the result, I want to see the path name of the grouped counts. I am also testing this:
dir -recurse | ?{ $_.PSIsContainer } | %{ Write-Host $_.FullName (dir $_.FullName | Measure-Object).Count }
but I cannot implement the date filter from inside the name in this functions. I am also attaching an example of how is the format and how I would like the results.
Any help?
I am looking for a way to count files from many sub-folders but the tricky part is that I want to filter them by part of their names. To be more specific, all files have a date at the middle of their names.
It is not 100% clear to me, if you really want to filter them or to group them before counting, so I'll show both.
Assuming that this middle of their names is, e.g., delimited by _ this can be achieved the following way:
# C:/temp/testFolder/myName_123_folder/text.txt
Get-ChildItem * -Recurse |
Select-Object -Property Name, #{Name = "CustomDate"; Expression = {$_.Name.Split("_")[1]}} |
#This is how you would _filter_
#Where-Object {$_.Custom -eq "123"} |
Group-Object -Property CustomDate |
Select-Object Name, Count
Don't forget to check if the file name matches this pattern, before splitting. This can be done with a Select-Object statement between gci and 1. select, which checks the file name for your specific pattern.
Your question shows also that you wanted to filter for only directories:
dir -recurse | ?{ $_.PSIsContainer } | %{ #[...]
Which is not very efficient.
From the Docs of Get-ChildItem:
-Directory
Gets directories (folders).
To get only directories, use the -Directory parameter and omit the -File parameter. To exclude directories, use the -File parameter and omit the -Directory parameter, or use the -Attributes parameter.
This means, the preferred way to search only for Directories is:
Get-ChildItem -Recurse -Directory | % { #[...]

Powershell -- Get-ChildItem Directory full path and lastaccesstime

I am attempting to output full directory path and lastaccesstime in one line.
Needed --
R:\Directory1\Directory2\Directory3, March 10, 1015
What I am getting --
R:\Directory1\Directory2\Directory3
March 10, 1015
Here is my code, It isn't that complicated, but it is beyond me.
Get-ChildItem -Path "R:\" -Directory | foreach-object -process{$_.FullName, $_.LastAccessTime} | Where{ $_.LastAccessTime -lt [datetime]::Today.AddYears(-2) } | Out-File c:\temp\test.csv
I have used foreach-object in the past in order to ensure I do not truncate the excessively long directory names and paths, but never used it when pulling two properties. I would like the information to be on all one line, but haven't been successful. Thanks in advance for the assist.
I recommend filtering (Where-Object) before selecting the properties you want. Also I think you want to replace ForEach-Object with Select-Object, and lastly I think you want Export-Csv rather than Out-File. Example:
Get-ChildItem -Path "R:\" -Directory |
Where-Object { $_.LastAccessTime -lt [DateTime]::Today.AddYears(-2) } |
Select-Object FullName,LastAccessTime |
Export-Csv C:\temp\test.csv -NoTypeInformation
We can get your output on one line pretty easily, but to make it easy to read we may have to split your script out to multiple lines. I'd recommend saving the script below as a ".ps1" which would allow you to right click and select "run with powershell" to make it easier in the future. This script could be modified to play around with more inputs and variables in order to make it more modular and work in more situations, but for now we'll work with the constants you provided.
$dirs = Get-ChildItem -Path "R:\" -Directory
We'll keep the first line you made, since that is solid and there's nothing to change.
$arr = $dirs | Select-Object {$_.FullName, $_.LastAccessTime} | Where-Object{ $_.LastAccessTime -lt [datetime]::Today.AddYears(-2) }
For the second line, we'll use "Select-Object" instead. In my opinion, it's a lot easier to create an array this way. We'll want to deal with the answers as an array since it'll be easiest to post the key,value pairs next to each other this way. I've expanded your "Where" to "Where-Object" since it's best practice to use the full cmdlet name instead of the alias.
Lastly, we'll want to convert our "$arr" object to csv before putting in the temp out-file.
ConvertTo-CSV $arr | Out-File "C:\Temp\test.csv"
Putting it all together, your final script will look like this:
$dirs = Get-ChildItem -Path "C:\git" -Directory
$arr = $dirs | Select-Object {$_.FullName, $_.LastAccessTime} | Where{ $_.LastAccessTime -lt [datetime]::Today.AddYears(-2) }
ConvertTo-CSV $arr | Out-File "C:\Temp\test.csv"
Again, you can take this further by creating a function, binding it to a cmdlet, and creating parameters for your path, output file, and all that fun stuff.
Let me know if this helps!

How to search a files in multiple folders that returns no duplicate in powershell?

I am trying to find all the files in the multiple folders but the only thing is that the files existed in some folders
E:\sample\cd.dll
E:\sample1\sample\cd.dll
If I am using the
Get-ChildItem -recurse
it returns Two FileSystemInfo of cd.dll.
The result should be only one FileName of cd.dll
thanks in advance.
Get-ChiltItem -recurse | Select-Object -Unique
Note that -Unique is case-sensitive so you may want to use the Sort-Object cmdlet:
Get-ChiltItem -recurse | Sort-Object -Unique
You can also eliminates duplicates with the Get-Unique cmdlet but it requires the objects to be sorted first for the cmdlet to work properly