doctorbill
asked on
User Profiles
Does anyone have a powershell script that checks the age of a user profile on a terminal server and deletes it if it has been unused for a specific time or is older than a certain date?
ASKER
This script gives an error:
gci -force 'C:\Users'-ErrorAction SilentlyContinue | ? { $_ -is [io.directoryinfo] } | % {$len = 0gci -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)
Error:
ForEach-Object : Cannot convert 'System.Object[]' to the type 'System.Management.Automation.ScriptBlock
parameter 'RemainingScripts'. Specified method is not supported.
At line:1 char:88
+ ... ryinfo] } | % {$len = 0gci -recurse -force $_.fullname -ErrorAction S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [ForEach-Object], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.ForEachObjectCommand
gci -force 'C:\Users'-ErrorAction SilentlyContinue | ? { $_ -is [io.directoryinfo] } | % {$len = 0gci -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)
Error:
ForEach-Object : Cannot convert 'System.Object[]' to the type 'System.Management.Automation.ScriptBlock
parameter 'RemainingScripts'. Specified method is not supported.
At line:1 char:88
+ ... ryinfo] } | % {$len = 0gci -recurse -force $_.fullname -ErrorAction S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [ForEach-Object], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.ForEachObjectCommand
ASKER
This also does not return anything:
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))}| Measure-Object
If I put in 0 rather than -60 it returns all profiles but any other value returns 0
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))}| Measure-Object
If I put in 0 rather than -60 it returns all profiles but any other value returns 0
Hello,
I found another site where the lines are well reported :
How to Delete Old User Profiles Using GPO and PowerShell? | Windows OS Hub (woshub.com)
So, the first script is working well, but not the second one for me. Probably because of the date format.
I found another site where the lines are well reported :
How to Delete Old User Profiles Using GPO and PowerShell? | Windows OS Hub (woshub.com)
So, the first script is working well, but not the second one for me. Probably because of the date format.
ASKER
Awesome:
The first script now works
What about the 2nd and data format - any ideas?
The first script now works
What about the 2nd and data format - any ideas?
Yes, we should have to work the format of the value of "LastUseTime" : 20210704161119.224000+000
Here is the little script I have done to have that working :
Here is the little script I have done to have that working :
function ConvertDate($LastDate){
$d=[string]$LastDate
if($d.length -ge 25){
$t=$d.split(".")
$d=$t[0]
$findDate=[System.DateTime]::ParseExact($d,'yyyyMMddHHmmss',[System.Globalization.DateTimeFormatInfo]::CurrentInfo)
}
Else {$FindDate=""}
Return $FindDate
}
#$a=convertDate("20210704182913.353000+000")
#echo $a
Get-WMIObject -class Win32_UserProfile| Where {(!$_.Special) -and (ConvertDate($_.LastUseTime) -lt (Get-Date).AddDays(-60))}| Measure-Object
You can also remove the part "|measure" to have the list of profiles detected. The LocalPath field should indicate the name of found profiles.ASKER
I tried to adapt the script so that it in UK date (04/07/2021 4th July 2021):
----------
function ConvertDate($LastDate){
$d=[string]$LastDate
if($d.length -ge 25){
$t=$d.split(".")
$d=$t[0]
$findDate=[System.DateTime]::ParseExact($d,'ddMMyyyyHHmmss',[System.Globalization.DateTimeFormatInfo]::CurrentInfo)
}
Else {$FindDate=""}
Return $FindDate
}
#$a=convertDate("20210704182913.353000+000")
#echo $a
Get-WMIObject -class Win32_UserProfile| Where {(!$_.Special) -and (ConvertDate($_.LastUseTime) -lt (Get-Date).AddDays(-60))}| Measure-Object
Got this error:
Exception calling "ParseExact" with "3" argument(s): "The DateTime represented by the string is not supported in
calendar System.Globalization.GregorianCalendar."
At line:6 char:5
+ $findDate=[System.DateTime]::ParseExact($d,'ddMMyyyyHHmmss',[Syst ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FormatException
----------
function ConvertDate($LastDate){
$d=[string]$LastDate
if($d.length -ge 25){
$t=$d.split(".")
$d=$t[0]
$findDate=[System.DateTime]::ParseExact($d,'ddMMyyyyHHmmss',[System.Globalization.DateTimeFormatInfo]::CurrentInfo)
}
Else {$FindDate=""}
Return $FindDate
}
#$a=convertDate("20210704182913.353000+000")
#echo $a
Get-WMIObject -class Win32_UserProfile| Where {(!$_.Special) -and (ConvertDate($_.LastUseTime) -lt (Get-Date).AddDays(-60))}| Measure-Object
Got this error:
Exception calling "ParseExact" with "3" argument(s): "The DateTime represented by the string is not supported in
calendar System.Globalization.GregorianCalendar."
At line:6 char:5
+ $findDate=[System.DateTime]::ParseExact($d,'ddMMyyyyHHmmss',[Syst ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FormatException
ASKER
Correction:
---------
function ConvertDate($LastDate){
$d=[string]$LastDate
if($d.length -ge 25){
$t=$d.split(".")
$d=$t[0]
$findDate=[System.DateTime]::ParseExact($d,'ddMMyyyyHHmmss',[System.Globalization.DateTimeFormatInfo]::CurrentInfo)
}
Else {$FindDate=""}
Return $FindDate
}
#$a=convertDate("04072021182913.353000+000")
#echo $a
Get-WMIObject -class Win32_UserProfile| Where {(!$_.Special) -and (ConvertDate($_.LastUseTime) -lt (Get-Date).AddDays(-60))}| Measure-Object
Same error
---------
function ConvertDate($LastDate){
$d=[string]$LastDate
if($d.length -ge 25){
$t=$d.split(".")
$d=$t[0]
$findDate=[System.DateTime]::ParseExact($d,'ddMMyyyyHHmmss',[System.Globalization.DateTimeFormatInfo]::CurrentInfo)
}
Else {$FindDate=""}
Return $FindDate
}
#$a=convertDate("04072021182913.353000+000")
#echo $a
Get-WMIObject -class Win32_UserProfile| Where {(!$_.Special) -and (ConvertDate($_.LastUseTime) -lt (Get-Date).AddDays(-60))}| Measure-Object
Same error
Have you verified the actual format of LastUseTime?
- You can try and test the function directly with a specific value.
Is the content of $a in comment corresponding at your data?
ASKER
The server time is set to ddMMyyyy
ie 04/07/2021
Should I be using the / characters?
ie 04/07/2021
Should I be using the / characters?
No, that is not linked to your server time:
Can you indicate what are the numbers displayed by this command ? (here is a sample on my system)
Can you indicate what are the numbers displayed by this command ? (here is a sample on my system)
PS U:\test> Get-WMIObject -class Win32_UserProfile | ft lastusetime
lastusetime
-----------
20210704201058.640000+000
ASKER
lastusetime
-----------
20210704082448.091000+000
20210704082447.966000+000
20210704201545.436000+000
20210704201545.444000+000
20210704082447.716000+000
20210704082447.591000+000
20210704082447.419000+000
20210704082447.138000+000
20210704082446.872000+000
20210704082442.997000+000
20210704082446.684000+000
20210704082446.544000+000
20210704082446.388000+000
20210704082446.247000+000
20210704082446.091000+000
20210704082445.919000+000
20210704082445.684000+000
20210704082445.528000+000
20210704082445.450000+000
20210704082445.403000+000
20210704082445.356000+000
20210704082445.278000+000
20210704082445.184000+000
20210704082445.122000+000
20210704082445.044000+000
20210704082444.966000+000
20210704082444.903000+000
20210704201546.366000+000
20210704082444.778000+000
20210704201546.408000+000
20210704201546.415000+000
20210704201546.422000+000
-----------
20210704082448.091000+000
20210704082447.966000+000
20210704201545.436000+000
20210704201545.444000+000
20210704082447.716000+000
20210704082447.591000+000
20210704082447.419000+000
20210704082447.138000+000
20210704082446.872000+000
20210704082442.997000+000
20210704082446.684000+000
20210704082446.544000+000
20210704082446.388000+000
20210704082446.247000+000
20210704082446.091000+000
20210704082445.919000+000
20210704082445.684000+000
20210704082445.528000+000
20210704082445.450000+000
20210704082445.403000+000
20210704082445.356000+000
20210704082445.278000+000
20210704082445.184000+000
20210704082445.122000+000
20210704082445.044000+000
20210704082444.966000+000
20210704082444.903000+000
20210704201546.366000+000
20210704082444.778000+000
20210704201546.408000+000
20210704201546.415000+000
20210704201546.422000+000
ASKER
Is this suggesting ALL profiles have been used today?
So you should change nothing in the script that I proposed. The format is the same:
Year (4 digits), Month, day, hour, minutes, seconds.
All dates are for the 4th of July.
Year (4 digits), Month, day, hour, minutes, seconds.
All dates are for the 4th of July.
Perhaps you should use another approach :
PS U:\test> get-childitem c:\users |ft name,lastwritetime,lastaccesstime
Name LastWriteTime LastAccessTime
---- ------------- --------------
administrator 04/06/2020 10:19:46 04/07/2021 12:18:46
annick 11/05/2021 16:40:17 04/07/2021 12:18:46
Public 25/11/2020 15:41:03 04/07/2021 22:09:05
UserNa.DOMAIN 01/07/2021 19:35:12 04/07/2021 21:50:29
ASKER
Using that I get the following:
-------------------------------------------------------
PS C:\Users\administrator.VIVANT> get-childitem c:\users |ft n
Name LastWriteTime LastAccessTime
---- ------------- --------------
.NET v4.5 06/06/2018 16:37:33 06/06/2018 16:37:33
.NET v4.5 Classic 06/06/2018 16:37:29 06/06/2018 16:37:29
aaron 22/06/2020 15:44:49 22/06/2020 15:44:49
adam 18/03/2021 13:27:44 18/03/2021 13:27:44
Administrator 29/03/2019 16:58:07 29/03/2019 16:58:07
administrator.VIVANT 02/07/2021 09:17:39 02/07/2021 09:17:39
carmine.pertosa 09/09/2020 11:10:30 09/09/2020 11:10:30
carolann.tullett 22/04/2021 15:42:40 22/04/2021 15:42:40
carolina.murcia 13/02/2019 11:15:56 13/02/2019 11:15:56
Cody.Dixon 20/03/2020 13:00:45 20/03/2020 13:00:45
Daniel.Crockett 02/07/2021 14:13:53 02/07/2021 14:13:53
darren.chowrimootoo 02/07/2021 08:46:41 02/07/2021 08:46:41
Hatice.Yusuf 18/02/2019 15:56:01 18/02/2019 15:56:01
inventas.admin 31/03/2020 13:39:18 31/03/2020 13:39:18
ishaq.javed 28/04/2021 12:00:36 28/04/2021 12:00:36
John.Zierold 10/02/2020 14:04:09 10/02/2020 14:04:09
jordan.kyriakou 24/11/2020 14:04:31 24/11/2020 14:04:31
krishna.mehta 02/07/2021 09:10:57 02/07/2021 09:10:57
Matt.Smith 20/03/2020 12:27:45 20/03/2020 12:27:45
michael.c 06/06/2019 20:23:40 06/06/2019 20:23:40
MSSQL$MICROSOFT##WID 01/01/2020 16:55:35 01/01/2020 16:55:35
neil.moonesawmy 02/07/2021 10:31:38 02/07/2021 10:31:38
nicole.czaja 10/02/2020 13:58:23 10/02/2020 13:58:23
peter.pieri 13/03/2020 12:31:55 13/03/2020 12:31:55
Public 12/09/2016 12:34:54 12/09/2016 12:34:54
Saidullah.Rahmani 08/01/2019 11:05:51 08/01/2019 11:05:51
sean.kapoor 13/09/2019 14:03:33 13/09/2019 14:03:33
shoheb.rahman 02/07/2021 09:09:26 02/07/2021 09:09:26
Voyager 28/06/2019 10:00:29 28/06/2019 10:00:29
Yasmin.Cadinouche 14/04/2020 10:23:34 14/04/2020 10:23:34
-------------------------------------------------------
PS C:\Users\administrator.VIVANT> get-childitem c:\users |ft n
Name LastWriteTime LastAccessTime
---- ------------- --------------
.NET v4.5 06/06/2018 16:37:33 06/06/2018 16:37:33
.NET v4.5 Classic 06/06/2018 16:37:29 06/06/2018 16:37:29
aaron 22/06/2020 15:44:49 22/06/2020 15:44:49
adam 18/03/2021 13:27:44 18/03/2021 13:27:44
Administrator 29/03/2019 16:58:07 29/03/2019 16:58:07
administrator.VIVANT 02/07/2021 09:17:39 02/07/2021 09:17:39
carmine.pertosa 09/09/2020 11:10:30 09/09/2020 11:10:30
carolann.tullett 22/04/2021 15:42:40 22/04/2021 15:42:40
carolina.murcia 13/02/2019 11:15:56 13/02/2019 11:15:56
Cody.Dixon 20/03/2020 13:00:45 20/03/2020 13:00:45
Daniel.Crockett 02/07/2021 14:13:53 02/07/2021 14:13:53
darren.chowrimootoo 02/07/2021 08:46:41 02/07/2021 08:46:41
Hatice.Yusuf 18/02/2019 15:56:01 18/02/2019 15:56:01
inventas.admin 31/03/2020 13:39:18 31/03/2020 13:39:18
ishaq.javed 28/04/2021 12:00:36 28/04/2021 12:00:36
John.Zierold 10/02/2020 14:04:09 10/02/2020 14:04:09
jordan.kyriakou 24/11/2020 14:04:31 24/11/2020 14:04:31
krishna.mehta 02/07/2021 09:10:57 02/07/2021 09:10:57
Matt.Smith 20/03/2020 12:27:45 20/03/2020 12:27:45
michael.c 06/06/2019 20:23:40 06/06/2019 20:23:40
MSSQL$MICROSOFT##WID 01/01/2020 16:55:35 01/01/2020 16:55:35
neil.moonesawmy 02/07/2021 10:31:38 02/07/2021 10:31:38
nicole.czaja 10/02/2020 13:58:23 10/02/2020 13:58:23
peter.pieri 13/03/2020 12:31:55 13/03/2020 12:31:55
Public 12/09/2016 12:34:54 12/09/2016 12:34:54
Saidullah.Rahmani 08/01/2019 11:05:51 08/01/2019 11:05:51
sean.kapoor 13/09/2019 14:03:33 13/09/2019 14:03:33
shoheb.rahman 02/07/2021 09:09:26 02/07/2021 09:09:26
Voyager 28/06/2019 10:00:29 28/06/2019 10:00:29
Yasmin.Cadinouche 14/04/2020 10:23:34 14/04/2020 10:23:34
So you have interesting dates with old access on some profiles you can use this command:
Now, you just have to remove selected folder, after selecting only "regular" users and not "system" users.
get-childitem c:\users |where { $_.lastaccesstime -lt (Get-Date).AddDays(-60)}
Now, you just have to remove selected folder, after selecting only "regular" users and not "system" users.
ASKER
Almost there
Can you give me the script as an example of a folder removal please
Can you give me the script as an example of a folder removal please
Here is a folder removal with all the content (you need full permissions on the folders):
remove-item c:\users\user1 -force -Recurse
ASKER
Can I use the powershell to do this - ie select all folders older than a certain date and delete them, but using the powershell as above with the changed script:
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))} | Remove-WmiObject –WhatIf
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))} | Remove-WmiObject –WhatIf
You could use the folders found (with ChildItem), to search with Get-wmiobject the Win32_Userprofile where the localpath correspond.
A complete script could be something like :
get-WMIObject -class Win32_UserProfile | Where { $_.localpath -eq "c:\users\folderFound"}
A complete script could be something like :
$f=get-childitem c:\users |where { $_.lastwritetime -lt (Get-Date).AddDays(-60)} | select fullname
foreach ($i in $f){ $g=$i.fullname; get-WMIObject -class Win32_UserProfile | Where { $_.localpath -like "$g"} }
ASKER
Sorry - still not clear to me
How do I use this:
$f=get-childitem c:\users |where { $_.lastwritetime -lt (Get-Date).AddDays(-60)} | select fullname foreach ($i in $f){ $g=$i.fullname; get-WMIObject -class Win32_UserProfile | Where { $_.localpath -like "$g"} }
In this script:
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))} | Remove-WmiObject –WhatIf
And to keep user profiles such as system, network service, local administrator etc
How do I use this:
$f=get-childitem c:\users |where { $_.lastwritetime -lt (Get-Date).AddDays(-60)} | select fullname foreach ($i in $f){ $g=$i.fullname; get-WMIObject -class Win32_UserProfile | Where { $_.localpath -like "$g"} }
In this script:
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))} | Remove-WmiObject –WhatIf
And to keep user profiles such as system, network service, local administrator etc
ASKER
Would it be:
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))} | Remove-WmiObject –WhatIf | Remove-WmiObject –WhatIf
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-30))} | Remove-WmiObject –WhatIf | Remove-WmiObject –WhatIf
ASKER
Sorry:
Would it be:
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))} | Remove-WmiObject –WhatIf | Remove-WmiObject –WhatIf
Would it be:
Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.ConvertToDateTime($_.LastUseTime) -lt (Get-Date).AddDays(-60))} | Remove-WmiObject –WhatIf | Remove-WmiObject –WhatIf
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ASKER
Sorry
Still unclear - I am not so versed in Powershell as you are
What is the script to remove all profiles older than 60 Days and exclude profiles such as system, network service, local administrator etc
Can you give the whole working script together so I understand please
I think we are almost there with this
Still unclear - I am not so versed in Powershell as you are
What is the script to remove all profiles older than 60 Days and exclude profiles such as system, network service, local administrator etc
Can you give the whole working script together so I understand please
I think we are almost there with this
ASKER
What does the -WhatIf do?
ASKER
Or does this script do that:
$f=get-childitem c:\users |where { $_.lastwritetime -lt (Get-Date).AddDays(-60)} | select fullname
foreach ($i in $f){ $g=$i.fullname; get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.localpath -like "$g")} } | Remove-WmiObject –WhatIf
Again - what is the function of the WhatIf please
$f=get-childitem c:\users |where { $_.lastwritetime -lt (Get-Date).AddDays(-60)} | select fullname
foreach ($i in $f){ $g=$i.fullname; get-WMIObject -class Win32_UserProfile | Where {(!$_.Special) -and (!$_.Loaded) -and ($_.localpath -like "$g")} } | Remove-WmiObject –WhatIf
Again - what is the function of the WhatIf please
ASKER
I am not sure about the following:
{(!$_.Special) -and (!$_.Loaded)
I know the ! means do not remove but what are .Special and .Loaded referring to
{(!$_.Special) -and (!$_.Loaded)
I know the ! means do not remove but what are .Special and .Loaded referring to
SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ASKER
Thanks so much for your help
Great to work with a PowerShell script expert
Great to work with a PowerShell script expert
some old solutions were using a Microsoft tool "DelProf.exe". But I don't have seen recent updates of this tool.
Here is another scripted solution based on GPO that could do the work :
How to delete old profiles with GPO and Powershell