Parsing a file name and comparing a string to file creation date

Brass Contributor

I'm still a novice in PowerShell, but I have continuing problems to solve.

 

I have automatically created file names of this form:

event-20220630T1420405650000.pqd

Where event- is constant, the next 8 characters represent yyyymmdd, T is a constant, and the remaining 13 characters represent an incrementing time, possibly in seconds since some starting date.

My challenge is to compare the yyyymmdd in the file name to the yyyymmdd in the file creation date and determine if the date in the file name is in the future when compared to the creation date.

 

Any assistance will be greatly appreciated!

 

Thanks,

Fred

7 Replies
try this code and let know if this will solve your problem

$file_name = "event-20220630T1420405650000.pqd"
$date_str = $file_name.Substring(6, 8)
$date_obj = [datetime]::ParseExact($date_str, "yyyyMMdd", $null)

$file_path = "C:\path\to\event-20220630T1420405650000.pqd"
$creation_time = (Get-ItemProperty -Path $file_path).CreationTime
$creation_date = $creation_time.Date

if ($date_obj -gt $creation_date) {
Write-Output "Date in file name is in the future."
} else {
Write-Output "Date in file name is not in the future."
}
Thank you for your quick reply. I've been trying to incorporate your code into an existing script that I'm using to recurse a directory structure and extract specific information including the latest file name, size, and creation time, along with the parent folder name and the total file count in the folder and direct the output to a .csv file. That original script is functioning properly. My goal is to incorporate your code in such a way that as the folders are recursed, any file name date pattern that is in the future compared to the creation date of that specific file will be flagged as "Date in file name is in the future". So far, things are working with one exception. The $creation_date is the creation date of the parent folder, not the file. Here's the ugly code I have put together so far, and a sample of the output. Any additional assistance will be greatly appreciated.

$dirs = Get-ChildItem "\\fileshare\level1\level2\level3\parentdirectory" -Directory
$csvLog = "\\fileshare\toplevel\myprofile\myfolders\Documents\PowerShellOutput\Ion Future Events.csv"

foreach ($dir in $dirs) {

$recentFile = $null
$folder = $dir.Name
$directory = $dir.FullName

echo "Directory" $directory

$filesCount = (Get-ChildItem $directory -Filter "event*.pqd" -Recurse).Count
$recentFile = Get-ChildItem $directory -Filter "event*.pqd" -Recurse | Sort-Object LastWriteTime -Descending| Select-Object -First 1
$recentFileName = $recentFile.Name
$recentFileLength = $recentFile.Length
$recentFileWriteTime = $recentFile.LastWriteTime

if ($recentFile) {

$file_name = $recentFileName
$date_str = $file_name.Substring(6, 8)

echo "Date_str" $date_str

$date_obj = [datetime]::ParseExact($date_str, "yyyyMMdd", $null)

echo "Date Obj" $date_obj

$file_path = "\\fileshare\level1\level2\level3\parentdirectory"
$creation_time = (Get-ItemProperty -Path $file_path).CreationTime

echo "Creation Time" $creation_time

$creation_date = $creation_time.Date

echo "Creation Date" $Creation_date

if ($date_obj -gt $creation_date) {
Write-Output "Date in file name is in the future."
} else {
Write-Output "Date in file name is not in the future."
}

$object = New-Object -TypeName psobject
$object | Add-Member -MemberType NoteProperty -Name "Site" -Value $folder
$object | Add-Member -MemberType NoteProperty -Name "File Name" -Value $recentFileName
$object | Add-Member -MemberType NoteProperty -Name "File Size" -Value $recentFileLength
$object | Add-Member -MemberType NoteProperty -Name "Date Time" -Value $recentFileWriteTime
$object | Add-Member -MemberType NoteProperty -Name "File Count" -Value $filesCount
$object | Export-Csv $csvLog -Encoding ASCII -Append -NoTypeInformation

}

}

Directory
\\fileshare\level1\level2\level3\parentdirectory
Date_str
20230310
Date Obj

Friday, March 10, 2023 12:00:00 AM
Creation Time
Wednesday, January 5, 2022 2:13:48 PM
Creation Date
Wednesday, January 5, 2022 12:00:00 AM
Date in file name is in the future.

Based on your code, it seems that you're retrieving the creation date of the parent folder instead of the creation date of the file. To get the creation date of the file, you need to use the CreationTime property of the file object, which you already have stored in the $recentFile variable. Here's the modified code that retrieves the creation date of the file and compares it with the date in the file name:

 

$dirs = Get-ChildItem "\\fileshare\level1\level2\level3\parentdirectory" -Directory
$csvLog = "\\fileshare\toplevel\myprofile\myfolders\Documents\PowerShellOutput\Ion Future Events.csv"

foreach ($dir in $dirs) {
    $recentFile = $null
    $folder = $dir.Name
    $directory = $dir.FullName
    echo "Directory" $directory

    $filesCount = (Get-ChildItem $directory -Filter "event*.pqd" -Recurse).Count
    $recentFile = Get-ChildItem $directory -Filter "event*.pqd" -Recurse | Sort-Object LastWriteTime -Descending| Select-Object -First 1
    $recentFileName = $recentFile.Name
    $recentFileLength = $recentFile.Length
    $recentFileWriteTime = $recentFile.LastWriteTime

    if ($recentFile) {
        $date_str = $recentFileName.Substring(6, 8)
        echo "Date_str" $date_str
        $date_obj = [datetime]::ParseExact($date_str, "yyyyMMdd", $null)
        echo "Date Obj" $date_obj
        $creation_date = $recentFile.CreationTime.Date
        echo "Creation Date" $creation_date

        if ($date_obj -gt $creation_date) {
            Write-Output "Date in file name is in the future."
        } else {
            Write-Output "Date in file name is not in the future."
        }

        $object = New-Object -TypeName psobject
        $object | Add-Member -MemberType NoteProperty -Name "Site" -Value $folder
        $object | Add-Member -MemberType NoteProperty -Name "File Name" -Value $recentFileName
        $object | Add-Member -MemberType NoteProperty -Name "File Size" -Value $recentFileLength
        $object | Add-Member -MemberType NoteProperty -Name "Date Time" -Value $recentFileWriteTime
        $object | Add-Member -MemberType NoteProperty -Name "File Count" -Value $filesCount
        $object | Export-Csv $csvLog -Encoding ASCII -Append -NoTypeInformation
    }
}

With this modification, the code should now compare the date in the file name with the creation date of the file

@Varun_Ghildiyal 

 

Yes. Now the comparison is correct. 

 

The only remaining issue is that I need to do the date comparison for every event*.pqd file, not just the most recent one in each folder. I'm not sure how to move the comparison to the right location in the code to get that result.

@Fred_Elmendorf 

 

To compare the date for every event*.pqd file in each folder, you can modify the existing foreach loop to loop through all the files instead of just the most recent file in each folder. Here's an updated version of the code with the necessary changes:

$dirs = Get-ChildItem "\\fileshare\level1\level2\level3\parentdirectory" -Directory
$csvLog = "\\fileshare\toplevel\myprofile\myfolders\Documents\PowerShellOutput\Ion Future Events.csv"

foreach ($dir in $dirs) {
    $folder = $dir.Name
    $directory = $dir.FullName
    echo "Directory" $directory

    $files = Get-ChildItem $directory -Filter "event*.pqd" -Recurse
    $filesCount = $files.Count

    foreach ($file in $files) {
        $date_str = $file.Name.Substring(6, 8)
        echo "Date_str" $date_str
        $date_obj = [datetime]::ParseExact($date_str, "yyyyMMdd", $null)
        echo "Date Obj" $date_obj
        $creation_date = $file.CreationTime.Date
        echo "Creation Date" $creation_date

        if ($date_obj -gt $creation_date) {
            Write-Output "File $($file.Name) in folder $folder has date in the future."
        } else {
            $object = New-Object -TypeName psobject
            $object | Add-Member -MemberType NoteProperty -Name "Site" -Value $folder
            $object | Add-Member -MemberType NoteProperty -Name "File Name" -Value $file.Name
            $object | Add-Member -MemberType NoteProperty -Name "File Size" -Value $file.Length
            $object | Add-Member -MemberType NoteProperty -Name "Date Time" -Value $file.LastWriteTime
            $object | Add-Member -MemberType NoteProperty -Name "File Count" -Value $filesCount
            $object | Export-Csv $csvLog -Encoding ASCII -Append -NoTypeInformation
        }
    }
}

 

This code uses a nested foreach loop to loop through all the event*.pqd files in each folder. For each file, it extracts the date from the file name, converts it to a datetime object, and compares it to the file creation date. If the date in the file name is in the future, it writes a message to the console. Otherwise, it creates a new psobject with the relevant file information and exports it to the CSV file. the Export-Csv cmdlet is inside the inner loop, so it exports data for each file separately.

 

This is getting really close to what I need, but there are a couple remaining issues.
1. I only need output for the files where the datetime object is greater than the creation date, so I removed some of the NoteProperty definitions and moved the export inside the if statement. I also tried to create a new NoteProperty -Name "Has a date greater than creation date" -$creation_date, but as you can see from the sample output it did not get added to the output file.

2. The second issue is that with the results so far, I have discovered that there are many valid files where the creation date is one day greater than the date in the file name, but it should never be more than one day greater. How can I change the comparison to effectively be if($date_obj -gt $creation_date+1)?

Here's my modified code and sample output.
Modified code:

$dirs = Get-ChildItem "\\fileshare\level1\level2\level3\parentdirectory" -Directory
$csvLog = "\\fileshare\toplevel\myprofile\myfolders\Documents\PowerShellOutput\Ion Future Events.csv"

foreach ($dir in $dirs) {
$folder = $dir.Name
$directory = $dir.FullName
# echo "Directory" $directory

$files = Get-ChildItem $directory -Filter "event*.pqd" -Recurse
$filesCount = $files.Count

foreach ($file in $files) {
$date_str = $file.Name.Substring(6, 8)
# echo "Date_str" $date_str
$date_obj = [datetime]::ParseExact($date_str, "yyyyMMdd", $null)
# echo "Date Obj" $date_obj
$creation_date = $file.CreationTime.Date
# echo "Creation Date" $creation_date

if ($date_obj -gt $creation_date) {
$object = New-Object -TypeName psobject
# $object | Add-Member -MemberType NoteProperty -Name Write-Output "File $($file.Name) in folder $folder has date in the future."
$object | Add-Member -MemberType NoteProperty -Name "Site" -Value $folder
$object | Add-Member -MemberType NoteProperty -Name "File Name" -Value $file.Name
$onject | Add-Member -MemberType NoteProperty -Name "Has a date greater than creation date" -$creation_date
$object | Export-Csv $csvLog -Encoding ASCII -Append -NoTypeInformation
} else {
}
}
}

Sample output:
"Site","File Name"
"SiteA","event-20221110T0324065380000.pqd"
"SiteA","event-20221110T0323011310000.pqd"
"SiteB","event-20220904T0217282030000.pqd"
"Site1","event-20220904T0217268210000.pqd"
"Site2","event-20220705T0056043380000.pqd"
"Site2","event-20220707T0031091680000.pqd"
"Site3","event-20220707T0031094020000.pqd"

@Fred_Elmendorf 

 

Here's a version with a little bit of flexibility insofar as:

 

  1. It doesn't care what the prefix is, so long as the filename format adheres to:
    somePrefix-timestamp.pqd
  2. It'll silently exclude any files where the timestamp component isn't parsable.

 

It's also more efficient over larger file repositories as it's not storing the file system structure in a local variable prior to doing the work.

 

I went with using the full path to the file in the output but you can change that to your liking.

 

$LogFile = ".\SomeLogFile.log";
$Root = "D:\Data";
$FilenameTimestamp = [datetime]::MinValue;

Remove-Item -Path $LogFile -ErrorAction:SilentlyContinue;

Get-ChildItem -Directory -Path $Root |
    ForEach-Object {
        $Directory = $_;

        Get-ChildItem -File -Recurse -Path ($_.FullName) -Filter "event-*.pqd" |
            ForEach-Object {
                if ((($NameParts = $_.Name.Split(@("-", "."))).Count -eq 3) -and ([datetime]::TryParseExact($NameParts[1].Substring(0, 8), "yyyyMMdd", $null, [System.Globalization.DateTimeStyles]::None, [ref] $FilenameTimestamp)) -and ($FilenameTimestamp.Date -gt $_.CreationTime.Date))
                {
                    [PSCustomObject] @{
                        Site = $Directory.Name;
                        Path = $_.FullName;
                    }
                }
            }
    } | Export-Csv -Path $LogFile -NoTypeInformation;

 

Sample output from the log file:

"Site","Path"
"Temp","D:\Data\Temp\event-20230630T1420405650000.pqd"

 

Cheers,

Lain