The Surly Admin

Father, husband, IT Pro, cancer survivor

Windows Profiles – Saving a copy and deleting

Another script request out of Spiceworks the other day.  This turned out to be a long discussion as the OP wasn’t too familiar with scripting and Powershell scripting in particular.  This can be a bit of a problem sometimes as I speak in using Powershellese that can be a bit difficult for some.  The OP wanted a script that would hit a computer, copy all profiles older then 60 days to a central server then delete the profiles.  This was another interesting use of WMI and taking advantage of Powershell looping and PSObjects.  Let’s see how we solve this problem.

First, we need to figure out how to look at the profiles and determine if they’re 60 days old or not.  One thought I had was to go through the directories and find the NTUsers.dat file and check it’s age.  But this seemed inelegant.  I couldn’t remember the class but I was pretty sure WMI could do this so a quick Google search found what I needed–and I really have to do a better job of saving these sites so I can link to them.  So to whoever did the original work, thanks!

$LocalProfiles = Get-WMIObject Win32_UserProfile -filter "Special != 'true'"

This was a great snippet because it gets the profile and automatically filters out any profile that’s system related.  Nice.  From here I used Get-member on the $LocalProfiles variable and discovered the “LastUseTime” property.  Perfect, now we can loop through all the profiles and check the LastUseTime against 60 days ago:

$LocalProfiles | ForEach {

If ($_.ConvertToDateTime($_.LastUseTime) -le (Get-Date).AddDays(-$Days)) stuff..

Now I know my profiles, I need to copy them to a central location.  But if we have multiple users using the same computers we could easily have the same name’s all over the place.  So we need to build a directory that includes not only the computer name but the profile name.  One problem is there is no propery “ProfileName” or just plain “Name”.  All I have is LocalPath which has the full path to the profile in it.  What I decided to do is use a little Powershell trick when using arrays.  It’s actually possible to address the last element of an array using “-1” notation.  Next to last would be “-2” and so on.  If I take the local path, split it into an array using the “\” key, then the last array element will be the profile name.  Here’s how I built the path:

$OldProfilePath = "$OutPath\$env:computername-$(($_.LocalPath.Split("\"))[-1])"

$OutPath is a variable that is declared at the beginning and points to where the profiles will be saved. $env:computername is how Powershell accesses environment variables in Windows, and computername is simply the name of the computer.  Then we take the pipeline variable, get the .LocalPath property, split it on “\” and reference the last element “-1”.

After that, it’s just a matter of copying the profile to the path we created.  I also wanted to produce a nice result, so we need to create a PSObject for our results and pipe that to good old “Out-Gridview”.  I’m not going to bother to post this to Spiceworks as the code is fairly specific to one person’s problem but if you’d like to see it there simply post in comments and I will.

Here’s the full code:

[string]$OutPath = "\\server\share\OldProfiles",
[Int]$Days = 60

$LocalProfiles = Get-WMIObject Win32_UserProfile -filter "Special != 'true'"
$Result = @()

$LocalProfiles | ForEach {
$Status = "Kept"
If ($_.ConvertToDateTime($_.LastUseTime) -le (Get-Date).AddDays(-$Days))
{ $OldProfilePath = "$OutPath\$env:computername-$(($_.LocalPath.Split("\"))[-1])"
If (Test-Path $OldProfilePath)
{ $Status = "Unable to copy, path exists: $OldProfilePath"
{ Copy-Item $_.LocalPath $OldProfilePath -Recurse
$_ | Remove-WmiObject -whatif
$Status = "Removed"
$Result += New-Object PSObject -Property @{
'Profile Path' = $_.LocalPath
'Last Used' = $_.ConvertToDateTime($_.LastUseTime)
'Trigger Date' = (Get-Date).AddDays(-$Days)
Status = $Status
$Result | Out-GridView

As usual, I declare my variables as parameters so you can override them to your needs using -Outpath and -Days. If you want to use this, make sure to remove the -WhatIf from line #19 when you’ve done your testing.

One last note about when this script copies the profile.  It’s going to generate several error messages.  I blame Microsoft.  In their neverending quest to make redicuously complex code to solve simple problems they have really mangled the Profile directory.  It has links, and other junk into it that just doesn’t copy (because they’re not really there).  I ignore it all and move on as the script will get the data you really care about copied.


September 17, 2012 - Posted by | PowerShell |

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: