Powershell Example Output

The Quick Gist

A user in the MSPGeek Slack asked a question about monitoring a file for not being changed. He wanted to setup an alert if the file hadn’t been modified in x number of days, so I wrote this quick one liner to help him, then over the next hour I came back and tweaked it several times. Here is the final result.

get-item test1.txt,test2.txt | %{if($_.LastWriteTime -lt (Get-Date).AddDays(-5)) {Write-Output ('Failure: {0} - {1}' -f $_.Name, $_.LastWriteTime)} else { Write-Output ('Success: {0} - {1}' -f $_.Name, $_.LastWriteTime)}}

A quick and dirty command to do the job. I could end the blog post here, but…

%? What’s that?

% is an alias for ForEach-Object. When you are making a quick and dirty one liner, it’s nice to keep things shorter, but might be a little hard to reader to read. That’s why when you are writing a full script, you should probably explode that out completely.

Write-Output vs Write-Host

If you’ve been PowerShelling on the side for some time, you might have picked up the habit of using Write-Host. Very, very rarely is it the right option. Write host writes to the console no mater what. Write-Output, however, will write into the stream. In my example, that doesn’t matter much, but what if you wanted to pump the results into a variable? We could do $results = get-item .... Now it is in a variable we could use later down on the line. Although if we were doing that, I’d probably just push the objects, or create new objects, but for the scope we were working at, it was fine.

What’s with the weird strings?

In this use case, double quotes were likely to cause problems. They would need to be escaped. Not to mention that inside those strings inside of For-EachObject would need to be wrapped in $() because the string would get confused with $_. and not realize you wanted the Name and LastWriteTime. So instead I used a single quote, then used the -f parameter on the string to fill in variables where the {0} and {1} are. Pretty handy when you are embedding the powershell scripts in your RMM or somewhere else that might have conflicting quotes.

What if we wanted it to be more dynamic?

So it’s setup pretty well to be expanded or embedded in another script. Let’s blow it out past a one liner.

$files = 'test1.txt','test2.txt'
$MaximumAgeDays = 5
get-item $files | ForEach-Object {
    if( $_.LastWriteTime -lt (Get-Date).AddDays(-$MaximumAgeDays) ) {
        Write-Output ('Failure: {0} - {1}' -f $_.Name, $_.LastWriteTime)
    } else {
        Write-Output ('Success: {0} - {1}' -f $_.Name, $_.LastWriteTime)

Hey look at that, with a few small edits, we can now easily change the files and age. Great if you are getting the list of files from another location like registry keys. Could be embedded well in an existing script, and is easy to understand.