2

I'm attempting to create a PowerShell script that will run once every morning (via Task Scheduler) and alert someone (via Direct Send (I know how to do this and will implement said feature later)) if a file wasn't created during each hour for the day before, in order to no longer have to do this manually or when a problem arises. The filenames, as shown in the $FilePattern, all contain the date they're created, along with the time. Obviously, the logic in my Foreach loop is flawed, because $Time will always be in $Hours, but I've been scratching my head and haven't been able to figure out how I should go about this. I thought I'd be able to compare two arrays, but I'm not so sure now. I also ran across Compare-Object which seemed promising, but I couldn't quite grasp it. My apologies for the mess. My current code is as follows.

[CmdletBinding()]

param(

    [Parameter(Mandatory=$false)]
    [ValidateScript({ Test-Path $_ -PathType Container })]
    [string]
    $Path = "C:\Users\<username>\Desktop\Archive",
    $Year = [DateTime]::Today.AddDays(-1).Year,
    $Month = [DateTime]::Today.AddDays(-1).Month,
    $Day = ([DateTime]::Today.AddDays(-1).Day),
    $strMonth = ([String]$Month).PadLeft(2,'0'),
    $strDay = ([String]$Day).PadLeft(2,'0'),
    $Date = "$Year" + "$strMonth" + "$strDay",
    $FilePattern = @("850_" + $Date + "*.txt"),
    $Files = (Get-ChildItem -Path $Path -Include $FilePattern -Recurse | 
        Select-Object -ExpandProperty CreationTime | Get-Date -f "yyyyMMdd"),
    $Time = (Get-ChildItem -Path $Path -Include $FilePattern -Recurse |
        Select-Object -ExpandProperty CreationTime | Get-Date -f "hh"),
    $Hours = @(0..23)

)

Foreach ($File in $Files) {

    #if (-Not (Test-Path "$Path\$FilePattern")) {
    #    Write-Host "Warning: The file path doesn't exist!"
    #} else {
    #    Write-Host "The file path exists..."
    #}

    if ($Hours -notin $Time) {
        Write-Host "There's no file present for $Time o'clock for $Date."
    } else {
        Write-Host "There's at least one file per hour for $Date."
    }

}
Mentat
  • 70
  • 1
  • 8

2 Answers2

1

I still need to refactor and change a few things, but this appears to work.

[CmdletBinding()]

param(

    $Path = "C:\Users\<username>\Desktop\Archive",
    $Year = [DateTime]::Today.AddDays(-1).Year,
    $Month = [DateTime]::Today.AddDays(-1).Month,
    $strMonth = ([String]$Month).PadLeft(2,'0'),
    $Day = ([DateTime]::Today.AddDays(-1).Day),
    $strDay = ([String]$Day).PadLeft(2,'0'),
    $Date = "$Year" + "$strMonth" + "$strDay",
    $Hours = @(
        "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11",
        "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"
    ),
    $strHours = $Hours.ToString().PadLeft(2,'0'),
    $FilePattern = @("850_" + $Date + "*.txt"),
    $Files = (Get-ChildItem -Path $Path -Include $FilePattern -Recurse | 
        Select-Object -ExpandProperty CreationTime | Get-Date -f "HH")

)

ForEach ($Hour in $Hours) {

    if ($Hour -notin $Files) {

        Write-Host "There's no file present for $Hour o'clock for $Date."

    } else {

        Write-Host "There's at least one file for $Hour o'clock for $Date."

    }

}
Mentat
  • 70
  • 1
  • 8
1

Here is a shorter and probably more readable implementation:

$Path = "C:\Users\<username>\Desktop\Archive\*"
$Date = (Get-Date).AddDays(-1).ToString('yyyyMMdd')
$Hours = Get-ChildItem -Path $Path -Include "850_$($Date)*.txt" | ForEach-Object {(Get-Date $_.CreationTime).Hour} | Sort-Object | Get-Unique
for ($Hour = 0; $Hour -lt 24; $Hour++) {
    if ($Hour -in $Hours) {
        Write-Host "There's at least one file for $Hour o'clock for $Date." -ForegroundColor Green
    } else {
        Write-Host "There's no file present for $Hour o'clock for $Date." -ForegroundColor Red
    }
}

So what have I changed:

  • I removed the params block as I think you just used it to initialize variables, but it is designed to define parameters you want pass to a function. It does not look like you want to pass anything to that script. Correct me, if I'm wrong.
  • I added an asterisk (*) to your path to make the -Include parameter work (see docs). I think you added -Recurse to make it work. Use -Recurse only if your logs are located in subdirectories.
  • I added a way more readable and easier to understand method to create your desired timestamp.
  • I extracted the hours, you are looking for as numbers, so you can compare them against numbers and don't have to create an array of two digits stringified hours.
  • I added colors to the output to get a faster overview, if any file is missing.
stackprotector
  • 10,498
  • 4
  • 35
  • 64
  • A far more elegant solution than what I came up with. I wasn't aware of many of the things that you mentioned, and the book I'm reading didn't cover them well, so it's much appreciated. I especially liked the way you did your For Loop, which reminds me of how I'd traditionally do things in C, and how you cut $Date down to one line vs. my six. – Mentat May 03 '20 at 19:37