Удалить профиль пользователя windows powershell

Администраторы время от времени должны удалять старые профили пользователей (уволенные пользователи, неактивные пользователи, и т.д.) в каталоге C:\Users на рабочих станциях и серверах Windows. Чаще всего с задачей очисткой профилей пользователей Windows сталкиваются на терминальных серверах RDS (Remote Desktop Services).

Основная проблема терминальных серверов – постоянный рост размеров каталогов профилей пользователей на диске. Частично эта проблема решается политиками квотирования размера профиля пользователя с помощью FSRM или NTFS квот, использованием профилей типа FSLogix или User Profile Disk, перемещаемыми папками и т.д. Но при большом количестве RDS пользователей в папке C:\Users со временем накапливается огромное количество каталогов с неиспользуемыми профилями пользователей.

Содержание:

  • Как вручную удалить профиль пользователя в Windows?
  • Групповая политика для автоматической очистки старых профилей
  • PowerShell скрипт для удаления старых профилей пользователей в Windows

Как вручную удалить профиль пользователя в Windows?

В Windows вы можете вручную удалить профиль пользователя через панель управления.

  1. Откройте Advanced System Settings (команда
    SystemPropertiesAdvanced
    ) -> User Profiles -> Settings;
  2. В этом окне перечислен список всех профилей пользователей (локальных и доменных), которые хранятся на этом компьютере. Размер каждого профиля пользователя на диске указан в столбце Size.
  3. Выберите пользователя, чей профиль нужно удалить и нажмите кнопку Delete.Удалить с диска профиль пользователя Windows вручную

В Windows 11/10 и Windows Server 2022/2019 вы можете удалить профили пользователей с диска через приложение Settings. Перейдите в раздел Accounts -> Access work and school (или выполните команду быстрого доступа
ms-settings:otherusers
). Выберите пользователя и нажмите Remove чтобы удалить его данные с компьютера.

ms-settings: удалить с диска профиль пользователя windows 11

При корректном удалении профиля пользователя с диска будет удален каталог профиля в C:\Users и запись о пользователе в реестре.

Многие начинающиеся администраторы пытаются вручную удалить каталог с профилем пользователя из папки C:\Users. В этом случае нужно обязательно вручную удалить информацию о профиле из реестра Windows:

  1. Откройте редактор реестра
    regedit.exe
    ;
  2. Перейдите в ветку HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
  3. Для каждого пользователя, выполнившего локальный вход в систему (этот метод входа должен быть разрешен пользователю настройками параметра Allow log on locally в GPO), создается отдельная ветка с SID пользователя в качестве имени;
  4. Вы можете найти раздел реестра, соответствующий пользователю по SID, или можете вручную просмотреть содержимое всех вложенных разделв, пока не найдете раздел, в котором значение ProfileImagePath указывает на каталог с профилем пользователя на диске (например,
    C:\Users\kbuldogov
    );путь к профилю пользователя в реестре ProfileImagePath
  5. Удалите данный раздел реестра, чтобы завершить корректное удаление профиля.

Также вы можете удалить профиль конкретного пользователя с помощью PowerShell:

Get-CimInstance -Class Win32_UserProfile | Where-Object { $_.LocalPath.split(‘\’)[-1] -eq 'kbuldogov' } | Remove-CimInstance

Эта команда удалит как каталог на диске, так и ссылку на профиль пользователя kbuldogov в реестре HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList.

Эта команда будет работать как в Windows PowerShell, так и в новых версиях PowerShell Core 6.x,7.x

Можно удалить профиль пользователя на удаленном компьютере с помощью PowerShell Remoting и командлета Invoke-Command:

$compname="wks21s32"
$user = "kbuldogov"
Invoke-Command -ComputerName $compname -ScriptBlock {
param($user)
Get-CimInstance -Class Win32_UserProfile | Where-Object { $_.LocalPath.split(‘\’)[-1] -eq $user } | Remove-CimInstance
} -ArgumentList $user

Групповая политика для автоматической очистки старых профилей

В Windows есть специальный параметр групповой политики для автоматического удаления старых профилей пользователей старше xx дней. Вы можете включить этот параметр с помощью локального редактора GPO (
gpedit.msc
) или с помощью консоли управления доменными GPO (
gpmc.msc
). В этом примере на назначим политику автоматической очистки профилей на хосты в ферме RDS, которые вынесены в отдельный контейнер (Organizational Unit) Active Directory.

Прежде чем применять политику удаления старых профилей ко всем хостам, настоятельно рекомендуем проверить ее на тестовом сервере. Выведите один из серверов RDSH в режим обслуживания и протестируйте политику на нем.

  1. Найдите OU с компьютерами/серверами, на который вы хотите применить политику очистки старых профилей пользователей. Щелкните по OU и выберите Create a GPO in this domain and Link it here;gpo создать политику для удаления старых и неактивных профилей
  2. Укажите имя политики и отредактируйте GPO;
  3. Перейдите в раздел Конфигурация компьютера -> Административные шаблоны -> Система -> Профили пользователей (Computer Configuration -> Administrative Templates -> System -> User Profiles);
  4. Откройте параметр “Удалять при перезагрузке системы профили пользователей по истечении указанного числа дней” (Delete user profiles older than a specified number days on system restart);
  5. Включите политику и укажите через сколько дней профиль пользователя считается неактивным и “Служба профилей пользователей Windows” можно автоматически удалить такой профиль при следующей перезагрузке. Обычно тут стоит указать не менее 45-90 дней;gpo удалить профили старше 60 дней при перезагрузке
  6. После применения новых настроек групповых политк, служба User Profile Services на ваших серверах Windows будет автоматически удалять старые профили пользователей. Удаление выполняется при перезагрузке сервера.

При использовании этой политики нужно быть уверенным, что при выключении/перезагрузке сервера нет проблем с системным временем (время не сбивается), иначе могут быть удалены профили активных пользователей.

Другой недостаток — вы не можете запретить удаление определенных профилей, например, локальных учетных записей, администраторов и т.д.

В версиях до Windows 11/10 и Windows Server 2022/2019 эта политика работала некорректно. Дело в том, что неактивноть профиля пользователя ранее определялась по дате именения файла NTUSER.dat. При установке обновлений Windows, служба Trusted Installer может менять дату изменения файла NTUSER.dat в профиле каждого пользователя. В результате служба Win32_UserProfile считает, что профиль использовался недавно.

В современных версиях Windows эта политика проверяет активность профиля пользователей по параметрам LocalProfileUnloadTimeLow и LocalProfileUnloadTimeHigh в ветке
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\<User Sid>
.

LocalProfileLoadTimeLow в ветке реестра ProfileList

Вы можете получить значения параметров реестра LocalProfileLoadTimeLow и LocalProfileUnloadTimeHigh в привычном формате времени с помощью скрипта:

$profilelist = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
foreach ($p in $profilelist) {
    try {
        $objUser = (New-Object System.Security.Principal.SecurityIdentifier($p.PSChildName)).Translate([System.Security.Principal.NTAccount]).value
    } catch {
        $objUser = "[UNKNOWN]"
  }
    Remove-Variable -Force LTH,LTL,UTH,UTL -ErrorAction SilentlyContinue
    $LTH = '{0:X8}' -f (Get-ItemProperty -Path $p.PSPath -Name LocalProfileLoadTimeHigh -ErrorAction SilentlyContinue).LocalProfileLoadTimeHigh
    $LTL = '{0:X8}' -f (Get-ItemProperty -Path $p.PSPath -Name LocalProfileLoadTimeLow -ErrorAction SilentlyContinue).LocalProfileLoadTimeLow
    $UTH = '{0:X8}' -f (Get-ItemProperty -Path $p.PSPath -Name LocalProfileUnloadTimeHigh -ErrorAction SilentlyContinue).LocalProfileUnloadTimeHigh
    $UTL = '{0:X8}' -f (Get-ItemProperty -Path $p.PSPath -Name LocalProfileUnloadTimeLow -ErrorAction SilentlyContinue).LocalProfileUnloadTimeLow
    $LoadTime = if ($LTH -and $LTL) {
        [datetime]::FromFileTime("0x$LTH$LTL")
    } else {
        $null
    }
    $UnloadTime = if ($UTH -and $UTL) {
        [datetime]::FromFileTime("0x$UTH$UTL")
    } else {
        $null
    }
    [pscustomobject][ordered]@{
        User = $objUser
        SID = $p.PSChildName
        Loadtime = $LoadTime
        UnloadTime = $UnloadTime
    }
} 

получить время последнего входа в профиль в windows

PowerShell скрипт для удаления старых профилей пользователей в Windows

Вы можете удалять профили неактивных или заблокированных пользователей с помощью скрипта PowerShell.

Сначала попробуем подсчитать размер профиля каждого пользователя в папке C:\Users c помощью простого скрипта из статьи “Вывести размер папок с помощью PowerShell”:

gci -force ‘C:\Users\’-ErrorAction SilentlyContinue | Where { !($_.Attributes -match " ReparsePoint") }| ? { $_ -is [io.directoryinfo] } | % {
$len = 0
gci -recurse -force $_.fullname -ErrorAction SilentlyContinue | % { $len += $_.length }
$_.fullname, ‘{0:N2} GB’ -f ($len / 1Gb)
$sum = $sum + $len
}
“Общий размер профилей”,'{0:N2} GB’ -f ($sum / 1Gb)

Итого суммарный размер всех профилей пользователей в каталоге C:\Users около 22 Гб.

суммарный размер всех профилей пользвоателей

Теперь выведем список пользователей, профиль которых не использовался более 60 дней. Для поиска можно использовать значение атрибута профиля LastUseTime.

Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))}| Measure-Object

У меня на терминальном сервере оказалось 143 профиля неактивных пользователей (общим размером около 10 Гб).

получить список неактивных пользователей с профилями

Следующий PowerShell скрипт выведет список подробную информацию о профилях пользователей, которые не обновлялись более 60 дней. Скрипт сконвертирует SID пользователя в имя, посчитает размер профиля каждого пользователя и выведет все в таблице:

$allprofilesinfo = @()
$OldProfiles=Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))}
Foreach ($OldProfile in $OldProfiles)
   {$objSID = New-Object System.Security.Principal.SecurityIdentifier ($OldProfile.SID)
    $objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
        $userinfo = New-Object PSObject -Property @{
            userName = $objUser.Value
            ProfilePath = $OldProfile.localpath
            LastUsedDate = $OldProfile.ConvertToDateTime($OldProfile.LastUseTime)
            FolderSize =  "{0:N2} GB" -f ((gci –force $OldProfile.localpath –Recurse -ErrorAction SilentlyContinue| measure Length -s).sum / 1Gb) 
        }
    $allprofilesinfo += $userinfo
   }
$allprofilesinfo 

скрипт для получения размера старых профилей на диске

Чтобы удалить все эти профили достаточно добавить перенаправить список на команду Remove-WmiObject (перед использование скрипта удаления желательно несколько раз перепроверить его вывод с помощью параметра –WhatIf ):

Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))} | Remove-WmiObject –WhatIf

Как мы уже упомянули выше, при установке некоторых обновлений Windows, служба Trusted installer может менять дату изменения файла NTUSER.dat в профиле каждого пользователя.

На скриншоте выше видно, что все профили были изменены примерно в одно и тоже время. Проверьте дату последней установки обновлений в Windows:

gwmi win32_quickfixengineering |sort installedon  |select InstalledOn -Last 1

Или с помощью модуля PSWindowsUpdate:

Get-WUHistory | Select-Object -First 20

Скорее всего она совпадет с датой изменения профилей. Поэтому в старых версиях Windows можно получить список неактивных профилей с помощью другого скрипта, который проверяет атрибуту lastwritetime каталога пользователя:

$USERS= (Get-ChildItem -directory -force 'C:\Users' | Where { ((Get-Date) — $_.lastwritetime).days -ge 60 } | % {'c:\users\' + $_.Name})
foreach ($User in $USERS) {
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.LocalPath -eq $User)} | Remove-WmiObject WhatIf }

Чтобы не удалять профили некоторых пользователей, например, специальные аккаунты System и Network Service, учетную запись локального администратора, пользователей с активными сессиями, список аккаунтов-исключений), нужно модифицировать скрипт следующим образом:

#Список аккаунтов, чьи профили нельзя удалять
$ExcludedUsers ="Public","zenoss","svc",”user_1”,”user_2”
$LocalProfiles=Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))}
foreach ($LocalProfile in $LocalProfiles)
{
if (!($ExcludedUsers -like $LocalProfile.LocalPath.Replace("C:\Users\","")))
{
$LocalProfile | Remove-WmiObject
Write-host $LocalProfile.LocalPath, "профиль удален” -ForegroundColor Magenta
}
}

Вы можете настроить запуск этого скрипта через shutdown скрипт групповой политики или по расписанию заданием планировщика. (перед настройкой автоматического удаления профилей внимательно протестируйте скрипт в своей среде!).

Можно модифицировать скрипт, чтобы автоматически удалять пользователи всех пользователей, которые добавлены в определенную группу AD. Например, вы хотите автоматически удалять профили уволившихся пользователей. Просто добавьте такие учетные записи в группу DisabledUsers и выполните на сервере скрипт:

$users = Get-ADGroupMember -Identity DisabledUsers | Foreach {$_.Sid.Value}
$profiles = Get-WmiObject Win32_UserProfile
$profiles | Where {$users -eq $_.Sid} | Foreach {$_.Delete()}

A common pain point in an IT administrator’s career is user profiles. User profiles are a ubiquitous part of a Windows IT pro’s life; especially those that manage virtual desktop environments like Remote Desktop Services (RDS) or Citrix. In this post, I’m going to demonstrate a way you take out your aggression by using PowerShell to delete user profiles (and discover them).

Windows system administrators have to deal with:

  • corrupted user registry hives
  • files that need shared across all user profiles
  • figuring out how to recreate corrupt profiles
  • …and more

What was once a frustrating experience has gotten a little less frustrating with PowerShell. Here are a few ways that PowerShell can make managing Windows user profiles easier.

Manage and Report Active Directory, Exchange and Microsoft 365 with ManageEngine ADManager Plus. Download Free Trial!

Enumerating User Profiles

It’s easy to take a peek at user profiles on the file system on a single Windows computer. Simply look in the C:\Users folder. But not only are you not getting the full picture when you do this, it’s also troublesome due to potential file system access problems. There’s a better way and that’s through WMI or CIM. In CIM, a class exists called Win32_UserProfile. This class contains all of the profiles that exist on a machine and lots of other useful information that a simple file system folder won’t tell you.

Using PowerShell, you can access this CIM class with the Get-CimInstance command.

Below, I’m finding the first user profile on the the local computer. You’ll notice many useful tidbits of information like LastUseTime, SID and so on.

PS C:\> Get-CimInstance -ClassName win32_userprofile | Select-Object -First 1


AppDataRoaming                   : Win32_FolderRedirectionHealth
Contacts                         : Win32_FolderRedirectionHealth
Desktop                          : Win32_FolderRedirectionHealth
Documents                        : Win32_FolderRedirectionHealth
Downloads                        : Win32_FolderRedirectionHealth
Favorites                        : Win32_FolderRedirectionHealth
HealthStatus                     : 3
LastAttemptedProfileDownloadTime :
LastAttemptedProfileUploadTime   :
LastBackgroundRegistryUploadTime :
LastDownloadTime                 :
LastUploadTime                   :
LastUseTime                      : 3/14/2019 3:06:39 PM
Links                            : Win32_FolderRedirectionHealth
Loaded                           : False
LocalPath                        : C:\Users\.NET v4.5 Classic
Music                            : Win32_FolderRedirectionHealth
Pictures                         : Win32_FolderRedirectionHealth
RefCount                         :
RoamingConfigured                : False
RoamingPath                      :
RoamingPreference                :
SavedGames                       : Win32_FolderRedirectionHealth
Searches                         : Win32_FolderRedirectionHealth
SID                              : S-1-5-82-3876422241-1344743610-1729199087-774402673-2621913236
Special                          : False
StartMenu                        : Win32_FolderRedirectionHealth
Status                           : 0
Videos                           : Win32_FolderRedirectionHealth
PSComputerName                   :

The Get-CimInstance cmdlet not only works locally but remotely as well. By using the ComputerName parameter, you can specify, 1, 10 or 100 different remote computers and it will happily query each one.

PS C:\> Get-CimInstance -ClassName Win32_UserProfile -ComputerName localhost,WINSRV

Deleting User Profiles

Once you understand how to enumerate user profiles on computers, you can take it one step further and delete those user profiles as well.

I can’t count how many times I’ve had to delete user profiles because something got corrupted and I just needed the user to log in again and recreate it. At one time, I would simply have the user log off and remove the C:\Users<UserName> folder from the file system. Usually it works, sometimes it didn’t. What I didn’t realize was that I was actually leaving some remnants behind.

The proper way to do this is to initiate a removal via CIM.

Using the same CIM class you just went over, it’s possible to not only just view profiles but you can completely remove them as well. This is the same as going into the User Profiles box under System settings and hitting the Delete button.

User Profiles
User Profiles

To do this, enumerate the user profiles again and this time apply a filter to pick a single user profile to remove. In this case, remove the user profile called UserA. You can do this by using PowerShell’s Where-Object cmdlet and some string manipulation to grab the user folder name from the LocalPath property as shown below.

Once you’re able to narrow down that single profile you can pass that CIM instance to the Remove-CimInstance cmdlet for each object that Get-CimInstance returns. This process will remove the user profile from the file system and the registry.

Get-CimInstance -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq 'UserA' } | Remove-CimInstance

Again, if you’d like to extend this to multiple computers you’d simply use the ComputerName parameter on Get-CimInstance.

Get-CimInstance -ComputerName SRV1,SRV2,SRV3 -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq 'UserA' } | Remove-CimInstance

Manage and Report Active Directory, Exchange and Microsoft 365 with ManageEngine ADManager Plus. Download Free Trial!

Summary

You’ve now seen an easy way to enumerate and delete Windows user profiles. If you weren’t aware of the CIM class Win32_UserProfile you may have been correlating the C:\Users<Username> folder as the profile but you should know to delete the Win32_UserProfile CIM instance now.

You can see there’s much more to the user profile than a simple file system folder. Use CIM the next time you need to query or delete user profiles from Windows computers in your environment.

  • Remove From My Forums
  • Question

  • Helo, guys!

    I need to be able to delete all user’s profiles on all workstations in case of emergency. I have read similiar topics, but don’t think it’s suitable for me, so I need some help.

    All workstations are working under Win7Pro, so I want to use PowerShell for this duty and I think I can use New-PSSession cmdlet to establish sessions to all my workstations, after that I need to log off users and delete profiles.

    I tried to delete a profile at my localhost with next command:

    ( Get-WmiObject -Class Win32_UserProfile | Where-Object { $_.LocalPath -eq ‘c:\users\user’ } ).Delete()

    but get an exception: Exception calling «Delete» with «0» argument(s)

    I thought this method needs some args, but I couldn’t find its definition or syntax neither with Get-Member, nor at MSDN. Can you point me — what does this error mean?

    By the way — is there an easy way to log off users from system with PowerShell?

    Thanks for all replies!

Answers

  • Hi,

    As Thomas mentioned, the Win32_Profile class has no Delete method. Also, I don’t recommend simply deleting the directory as this doesn’t remove the data associated with the profile from the registry (see

    Deleting a Local User Profile — Not as easy as one Might Assume). I haven’t used it, but Helge Klein’s

    delprof2.exe program looks like a workable replacement for Microsoft’s
    Delprof utility (which looks like in only works on XP/2003 and older).

    HTH,

    Bill

    • Marked as answer by

      Tuesday, May 24, 2011 12:40 PM

    • Unmarked as answer by
      DmitriyPKCC
      Saturday, March 24, 2012 5:47 PM
    • Proposed as answer by
      Bill_Stewart
      Saturday, March 24, 2012 5:56 PM
    • Marked as answer by
      DmitriyPKCC
      Saturday, March 24, 2012 6:30 PM

Administrators should occasionally delete old user profiles (retired or inactive users, etc.) from C:\Users on Windows workstations and servers. The Windows user profile cleanup task is most commonly performed on Remote Desktop Services (RDS) terminal servers.

The main problem with RDS servers is the constant growth in the size of the user profile directories on the hard disk. This problem is partially solved by user profile size quotas using FSRM or NTFS quotas, using roaming profiles such as FSLogix or User Profile Disk, redirected folders, etc. However, if you have a large number of RDS users, over time the C:\Users folder will contain a large number of directories with old (unused) user profiles.

Contents:

  • How to Delete a User Profile in Windows Manually?
  • GPO: Delete User Profiles Older Than a Specified Number of Days
  • Delete Old User Profiles with PowerShell Script

How to Delete a User Profile in Windows Manually?

In Windows, you can delete a profile manually from the Control Panel:

  1. Open the Advanced System Settings (run the command SystemPropertiesAdvanced ) and go to User Profiles -> Settings;
  2. This window lists all the user profiles (local, domain, and Microsoft accounts) stored on this computer. The size of each user profile on disk is listed in the Size column;
  3. Select the user whose profile you want to delete and click the Delete button. removing user profile manually in windows

On Windows 11/10 and Windows Server 2022/2019, you can delete user profiles from disk through the Settings app. Go to Accounts -> Access work and school (or run the URI shortcut ms-settings:otherusers ). Select a user and click Remove to delete their profile data from the computer.

ms-settings - remove user profile in windows 11

When a user profile is properly deleted in Windows, the profile directory in C:\Users and the user entry in the registry are deleted.

Many novice administrators try to manually remove the user profile directory from the C:\Users folder. In this case, you will need to manually delete the profile reference from the Windows registry:

  1. Run the Registry Editor (regedit.exe);
  2. Go to the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList;
  3. For each user logged in locally (this login method must be allowed for the user by the Allow log on locally GPO option), a separate sub-key is created with the user’s SID as the name;
  4. You can find the registry key corresponding to the user by its SID, or you can manually browse the contents of all subkeys until you find a key in which the ProfileImagePath value points to the directory with the user profile on disk (for example, C:\Users\j.smith);profileimagepath in registry
  5. Delete this registry key to complete the correct removal of the profile.

You can also delete a specific user’s profile using PowerShell:

Get-CimInstance -Class Win32_UserProfile | Where-Object { $_.LocalPath.split(‘\’)[-1] -eq 'j.smith' } | Remove-CimInstance

This command removes both the hard drive directory and the j.smith user profile reference uthe nder HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList registry.

You can remove a user profile on a remote computer using PowerShell Remoting and the Invoke-Command cmdlet:

$compname="mun-wks92s3"
$user = "j.smith"
Invoke-Command -ComputerName $compname -ScriptBlock {
param($user)
Get-CimInstance -Class Win32_UserProfile | Where-Object { $_.LocalPath.split(‘\’)[-1] -eq $user } | Remove-CimInstance
} -ArgumentList $user

GPO: Delete User Profiles Older Than a Specified Number of Days

In Windows, there is a built-in Group Policy option to automatically delete user profiles older than xx days. You can enable this option using the Local Group Policy Editor (gpedit.msc) or with the domain GPO management console (gpmc.msc). In this example, we are going to apply an automatic profile cleanup policy to hosts in the RDS farm that are in a separate container (Organizational Unit, OU) in Active Directory.

  1. Locate the OU containing the computers/servers to which you want to apply the user profile cleanup policy.  Right-click on the OU and select Create a GPO in this domain and Link it here;create new domain gpo
  2. Specify the policy name and edit the GPO;
  3. Navigate to Computer Configuration -> Administrative Templates -> System -> User Profiles;
  4. Open the option Delete user profiles older than a specified number of days on system restart;
  5. Enable the policy and specify the number of days a user profile is considered active. When this period is over, Windows User Profile Service will automatically delete the profile at the next restart. It is recommended to specify the period of 45-90 days here;Group Policy: Delete user profiles older than a specified number days on system restart
  6. After you apply the new Group Policy settings, User Profile Service on your Windows Server will automatically delete the old user profiles. User profiles will be deleted at the next server reboot.

If you use this policy, you must ensure that there are no problems with the system time when the server is stopped/restarted (check the article “System time and date changes after reboot”). Otherwise, active user profiles may be deleted.

Another disadvantage is that you cannot prevent certain profiles from being removed, such as local accounts, administrators, etc.

This policy didn’t work correctly in versions prior to Windows 11/10 and Windows Server 2022/2019. Previously, user profile inactivity was determined by the date the NTUSER.dat file was modified. When installing Windows updates, the Trusted Installer service can change the modification date of the NTUSER.dat file in each user’s profile. As a result, the Win32_UserProfile service thinks that the profile has been used recently.

In modern versions of Windows, this Group Policy option checks for user profile activity against the values of the LocalProfileUnloadTimeLow and LocalProfileUnloadTimeHigh parameters under in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\<USER_SID>

Get profile load time from registry parameter LocalProfileUnloadTimeHigh

You can use the following script to get the LocalProfileLoadTimeLow and LocalProfileUnloadTimeHigh registry values in normal time format:

$profilelist = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
foreach ($p in $profilelist) {
    try {
        $objUser = (New-Object System.Security.Principal.SecurityIdentifier($p.PSChildName)).Translate([System.Security.Principal.NTAccount]).value
    } catch {
        $objUser = "[UNKNOWN]"
  }
    Remove-Variable -Force LTH,LTL,UTH,UTL -ErrorAction SilentlyContinue
    $LTH = '{0:X8}' -f (Get-ItemProperty -Path $p.PSPath -Name LocalProfileLoadTimeHigh -ErrorAction SilentlyContinue).LocalProfileLoadTimeHigh
    $LTL = '{0:X8}' -f (Get-ItemProperty -Path $p.PSPath -Name LocalProfileLoadTimeLow -ErrorAction SilentlyContinue).LocalProfileLoadTimeLow
    $UTH = '{0:X8}' -f (Get-ItemProperty -Path $p.PSPath -Name LocalProfileUnloadTimeHigh -ErrorAction SilentlyContinue).LocalProfileUnloadTimeHigh
    $UTL = '{0:X8}' -f (Get-ItemProperty -Path $p.PSPath -Name LocalProfileUnloadTimeLow -ErrorAction SilentlyContinue).LocalProfileUnloadTimeLow
    $LoadTime = if ($LTH -and $LTL) {
        [datetime]::FromFileTime("0x$LTH$LTL")
    } else {
        $null
    }
    $UnloadTime = if ($UTH -and $UTL) {
        [datetime]::FromFileTime("0x$UTH$UTL")
    } else {
        $null
    }
    [pscustomobject][ordered]@{
        User = $objUser
        SID = $p.PSChildName
        Loadtime = $LoadTime
        UnloadTime = $UnloadTime
    }
} 

Get last profile load and unload date with PowerShell

This list contains the last load time for each user profile.

Delete Old User Profiles with PowerShell Script

Instead of using the automatic profile cleanup policy described above, you can use a simple PowerShell script to find and remove the profiles of disabled or inactive users.

First, let’s try to calculate the size of each user’s profile in C:\Users using a simple script from the article Getting Folder Size with PowerShell

gci -force ‘C:\Users\’-ErrorAction SilentlyContinue | Where { !($_.Attributes -match " ReparsePoint") }| ? { $_ -is [io.directoryinfo] } | % {
$len = 0
gci -recurse -force $_.fullname -ErrorAction SilentlyContinue | % { $len += $_.length }
$_.fullname, ‘{0:N2} GB’ -f ($len / 1Gb)
$sum = $sum + $len
}
"Total size of profiles",'{0:N2} GB' -f ($sum / 1Gb)

The total size of all user profiles in C:\Users is about 32 GB.

count the total user profile size on RDS host

Let’s see the list of users whose profiles have not been used for more than 60 days. You can use the value in the LastUseTime field of the profile to find them.

Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))}| Measure-Object

It turned out that I had 127 inactive user accounts on my RDS host (with profiles total size of about 18 GB).

get inactive users list by profile LastUseTime on RDSH

The following PowerShell script lists the details of user profiles that have not been updated for more than 60 days. The script converts the user’s SID to a name, calculates the size of each user’s profile, and displays a resulting table:

$allprofilesinfo = @()
$OldProfiles=Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))}
Foreach ($OldProfile in $OldProfiles)
   {$objSID = New-Object System.Security.Principal.SecurityIdentifier ($OldProfile.SID)
    $objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
        $userinfo = New-Object PSObject -Property @{
            userName = $objUser.Value
            ProfilePath = $OldProfile.localpath
            LastUsedDate = $OldProfile.ConvertToDateTime($OldProfile.LastUseTime)
            FolderSize =  "{0:N2} GB" -f ((gci –force $OldProfile.localpath –Recurse -ErrorAction SilentlyContinue| measure Length -s).sum / 1Gb) 
        }
    $allprofilesinfo += $userinfo
   }
$allprofilesinfo

powershell: list local profiles info

To remove all these user profiles, it is sufficient to pipe the list of users to the Remove-WmiObject command (it is recommended that you check the output of the script with the -WhatIf parameter before running it):

Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))} | Remove-WmiObject –WhatIf

As mentioned earlier, when installing some Windows updates, the Trusted Installer service can change the modification date of the NTUSER.dat file in each user’s profile.

The screenshot above shows that all profiles were changed at about the same time. Check the date of the last updates installed in Windows:

gwmi win32_quickfixengineering |sort installedon  |select InstalledOn -Last 1

Or using the PSWindowsUpdate module:

Get-WUHistory | Select-Object -First 10

It will most likely coincide with the date the profiles were changed. Therefore, on earlier versions of Windows, you can get a list of inactive profiles using another script that checks the lastwritetime attribute of the user’s profile directory:

$USERS= (Get-ChildItem -directory -force 'C:\Users' | Where { ((Get-Date) — $_.lastwritetime).days -ge 60 } | % {'c:\users\' + $_.Name})
foreach ($User in $USERS) {
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.LocalPath -eq $User)} | Remove-WmiObject WhatIf }

To avoid deleting the profiles of some users (such as System and Network Service accounts, a local administrator account, accounts of users having active sessions, and other accounts from the exception list), you can modify the script as follows:

#The list of accounts, which profiles must not be deleted
$ExcludedUsers ="Public","zabbix_agent","svc",”user_1”,”user_2”
$LocalProfiles=Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))}
foreach ($LocalProfile in $LocalProfiles)
{
if (!($ExcludedUsers -like $LocalProfile.LocalPath.Replace("C:\Users\","")))
{
$LocalProfile | Remove-WmiObject
Write-host $LocalProfile.LocalPath, "profile deleted” -ForegroundColor Magenta
}
}

You can run this PowerShell script via a GPO at shutdown or with a PowerShell script in Task Scheduler.

It is recommended that you test the script in your environment before configuring automatic profile deletion!

You can modify the script to automatically delete all user profiles added to the specific AD group. For example, you want to delete the profiles of users who have quit. Just add these accounts to the DisabledUsers group and run the script on the target host:

$users = Get-ADGroupMember -Identity DisabledUsers | Foreach {$_.Sid.Value}
$profiles = Get-WmiObject Win32_UserProfile
$profiles | Where {$users -eq $_.Sid} | Foreach {$_.Delete()}

WHy script this when the enterprise approach is GPO.

How to Delete Old User Profiles Using GPO and PowerShell?

No reason to do this from scratch, leverage what others have provided…

Use PowerShell to remove local profiles

How to delete user profiles older than a specified number of days in Windows

…as well as the modules from the MS powershellgallery.com, as you look at whatever approach you decide use.

Find-Module -Name '*user*profile*' | Format-Table -AutoSize

<#
# Results

Version Name                               Repository Description
------- ----                               ---------- -----------
1.0     UserProfile                        PSGallery  This module manages user profiles on local and remote computers
0.1.1   Microsoft.Graph.Users.ProfilePhoto PSGallery  Microsoft Graph PowerShell Cmdlets
1.0.6   Get-UserProfile                    PSGallery  The Get-UserProfile module list or remove User Profiles from local
#>

Find-Module -Name '*userprofile*' | Format-List -Force

Update

Yet, you specifically said…

‘I understand the method I am using is not the best. I was wondering
what would be a better way to do it?

… and what we all have suggested, using GPO is the best way, the normal industry-accepted enterprise way to do this. Don’t script, unless you have no other choice. Windows AD will do this for you.

Don’t reinvent the wheel unless you know it’s really a better wheel. In learning, of course, there is study, trial, and error, but learn and use from sources that have already done this. There are tons of examples all over the web for this use case. Just search for it. No reason to do this from scratch.

‘powershell remove user profiles’

Which are showing what you are already doing… Example(s) — pre-built scripts for this use case via the Ms powershellgallery.com.

Use PowerShell delete a user profile (step-by-step guide)

Get-CimInstance -ComputerName SRV1,SRV2,SRV3 -Class Win32_UserProfile | 
Where-Object { $_.LocalPath.split('\')[-1] -eq 'UserA' } | 
Remove-CimInstance

Remove-UserProfile — Remove Local User Profiles and Clean C:\Users Directory

This script contains a function (Remove-UserProfile) which is used to
remove user profiles, and additional contents of the C:\Users
directory (if specified) on a local computer.

Download: Remove-UserProfile.ps1

Delete Unused user Profiles on local machine (PowerShell)

Script Delete user profiles over multiple servers v2

ANd using the modules that you see from the above commands, is not something to do later in life. Those are in / available from MS and in PowerShell directly for a reason. Everything you are using in PowerShell is coming from modules hosted on your machine and the ones you download and install from MS and other resources.

Again, use the built-in enterprise tools in Windows or other chosen OS as designed, and if they don’t provide what you need, then look to other options, like scripting to an object-level that the enterprise tool is not exposing in its GUI.

  • Удалить прокси сервер на windows 10 как
  • Удалить программу по умолчанию windows 10
  • Удалить приложения windows 10 скачать
  • Удалить приложение погода windows 10
  • Удалить приложение из командной строки windows