Home > Software design >  Prevent output from writing multiple times in Powershell script
Prevent output from writing multiple times in Powershell script

Time:12-05

I am trying to output $message in case a file or multiple files in a folder match today's or yesterday's date. In this case, if the file matches the dates, it should output a message for each file, for example, "file $filename matches", where $filename is the name of the file that matched the date.

On the other hand if a file doesn't match the current date or yesterday's date it will also return a message, but only one message with the filenames which doesn't match the date.

That is not happening with the following code:

    $in = $false
    foreach ($file in Get-ChildItem -Path $Directory) {
        $today = $file.LastWriteTime.Date -eq [datetime]::Today
        $yesterday = $file.LastWriteTime.Date -eq [datetime]::Today.AddDays(-1)
        
        if ($today -or $yesterday) {
            $message = "file exists"
            $in = $true
            Write-Output $message
        }
    }
    

    if ($in -eq $false) {
        $message_error = "file does not exist" 
        Write-Output $message_error
    }

Instead when a file matches the dates (yesterday's or today's date) it outputs the message multiple times, more than 20x if indented like above.

As for if it doesn't match, it is outputting only 1x but it should be 2x because there are 2 files that don't match the dates.

Can anyone give me an hint?


Output should look like

If file or files in folder matches date:

"File example.txt matches date
and
File example2.txt matches date"

Else if files in folder don't match date:

"File example.txt, example2.txt don't match dates"

EDIT

Instead I am trying like this:

 $in = $false
 foreach ($file in Get-ChildItem -Path $Directory) {
    $today = $file.LastWriteTime.Date -eq [datetime]::Today
    $yesterday = $file.LastWriteTime.Date -eq [datetime]::Today.AddDays(-1)
                
    if ($today -or $yesterday) {
        $msg_found = "file"   $file "exists" 
        $in = $true
               
    } else {
        $msg_notfound = "File"   $file   "Not found"
            
    }
      
 Write-Output $msg_notfound
 Write-Output $msg_found

Here the messages are outputted in the right amount but they appear both in any circunstance. Would it solve if I use an if loop?

CodePudding user response:

Simply collect the dates that do not match the reference date in a variable and write the files that do match out directly to the console:

# set the reference date to midnight using .Date
$refDate = [datetime]::Today.AddDays(-1).Date
# loop through the files in the directory and test their LastWriteTime dates
$notMatch = foreach ($file in (Get-ChildItem -Path $Directory -File)) {
    if ($file.LastWriteTime -ge $refDate) { 
        # use Write-Host so this message doesn't end up in variable $notMatch
        Write-Host "File '$($file.Name)' matches the date"
    }
    else {
        # output the filename so it gets collected in variable $notMatch
        $file.Name
    }
}

# now output the list of files that didn't match to the console
if (@($notMatch).Count) {
    $message = "Files that don't match the date:`r`n{0}" -f ($notMatch -join [environment]::NewLine)
    Write-Host $message -ForegroundColor Red
}
else {
    Write-Host "All files matched the date!" -ForegroundColor Green
}

CodePudding user response:

continuing from my comments... if you're looking to output the names of the files that are greater than or equal to, yesterdays date, there's a couple of ways you can go about this:

Get-ChildItem -Path $Directory | 
    ForEach-Object -Begin {
        $notMatch = [System.Collections.ArrayList]::new()
        $date     = [datetime]::Today.AddDays(-1)
    } -Process {
        if ($_.LastWriteTime -ge $date) {
            Write-Host -Object  "File: [$($_.Name)] - Matches Date"
        }
        else {
            $null = $notMatch.Add($_.Name)
        }
    } -End {
        ($notMatch -join ', ' )   "don't match dates."
    }

Fortunately, matching the dates as they come is an easy solution for the files that are a match. As for the ones that aren't, you can create an array to hold the values of the name until the end of your loop to display the values concatenated by a (", ").

CodePudding user response:

Try this:

 foreach ($file in Get-ChildItem -Path $Directory) {
    $today = $file.LastWriteTime.Date -eq [datetime]::Today
    $yesterday = $file.LastWriteTime.Date -eq [datetime]::Today.AddDays(-1)
    
    # If file was written to today or yesterday, write $msg_found           
    if ($today -or $yesterday) {
        $msg_found = "File "   $file   " exists"
        Write-Output $msg_found         
    }
    
    # If not, write $msg_notfound 
    else {
        $msg_notfound = "File "   $file   " not found"
        Write-Output $msg_notfound
            
    }
}

If I'm understanding correctly, the reason why it was writing both the $msg_found and $msg_notfound variables is because you had them outside of the If/Else statement.

Keeping them inside the If/Else will make it so it only writes the $msg within the If or the Else.

Edit: Above, I removed the $in variable, but I wasn't sure if you needed that. So I modified the script you posted before the edit to do the same thing as the script I put originally in case you do.

I left comments to tell you what I changed, but let me know if you have any questions:

$in = $false
foreach ($file in Get-ChildItem -Path $Directory) {
    $today = $file.LastWriteTime.Date -eq [datetime]::Today
    $yesterday = $file.LastWriteTime.Date -eq [datetime]::Today.AddDays(-1)
    
    # If file was made today or yesterday, $in is true, write $message 
    if ($today -or $yesterday) {
        $message = "$File exists"
        $in = $true
        Write-Output $message
    }
    
    # If not, $in is false for this file in the ForEach loop
    else{
        $in = $false
    }
    
    # Moved the second If statement into the ForEach loop 
    # If the If/Else set $in as false for this file, write $message_error
    if ($in -eq $false) {
    $message_error = "$File does not exist" 
    Write-Output $message_error
    }
}

CodePudding user response:

$Directory="T:\temp2"
$in = $false
$message=""
foreach ($file in Get-ChildItem -Path $Directory) {
    $today = $file.LastWriteTime.Date -eq [datetime]::Today
    $yesterday = $file.LastWriteTime.Date -eq [datetime]::Today.AddDays(-1)
    
    if ($today -or $yesterday) {
        $in = $true
        Write-Output ("File "   $file.Name  " matches date")
    } else {
        $message  =(" " $file.Name ",")
    }
}


if ($in -eq $false) {
    $message_error= ("File"   $message.Substring(0,$message.Length-1)   " don't matches date")
    Write-Output $message_error
}
  • Related