PS - Iterate over string array to detect orphaned user directories

40 views Asked by At

We have an issue whereby standard windows profile removal methods via intune are not working correctly, often leaving orphaned user directories in C\Users, which saturates the C: drive.

I'm trying to make a PS script to:

  • Get user profiles (normal users)
  • Get (normal) user directories in C:\Users
  • Determine which directories do not correspond to a user profile
  • Delete those directories

(I'm a PS novice.. )

# Get user directories
[string[]]$Directories = Get-ChildItem C:\users | 
       Where-Object {$_.PSIsContainer -and $_ -notlike "*Windows*" -and $_ -notlike "*default*" -and $_ -notlike "*Public*" -and $_ -notlike "*Admin*"} | 
       Foreach-Object {$_.Name}    

# Get user profiles
[string[]]$Profiles = Get-CimInstance -ClassName Win32_UserProfile -Filter "Special = 'False'" | Select-Object LocalPath | Out-String

#Iterate
Foreach($Directory in $Directories) {
    
    if(("C:\users\" + $Directory) -notin $Profiles){
        ## complete some task
    }

}

I can see that I'm missing something basic r.e. the iteration. If I comment out the if loop add write-host $Directory it will list the directories, but only the first has C:\Users\ prepended.

I'm also assuming I've constructed the arrays incorrectly, althoguh they appear to be arrays of strings?

If working correctly, creating an empty folder 'Test' in C:\Users\ and adding write-host $Directory inside the if loop should result in only 'Test' being output.

Thanks in advance :)

1

There are 1 answers

0
Abraham Zinala On

PowerShell as a language, unlike a lot of languages, is a dynamically typed language. Meaning, there's no need to typecast (in most situations) anything for a returning output.

That said, you also don't have to stringify any of its output (via Out-String) when you can work with the properties directly:

$users_folders = (Get-ChildItem -Path 'C:\Users' -Exclude 'Admin', 'Public' -Directory).FullName
$profile_paths = (Get-CimInstance -ClassName 'Win32_UserProfile' -Filter "Special = 'False'").LocalPath
foreach ($folder in $users_folders)
{
    if ($folder -notin $profile_paths)
    {
        $folder
    }
}

You'll have to take note of the grouping operator (...), when applied to collections, it allows direct access to properties of the items inside. If you have an array of objects and you use the grouping operator followed by a property name, such as LocalPath or FullName, PowerShell will return the value of that property for each object in the collection. This is also known as Member-Access Enumeration.