Forum Discussion
Issue with date modified for NTUSER.DAT
- Feb 23, 2018
Here is the code from the script:
#Purpose: Used to set the ntuser.dat last modified date to that of the last modified date on the user profile folder.
#This is needed because windows cumulative updates are altering the ntuser.dat last modified date which then defeats
#the ability for GPO to delete profiles based on date and USMT migrations based on date.$ErrorActionPreference = "SilentlyContinue"
$Report = $Null
$Path = "C:\Users"
$UserFolders = $Path | GCI -DirectoryForEach ($UserFolder in $UserFolders)
{
$UserName = $UserFolder.Name
If (Test-Path "$Path\$UserName\NTUSer.dat")
{
$Dat = Get-Item "$Path\$UserName\NTUSer.dat" -force
$DatTime = $Dat.LastWriteTime
If ($UserFolder.Name -ne "default"){
$Dat.LastWriteTime = $UserFolder.LastWriteTime
}
Write-Host $UserName $DatTime
Write-Host (Get-item $Path\$UserName -Force).LastWriteTime
$Report = $Report + "$UserName`t$DatTime`r`n"
$Dat = $Null
}
}
Joe_Friedel, Hilde Claeys, Deleted, Ryan Pertusio, Ryan Pertusio, AHDoug, SSUtech, millermike - Tagging folks who've contributed for visibility.
I don't believe this issue is as cut and dry as everyone here is presenting. As you've likely found out, sometimes these files you are checking for don't exist, and in some cases, they have unexpected timestamps. These values get updated for various reasons (I think mostly during OS updates). How do we know which ones to trust? Based on my experience, the LastWriteTime of the user profile directory itself and the IconCache.db file seem to be the most accurate. What do you guys think? Has anyone made any progress on this? I've created a script to gather data on all of the profiles on the device. I have this problem on thousands of computers. I've attached the data for just one of those computers. The data in the linked file represents data from one of my high traffic workstations where I've used the value of 30 for the $Delete_if_Older variable. You can see by the data, many of the profiles should be flagged for deletion, but one or more of the write times are newer, so I've set the Delete flag to False. Like I stated earlier, from what I can tell, the LastWriteTime of the user profile directory itself and the IconCache.db file seem to be the most accurate. So is it best to use the LastWriteTime from IconCache.db if it exists, and if it doesn't use the LastWriteTime of the user profile directory? I found Win32_UserProfile LastUseTime to be the least accurate out of the bunch so I just excluded it from being considered for the LastUpdated variable. What do you guys think?
Here's the data from my high traffic workstation. https://1drv.ms/x/s!AoQvLmouCXZPgaApOK6SGY_bQShhGw?e=rPCjFm
Green indicates it should have been flagged for deletion, red would indicate it should not be flagged for deletion, yellow indicates the value did not exist. All-in-all, out of 173 profiles, none of them qualified to be deleted based on a 30 day threshold. I have a feeling a Windows update ran recently on this device causing the timestamps to update.
Anxious to know everyone's thoughts on this as it seems to be an issue Microsoft has swept under the rug. What about the LocalProfileUnloadTime values - did anyone figure out how to get those values with PowerShell and/or determine a timestamp from this data? Maybe we can get a Microsoft rep to reply here with a good alternative.
$Delete_if_older = '30'
$DeleteProfile = (Get-Date).AddDays(-$Delete_if_older)
$ErrorActionPreference = "SilentlyContinue"
$Path = "C:\Users"
$ExcludedUsers = @('Administrator','Public','Default')
$UserFolders = $Path | Get-ChildItem -Directory -Exclude $ExcludedUsers
$CimProfiles = Get-CimInstance -Class Win32_UserProfile
$NA = [datetime] "11/11/1111 11:11:11 AM"
$ProfileData = ForEach ($UserFolder in $UserFolders) {
$UserName = $UserFolder.Name
$UserProfileTime = $UserFolder.LastWriteTime
$CimProfile = $CimProfiles | Where-Object { $_.localpath -eq $UserFolder.FullName }
if ($CimProfile) { $CimProfileTime = $CimProfile.LastUseTime } else { $CimProfileTime = $NA }
$NTUsr = Get-Item "$UserFolder\NTUSer.dat" -Force
if ($NTUsr) { $NTUsrTime = $NTUsr.LastWriteTime } else { $NTUsrTime = $NA }
$UsrClass = Get-Item "$UserFolder\AppData\Local\Microsoft\Windows\UsrClass.dat" -force
if ($UsrClass) { $UsrClassTime = $UsrClass.LastWriteTime } else { $UsrClassTime = $NA }
$IconCache = Get-Item "$UserFolder\AppData\Local\IconCache.db" -Force
if ($IconCache) { $IconCacheTime = $IconCache.LastWriteTime } else { $IconCacheTime = $NA}
$LastUpdated = $UserProfileTime,$NTUsrTime,$UsrClassTime,$IconCacheTime | Sort-Object | Select-Object -Last 1
if ($LastUpdated -lt $DeleteProfile) { $Delete = $True } else { $Delete = $False }
# $NTUsr.LastWriteTime = $UsrClassTime # Update NTUser.dat LastWriteTime to that of the UsrClass.dat File
[PSCustomObject]@{
UserName = $UserName
ProfileFullname = $UserFolder.FullName
UserProfileTime = $UserProfileTime
CimProfileTime = $CimProfileTime
NTUsrTime = $NTUsrTime
UsrClassTime = $UsrClassTime
IconCacheTime = $IconCacheTime
LastUpdated = $LastUpdated
Delete = $Delete
}
'UserName','UserProfileTime','CimProfile','CimProfileTime','NTUsr','NTUsrTime','UsrClass','UsrClassTime','IconCache','IconCacheTime','LastUpdated','Delete' | ForEach-Object { Remove-Variable $_ }
}
midnight51 : I found you solution to most perfect or best resolution to whatever solution or approach mentioned over web.
Great and appreciate