Use PowerShell to Find Files that Have Not Been Accessed

Use PowerShell to Find Files that Have Not Been Accessed

  • Comments 10
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to find files that have not been accessed for some time.

Hey, Scripting Guy! Question Hey, Scripting Guy! On our server, we have tons of files. Unfortunately, many of them haven’t been accessed for years. I know the cost of storage is coming down, but the management overhead and cost of building new datacenters does not come down. In fact, it is going up. So we need a way to identify files that have not been accessed in a long time. If we could delete them, it would be even better.

—AB

Hey, Scripting Guy! Answer Hello AB,

Microsoft Scripting Guy, Ed Wilson, is here. Tonight is the speaker’s dinner for Windows PowerShell Saturday event in Charlotte, North Carolina. We have around 50 people coming to the Scripting House. We also have a couple of people who will be spending the night. Expect to see some new videos coming out as Honorary Scripting Guy and Windows PowerShell MVP, Sean Kearney, and I get together and spend the night playing around with cameras and video equipment.

If you have not yet registered, I think there are a couple of tickets left, so don’t delay or they will be gone. The list of speakers reads like a who’s who in the Windows PowerShell world. In fact, six of the speakers at our event in Charlotte are also going to be speaking at the Windows PowerShell Summit in Seattle in April. To register, go to PowerShell Saturday #007.

Image of logo

     Note  This is the fifth in a series of posts that talk about working with files and folders by using Windows PowerShell. 
     You should read the previous posts:

There are three basic properties of a file that I commonly use when looking at files that are neglected. The first is the date it was created, the second is when it was modified, and last is when it was accessed. These properties are visible when I to go the General tab of a file in File Explorer. An example of these values is shown here:

Image of menu

I can use the Get-ChildItem cmdlet and the Select-Object cmdlet and return the three properties. The command to do this is:

Get-ChildItem c:\fso -File | select name, *time

The following image illustrates the command and its output:

Image of command output

It is possible that a file may have been accessed, but the access did not modify the file. It is also possible that a file may have been created, and then neither accessed or written to again. For my purpose today, I am going to use the LastWriteTime property.  I want to create a simple function that I can use that permits me to supply an array of folders and a begin date. The function is shown here:

Function Get-NeglectedFiles

{

 Param([string[]]$path,

       [int]$numberDays)

 $cutOffDate = (Get-Date).AddDays(-$numberDays)

 Get-ChildItem -Path $path |

 Where-Object {$_.LastAccessTime -le $cutOffDate}

}

I write the function in the Windows PowerShell ISE, and I run it to load the Get-NeglectedFiles function. Now, I go to the interactive pane at the bottom of the Windows PowerShell ISE, and I call the function a couple of times. In the first command line, I look for files that have not been accessed in 60 days:

Get-NeglectedFiles -path c:\fso -numberDays 60 | select name, lastaccesstime

Next, I look for files that have not been accessed in 90 days:

Get-NeglectedFiles -path c:\fso -numberDays 90 | select name, lastaccesstime

The following image illustrates this process:

Image of command output

The reason for doing this is so I can gain confidence that the function works as I think it should. It appears to do so. Now, I am going to look for files that have not been accessed in 180 days, as shown here:

Image of command output

Cool, I found a few files. Now, I know that I have backups of these files, so I am going to delete them. To do this, I change the Select command to Remove-Item:

Get-NeglectedFiles -path c:\fso -numberDays 180 | Remove-Item -Force

When I check for the files, nothing reports back. This is shown in the following image:

Image of command output

AB, that is all there is to using Windows PowerShell to find files that have not been accessed in an extended period of time. This also concludes File Week. Join me tomorrow when I will talk about more really cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • It seems to me that it could be quite helpful to mention the implications of NtfsDisableLastAccessUpdate before some poor careless copy-and-paste administrator wipes out more than they meant to. Hope this helps.

  • @RJ Subramanian Are you talking about checking if DisableLastAccess=0 via the following command: fsutil behavior query DisableLastAccess. If it doesn't equal 0, then you would have to change it using: fsutil behavior set DisableLastAccess 0 (reboot is required)

  • Exactly, and thanks for offering the clarification. Perhaps it should also be noted that after DisableLastAccess has been turned off, $numberDays will need to elapse before the results are useful.

  • This works great. Thanks.

  • Hello Somewhat new to this and I am trying to follow your procedure but I am having an issue resolving the Get-NeglectedFiles command I listed my commands and don't see it available, is there an admin pack or something further I need to install?

    Thank you

  • how would you modify this to ask... Have any files in a root project folder been modified in the past 365 days? IF none have been modified the MOVE to the archive PATH.

  • Good one but it only Works for one level folder, what hapen when I need to search for files older tan 180 days in all the volumen?

  • To do this on a whole volume or directory tree, add -recurse or -r to the Get-ChildItem cmdlet.

  • This works really well and I have added a few things to it. I can now select file types and search all sub folders from a given root folder. this first creates a spreadsheet to show what would be moved. the 2nd part of the script uses the spreadsheet to recreate the old folder structure under a new root folder called DoNotBackup and copies the files listed.

    Clear-Host
    <#Function is loaded into memory#>
    Function Get-NeglectedFiles
    {
    Param([string[]]$path,
    [int]$numberDays)
    $cutOffDate = (Get-Date).AddDays(-$numberDays)
    Get-ChildItem -Path $path -recurse -include *.pdf,*.txt,*.html,*.htm,*.doc,*.docx,*.xlsl,*.xlsx, *.xlsm,*.pub,*.pubx,*.ppt,*.pptx,*.zip,*.7z,*.jpg,*.bmp,*.mov,*.avi,*.mp4|
    Where-Object {$_.LastWriteTime -le $cutOffDate}
    }

    <#CSV file is created on the route of the D drive#>
    Get-NeglectedFiles -path d:\Users -numberDays 360 | select name, LastWriteTime, CreationTime, Attributes, directory, DirectoryName, LastAccessTime, length| Export-Csv -Path d:\DataAgeUsers.csv -Encoding ascii -NoTypeInformation
    Get-NeglectedFiles -path d:\Common -numberDays 360 | select name, LastWriteTime, CreationTime, Attributes, directory, DirectoryName, LastAccessTime, length| Export-Csv -Path d:\DataAgeCommon.csv -Encoding ascii -NoTypeInformation

    <# Could have wrapped this in an array, but its easy for everyone to add and modify it this way#>

    <#new folder structure is created and files are moved into it#>
    $UserList=IMPORT-CSV d:\DataAgeUsers.csv
    $USERLIST | FOREACH-OBJECT { $_ }
    FOREACH ($Person in $UserList) {
    $NewPerson=$Person.Directory -replace "d:\\", "d:\\DoNotBackup\\"
    new-item $NewPerson -itemtype directory
    echo $($Person.Directory + "\" + $Person.Name)
    Move-Item $($Person.Directory + "\" + $Person.Name) $NewPerson
    }

    <#new folder structure is created and files are moved into it#>
    $UserList=IMPORT-CSV d:\DataAgeCommon.csv
    $USERLIST | FOREACH-OBJECT { $_ }
    FOREACH ($Person in $UserList) {
    $NewPerson=$Person.Directory -replace "d:\\", "d:\\DoNotBackup\\"
    new-item $NewPerson -itemtype directory
    echo $($Person.Directory + "\" + $Person.Name)
    Move-Item $($Person.Directory + "\" + $Person.Name) $NewPerson
    }