Using Where-Object to find files created within time range - powershell

all. I'm trying to take the creation date of a file in one folder and use it to filter files in another while also making sure they contain the phrase 'MS'. This is what I have so far:
$MSdat_time = $MSdat_file.CreationTime
# Defining maximum and minimum auto save creation times with a window of +/- 5 min
$auto_maxtime = ($MSdat_time).AddMinutes(5)
$auto_mintime = ($MSdat_time).AddMinutes(-5)
# Locating any Auto Save files created within time frame using 'MS' pattern as a parameter in case of multiple files
$autsav_file = Get-ChildItem "\\IP.Address\Test Data\Auto Saves" | `
Where-Object {($_.LastWriteTime -ge $auto_mintime) -and ($_.LastWriteTime -le $auto_maxtime)} | `
Select-String -Pattern 'MS' | Select-Object -Unique Path
I put in 'IP address' as a place holder. So far, it's returning nothing even though I know a file with those parameters exists and this section of code was working fine yesterday.

Check that your $MSdat_file variable has a value. It could be that your previous PS sessions had given that variable a value outside of your script.
After assigning $MSdat_file = Get-Item "./out.wav", I was able to get expected output:
PS /Users/ethansmith> /Users/ethansmith/Documents/test.ps1
PS /Users/ethansmith> $autsav_file
Path
----
/Users/ethansmith/Documents/test.ps1

Thank you everyone for your help! #ethan was right, the issue was with my $MSdat_file variable having an old value saved to it. Should have traced my code back to the beginning sooner haha. Thanks everyone!

Related

PowerShell: Find similar filenames in a directory

In a purely hypothetical situation of a person that downloaded some TV episodes, but is wondering if he/she accidentally downloaded an HDTV, a WEBRip and a WEB-DL version of an episode, how could PowerShell find these 'duplicates' so the lower quality versions can be automagically deleted?
First, I'd get all the files in the directory:
$Files = Get-ChildItem -Path $Directory -Exclude '*.nfo','*.srt','*.idx','*.sub' |
Sort-Object -Property Name
I exclude the non-video extensions for now, since they would cause false positives. I would still have to deal with them though (during the delete phase).
At this point, I would likely use a ForEach construct to parse through the files one by one and look for files that have the same episode number. If there are any, they should be looked at.
Assuming a common spaces equals dots notation here, a typical filename would be AwesomeSeries.S01E01.HDTV.x264-RLSGRP
To compare, I need to get only the episode number. In the above case, that means S01E01:
If ($File.BaseName -match 'S*(\d{1,2})(x|E)(\d{1,2})') { $EpisodeNumber = $Matches[0] }
In the case of S01E01E02 I would simply add a second if-statement, so I'm not concerned with that for now.
$EpisodeNumber should now contain S01E01. I can use that to discover if there are any other files with that episode number in $Files. I can do that with:
$Files -match $EpisodeNumber
This is where my trouble starts. The above will also return the file I'm processing. I could at this point handle the duplicates immediately, but then I would have to do the Get-ChildItem again because otherwise the same match would be returned when the ForEach construct gets to the duplicate file which would then result in an error.
I could store the files I wish to delete in an array and process them after the ForEach contruct is over, but then I'd still have to filter out all the duplicates. After all, in the ForEach loop,
AwesomeSeries.S01E01.HDTV.x264-RLSGRP
would first match
AwesomeSeries.S01E01.WEB-DL.x264.x264-RLSGRP, only for
AwesomeSeries.S01E01.WEB-DL.x264.x264-RLSGRP
to match
AwesomeSeries.S01E01.HDTV.x264-RLSGRP afterwards.
So maybe I should process every episode number only once, but how?
I get the feeling I'm being very inefficient here and there must be a better way to do this, so I'm asking for help. Can anyone point me in the right direction?
Filter the $Files array to exclude the current file when matching:
($Files | Where-Object {$_.FullName -ne $File.FullName}) -match $EpisodeNumber
Regarding the duplicates in the array the end, you can use Select-Object -Unique to only get distinct entries.
Since you know how to get the episode number let's use that to group the files together.
$Files = Get-ChildItem -Path $Directory -Exclude '*.nfo','*.srt','*.idx','*.sub' | Select-Object FullName, #{Name="EpisodeIndex";Expression={
# We do not have to do it like this but if your detection logic gets more complicated then having
# this select-object block will be a cleaner option then using a calculated property
If ($_.BaseName -match 'S*(\d{1,2})(x|E)(\d{1,2})'){$Matches[0]}
}}
# Group the files by season episode index (that have one). Return groups that have more than one member as those would need attention.
$Files | Where-Object{$_.EpisodeIndex } | Group-Object -Property EpisodeIndex |
Where-Object{$_.Count -gt 1} | ForEach-Object{
# Expand the group members
$_.Group
# Not sure how you plan on dealing with it.
}

PowerShell find most recent file

I'm new to powershell and scripting in general. Doing lots of reading and testing and this is my first post.
Here is what I am trying to do. I have a folder that contains sub-folders for each report that runs daily. A new sub-folder is created each day.
The file names in the sub-folders are the same with only the date changing.
I want to get a specific file from yesterday's folder.
Here is what I have so far:
Get-ChildItem -filter “MBVOutputQueriesReport_C12_Custom.html” -recurse -path D:\BHM\Receive\ | where(get-date).AddDays(-1)
Both parts (before and after pipe) work. But when I combine them it fails.
What am I doing wrong?
What am I doing wrong?
0,1,2,3,4,5 | Where { $_ -gt 3 }
this will compare the incoming number from the pipeline ($_) with 3 and allow things that are greater than 3 to get past it - whenever the $_ -gt 3 test evaluates to $True.
0,1,2,3,4,5 | where { $_ }
this has nothing to compare against - in this case, it casts the value to boolean - 'truthy' or 'falsey' and will allow everything 'truthy' to get through. 0 is dropped, the rest are allowed.
Get-ChildItem | where Name -eq 'test.txt'
without the {} is a syntax where it expects Name is a property of the thing coming through the pipeline (in this case file names) and compares those against 'test.txt' and only allows file objects with that name to go through.
Get-ChildItem | where Length
In this case, the property it's looking for is Length (the file size) and there is no comparison given, so it's back to doing the "casting to true/false" thing from earlier. This will only show files with some content (non-0 length), and will drop 0 size files, for example.
ok, that brings me to your code:
Get-ChildItem | where(get-date).AddDays(-1)
With no {} and only one thing given to Where, it's expecting the parameter to be a property name, and is casting the value of that property to true/false to decide what to do. This is saying "filter where *the things in the pipeline have a property named ("09/08/2016 14:12:06" (yesterday's date with current time)) and the value of that property is 'truthy'". No files have a property called (yesterday's date), so that question reads $null for every file, and Where drops everything from the pipeline.
You can do as Jimbo answers, and filter comparing the file's write time against yesterday's date. But if you know the files and folders are named in date order, you can save -recursing through the entire folder tree and looking at everything, because you know what yesterday's file will be called.
Although you didn't say, you could do approaches either like
$yesterday = (Get-Date).AddDays(-1).ToString('MM-dd-yyyy')
Get-ChildItem "d:\receive\bhm\$yesterday\MBVOutputQueriesReport_C12_Custom.html"
# (or whatever date pattern gets you directly to that file)
or
Get-ChildItem | sort -Property CreationTime -Descending | Select -Skip 1 -First 1
to get the 'last but one' thing, ordered by reverse created date.
Read output from get-date | Get-Member -MemberType Property and then apply Where-Object docs:
Get-ChildItem -filter “MBVOutputQueriesReport_C12_Custom.html” -recurse -path D:\BHM\Receive\ | `
Where-Object {$_.LastWriteTime.Date -eq (get-date).AddDays(-1).Date}
Try:
where {$_.lastwritetime.Day -eq ((get-date).AddDays(-1)).Day}
You could pipe the results to the Sort command, and pipe that to Select to just get the first result.
Get-ChildItem -filter “MBVOutputQueriesReport_C12_Custom.html” -recurse -path D:\BHM\Receive\ | Sort LastWriteTime -Descending | Select -First 1
Can do something like this.
$time = (get-date).AddDays(-1).Day
Get-ChildItem -Filter "MBVOutputQueriesReport_C12_Custom.html" -Recurse -Path D:\BHM\Receive\ | Where-Object { $_.LastWriteTime.Day -eq $time }

Powershell Where command not working

I have a text file that contains elements separated by an '=' sign (i.e. color1=red, color2=blue, etc.
I used the import-csv command and provide headers (i.e.
$Import_Cfg = Import-Csv .\Env.cfg -Header Title,Setting -Delimiter =
)
Now this works fine if I want to assign a particular item to another variable if I know the index number and I have used that approach but it won't always work for me because I don't always know what other data will be there.
I thought that by using something like:
$MyColor1 = $Import_Cfg.Setting |where {$_.Title -match "Blue"}
$MyColor2 = $Import_Cfg.Setting |where {$_.Title -match "Red"}
it should work, but I get no returns for either item. When I type in $Import_cfg I can see the entire array (without the "=" signs). If I tell use the command
$MyColor1 = $import_cfg[0].setting
I get the right answer.
Obviously I'm not using colors but a bunch of different items that I need to assign to variables for use elsewhere. Any thoughts on what I'm doing wrong? Everything I've read says that what I have above should work.
Please no flames on why I'm using import-csv vs get-content. I'm sure either will work. This is an approach that I've used and computationally it doesn't matter. If programatically it makes a difference I'm all ears!!!
Thanks for all your help.
The value of the Setting property itself has no Title property.
You need to apply Where before you extract the property value you need (as mentioned in the comments):
$BlueSettings = $Import_Cfg |where {$_.Title -match "Blue"} |Select-Object -ExpandProperty Setting
or, using property enumeration:
$BlueSettings = ($Import_Cfg |where {$_.Title -match "Blue"}).Setting

Get PathTwo Counts In Dynamic PathOne

I need to find all the PathTwos in PathOne under the directory Path; currently I can get all the PathOne's by using:
$path = Get-ChildItem "C:\Path\" | ?{ $_.PSIsContainer }
Since PathOne is dynamic (it's name may be anything), this helps me loop through all the possible paths. Now, PathOne may have 2 or more folders, like PathTwo1, PathTwo2 and PathTwo3. I need to know how many folders are in the dynamic PathOne. Originally I thought that I could loop within PathOne, get the name of the dynamic path and then loop through PathOne, counting all the PathTwos and return everything over 1; unfortunately that doesn't return what I need.
I've tried:
A loop within a loop: creates a mess and doesn't return the correct result.
Use C:\Path\.\ to get the count of the folders within PathOne, by jumping to whatever the next folder would be.
Based on comments, example:
C:\Path\PathOne1\PathTwo1
C:\Path\PathOne1\PathTwo2
C:\Path\PathOne2\PathTwo1
C:\Path\PathOne2\PathTwo2
C:\Path\PathOne2\PathTwo3
C:\Path\PathOne3\PathTwo1 # don't want because only one PathTwo
I don't care how many PathOnes there are, but I do need every PathOne that has more than one PathTwos.
You can get desired result by this command:
# Get all items on two level deep.
Get-Item C:\Path\*\* |
# Get only directories.
Where-Object PSIsContainer |
# Group them by parent.
Group-Object {$_.Parent.FullName} -NoElement |
# Choose groups with Count more then one.
Where-Object Count -gt 1 |
# Select name of parent directory
Select-Object -ExpandProperty Name

Check if data coming continuously

Every hour data comes into every folder of my dir tree. I need to check if it does come in every hour, or of there was any interruption. (For example, no data coming in for 2–3 hours.)
I am trying to write a PowerShell script that will check LastWriteTime for every folder, but it would solve the problem with gaps. If I would check the logs in the morning I would see that all is OK if some data come to folder one hour ago, but was not there a few hours earlier.
So IMHO LastWriteTime is not suitable for it.
Also there is a problem with subfolders. I need to check only the last folder in every dir tree. I do not know how to drop any previous folders like:
Z:\temp #need to drop
Z:\temp\foo #need to drop
Z:\temp\foo\1 #need to check
I had tried to write a script that checks the LastAccessTime, but it throws an error:
Expressions are only allowed as the first element of a pipeline.
The script is as follows:
$rootdir = "Z:\SatData\SatImages\nonprojected\"
$timedec1 = (Get-date).AddHours(-1)
$timedec2 = (Get-date).AddHours(-2)
$timedec3 = (Get-date).AddHours(-3)
$timedec4 = (Get-date).AddHours(-4)
$dir1 = get-childitem $rootdir –recurse | ?{ $_.PSIsContainer } | Select-Object FullName | where-object {$_.lastwritetime -lt $timedec1} | $_.LastWriteTime -gt $timedec4 -and $_.LastWriteTime -lt $timedec3
$dir1
But as I said before it does not solve the problem.
--
The main question exactly about checking of continuously data collections. I would make dir tree bu hands, but I need to way to check if data had come to folder every hour or there was any hours without data...
you can try to setup the powershell script to run in a Windows Scheduler (which will run every hour). This way, the script will only have to check if any data arrived within the past one hour.