I have some date variables, with which to perform queries against files in a specific directory. I can GCI each file no problem, as shown in the example below:
File1.xml 14/07/2016 17:09
File2.xml 15/07/2016 09:32
So I am searching for all files between a specific age range and my criteria is:
Older than:
$Today4am = Get-Date -Hour 4 -Minute 0 -Second 0
But later than
$Yesterday4am = $Today4am.AddDays(-1)
The variables output
$Today4am = 15 July 2016 04:00:00
$Yesterday4am = 14 July 2016 04:00:00
So the variable pipes out the date in a different format to the file themselves, so I need to ensure both formats are the same in order to do the comparison. Here is the original script:
$Filter = gci c:\temp\*.xml |
Where {$_.LastWriteTime -gt $Yesterday4am -and {$_.LastWriteTime-lt $Today4am}}
Bad argument to operator '-gt': Could not compare "14/07/2016 17:09:52" to "14/07/2016 0
4:00". Error: "Cannot convert value "14/07/2016 04:00" to type "System.DateTime". Error:
"String was not recognized as a valid DateTime."".
So I try to convert the variables to add -Format "dd/MM/yyyy HH:mm" and this outputs the correct format. But converting $Yesterday4am = $Today4am.AddDays(-1) -Format "dd/MM/yyyy HH:mm" produces the error:
Cannot convert value "15/07/2016 04:00" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
How can I get both date formats to agree?
Try using Get-date again to convert $Yesterday4am to DateTime:
| Where {$_.LastWriteTime -gt (Get-Date $Yesterday4am) -and {$_.LastWriteTime-lt $Today4am}}
And if you're worried about performance you can do the Get-Date conversion outside of the Where operator:
$Yesterday4am = Get-Date $Yesterday4am
$Filter = gci c:\temp\*.xml `
| Where {$_.LastWriteTime -gt $Yesterday4am -and {$_.LastWriteTime-lt $Today4am}}
I believe this was just an issue with your comparisons. If you run my script below you will see that they are both types "DateTime". If you format them they become strings which will not easily compare. When I ran my Where-Object command below I had no errors. Note: I am using PowerShell version 5.
PS> Write-Host "PowerShell Version: $($PSVersionTable.PSVersion.ToString())"
PowerShell Version: 5.0.10586.122
PS> $Today4am = Get-Date -Hour 4 -Minute 0 -Second 0
PS> Write-Host "`$Today4am is type `"$($Today4am.GetType().FullName)`""
$Today4am is type "System.DateTime"
PS> $Yesterday4am = $Today4am.AddDays(-1)
PS> Write-Host "`$Yesterday4am is type `"$($Yesterday4am.GetType().FullName)`""
$Yesterday4am is type "System.DateTime"
PS> $Filter = Get-ChildItem c:\temp\* | Where-Object -FilterScript { ( $_.LastWriteTime -gt $Yesterday4am ) -and ( $_.LastWriteTime-lt $Today4am ) }
PS> $Filter
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 7/14/2016 1:13 PM 0 asdfasd
Related
I have file with below data, I want to get the highest time difference from this using PowerShell.
STARTTIME:2018-12-01 04:13:15
ENDTIME:2018-12-01 04:17:15
--
--
STARTTIME:2018-12-01 04:11:15
ENDTIME:2018-12-01 04:13:15
--
STARTTIME:2018-12-01 04:10:15
ENDTIME:2018-12-01 04:10:40
I expect the output to be 00:04:00
Use a Regular Expression to select lines and STARTTIME/ENDTIME
to set a variable with that name and the [datetime] value
## Q:\Test\2019\05\15\SO_56150523.ps1
$FileIn = '.\times.txt'
$RE = [regex]'^(STARTTIME|ENDTIME):(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})'
$Data = (Get-Content $FileIn)| Where-Object {$_ -match $RE}| ForEach-Object{
Set-Variable -Name $Matches[1] -Value (Get-Date $Matches[2])
if ($Matches[1] -eq 'ENDTIME'){
[PSCustomObject]#{
StartTime = $StartTime
EndTime = $EndTime
Duration = New-TimeSpan -Start $StartTime -End $EndTime
}
}
}
$Data
"`nThe longest duration is {0}" -f ($Data|Sort-Object Duration -Descending)[0].Duration
Sample output based on the complete text from question in file times.txt
> Q:\Test\2019\05\15\SO_56150523.ps1
StartTime EndTime Duration
--------- ------- --------
2018-12-01 04:13:15 2018-12-01 04:17:15 00:04:00
2018-12-01 04:11:15 2018-12-01 04:13:15 00:02:00
2018-12-01 04:10:15 2018-12-01 04:10:40 00:00:25
The longest duration is 00:04:00
I have lots of file scanned PDF documents that have the file named with an included date. For example:
FileA_2017-10-15.pdf
FileB_2016-04-08.pdf
FileC_2018-01-30.pdf
some files also are formatted with an underscore at the end as well such as...
FileD_2018-01-30_1.pdf
FileE_2018-01-30_2.pdf
there are even a few that have two underscores before the date such as...
FileF_Example_2018-01-30_1.pdf
FileG_Example_2018-01-30_2.pdf
Unfortunately, the date they were scanned in is different than the actual date of the document. So the "Date Created" and "Date Modified" attributes are different than what is shown in the file name.
I would like a script that I could run to change the "Date Created" and "Date Modified" to match that of the filename.
I attempted this using someone else's script but I don't know enough about PowerShell to make it actually work. Note that I do not want to change the name of the file, only the time stamp.
$Directory = "C:\TestFolder"
$DateFormat = "yyyy-MM-dd"
foreach ($file in (Get-ChildItem $Directory)) {
$date_from_file=GetFileName::[datetime])
$file.CreationTime = $date_from_file
$file.LastAccessTime = $date_from_file
$file.LastWriteTime = $date_from_file
Write-Host ($file.Name + " - " + $date_from_file)
}
The code above can be scraped if something else has already been written since what I have doesn't work.
Edit
Wondering if it would also be possible to add to the script so that it could include files in sub-folders as well. Maybe it could be scripted in a way that would only consider the files in a folder if the Date Modified on the folder is today. I would like to run this on a parent folder that could potentially have many sub-folders and if those folders don't have a "Date Modified" of today, then it should skip the files in that folder. I was thinking that could speed up the process. Open to thoughts and thanks for the help!
You are quite near, you need
split the date part from filename and convert it to a [datetime]
I use a RegEx with a capture group anchored at the end $ of the BaseName
## Q:\Test\2019\05\19\SO_56211626.ps1
$Directory = "C:\TestFolder"
foreach ($file in (Get-ChildItem -Path $Directory -Filter *.pdf)){
if($File.BaseName -match '_(\d{4}-\d{2}-\d{2})(_\d)?$'){
$date_from_file= (Get-Date $Matches[1])
$file.CreationTime = $date_from_file
$file.LastAccessTime = $date_from_file
$file.LastWriteTime = $date_from_file
$file | Select-Object Name,CreationTime,LastAccessTime,LastWriteTime
}
}
Sample output:
> Q:\Test\2019\05\19\SO_56211626.ps1
Name CreationTime LastAccessTime LastWriteTime
---- ------------ -------------- -------------
FileA_2017-10-15.pdf 2017-10-15 00:00:00 2017-10-15 00:00:00 2017-10-15 00:00:00
FileB_2016-04-08.pdf 2016-04-08 00:00:00 2016-04-08 00:00:00 2016-04-08 00:00:00
FileC_2018-01-30.pdf 2018-01-30 00:00:00 2018-01-30 00:00:00 2018-01-30 00:00:00
An English locale (en-US) produces:
Name CreationTime LastAccessTime LastWriteTime
---- ------------ -------------- -------------
FileA_2017-10-15.pdf 10/15/2017 12:00:00 AM 10/15/2017 12:00:00 AM 10/15/2017 12:00:00 AM
FileB_2016-04-08.pdf 4/8/2016 12:00:00 AM 4/8/2016 12:00:00 AM 4/8/2016 12:00:00 AM
FileC_2018-01-30.pdf 1/30/2018 12:00:00 AM 1/30/2018 12:00:00 AM 1/30/2018 12:00:00 AM
[
edit - since the OP is getting very strange errors with my suggested fix - errors that i cannot reproduce with the sample data - i've changed this answer to the full suggested code.
edit 2 - added new file name variants and code to deal with them.
edit 3 - changed from splitting to a regex match since the sample data has changed yet again. [*sigh ...*]
]
you are not actually creating the datetime object that you need. the $date_from_file= line doesn't actually do anything other than create red error msgs ... [grin]
replace this line ...
$date_from_file=GetFileName::[datetime])
... with this line ...
$date_from_file = [datetime]::ParseExact($File.BaseName.Split('_')[-1], $DateFormat, $Null)
... and your $date_from_file variable will contain a proper [datetime] object that will work in your assignments.
i would likely change the sequence of those assignments to put the $file.LastAccessTime = $date_from_file LAST so that it doesn't get changed by the next line.
also, that value will change any time that the file is accessed, so it may not be worth changing. [grin]
here is the full script along with what it does -
what it does ...
sets the location & the date format to use
creates a set of test files from the OPs sample file names
gets the files from the source
converts the .BaseName into a [datetime] object
assigns the .CreationTime, .LastWriteTime, & .LastAccessTime values to the datetime from the file name
displays the changed values
here is the code ...
$Directory = $env:TEMP
$DateFormat = "yyyy-MM-dd"
# create some test files
$TestFileList = #(
'FileA_2017-10-15.pdf'
'FileB_2016-04-08.pdf'
'FileC_2018-01-30.pdf'
'FileD_2019-09-09_1.pdf'
'FileE_2015-05-05_2.pdf'
)
foreach ($TFL_Item in $TestFileList)
{
$Null = New-Item -Path $Directory -Name $TFL_Item -ItemType File -Force
}
$FileList = Get-ChildItem -LiteralPath $Directory -Filter '*.pdf' -File
foreach ($FL_Item in $FileList) {
# removed split, added regex match to work with ever-growing list of variant file names
$Null = $FL_Item.BaseName -match '_(?<DateString>\d{4}-\d{2}-\d{2})'
$DateString = $Matches.DateString
$date_from_file = [datetime]::ParseExact($DateString, $DateFormat, $Null)
$FL_Item.CreationTime = $date_from_file
$FL_Item.LastWriteTime = $date_from_file
$FL_Item.LastAccessTime = $date_from_file
# show the resulting datetime info
'=' * 20
$CurrentFileInfo = Get-Item -LiteralPath $FL_Item.FullName
$CurrentFileInfo.FullName
$CurrentFileInfo.CreationTime
$CurrentFileInfo.LastWriteTime
$CurrentFileInfo.LastAccessTime
}
screen output ...
====================
C:\Temp\FileA_2017-10-15.pdf
2017 October 15, Sunday 12:00:00 AM
2017 October 15, Sunday 12:00:00 AM
2017 October 15, Sunday 12:00:00 AM
====================
C:\Temp\FileB_2016-04-08.pdf
2016 April 08, Friday 12:00:00 AM
2016 April 08, Friday 12:00:00 AM
2016 April 08, Friday 12:00:00 AM
====================
C:\Temp\FileC_2018-01-30.pdf
2018 January 30, Tuesday 12:00:00 AM
2018 January 30, Tuesday 12:00:00 AM
2018 January 30, Tuesday 12:00:00 AM
====================
C:\Temp\FileD_2019-09-09_1.pdf
2019 September 09, Monday 12:00:00 AM
2019 September 09, Monday 12:00:00 AM
2019 September 09, Monday 12:00:00 AM
====================
C:\Temp\FileE_2015-05-05_2.pdf
2015 May 05, Tuesday 12:00:00 AM
2015 May 05, Tuesday 12:00:00 AM
2015 May 05, Tuesday 12:00:00 AM
i checked the files directly in explorer & they match the displayed values.
Thanks. I was stuck without this thread. I ended up with a variation that matched any filename with a correctly formatted date, thus:
# Call like:
# powershell -NoLogo -ExecutionPolicy Unrestricted -Sta -NonInteractive -WindowStyle Normal -File ".\Rename_files_selected_folders_ModifyDateStamps.ps1" -Folder "T:\files"
# 1. capture a commandline parameter 1 as a mandatory "Folder string" with a default value
param ( [Parameter(Mandatory=$true)] [string]$Folder = "T:\HDTV\autoTVS-mpg\Converted" )
[console]::BufferWidth = 512
$DateFormat = "yyyy-MM-dd"
write-output "Processing Folder: ",$Folder
# 2. Iterate the files
$FileList = Get-ChildItem -Recurse $Folder -Include '*.mp4','*.bprj','*.ts' -File
foreach ($FL_Item in $FileList) {
$ixxx = $FL_Item.BaseName -match '(?<DateString>\d{4}-\d{2}-\d{2})'
if($ixxx){
#write-output $FL_Item.FullName
$DateString = $Matches.DateString
$date_from_file = [datetime]::ParseExact($DateString, $DateFormat, $Null)
$FL_Item.CreationTime = $date_from_file
$FL_Item.LastWriteTime = $date_from_file
$FL_Item | Select-Object FullName,CreationTime,LastWriteTime
}
}
# https://stackoverflow.com/questions/56211626/powershell-change-file-date-created-and-date-modified-based-on-filename
Trying to import a list of users with Name, Email, Termination Date, Stop Date and first check if either stop date or termination date has passed.
Tried adding [datetime] and using get-date $user.'stop date' but without any luck.
It seems to work with the below code without the same issues though, or I get the same error, but it does check and write out that one of the values is greater:
$StopFolder = Get-ChildItem C:\test\123\*.csv |sort LastWriteTime -descending|select -first 1
$Stoplist = Import-Csv $StopFolder -delimiter ';'
$CurrentDate = Get-Date
foreach($Date in $Stoplist){
if($CurrentDate -eq (get-date $Date.'Stop Date')){write-host Equal}
if($CurrentDate -gt (get-date $Date.'Stop Date')){write-host Greater}
if($CurrentDate -lt (get-date $Date.'Stop Date')){write-host Less}}
But the same didn't seem to work for the below and can't really figure out why. I think I need to convert it to a date, but not sure why it's working in the above and not the below, nor how exactly to convert it if get-date doesn't work.
$StopFolder = Get-ChildItem C:\test\123\*.csv |sort LastWriteTime -descending|select -first 1
$Stoplist = Import-Csv $StopFolder -delimiter ';'
$CurrentDate = Get-Date
foreach($User in $Stoplist|where($_.'stop date' -lt $CurrentDate)){
try{
$Usermail = $User.'e-mail address'
$Username = get-aduser -Filter "EmailAddress -eq '$Usermail'" -properties Enabled
if($Username.enabled){
echo $Username 'still exists and is NOT disabled' >> C:\NotDisabled.txt
}
if($Username.enabled -eq $false){
echo $Username 'still exists and is disabled' >> C:\NotDeleted.txt
}
}
catch{continue}
}
Expected result is to have it only initiate the loop if the current users stop date is less than the current date. Currently nothing happens, removing the where part and the rest seems to run fine.
Any help is much appreciated.
Edit:
CSV dates are like this:
stop date
01-02-2023
21-09-2019
21-01-2019
01-01-2019
01-01-2019
Edit: the error was not just within the logic but a typo: | where needs curly braces > | where {} not parenthesis.
Create a date from 'stop date':
(get-date -date $_.'stop date')
in one line:
foreach($User in $Stoplist|where{(get-date -date $_.'stop date') -lt $CurrentDate}){...}
Here $Stoplist|where{(get-date -date $_.'stop date') -lt $CurrentDate} is one unit and could be encapsulated in brackets:
foreach($User in ($Stoplist|where{(get-date -date $_.'stop date') -lt $CurrentDate}) ){...}
But without brackets around $User in $Stoplist the pipe | only refers to the last object $Stoplist
I'm trying to compare two TICKS times, and i need the comparisons to be a little less precise and consider DateTime objects equal even if they were a few milliseconds apart (half minute tops) by removing any excess milliseconds and ticks from their DateTime objects (following jacubs guide).
problem is that my first ticks value ($date1) is generate from a performance counter, and i cannot convert him back to Date time again (Get-Date -Date ($date1)), getting the following error message:
Get-Date : Cannot bind parameter 'Date'. Cannot convert value
"636763462457113590" to type "System.DateTime". Error: "String was
not recognized as a valid dateTime"
This is my script:
$date1 = (Get-Counter -Counter '\TimeCheck\TIME').CounterSamples[0] | Select-Object -ExpandProperty RawValue
Get-Date $date1
Get-Date -Date ($date1) -Millisecond 0 | Select -ExpandProperty Ticks
$date2 = Get-Date
$date2.Ticks
Get-Date -Date ($date2) -Millisecond 0 | Select -ExpandProperty Ticks
$date1 -eq $date2
The only method this command works for me is if i wrote the TICKS time itself:
PS C:> Get-Date -Date 636763462457113590
Sunday, October 28, 2018 5:57:25 PM
What i'm doing wrong? even using out-string isn't working.
looks like $date1 in "Get-Date -Date ($date1)" is not numeric (based on error)
try Get-Date -Date ([int64]$date1) or [datetime][int64]$date1
this will convert from a tick count to a datetime object ...
$Ticks = 636763462457113590
$TimeFromTicks = [datetime]$Ticks
$TimeFromTicks
output = 2018 October 28, Sunday 5:57:25 PM
I am parsing through a directory with multiple sub-directories and want to compare the LastAccessed time with the get-date time to see if the file has been accessed since yesterday, and based on that I will either delete the file or leave it alone. I have tried piping the get-date results out to a text file and pull it back as a string, I have tried wildcard I have even gone as far as using the -like as opposed to -eq in order to get the comparison to work, but it is not properly comparing the data. Any help would be greatly appreciated.
Here is my current code:
$servers="servera","serverb"
$date3=get-date -Format d
foreach($a in $servers){
$CTXGPDir="\C$\ProgramData\Citrix\GroupPolicy"
$CTXGPDirFP="\\"+"$a"+"$CTXGPDir"
$CTXGPUserDirstoRM=Get-ChildItem "$CTXGPDirFP"|where-Object{$_.Name -notlike "*.gpf"}
foreach($i in $CTXGPUserDirstoRM){
$datestring="$date3"+" *"
$CTXUserGPPath="\C$\ProgramData\Citrix\GroupPolicy\$i"
$CTXUserGPFP="\\"+"$a"+"$CTXUserGPPath"
$file=get-item $CTXUserGPFP
$isFileInactive=$file|select-object -expandproperty LastAccessTime
write-host $file
write-host $isFileInactive
write-host $datestring
if($isFileInactive -like "$datestring *"){write-host "$CTXUserGPFP on $a has lastwritetime of $isFileInactive and should NOT BE deleted"}
if($isFileInactive -notlike "$datestring *"){write-host "$CTXUserGPFP on $a has lastwritetime of $isFileInactive and SHOULD BE deleted"}
}
Your date comparison is deeply flawed.
get-date -format d returns a String representing the current date based on your regional settings.
get-childitem <file> | select -expandproperty lastaccesstime returns a DateTime object, which gets formatted as a "long" date/time using your regional settings.
To compare these two dates effectively, you need to convert the latter to the same format.
$isFileInactive=($file|select-object -expandproperty LastAccessTime).ToShortDateString()
$isFileInactive is now a String formatted the same as you get with get-date -format d and you can make a proper comparison.
if($isFileInactive -eq $datestring){write-host "$CTXUserGPFP on $a has lastwritetime of $isFileInactive and should NOT BE deleted"}
If you have to deal with timezones, you may want to amend it to add .ToLocalTime() before ToShortDateString();