Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Script to delete local user profiles across multiple servers NOT working 1

Status
Not open for further replies.

win2kwire

Technical User
Dec 14, 2005
35
ES
Hi,

I wonder if anyone can help me with the powershell script (below) for deleting cached local user profiles on multiple Terminal servers.

The script runs without errors but cannot find the location of user profiles and as such cannot display them.

Please see script below, I pasted only the sections that's not working.


#Run through each computer in the computers variable to compile a list of unique user accounts across all servers
ForEach ($computer in $Computers) {

#use WMI to find all users with a profile on the servers
Try{
[array]$users = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" -ea stop
}
Catch {
Write-Warning "$($error[0]) "
Break
}

#compile the profile list and remove the path prefix leaving just the usernames
$profilelist = $profilelist + $users.localpath -replace "C:\\users\\"

#filter the user names to show only unique values left to prevent duplicates from profile existing on multiple computers
$uniqueusers = $profilelist | Select-Object -Unique
}

#adds the unique users to the combo box
ForEach($user in $uniqueusers) {
[void] $objCombo.Items.Add($user)
}

$objForm.Controls.Add($objCombo)

$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
}


Function DeleteProfile {
#Add the path prefix back to the selected user
$selectedUser = "C:\Users\$selecteduser
 
Change your WMI query to this:
Code:
[array]$users = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" [highlight #FCE94F]| Select LocalPath[/highlight] -ea stop

Then you just need to enumerate the array $users to get the folder paths without any manipulation.

I hope that helps.

Regards,

Mark

Check out my scripting solutions at
Work SMARTER not HARDER. The Spider's Parlor's Admin Script Pack is a collection of Administrative scripts designed to make IT Administration easier! Save time, get more work done, get the Admin Script Pack.
 
Many thanks Mark,

Changed but it did not help, when I run the script I get the required select user(s) box but it cannot find the profiles in the path so the list is empty.
 
Try just executing this to return the profile directories to the screen. If this works then you need to look at the rest of your code.
Code:
$Computer = $env:computername
[array]$users = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" | Select LocalPath -ea stop
ForEach($userProfile in $users){
write-host $userprofile.LocalPath
}

I hope that helps.

Regards,

Mark

Check out my scripting solutions at
Work SMARTER not HARDER. The Spider's Parlor's Admin Script Pack is a collection of Administrative scripts designed to make IT Administration easier! Save time, get more work done, get the Admin Script Pack.
 
Adapting what I gave you to your code (this is a little more concise):

Code:
[array]$users = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" | Select LocalPath -ea stop
ForEach($userProfile in $users){
[void] $objCombo.Items.Add($userprofile.LocalPath)
}
$objForm.Controls.Add($objCombo)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
}
}



I hope that helps.

Regards,

Mark

Check out my scripting solutions at
Work SMARTER not HARDER. The Spider's Parlor's Admin Script Pack is a collection of Administrative scripts designed to make IT Administration easier! Save time, get more work done, get the Admin Script Pack.
 
Mark,

You sir are a STAR.

Your last bit of code added to my script and it worked like a charm. Someone give that man a cigar!

Wonderful help that will always be appreciated.

Mucha Gracias
 
Mark,

It is working as should but would be nice if I can exclude the Admin and system accounts from displaying in the list.

Only if you know how to if not I guess I will just have to live with it.

Thanks
 
Glad it worked for you. Here is how you can add an ignore list. If this was helpful, don't forget to click that little link to "Like the post with a star"
Code:
$ignoreList = @{
"C:\Users\mmaclach" = "1"
"C:\Users\Administrator" = "1"
}


[array]$users = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" | Select LocalPath -ea stop

ForEach($userProfile in $users){
    if (-Not ($ignoreList.ContainsKey($userprofile.LocalPath)))
    {
        [void] $objCombo.Items.Add($userprofile.LocalPath)
    }
}
$objForm.Controls.Add($objCombo)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
}
}

I hope that helps.

Regards,

Mark

Check out my scripting solutions at
Work SMARTER not HARDER. The Spider's Parlor's Admin Script Pack is a collection of Administrative scripts designed to make IT Administration easier! Save time, get more work done, get the Admin Script Pack.
 
Not really sure how you are using this script, sounds like you are creating a display to pick and choose who to delete. You might want to consider grabbing just the user names from the profiles, then query AD to see if that user exists and if not automatically delete the user profile. Let me know if you would want help in achieving that.

I hope that helps.

Regards,

Mark

Check out my scripting solutions at
Work SMARTER not HARDER. The Spider's Parlor's Admin Script Pack is a collection of Administrative scripts designed to make IT Administration easier! Save time, get more work done, get the Admin Script Pack.
 
Thanks Mark,

Ignore list created in script and working but I am getting an error when I try to delete a user from the list
error: "INFO: C:\Users\C:\Users\user3 Profile does not exist on server-1"
"INFO: C:\Users\C:\Users\user3 Profile does not exist on server-2"

I can see the user profile exists on the servers

Briefly,
I have several Citrix servers (although I have a script that runs every night to clear orphaned profiles), now and again I get corrupted profiles during the day, this script is to allow me delete a single user from multiple servers. I like the GUI because it lets me select a single user and delete from all servers listed in the script.

My script:

#GUI interface to delete user profiles from remote desktop session host server

#Setup script variables
#add computers to computers variable to search for profiles on those computers
[array] $Computers = "server1","server2"
$log = "\\server5\c$\logs\logs.txt"
$date = Get-Date

#Reset variables
$selecteduser = ""
$profilelist = @()


Function SetupForm {
#Setup the form
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Select user(s)"
$objForm.Size = New-Object System.Drawing.Size(300,320)
$objForm.StartPosition = "CenterScreen"

$btnDelete = New-Object System.Windows.Forms.Button
$btnDelete.Location = New-Object System.Drawing.Size(120,240)
$btnDelete.Size = New-Object System.Drawing.Size(75,23)
$btnDelete.Text = "Delete Profile"
$objForm.Controls.Add($btnDelete)

#When a user clicks the log off button get the details of the logged in users and call the scriptactions function
$btnDelete.Add_Click(
{
#set the selecteduser variable to be that of the user selected in the form
$selecteduser = $objCombo.SelectedItem
DeleteProfile
#$objForm.Close()

})

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(200,240)
$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 select user to delete profile:"
$objForm.Controls.Add($objLabel)

$objCombo = New-Object System.Windows.Forms.ComboBox
$objCombo.Location = New-Object System.Drawing.Size(10,40)
$objCombo.Size = New-Object System.Drawing.Size(260,20)
$objCombo.Height = 80



#Run through each computer in the computers variable to compile a list of unique user accounts across all servers
ForEach ($computer in $Computers) {

#use WMI to find all users with a profile on the servers
Try{
$ignoreList = @{
"C:\Users\mmaclach" = "1"
"C:\Users\Administrator" = "1"
"C:\Users\Ctx_StreamingSvc" = "1"
"C:\Users\Default" = "1"
"C:\Users\CitrixSQLsvc" = "1"
"C:\Users\Public" = "1"
}


[array]$users = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" | Select LocalPath -ea stop

ForEach($userProfile in $users){
if (-Not ($ignoreList.ContainsKey($userprofile.LocalPath)))
{
[void] $objCombo.Items.Add($userprofile.LocalPath)
}
}
$objForm.Controls.Add($objCombo)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
}
Catch {
Write-Warning "$($error[0]) "
Break
}

#compile the profile list and remove the path prefix leaving just the usernames
$profilelist = $profilelist + $users.localpath -replace "C:\\users\\"

#filter the user names to show only unique values left to prevent duplicates from profile existing on multiple computers
$uniqueusers = $profilelist | Select-Object -Unique
}

#adds the unique users to the combo box
ForEach($user in $uniqueusers) {
[void] $objCombo.Items.Add($user)
}

$objForm.Controls.Add($objCombo)

$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
}


Function DeleteProfile {
#Add the path prefix back to the selected user
$selectedUser = "C:\Users\$selecteduser"

#This section reads through all the computers and deletes the profile from all the computers - it catches any errors.
ForEach ($computer in $Computers) {
Try {
(Get-WmiObject -ComputerName $computer Win32_UserProfile | Where {$_.LocalPath -eq $selecteduser}).Delete()
Write-Host -ForegroundColor Green "$selecteduser has been deleted from $computer"
Add-Content $log "$date $selecteduser profile has been deleted from $computer"
}
Catch [System.Management.Automation.MethodInvocationException]{
Write-Host -ForegroundColor Red "ERROR: Profile is currently locked on $computer - please use log off user script first"
Add-Content $log "$date $selecteduser Profile is currently locked on $computer - please use log off user script first"
}

Catch [System.Management.Automation.RuntimeException] {
Write-Host -ForegroundColor Yellow "INFO: $selecteduser Profile does not exist on $computer"
Add-Content $log "$date INFO: $selecteduser Profile does not exist on $computer"
}

Catch {
Write-Host -ForegroundColor Red "ERROR: an unknown error occoured. The error response was $error[0]"
Add-Content $log "$date ERROR: an unknown error occoured. The error response was $error[0]"
}
}




#Add a label to say process is complete
$objLabel1 = New-Object System.Windows.Forms.Label
$objLabel1.Location = New-Object System.Drawing.Size(10,100)
$objLabel1.Size = New-Object System.Drawing.Size(280,20)
$objLabel1.Text = "Deletion complete, check log for more details."
$objForm.Controls.Add($objLabel1)

#Add a view log button to view the log file
$LogButton = New-Object System.Windows.Forms.Button
$LogButton.Location = New-Object System.Drawing.Size(50,150)
$LogButton.Size = New-Object System.Drawing.Size(75,23)
$LogButton.Text = "View Log"
$LogButton.Add_Click({Invoke-Item $log})
$objForm.Controls.Add($LogButton)
}

#Check script was run as admin
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
[System.Windows.Forms.MessageBox]::Show("It doesn't appear you have run this PowerShell session with administrative rights, the script may not function correctly. If no users are displayed please ensure you run the script again using administrive rights.")
}


#Start the form
SetupForm

 
I would recommend you change the delete code to use PowerShell Remove-Item and convert the local path to a UNC path to delete the profile. If you still wish to use WMI, then you need to set the impersonation level in your command so it will run elevated against the remote system.

I hope that helps.

Regards,

Mark

No trees were harmed in posting this message, however a significant number of electrons were terribly inconvenienced.

Check out my scripting solutions at
Work SMARTER not HARDER.
 
Thanks Mark, any idea how to actually do it will be appreciated as I have very basic powershell and scripting knowledge.

My script is as a result of weeks of hit and miss

Regards
Ben
 
You could try modifying what you have and just change the WMI query to see if the Impersonation level is the problem, that is a simple change:
Code:
(Get-WmiObject -ComputerName $computer Win32_UserProfile -Impersonation 3| Where {$_.LocalPath -eq $selecteduser}).Delete()

But I suspect that won't do it for you. Instead I would propose that you use this to delete:
Code:
$DelPath = $SelectedUser.Replace("C:\","\\$Computer\C$\")
Remove-Item $DelPath

Essentially all this does is convert your path such as C:\Users\SomeUser to a UNC that would be \\ComputerName\C$\Users\SomeUSer and then issues the Remove-Item cmdlet to delete it. As long as your running the script as a domain admin it should then have the needed rights.

I hope that helps.

Regards,

Mark

No trees were harmed in posting this message, however a significant number of electrons were terribly inconvenienced.

Check out my scripting solutions at
Work SMARTER not HARDER.
 
I realized there will likely be data still int hat profile so you need to tell it to delete sub folders and files and force the deletion/
Code:
Remove-Item $DelPath -Recurse -Force

I hope that helps.

Regards,

Mark

No trees were harmed in posting this message, however a significant number of electrons were terribly inconvenienced.

Check out my scripting solutions at
Work SMARTER not HARDER.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top