PowerShell

Löschen von veralteten User-Profilen auf Servern

Löschen von veralteten User-Profilen auf Servern

Heute möchte ich kurz über ein Powershell Script schreiben, welches ich im Auftrag eines grossen Kunden erstellt habe.

Der Kunde, der weit über 1000 Windows Server weltweit betreibt, bat mich eine Lösung zu finden, wie man User-Profile von ausgeschiedenen Mitarbeitern der IT von den Servern löschen könnte.

In Unternehmen dieser Grösse findet eine gewisse Fluktuation statt, Mitarbeiter gehen in Rente, wechseln in ein anders Unternehmen und es gibt häuf externe Mitarbeiter in der IT (so wie mich), deren Vertrag irgendwann ausläuft. Sie alle hinterlassen ihre User-Profile für immer auf den Servern, sofern man sie nicht löscht. Zudem können die Profile doch einiges an Speicherplatz auf den Servern verbrauchen.

Jedes einzelne Profil auf jedem der Server per GUI zu löschen, war natürlich keine Option. Also musste ein Script her, das bei Bedarf auch in Zukunft regelmässig die Aufgabe erfüllt.

Schon am Anfang stellte sich die Frage, wie man das Script auf die Server bringt. Powershell Remoting bat sich als Lösung an, konnte aber aus technischen Gründen nicht benutzt werden.

Da der Kunde SCCM im Einsatz hatte lag es nah dies zu benutzen. Mit SCCM ausgeführt kann das Script unter „local System“ ausgeführt werden, so dass keine Berechtigungsprobleme zu erwarten waren.

Um die Profile auf den Servern auszulesen, bietet sich die WMI Class „win32_userprofile“ an, die auch verwendet werden kann um in einem späteren Schritt die veralteten Profile zu löschen.

Wie finde ich jetzt aber heraus, welche Profile von nicht mehr vorhandenen Mitarbeitern stammen?

Zuerst habe ich im Script das Powershell Command „Test-Connection“ benutzt, um sicherzustellen, dass eine Verbindung zur Domäne besteht.

Als nächstes frage ich mit ADSI ab, ob die User SID, die ich ja zuvor per WMI beim Auslesen der Profile ermittelt hatte, sich in einen DistinguishedName umwandeln lässt. Ist das nicht der Fall, kann man davon ausgehen, dass der Besitzer des Profiles nicht mehr als User im Active Directory besteht. Das Profil kann also gelöscht werden.

Ein wenig Kopfzerbrechen bereitete mir die Frage, wie ich sicherstellen kann, das keine Profile von lokalen Usern oder Profile von Systemkonten (Domain Admin, Server-Operator etc.) vom Script gelöscht werden. Das konnte dadurch gelöst werden, indem ich nur die ermittelten Profile in Betrachtung zog, deren SID identisch mit dem SID-Teil eines Domänenbenutzers war. Dazu stellte ich eine Domain-SID ohne den hinteren User Block der Domain SID des Profilebesitzers gegenüber.

Anschliessend wird wieder WMI benutzt (Remove-WMIObject) um das Profil zu löschen.

Jeder Löschvorgang und auch jeder gescheiterte Löschvorgang wird in ein Logfile auf den Server geschrieben. Das Logfile mit dem PS-Command „Send-Mailmessage“ an eine Mailbox gesendet, so dass am Ende für jeden Server ein Logfile existiert, das dann zur Kontrolle ausgewertet werden kann.

Zu guter Letzt löscht das Script das Logfile auf dem Server.

Hier nun das Script:


# ----------------------------------------
# Script Remove-UserProfil.ps1
# Author: Michael Schawel, Pohn-IT Consulting
# Date: 06/01/2015
# Version 2.0
# ----------------------------------------

<#
 .Synopsis
  This script deletes User Profiles stored on a local Server from users that no longer exists.
 .Description
  The script uses WMI to find all User Profiles stored on a Server. Then it checks in Active Directory if the owners for each Profile found still exists.
  If the user doesn't exist, the script deletes the following items:
  - c:\users\username
  - HKLM:\\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\SID
  For each Profile that is deleted an entry will be written in a logfile
  For each Profile that cannot be deleted an entry will be written in a logfile

  The script was tested on the following OS Versions:
  - WK12R2
  - W2K12
  - W2K8R2
  - W2K8 (Powershell 2.0 or higher)

 .Example
  .\Remove-UserProfil.ps1
 .Notes
  Author: Michael Schawel, Pohn-IT Consulting
  LastEdit: 06/January/2015
#>

# Functions----------------------------------------------

function Read-Profiles {

        Get-WmiObject -Class Win32_UserProfile | Select LocalPath,SID | Where-Object {$_.SID -match "$SIDDomain"}
}

function Remove-Profiles {

        get-wmiobject -class win32_userprofile | Where-Object {$_.SID -eq $U_Profile.SID} | Remove-WmiObject

        $Success ="Profile `'$U_Profile`'  has been deleted"
        $time = get-date
        "$time;$Success" | Out-file -FilePath $LogFile -Append -Encoding UTF8
}

function Send-Message {

        send-mailmessage -from "postmaster@domain.com" `
        -to "michael.schawel@domain.com" `
        -subject "Delete User Profiles" `
        -body "Report with deleted Admin Account Profiles attached." `
        -Attachments $LogFile `
        -smtpServer mailservername
}

function Remove-Logfile {

        Remove-Item $LogFile -Force -Recurse
}

#Declaring Variables--------------------------------------

$LogFile = "c:\Temp\DelUserProfiles$env:COMPUTERNAME.txt"
$SIDDomain = "S-1-5-21-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-"
$Domain = "Domain.com"
$U_Profiles = Read-Profiles

# Main----------------------------------------------------

$env:COMPUTERNAME| Out-file -FilePath $LogFile -Encoding UTF8

if(Test-Connection $Domain) {

    foreach($U_Profile in $U_Profiles)
            {
            $Sid= $U_Profile.SID
        Try
            {
            $User = $null
            $User = [adsi]"LDAP://<SID=$Sid>"
            $DestName = $User.distinguishedName
            }
        Catch
            {
             $message ="Cannot proceed LDAP Query."
            $time = get-date
            "$time;$message" | Out-file -FilePath $LogFile -Append -Encoding UTF8
            }
        if($User.distinguishedName -eq $null)
            {

        Try
            {Remove-Profiles}

         Catch
            {
            $message ="User Profile`'$U_Profile.LocalPath`' could NOT be deleted."
            $time = get-date
            "$time;$message" | Out-file -FilePath $LogFile -Append -Encoding UTF8
            }

         }
      }
  }

  Send-Message
  Remove-Logfile

2 thoughts on “Löschen von veralteten User-Profilen auf Servern
  1. ThinkAdvantage says:

    Bleiben bei dieser Methode die Ordner nicht trotzdem im C:\Users\* ?

    • Michael Schawel
      Michael Schawel says:

      Wie unter “Synopsis” beschrieben, führt das Scripts letztlich zwei Dinge aus, wenn es feststellt, dass der User nicht mehr im AD existiert:
      – Löschen des Registry Keys: HKLM:\\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\SID
      – Löschen des Pfades: c:\users\username
      Grüsse
      Michael

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.