Hey Scripting Guy! Our previous network administrator was a slouch. He did not maintain proper backups, never reviewed event logs, and never cleaned up user folders when he deleted users in Active Directory. This last omission is particularly egregious because it has taken a lot of cleanup work to find and delete the user folders. One of the big problems with doing this manually is taking ownership of the folders, granting the Administrator rights to the folders, and then deleting them. It is a real pain. I would love a script that would do this automatically.
— BE
Hello BE,
Microsoft Scripting Guy Ed Wilson here. Things are really getting hectic in Charlotte, North Carolina. The 2010 Scripting Games commence on April 26, and there are lots of last-minute details to take care of. I have been busy talking to the many guest commentators, and have had several interviews with various scripting related podcasts about the Games. I have spoken to several user groups, and even found a little bit of time to write Hey, Scripting Guy! Blog posts.
I even found one guest commentator by reviewing submissions to the Official Scripting Guys Forum. Andrew Barnes has been really busy answering questions, and I contacted him and asked him if he would like to be a forum moderator. He was thrilled. I then asked him if he would like to be a guest commentator for the 2010 Scripting Games—he was ecstatic. Andrew is from the United Kingdom, and his guest commentary on the games will appear in May when we begin posting the answers. Because I have spent so much time talking to Andrew recently, I went back through some of the pictures I took when I was in Reading teaching a VBScript class a few years. The following photo is one I took in downtown Reading.
BE, I decided to write the Get-ADUserAndRemoveProfileAndHomeDrive.ps1 script for you. In writing the script, I decided to query Active Directory to return the path to the user’s home drive and the user’s profile location. Next the script sets the security on the two folders to allow the Administrator to delete the files and folders, and finally it deletes the files and the folders. I did not add code to delete the user account in Active Directory, because there are dozens of scripts that do that in the Script Repository, and I did not want to clutter up an already complicated script with extra code. The complete Get-ADUserAndRemoveProfileAndHomeDrive.ps1 script is seen here.
Get-ADUserAndRemoveProfileAndHomeDrive.ps1
$psSession = New-PSSession -ComputerName HyperV -Credential nwtraders\administrator
Invoke-Command -Session $PSSession -ScriptBlock {
$HD=$PD=$null
$Filter = “(&(ObjectCategory=user)(Name=HSG Testuser))”
$Searcher = [adsiSearcher]($Filter)
$Searcher.Findall() |
ForEach-Object {
$HD = $_.properties.homedirectory
$PD = $_.properties.profilepath
$PD = “$PD.V2”
} #end foreach-object
} #end scriptblock
“Taking ownership of $hd”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “takeown /f $HD /r /d y” }
“Taking ownership of $pd”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “takeown /f $PD /r /d y” }
“Adding Administrator Rights to $hd”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “icacls $HD /grant administrators:F /t” }
“Adding Administrator Rights to $PD”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “icacls $PD /grant administrators:F /t” }
“Removing folder $hd”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “Remove-Item -Path $HD -Recurse -Force” }
“Removing Folder $PD”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “RD $PD -Recurse -Force” }
Remove-PSSession -Session $psSession
BE, the first thing that must be done is to locate the user’s profile path and home directory. These are two items that are often specified when the user account is created. The user profile page in Active Directory Users and Computers is shown in the following image.
To find the corresponding Active Directory Services Interface (ADSI) names, use the ADSI editor shown in the following image because the names used by the ADSI interface are seldom the names that are presented in the dialog box from Active Directory Users and Computers.
If you look up the user’s home drive location and attempt to access it—even as a Domain Administrator—it is likely that you will not be able to access the user’s home drive on the file server. You might be able to access the files, depending on the settings that were configured for the user home directories. This is seen in the following image.
On a Windows Server 2008 R2 server running Active Directory Domain Services (AD DS), you will not be able to access the user’s profile directory because the Domain Administrator does not have access. This is seen in the following image.
Therefore, it is likely you will not have access to the user’s home drive location, and it is virtually certain you will not have access to the user’s profile directory. When you delete a user from Active Directory Domain Services, their home drive information and their profile information are not deleted. This necessitates a rather cumbersome process of taking ownership of each folder, granting Administrator full control, backing out, and then deleting the folder. If you are attempting to do this manually, it is a real bother, particularly if you have more than one user to clean up after.
Because the script will be running against a remote server, create a new PSSession. This will allow you to run interactive commands against the remote server that is running Windows PowerShell 2.0. In addition, I used the –credential parameter because I want the script to specify the administrator credentials to use in the remote session. When using the credential parameter, the dialog box shown in the following image is displayed.
The first thing that needs to be done is to create a remote session on the server containing the user’s profile and home drive. Store the returned session object in the $psSession variable, as shown here:
$psSession = New-PSSession -ComputerName HyperV -Credential nwtraders\administrator
To run a command on the remote server, use the Invoke-Command cmdlet and specify the session to use. The session will be the session that was stored in the $psSession variable. The command to execute queries Active Directory for a specific user (HSG Testuser, in this example). It then returns the user’s homedirectory and profilepath, and stores these values in a couple of variables. On my Windows Server 2008 R2 server, when connecting using a Windows 7 client, the user’s profile path does not exactly match up with what is stored on the file server. The folder has a .V2 extension after the user name. To account for that, I append.V2 to the end of the user’s profile path. This is shown here:
Invoke-Command -Session $PSSession -ScriptBlock {
$HD=$PD=$null
$Filter = “(&(ObjectCategory=user)(Name=HSG Testuser))”
$Searcher = [adsiSearcher]($Filter)
$Searcher.Findall() |
ForEach-Object {
$HD = $_.properties.homedirectory
$PD = $_.properties.profilepath
$PD = “$PD.V2”
} #end foreach-object
} #end scriptblock
Next the takeown utility is used to take ownership of the folders, and to recurse through the subfolders and to take ownership of all the folders. The takeown utility is a standard utility included with the operating system. To execute the command on the remote server, use the Invoke-Command cmdlet to run the command in the remote session. In the scriptblock, use the Invoke-Expression cmdlet to execute the takeown command. The /r switch tells the command to recurse through subfolders. The /d switch specifies the default answer to prompts when the user does not have the “list folder” permission, which happens when taking ownership of subfolders. A “y” means yes, go ahead and take ownership of the folder. The takeown commands are shown here:
“Taking ownership of $hd”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “takeown /f $HD /r /d y” }
“Taking ownership of $pd”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “takeown /f $PD /r /d y” }
After the takeown command has run and taken ownership of the folders, the icacls utility is used to grant administrators full control of the folders. The “F” in the command grants administrators full control. The /t parameter for icacls tells the command to process all matching files and directories below the specified directory. The two icacls commands are shown here:
“Adding Administrator Rights to $hd”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “icacls $HD /grant administrators:F /t” }
“Adding Administrator Rights to $PD”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “icacls $PD /grant administrators:F /t” }
After the takeown and the icacls utilities have been used to grant administrator rights to the folders, the Remove-Item cmdlet can be used. The Invoke-Command cmdlet is used to execute the Remove-Item cmdlet on the remote computer. These two commands are shown here:
“Removing folder $hd”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “Remove-Item -Path $HD -Recurse -Force” }
“Removing Folder $PD”
Invoke-Command -Session $PSSession -ScriptBlock `
{ Invoke-Expression “RD $PD -Recurse -Force” }
After the folders have been removed, it is time to end the PSSession and to release the resources that the PSSession was using. The Remove-PSSession cmdlet will also close the connection between the local computer and the remote server. The session object would still be stored in the $psSession variable, unless we remove the variable by using the Remove-Variable cmdlet as shown here:
Remove-PSSession -Session $psSession
Remove-Variable –name psSession
BE, that is all there is to using Windows PowerShell to delete remote folders. Potpourri Week will continue tomorrow.
If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
0 comments