Updated version of script. Added logging and some small features.
------------------------------Logon_logoff-report_logs.ps1------------------------
#Run as Administrator (due to profile removal and system
info access).
#Set $dryRun = $false only when you're confident it's
safe.
#Check logs in C:\CleanupLogs.
#$dryRun = $true #
Set to $false to enable actual deletion
$dryRun = $false #
Set to $true to disable actual deletion
$logFolder = "C:\CleanupLogs"
if (-not
(Test-Path $logFolder)) { New-Item -Path $logFolder -ItemType Directory | Out-Null }
$timestamp = Get-Date -Format
"yyyy-MM-dd_HH-mm-ss"
$logFile = Join-Path $logFolder "ProfileCleanup_$timestamp.log"
function
Log {
param([string]$message)
$timeStamped = "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - $message"
Write-Host $timeStamped
Add-Content -Path
$logFile -Value $timeStamped
}
function
Translate-SID {
param (
[Parameter(Mandatory)]
[Alias("SID")]
$sid
)
try {
if ($sid -is [Security.Principal.SecurityIdentifier]) {
$sid.Translate([Security.Principal.NTAccount]).Value
} else {
$sidObj = New-Object
Security.Principal.SecurityIdentifier $sid
$sidObj.Translate([Security.Principal.NTAccount]).Value
}
}
catch {
return $sid
}
}
Log "Computer: $(systeminfo |
Select-String 'Host Name')"
Log "`nStarted: $(systeminfo
| Select-String 'System Boot Time')"
$freeSpaceStart = (Get-PSDrive C).Free / 1GB
Log "Free space before:
$([Math]::Round($freeSpaceStart,2)) GB"
$removedAcc = "special_user"
$currentUsers = @()
try {
$explorerOwners = Get-WmiObject -Class
Win32_Process | Where-Object { $_.Name
-eq "explorer.exe" } | ForEach-Object {
$_.GetOwner().User
}
$currentUsers += $explorerOwners
}
catch {
Log "Error retrieving user sessions: $_"
}
foreach ($user in $currentUsers) {
Log "Active session: $user"
if ($user -eq $removedAcc) {
$logoffId = ((quser
| Where-Object { $_ -match
$removedAcc }) -split '\s+')[2]
Log "Logging off $removedAcc (Session ID:
$logoffId)"
if (-not
$dryRun) {
logoff $logoffId
Get-CimInstance -Class Win32_UserProfile | Where-Object { $_.LocalPath.Split('\')[-1] -eq $removedAcc } | Remove-CimInstance
Log "$removedAcc profile removed"
} else {
Log "DRY RUN: Would log off and remove profile for
$removedAcc"
}
}
}
$temp1 =
Get-WinEvent -LogName "Microsoft-Windows-User
Profile Service/Operational" |
Where-Object { $_.Id -eq 1 } |
Select-Object @{Name='Account';
Expression={ Translate-SID1 $_.UserId
}}, TimeCreated
$uniqueAccounts = $temp1 | Select-Object -Unique
-Property
Account
$eventIn = foreach ($acct in $uniqueAccounts) {
$temp1 | Where-Object { $_.Account -eq $acct.Account
} | Select-Object -First
1
}
$userFolders = Get-ChildItem "C:\Users" | Select-Object -ExpandProperty
Name
$recentLogins = foreach ($folder in $userFolders) {
$acctName = "aka\$folder"
$eventIn | Where-Object { $_.Account -eq $acctName -and $_.TimeCreated
-gt (Get-Date).AddDays(-90) }
}
$recentLogins = $recentLogins | Where-Object { $_.Account -ne "aka\$removedAcc" }
$freshAccs = @("Public","admin","Administrator","Support","user8","TEMP",$env:USERNAME)
Log " Recent logins (last 90 days):"
if ($recentLogins.Count
-eq 0) {
Log "No recent logins (last 90 days)"
} else {
$recentLogins | ForEach-Object { Log $_.Account, $_.TimeCreated}
$freshAccs += $recentLogins.Account | ForEach-Object { $_.Split('\')[-1] }
}
$freshAccs = $freshAccs | Sort-Object -Unique
Log " Fresh accounts:"
$freshAccs | ForEach-Object { Log $_ }
#$deletedAccs = Compare-Object -ReferenceObject $freshAccs
-DifferenceObject $userFolders -PassThru
$deletedAccs = Compare-Object $freshAccs $userFolders -IncludeEqual | Where-Object { $_.SideIndicator
-eq '=>' }
Log " Accounts marked for deletion:"
$deletedAccs | ForEach-Object { Log $_.InputObject
}
foreach ($acct in $deletedAccs.InputObject) {
if ($freshAccs -notcontains $acct) {
$sidInfo = Get-WmiObject -Class
Win32_UserProfile | Where-Object { $_.LocalPath.Split('\')[-1] -eq $acct } | Select-Object -First
1
if ($sidInfo -and !$sidInfo.Loaded) {
if ($dryRun) {
Log "DRY RUN: Would delete profile for account $acct
(SID: $($sidInfo.SID))"
} else {
#Remove-CimInstance -InputObject $sidInfo
Get-CimInstance -Class Win32_UserProfile | Where-Object {($_.SID
-eq $sidInfo.SID) -and ($_.Loaded -eq $false)} |
Remove-CimInstance
Log "Account $acct (SID: $($sidInfo.SID)) DELETED"
}
}
}
}
$freeSpaceEnd = (Get-PSDrive C).Free / 1GB
$spaceSaved = $freeSpaceEnd - $freeSpaceStart
Log "Free space after:
$([Math]::Round($freeSpaceEnd, 2)) GB"
Log "Disk space saved:
$([Math]::Round($spaceSaved, 2)) GB"
Log "Cleanup script completed."
******************************
possible remove files:
del c:\Logon_logoff-report_logs.bat
del c:\Logon_logoff-report_logs.ps1
if need copy log files to shared folder:
NET USE U: \\192.168.1.10\Share Passw0rd9 /persistent:yes /user:aka\user1
xcopy "C:\CleanupLogs" "U:\CleanupLogs\" /Y
rd C:\CleanupLogs
/s /q