Removing home directories from a list of users.

rated by 0 users
This post has 5 Replies | 3 Followers

Not Ranked
Posts 4
Redmars Posted: 06-04-2010 12:06 AM

I'm using powershell v2 on a Windows 2003 domain. The script get the location from the users account in AD, and then after deleting it, should move on to the next one to delete, and so on....

Just specifying one user without the file list works deleting the users.  I'm just stuck on trying to feed it a list of users.

Error I'm getting is:

An error occurred while enumerating through a collection: The (&(ObjectCategory=user)(Na
me=)) search filter is invalid..
    + CategoryInfo          : InvalidOperation: (System.Director...sultsEnumerator:Resu
   ltsEnumerator) [], RuntimeException
    + FullyQualifiedErrorId : BadEnumeration
 

 

#this is a file with the list of users in it
[string]$UsersFile = "C:\TEMP\UsersList.txt"

#this gets the list of users from the file
$UsersList = Get-Content $UsersFile

#loops through list
foreach ($NextUser in $UsersList)
{
   write-host "Removing user $NextUser..."
   #your stuff goes here....
$psSession = New-PSSession -ComputerName w2k3svr1 -Credential windy8\Testaccount

Invoke-Command -Session $PSSession -ScriptBlock {
  $HD=$null
  $Filter = "(&(ObjectCategory=user)(Name=$NextUser))"
  $Searcher = [adsiSearcher]($Filter)
  $Searcher.Findall() |
    ForEach-Object {
      $HD = $_.properties.homedirectory
   } #end foreach-object
} #end scriptblock

"Taking ownership of $hd"
  Invoke-Command -Session $PSSession -ScriptBlock `
    { Invoke-Expression "takeown /f $HD /r /d y" }
"Adding Administrator Rights to $hd"
  Invoke-Command -Session $PSSession -ScriptBlock `
    { Invoke-Expression "icacls $HD /grant administrators:F /t" }
"Removing folder $hd"
  Invoke-Command -Session $PSSession -ScriptBlock `
    { Invoke-Expression "Remove-Item -Path $HD -Recurse -Force" }

Remove-PSSession -Session $psSession
}

Top 75 Contributor
Posts 46

I haven't had the opportunity to test, but this should work for you:

#### BEGIN SCRIPT ####

#creates all objectects used throught the script
BEGIN {
    #this is a file with the list of users in it
    [string]$UsersFile = "C:\TEMP\UsersList.txt"
   
    #this gets the list of users from the file
    $UsersList = Get-Content $UsersFile
   
    #create the PSSession outside of the foreach loop to enable faster script execution
    $psSession = New-PSSession -ComputerName w2k3svr1 -Credential windy8\Testaccount
   
    $ScriptBlock = {
        param (
            [string]$NextUser
        )
        write-host "Removing user $NextUser..."

        $HD=$null
        $Filter = "(&(ObjectCategory=user)(Name=$NextUser))"
        $Searcher = [adsiSearcher]($Filter)
        $Searcher.Findall() |
        ForEach-Object {
            $HD = $_.properties.homedirectory
        }
       
        "Taking ownership of $hd"
        "takeown /f $HD /r /d y"

        "Adding Administrator Rights to $hd"
        "icacls $HD /grant administrators:F /t"

        "Removing folder $hd"
        Remove-Item -Path $HD -Recurse -Force
    } #end scriptblock
}

#begin execution
PROCESS {
    #loops through list
    foreach ($NextUser in $UsersList) {
   
        #your stuff goes here....
        Invoke-Command -Session $PSSession -ScriptBlock $ScriptBlock -ArgumentList $NextUser
   
    }
}

#cleanup
END {
    Remove-PSSession -Session $psSession
}

#### END SCRIPT ####

As you can tell I've moved things around quite a bit.

  1. ##Where your script was breaking before###
    Invoke-Command needs the -ArguementList property and the scriptblock needs the param() list to pass the contents of an object through to the script block.
  2. Since $PSSession is the same for each foreach loop and requires no data from the loop there was quite a bit of excess processing being used to create the session repeatedly.
  3. Each time Invoke-Command is called it sends more data and waits again for it to process.  Send the data once in a larger block will allow the script execution to run more efficiently.
  4. Using BEGIN - PROCESS - END can be very beneficial when remoting in PoSh.  It's more efficient when passing variables in and out of the Invoke-Command block.  Instead of using a HUGE amount of Arguments (-ArguementList) they can be processed all together and Arguments minimalized.
Not Ranked
Posts 4

Cruisader03,

Thank you,  it worked perfectly. 

Is their a way to add output to a log file on success or failure?  Just want to have a record of what was and was not deleted.  It not a problem if it can't be done.

Thank again saved me a lot of time deleting files.

-RM

Top 75 Contributor
Posts 46

You could add a very crude logging mechanism using Tee-Object in one line:

Invoke-Command -Session $PSSession -ScriptBlock $ScriptBlock -ArgumentList $NextUser | Tee-Object "HomeFolder.log"

Logging can be as complex and you are willing to code, but this will get the job done.

Not Ranked
Posts 4

 

I figured out how to do it with appending the output:

        Invoke-Command -Session $PSSession -ScriptBlock $ScriptBlock -ArgumentList $NextUser | out-file c:\scripts\LogName.txt -append -enc ASCII

I have also figured out how to ask for the server name at the when the script runs.

Thank you for help.

-RM

 

Full script:

#creates all objectects used throught the script
BEGIN {
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Network Server Name"
$objForm.Size = New-Object System.Drawing.Size(300,200)
$objForm.StartPosition = "CenterScreen"

$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
    {$x=$objTextBox.Text;$objForm.Close()}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
    {$objForm.Close()}})

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close()})
$objForm.Controls.Add($OKButton)

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)

$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20)
$objLabel.Size = New-Object System.Drawing.Size(280,20)
$objLabel.Text = "Please enter Server Name below:"
$objForm.Controls.Add($objLabel)

$objTextBox = New-Object System.Windows.Forms.TextBox
$objTextBox.Location = New-Object System.Drawing.Size(10,40)
$objTextBox.Size = New-Object System.Drawing.Size(260,20)
$objForm.Controls.Add($objTextBox)

$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
    #this is a file with the list of users in it
    [string]$UsersFile = "C:\script\UsersList.txt"
  
    #this gets the list of users from the file
    $UsersList = Get-Content $UsersFile
  
    #create the PSSession outside of the foreach loop to enable faster script execution
    $psSession = New-PSSession -ComputerName $x -Credential domain-name\domain-admin
   
    $ScriptBlock = {
        param (
            [string]$NextUser
        )
        write-host "Removing user $NextUser..."

        $HD=$null
        $Filter = "(&(ObjectCategory=user)(Name=$NextUser))"
        $Searcher = [adsiSearcher]($Filter)
        $Searcher.Findall() |
        ForEach-Object {
            $HD = $_.properties.homedirectory
        }
      
        "Taking ownership of $hd"
        "takeown /f $HD /r /d y"

        "Adding Administrator Rights to $hd"
        "icacls $HD /grant administrators:F /t"

        "Removing folder $hd"
        Remove-Item -Path $HD -Recurse -Force
    } #end scriptblock
}

#begin execution
PROCESS {
    #loops through list
    foreach ($NextUser in $UsersList) {
  
        Invoke-Command -Session $PSSession -ScriptBlock $ScriptBlock -ArgumentList $NextUser | out-file c:\scripts\LogName.txt -append -enc ASCII
  
    }
}

#cleanup
END {
    Remove-PSSession -Session $psSession
}

Top 25 Contributor
Posts 123

Hi

I am trying to use this script, it seems to work great.  The problem I have is that I have multiple file servers where home folders exist, so I don't want it to prompt me for the file server name.  I want to get the script to work so that it will find the users home folder path automatically, then delete the home folder and ideally delete the user account as well.

I am not sure where to start, if anyone can offer help that would be great!

Thanks!

Page 1 of 1 (6 items) | RSS
Copyright 2012 PowerShell.com. All rights reserved.