mc-doubleyou
Goto Top

Powershell Script zum löschen von lokalen Profilen bei "Account Unknown"

Hallo zusammen,

ich habe nun schon einige Zeit gesucht und auch das ein oder andere gefunden, aber noch arbeitet nichts so wie ich mir das erhofft hatte.

Wir mussten die Domain neu machen und damit hat sich natürlich die RID, entsprechend auch die SID geändert.
Diese Leichen würde ich nun gerne aus unseren Servern entfernen.
Klar wäre es möglich das manuell zu machen, aber wenn es geht würde ich das gerne vermeiden.

Es soll also per Skript erkannt werden, dass das Userprofil aus der alten Domain stammt und dann entweder dadurch das Userprofil (wegen der Daten) an einen anderen Platz kopiert werden, alternativ sichere ich einfach alles vorher, viel wichtiger ist aber die anschließende Löschung dieses Userprofils.
Am liebsten wäre mir wenn ich zuvor auf einer Testmaschine ein whatif durchführen könnte.

Durch Get-ACL und Nutzung von WMI habe ich schon SID, Pfad, etc. herausbekommen, aber außer in der GUI scheint nirgendwo "Account Unknown" zu stehen.

Danke!

LG mcdy

Content-Key: 323387

Url: https://administrator.de/contentid/323387

Printed on: April 24, 2024 at 07:04 o'clock

Mitglied: 131381
131381 Dec 09, 2016 at 12:10:38 (UTC)
Goto Top
Member: mc-doubleyou
mc-doubleyou Dec 09, 2016 at 12:24:45 (UTC)
Goto Top

Hallo mirotik,

irgendwie dacht ich mir schon das du der erste sein wirst, faszinierend sowas ;)

Was deinen Vorschlag betrifft ist Delprof2 erstens eine Blackbox, was ich aber noch verschmerzen könnte, aber auch laut der Download Seite nicht frei verfügbar.

Zitat:

Delprof2

Delete user profiles from the command line
Please note that Delprof2 is free for non-commercial use only. For details please see the license.

Download DelProf2 1.6.0 for 32-bit and 64-bit Windows


Lässt sich das wirklich nicht per Powershell lösen?
Bin doch bestimmt nicht der erste mit dem Problem.

LG mcdy
Mitglied: 131381
131381 Dec 09, 2016 updated at 12:30:16 (UTC)
Goto Top
Du kannst ja mit der SID ein NTAccount-Object anlegen wenn das geht gibt es den User noch ansonsten nicht
(New-Object System.Security.Principal.SecurityIdentifier("S-1-5-21-99999999999-9999999999-999999999-1005")).Translate([System.Security.Principal.NTAccount]).Value  
Ein kompettes Script kann ich dir schreiben, aber nich ümmesöns ...
Member: mc-doubleyou
mc-doubleyou Dec 09, 2016 updated at 14:10:37 (UTC)
Goto Top
Hey mikrotik,

danke für den Tipp, damit bin ich dem ganzen doch merklich näher, leider ist es mir aktuell trotzdem nicht möglich eine Ausgabe zu machen wenn es eben nicht geht, der User also verwaist ist.
$UPs = gwmi win32_userprofile | select @{Name="SID";Expression={($_.sid)}},@{Name="LocalPath";Expression={($_.localpath)}}  
foreach ($UP in $UPs)
{
 if ((New-Object System.Security.Principal.SecurityIdentifier($UP.sid)).Translate([System.Security.Principal.NTAccount]).Value) {}
 else { write-host $UP.sid }
}

Die Hashtable wäre um vor dem Löschen das Profil wegsichern zu können.

So Sachen wie -eq "false" hab ich schon probiert, wars aber scheinbar nicht.

Danke!

LG mcdy
Mitglied: 131381
131381 Dec 09, 2016 at 15:52:30 (UTC)
Goto Top
gwmi win32_Userprofile | ?{try{$result = (New-Object System.Security.Principal.SecurityIdentifier($_.SID)).Translate([System.Security.Principal.NTAccount])}catch{};!$result}
Member: mc-doubleyou
mc-doubleyou Dec 12, 2016 at 09:35:23 (UTC)
Goto Top
Hey mikrotik,

wenn ich dein Beispiel nicht völlig falsch verstanden habe dann müsste man in catch{} schreiben was passieren soll wenn der erste Teil einen Fehler ausgelöst hat.
Warum du ein where-Object not result brauchst ist mir aber trotzdem nicht klar.

Wie auch immer, in catch{} kann ich mich offenbar nicht mehr auf die Variable von vorher beziehen sondern nur auf die Errorausgabe.
Hatte es zuvor mit $_.LocalPath probiert, offensichtlich wurde es aber erst als ich $_ benutzt habe.

gwmi win32_Userprofile | Where-Object {try{$result = (New-Object System.Security.Principal.SecurityIdentifier($_.SID)).Translate([System.Security.Principal.NTAccount])}catch{Write-Host $_};!$result}

output:
Exception calling "Translate" with "1" argument(s): "Some or all identity references could not be translated."
Exception calling "Translate" with "1" argument(s): "Some or all identity references could not be translated."

Hast du dafür auch eine Idee?
Im Moment sehe ich nur dass es zwei Userprofile betrifft, aber noch nicht mal welche.

Danke!

LG mcdy
Mitglied: 131381
131381 Dec 12, 2016 updated at 10:22:02 (UTC)
Goto Top
habe dann müsste man in catch{} schreiben was passieren soll wenn der erste Teil einen Fehler ausgelöst hat.
Nein.
Warum du ein where-Object not result brauchst ist mir aber trotzdem nicht klar.
Das Where-Object gibt nur die Profile zurück bei denen kein Fehler bei der Auflösung aufgetreten ist.

Wenn Fehler = User existiert nicht => $result muss also $true sein
Wenn kein Fehler = User existiert => $result muss also $false sein damit dieses Profil nicht zurückgegeben wird!
Member: mc-doubleyou
mc-doubleyou Dec 12, 2016 at 11:41:38 (UTC)
Goto Top
Hey nochmal,

dein Nein verwirrt mich nun erst recht, immerhin ist doch dafür das catch da.
Wenn ich einfach deinen Code ausführe dann bekomme ich überhaupt keine Rückmeldung.

Where-Object in Verbindung mit !$result liefert also nur die Fehler zurück, was auch funktioniert.
Schreibe ich zB. in catch Write-Host 1 dann bekomme ich 2x 1 genaus soviele Fehler sind entstanden.

Wie ich in diesem Fall aber die SID oder noch besser den Pfad zurück gebe, da kein Bezug mehr auf den Bereich vor der Pipe besteht, bleibt mir ein Rätsel.

Echt komplex der Code, ich hoffe du kannst mir nochmal helfen.

Danke!

LG mcdy
Mitglied: 131381
131381 Dec 12, 2016 updated at 12:05:49 (UTC)
Goto Top
Last chance ...
Das Where-Object erwartet als Ergebnis einen Wert oder keinen du kannst hier nicht irgendwas in der Konsole im catch ausgeben ...
Wenn im try ein Fehler geworfen wird ist $result = $null und mit dem ! wird das umgedreht in $true. So einfach ist das...
Wie ich in diesem Fall aber die SID oder noch besser den Pfad zurück gebe, da kein Bezug mehr auf den Bereich vor der Pipe besteht, bleibt mir ein Rätsel.
???? Alle Objekte die nicht mehr passen also eine SID nicht existiert werden dir doch in der PIPE zurückgegeben!!!! Was willst du mehr?? Hänge einfach eine FOREACH-Schleife hinten dran und du kannst auf alle Eigenschaften des Profils zurückgreifen.

gwmi win32_Userprofile | ?{try{$result = (New-Object System.Security.Principal.SecurityIdentifier($_.SID)).Translate([System.Security.Principal.NTAccount])}catch{};!$result} | %{$_.LocalPath}

I'm out now

Viel Erfolg
Gruß mik
Member: mc-doubleyou
mc-doubleyou Dec 12, 2016 at 17:24:57 (UTC)
Goto Top
Hey,

falls du, oder jemand anderes doch noch liest, entweder bin ich zu blöd dafür oder es klappt schlicht nicht.
Ich habe es aufgesplittet um das Ergebnis besser verstehen zu können.
Ich habe auch die Variable mal gezwungen ein Array zu werden um hoffentlich Einträge zu bekommen.

Hier der Code:
$varSID = gwmi win32_Userprofile
$varObj = @( $varSID | Where-Object {try{$resultObj = (New-Object System.Security.Principal.SecurityIdentifier($_.SID)).Translate([System.Security.Principal.NTAccount])}catch{};!$resultObj} )
$varLocalPath = @( $varObj | ForEach-Object {$_.LocalPath} )

Zuvor habe ich auch mal getestet $varSID direkt mit einer SID zu füttern, dann sah das Ergebnis so aus:
$varSID
S-1-5-21-191341062-2050075637-3301337001-500

$varObj
S-1-5-21-191341062-2050075637-3301337001-500

$resultObj
leer

Natürlich kann zur SID kein LocalPath aufgelöst werden, es sieht aber aus als würde es funktionieren.

Nutze ich aber den Code oben sieht es so aus:
$varSID.SID
S-1-5-21-191341062-2050075637-3301337001-500
(und natürlich auch andere)

$varObj
leer

$resultObj
Value
NT AUTHORITY\SYSTEM

Entsprechend bleibt $varLocalPath natürlich leer.

Also wie gesagt entweder zu blöd dafür oder da ist noch wo der Wurm drinnen face-sad

Danke nochmal für die bisherige Hilfe, könnte gut verstehen wenn nichts mehr kommt. (seh mich schon manuell die Server bereinigen)

LG mcdy