DeleteUserProfile.psm1
Function Get-RSUserProfile { <# .SYNOPSIS Return all user profiles that are saved on a computer .DESCRIPTION Return all user profiles that are saved on a local or remote computer and you can also delete one or all of the user profiles, the special windows profiles are excluded. You can also show all user profiles from multiple computers at the same time. .PARAMETER ComputerName The name of the remote computer you want to display all of the user profiles from. If you want to use it on a local computer you don't need to fill this one out. You can add multiple computers like this: -ComputerName "Win11-Test", "Win10" .EXAMPLE Get-RSUserProfile # This will return all of the user profiles saved on the local machine .EXAMPLE Get-RSUserProfile -ComputerName "Win11-Test" # This will return all of the user profiles saved on the remote computer "Win11-test" .EXAMPLE Get-RSUserProfile -ComputerName "Win11-Test", "Win10" # This will return all of the user profiles saved on the remote computers named Win11-Test and Win10 .LINK https://github.com/rstolpe/DeleteUserProfile/blob/main/README.md .NOTES Author: Robin Stolpe Mail: robin@stolpe.io Blog: https://stolpe.io Twitter: https://twitter.com/rstolpes Linkedin: https://www.linkedin.com/in/rstolpe/ GitHub: https://github.com/rstolpe PSGallery: https://www.powershellgallery.com/profiles/rstolpe #> [CmdletBinding()] Param( [Parameter(Mandatory = $false, HelpMessage = "Enter name of the computer or computers you want to collect user profiles from, multiple computer names are supported.")] [string[]]$ComputerName = "localhost" ) $CheckServiceModule = $(try { Get-InstalledModule -Name "rsServiceModule" -ErrorAction SilentlyContinue } catch { $null }) If ($null -eq $CheckServiceModule) { Write-Error "You must have rsServiceModule installed to use this function" break } $JobGetProfile = foreach ($_computer in $ComputerName) { Start-ThreadJob -Name $_computer -ThrottleLimit 50 -ScriptBlock { $CheckComputer = $(try { Test-WSMan -ComputerName $Using:_computer -ErrorAction SilentlyContinue } catch { $null }) if ($null -ne $CheckComputer) { try { # Open CIM Session $CimSession = $(try { New-CimSession -ComputerName $Using:_computer -ErrorAction SilentlyContinue } catch { $null }) if ($null -ne $CimSession) { # Collect all user profiles $GetUserData = Get-CimInstance -CimSession $CimSession -className Win32_UserProfile | Where-Object { $_.Special -eq $false } | Select-Object LocalPath, LastUseTime, Loaded | Sort-Object -Descending -Property LastUseTime $UserProfileData = foreach ($_profile in $GetUserData) { # Calculate how long it was the profile was used if (-Not([string]::IsNullOrEmpty($_profile.LastUseTime))) { $NotUsed = NEW-TIMESPAN -Start $_profile.LastUseTime -End (Get-Date) | Select-Object days, hours, Minutes | Foreach-Object { [PSCustomObject]@{ days = if ($Null -eq $_.Days -or $_.Days -eq "0") { $Null } else { $_.Days } hours = if ($Null -eq $_.Hours -or $_.Hours -eq "0") { $Null } else { $_.Hours } minutes = if ($Null -eq $_.Minutes -or $_.Minutes -eq "0") { $Null } else { $_.Minutes } } } } [PSCustomObject]@{ ProfileUserName = if ($null -ne $_profile.LocalPath) { $_profile.LocalPath.split('\')[-1] } ProfilePath = if ($null -ne $_profile.LocalPath) { $_profile.LocalPath } LastUsed = if ($null -ne $_profile.LastUseTime) { ($_profile.LastUseTime -as [DateTime]).ToString("yyyy-MM-dd HH:mm") } ProfileLoaded = if ($null -ne $_profile.Loaded) { $_profile.Loaded } NotUsed = if (-Not([string]::IsNullOrEmpty($NotUsed))) { $NotUsed } else { "N/A" } } } if ($null -ne $UserProfileData) { return $UserProfileData } else { Write-Output "No user profiles found on $($Using:_computer)" continue } } else { Write-Output "Could not connect to $($Using:_computer) trough WinRM, please check the connection and try again" continue } } catch { Write-Output "$($PSItem.Exception.Message)" continue } } else { Write-Output "Could not establish connection against $($Using:_computer)" continue } } } $ReturnProfiles = Receive-Job $JobGetProfile -AutoRemoveJob -Wait $ReturnProfiles } Function Remove-RSUserProfile { <# .SYNOPSIS Let you delete user profiles from a local or remote computer .DESCRIPTION Let you delete user profiles from a local computer or remote computer, you can also delete all of the user profiles. You can also exclude profiles. If the profile are loaded you can't delete it. The special Windows profiles are excluded .PARAMETER ComputerName The name of the remote computer you want to display all of the user profiles from. If you want to use it on a local computer you don't need to fill this one out. .PARAMETER UserName If you want to delete specific user profiles you can enter the username here. .PARAMETER Exclude This parameter only works if -All are used, here you can enter usernames that you want to exclude from the deletion. .PARAMETER All If you want to delete all of the user profiles on the local or remote computer you can use this switch .EXAMPLE Remove-RSUserProfile -All # This will delete all of the user profiles from the local computer your running the script from. Beside special and loaded profiles .EXAMPLE Remove-RSUserProfile -Exclude "User1", "User2" -All # This will delete all of the user profiles except user profile User1 and User2 on the local computer .EXAMPLE Remove-RSUserProfile -UserName "User1", "User2" # This will delete only user profile "User1" and "User2" from the local computer where you run the script from if the profile are not loaded. .EXAMPLE Remove-RSUserProfile -ComputerName "Win11-test" -All # This will delete all of the user profiles that are not special or loaded on the remote computer named "Win11-Test" .EXAMPLE Remove-RSUserProfile -ComputerName "Win11-test" -Exclude "User1", "User2" -All # This will delete all of the user profiles except user profile User1 and User2 on the remote computer named "Win11-Test" if the profile are not loaded .EXAMPLE Remove-RSUserProfile -ComputerName "Win11-test" -UserName "User1", "User2" # This will delete only user profile "User1" and "User2" from the remote computer named "Win11-Test" if the profile are not loaded .LINK https://github.com/rstolpe/DeleteUserProfile/blob/main/README.md .NOTES Author: Robin Stolpe Mail: robin@stolpe.io Blog: https://stolpe.io Twitter: https://twitter.com/rstolpes Linkedin: https://www.linkedin.com/in/rstolpe/ GitHub: https://github.com/rstolpe PSGallery: https://www.powershellgallery.com/profiles/rstolpe #> [CmdletBinding()] Param( [Parameter(Mandatory = $false, HelpMessage = "Enter computer name for the computer you want to delete user profiles from")] [string]$ComputerName = "localhost", [Parameter(Mandatory = $false, HelpMessage = "Enter the name of the user profiles that you want to delete, multiple names are supported")] [string[]]$UserName, [Parameter(Mandatory = $false, HelpMessage = "Use this switch if you want to delete all user profiles on the computer")] [switch]$All = $false, [Parameter(Mandatory = $false, HelpMessage = "Enter username of the user profiles that you want to exclude, multiple names are supported")] [string[]]$Exclude ) $CheckServiceModule = $(try { Get-InstalledModule -Name "rsServiceModule" -ErrorAction SilentlyContinue } catch { $null }) If ($null -eq $CheckServiceModule) { Write-Error "You must have rsServiceModule installed to use this function" break } if ($null -eq $UserName -and $All -eq $false) { Write-Output "You must enter a username or use the switch -All to delete user profiles!" break } $JobReturnMessage = [System.Collections.ArrayList]::new() $CheckComputer = $(try { Test-WSMan -ComputerName $_computer -ErrorAction SilentlyContinue } catch { $null }) if ($null -ne $CheckComputer) { # Open CIM Session $CimSession = $(try { New-CimSession -ComputerName $_computer -ErrorAction SilentlyContinue } catch { $null }) # Collecting all user profiles on the computer if ($null -ne $CimSession) { $GetAllProfiles = Get-CimInstance -CimSession $CimSession -ClassName Win32_UserProfile | Where-Object { $_.Special -eq $false } # Deleting all user profiles on the computer besides them that are special or loaded if ($All -eq $true) { $JobDelete = foreach ($_profile in $GetAllProfiles) { $UserNameFromPath = $_profile.LocalPath.split('\')[-1] $CheckProfile = Confirm-RSProfile -UserName $UserNameFromPath -ProfileData $GetAllProfiles -Exclude $Exclude if ($CheckProfile.ReturnCode -eq 0) { # Starting thread job to speed things up Start-ThreadJob -Name $UserNameFromPath -ThrottleLimit 50 -ScriptBlock { try { Write-Output "Deleting user profile $($Using:UserNameFromPath)..." $Using:_profile | Remove-CimInstance Write-Output "User profile $($Using:UserNameFromPath) are now deleted!" } catch { Write-Error "$($PSItem.Exception)" continue } } } else { [void]($JobReturnMessage.Add("$($CheckProfile.Message)")) continue } } } # if you don't want to delete all profiles but just one or more elseif ($All -eq $false) { $JobDelete = foreach ($_profile in $UserName) { $CheckProfile = Confirm-RSProfile -UserName $_profile -ProfileData $GetAllProfiles if ($CheckProfile.ReturnCode -eq 0) { $GetProfile = $GetAllProfiles | Where-Object { $_.LocalPath -like "*$($_profile)" } Start-ThreadJob -Name $_profile -ThrottleLimit 50 -ScriptBlock { Write-Output "Deleting user profile $($Using:_profile)..." try { $Using:GetProfile | Remove-CimInstance -ErrorAction SilentlyContinue Write-Output "The user profile $($Using:_profile) are now deleted!" } catch { Write-Error "$($PSItem.Exception)" continue } } } else { [void]($JobReturnMessage.Add("$($CheckProfile.Message)")) continue } } } if ($null -ne $JobDelete) { $ReturnProfileJob = Receive-Job $JobDelete -AutoRemoveJob -Wait $ReturnProfileJob $JobReturnMessage } else { $ReturnProfileJob $JobReturnMessage } } else { Write-Output "Could not connect to $($_computer) trough WinRM, please check the connection and try again" continue } } else { Write-Output "Could not establish connection against $($_computer)" continue } } Function Confirm-RSProfile { [CmdletBinding()] Param( [Parameter(Mandatory = $true, HelpMessage = ".")] [ValidateNotNullOrEmpty()] [string]$UserName, [Parameter(Mandatory = $true, HelpMessage = ".")] [ValidateNotNullOrEmpty()] $ProfileData, [Parameter(Mandatory = $true, HelpMessage = ".")] [ValidateNotNullOrEmpty()] $Exclude ) $CheckExists = $ProfileData | Where-Object { $_.LocalPath -like "*$($UserName)" } if ($UserName -in $Exclude) { $CheckExclude = $true } else { $CheckExclude = $false } if ($null -ne $CheckExists -and $CheckExclude -eq $false) { if ($CheckExists.Loaded -eq $true) { Get-ReturnMessageTemplate -ReturnType Error -Message "User profile $($UserName) are loaded can't remove it" } else { Get-ReturnMessageTemplate -ReturnType Success -Message "User profile $($UserName) exists and are not loaded" } } elseif ($null -ne $CheckExists -and $CheckExclude -eq $true) { Get-ReturnMessageTemplate -ReturnType Error -Message "User profile $($UserName) are excluded and will not be deleted" } else { Get-ReturnMessageTemplate -ReturnType Error -Message "User profile $($UserName) does not exist on the computer" } } |