9 May 2025

Remove old profile older than ... + logging (updated)

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 /