baeckster
Goto Top

PowerShell Script opSubtraction Überladung etc

Hallo zusammen,

Hintergrund:
Durch den Datenschutz sind wir gezwungen Dateien die für jedermann zugänglich sind von Zeit zu Zeit zu überprüfen bevor was böses passiert. Wir haben hier Tauschlaufwerke eingerichtet in denen Nutzer Daten untereinander easy austauschen können.
Hier bleiben Dateien oft lange liegen. Es soll jetzt für jeden User aus der AD geschaut werden wie lange die Daten da liegen und danach eine Mail geschickt werden, mit Warnung oder Hinweis dass etwas gelöscht wurde.

Script funktioniert, Nutzer werden ausgelesen und Mail geschickt. Daten zuverlässig gelöscht.

ABER:
Hat ein Benutzer Daten zur Löschung (älter als $loeschen Tage) aber nicht zur Warnung (älter als $warnung Tage aber jünger als $loeschen Tage) in seinem Laufwerk, dann springt er mir in die falsche Schleife.

Lange Rede kurzer Sinn. Hier der Code und die Operatorenverknüpfung um die es sich dreht:
If (((Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {(($heute - $_.LastWriteTime).Days -gt $warnung) -and (($heute - $_.LasWriteTime).Days -lt $loeschen)}) -ne $null) -and (Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $loeschen}) -ne $null) # herausfinden ob Dateien zur Warnung da sind und welche gelöscht werden.

Ich bekomme folgenden Fehler bei der Ausführung:

PS C:\Users\administrator\Documents> .\abfallpruefungwerk4_test.ps1Für "op_Subtraction" und die folgende Argumenteanzahl kann keine Überladung gefunden werden: "2".  
In C:\Users\administrator\Documents\abfallpruefungwerk4_test.ps1:68 Zeichen:75
+                         If (((Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {(($heu ...
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) , MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest


Danke schon einmal im voraus!

Content-ID: 279756

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

Ausgedruckt am: 16.11.2024 um 11:11 Uhr

122990
122990 10.08.2015 aktualisiert um 09:50:08 Uhr
Goto Top
Moin,
FullyQualifiedErrorId : MethodCountCouldNotFindBest
Diese Zeile gibt den entscheidenden Hinweis, die Powershell kann den Typ einer deiner Variablen nicht eindeutig identifizieren, deswegen findet es auch keine passende Funktionsüberladung mit deinen Variablen als Parameter.
D.h. also das eine deiner Date-Variablen die du zur Subtraktion nutzt keinen eindeutigen Typ aufweist.

Definiere sie von Anfang an mit expliziter Definition des Typs
Beispiel:
[datetime]$heute = Get-Date

Dann weiß die Powershell auch sicher
um welchen Typ es sich handelt.

Da du hier noch andere Variablen nutzt deren Definition du hier nicht gepostet hast, können wir also nur Vermutungen anstellen.
Aber das ist die Standardmeldung wenn ein Variablentyp nicht passt.

Gruß grexit
Baeckster
Baeckster 10.08.2015 aktualisiert um 10:40:10 Uhr
Goto Top
Hey,

ich habe es eben mit deiner Verbesserung versucht, leider ohne Erfolg. Es kommt immer noch die gleiche Fehlermeldung.

Das komplette Script:
# Die ersten Zeilen dienen nur zum laden des ActiveDirectory Moduls, falls vorhanden. 
if ((get-module | where { $_.Name -eq "ActiveDirectory"}) -eq $null) {    
        import-module ActiveDirectory;  
        if ((get-module | where { $_.Name -eq "ActiveDirectory"}) -eq $null) {throw "ActiveDirectory Module is required."}    
        }  
#-----------------------------------------
#Hier Alter der jeweiligen Daten definieren!
$loeschen = 30           # Tagesalter ab dem die Daten gelöscht werden
$warnung = 10            # Tagesalter ab dem eine Löschung vorgewarnt wird
#-----------------------------------------

#-----------------------------------------
# Definition der Variablen
$server = "w4srv1"  
#-----------------------------------------



#-------------------------------------------
# Benutzer aus der AD in OU Werk4 auslesen und für alle Ergebnisse eine Abfrage starten:
Get-ADUser -filter {name -like "*"} -searchbase "OU=Werktest,DC=******,DC=local" -properties EmailAddress, GivenName | foreach {   

                        # Variablen definieren pro Durchlauf
                        $user = $_.samaccountname
                        $mail = $_.emailaddress
                        [datetime]$heute = get-date
        
#-----------------------------------------
#Hier werden die Textbausteine für die Mail gebaut

$Einleitungmitwarnung1 = "  
TEXT
"  

$Einleitungmitwarnung2 = "  
TEXT
"  

$Einleitungohnewarnung = "  
TEXT
"  

$weiterleitung1 = "  
TEXT
"  

$weiterleitung2 = "  
TEXT
"  

                                                                                  
$abschluss = "  
TEXT
"  
#-------------------------------------------
If (((Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $warnung}) -ne $null) -and (Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $loeschen}) -ne $null) # herausfinden ob Dateien zur Warnung da sind und welche gelöscht werden.
                                               {
                                                           
#Hier der Fall, dass Dateien gelöscht werden /wurden und gewarnt wird
                                                                                  
Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $loeschen} > c:\temp_geloescht.txt          # Herausfinden welche Dateien gelöscht werden
$loeschenliste = get-content c:\temp_geloescht.txt             # Ausgabe einlesen in Variable $loeschenliste
$loeschenliste = out-string -InputObject $loeschenliste # Umwandeln der Variable vom Typ System.Object in System.String um per Mail verschickt werden zu können
 Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $loeschen} | Remove-Item -recurse  # Dateien löschen
 Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $warnung} > c:\temp_gewarnt.txt    # Herausfinden welche Dateien zur Löschung anstehen
$warnungliste = get-content c:\temp_gewarnt.txt                                       # Ausgabe einlesen in Variable $warnungliste
$warnungliste = out-string -InputObject $warnungliste # Umwandeln der Variable vom Typ System.Object in System.String um per Mail verschickt werden zu können
                                                                                  
#Mailversand mit Hinweis auf gelöschte Dateien und zur Löschung vorgesehene                                                                               
send-mailmessage -to $_.EmailAddress -from abfallreminder@******.com -Subject "Alte Dateien gefunden / Old Data found" -body "$Einleitungmitwarnung1 $warnungliste $weiterleitung1 $loeschenliste $abschluss"  -smtpserver w1srv04.******.local   
                                               }
 



# Hier der Fall, dass Warnungen vorhanden sind aber nichts gelöscht wird / wurde!!!
                                                                                  
Elseif (((Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $warnung}) -ne $null) -and (Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $loeschen}) -eq $null) # Herausfinden ob Dateien zur Warnung da sind aber keine gelöscht werden.
                                                           {                                  
                                                                                                          
Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $warnung} > c:\temp_gewarnt.txt    # Herausfinden welche Dateien zur Löschung anstehen
 $warnungliste = get-content c:\temp_gewarnt.txt                                        # Ausgabe einlesen in Variable $warnungliste
 $warnungliste = out-string -InputObject $warnungliste # Umwandeln der Variable vom Typ System.Object in System.String um per Mail verschickt werden zu können

 # Mailversand mit Hinweis auf gelöschte Dateien und zur Löschung vorgesehene                                            
send-mailmessage -to $_.EmailAddress -from abfallreminder@******.com -Subject "Alte Dateien gefunden / Old Data found" -body "$Einleitungmitwarnung1 $warnungliste $weiterleitung2 $abschluss"  -smtpserver w1srv04.*****.local   
                                                           }
                                                                       


# Hier der Fall, dass nicht gewarnt aber gelöscht wird!!!

ElseIf (((Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $loeschen}) -ne $null) -and (Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $warnung}) -eq $null) # Es wird gelöscht aber nicht gewarnt
                                                                                  {
                                                                                              
Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $loeschen} > c:\temp_geloescht.txt          # Herausfinden welche Dateien gelöscht werden
 $loeschenliste = get-content c:\temp_geloescht.txt             # Ausgabe einlesen in Variable $loeschenliste
 $loeschenliste = out-string -InputObject $loeschenliste # Umwandeln der Variable vom Typ System.Object in System.String um per Mail verschickt werden zu können
 Get-ChildItem \\$server\abfall\$user -Recurse | Where-Object {($heute - $_.LastWriteTime).Days -gt $loeschen} | Remove-Item -recurse  # Dateien löschen

# Mailversand mit Hinweis auf gelöschte Dateien ohne Warnungen          
send-mailmessage -to $_.EmailAddress -from abfallreminder@*****.com -Subject "Alte Dateien gefunden / Old Data found" -body "$Einleitungmitwarnung2 $loeschenliste $abschluss"  -smtpserver w1srv04.*****.local   
                                                                                  }
 

                                                                                
# Mailversand ohne Hinweis
Else     
                                                                                                          {
send-mailmessage -to $_.EmailAddress -from abfallreminder@*****.com -Subject "Keine alten Dateien gefunden / No Old Data found" -body "$Einleitungohnewarnung $abschluss"  -smtpserver w1srv04.*****.local   
  
                                                                                                        }


            #-------------------------------------------
            #Ende der Schleife für jeden Benutzer. Ab jetzt einmalige Aktionen!
            del c:\temp_geloescht.txt
            del c:\temp_gewarnt.txt                                                                                           
            }

Hoffe damit kannst du mehr anfangen face-smile

Gruß Timo
114757
Lösung 114757 10.08.2015, aktualisiert am 18.08.2015 um 08:36:28 Uhr
Goto Top
Moin Timo,
ich würde das ganze effektiver Lösen, da du ziemlich viel redundante Konstrukte mehrfach verwendest, das kostet Unmengen an CPU und Rechenzeit für das Skript.
Ich würde besser gleich alle Dateien durchlaufen und nur die zutreffenden Dateien ausfiltern und anschließend direkt über den Datei-Owner vie group die Dateien gruppieren.
Anschließend iterierst du über die beiden Gruppen von Dateien (Eine Warn-Gruppe und eine Löschgruppe) und erledigst darauf deine Aktionen (Löschen oder nur benachrichtigen):

Das sieht dann etwa so aus:
$warnung = 10
$loeschen = 30
$heute = get-date

# Set für Dateien die vorgewarnt werden sollen
$warn_set = gci "$server\Abfall" -Recurse | ?{$_.LastWriteTime -lt $heute.AddDays(-$warnung) -and $_.LastWriteTime -gt $heute.AddDays(-$loeschen)} | group {$_.GetAccessControl().GetOwner([System.Security.Principal.NTAccount])}  

# Set für Dateien die gelöscht werden
$deletion_set = gci "$server\Abfall" -Recurse | ?{$_.LastWriteTime -lt $heute.AddDays(-$loeschen)} | group {$_.GetAccessControl().GetOwner([System.Security.Principal.NTAccount])}  

#durchläuft das Set an Usern mit Dateien die vorgewarnt werden sollen
$warn_set | %{
    # Email des Users holen
    $user_mail = (get-aduser ($_.Name.toString().split('\')[1]) -Properties EMailAddress).EmailAddress  
    # Dateipfade in ein String laden welcher dann via send-mailmessage übermittelt werden kann
    $files = $_.Group.FullName -join "`r`n"  
    # Send-Mailmessage ...........
}
#durchläuft das Set an Usern mit Dateien die gelöscht werden
$deletion_set | %{
    # Email des Users holen
    $user_mail = (get-aduser ($_.Name.toString().split('\')[1]) -Properties EMailAddress).EmailAddress  
    # Dateien des Users die gelöscht werden
    $files = $_.Group
    $files | Remove-Item -Recurse -Force
    
    # Send-MailMessage ...........
}
Ist meiner Meinung nach wesentlich übersichtlicher und erheblich schneller!

Gruß jodel32
Baeckster
Baeckster 10.08.2015 um 15:56:04 Uhr
Goto Top
Hey jodel32,
danke für die super Hilfe und das Skript. Da merkt man den Unterschied face-wink
Wir haben versucht das Teil ans Laufen zu bekommen und scheitern am Einlesen der E-Mail Adresse.
Scheinbar kommt die PS nicht mit der geschweiften Klammer klar und meint, dass es ein Skript lesen muss an der Stelle.
Versuche mit anderen Klammerarten oder weglassen haben uns leider nicht weitergeholfen. Hast du hierfür noch eine Lösung? Anbei die Fehlermeldung:

Get-ADUser : Der Parameter "Identity" kann nicht ausgewertet werden, da dessen Argument als Skriptblock angegeben  
wurde und keine Eingabe vorhanden ist. Ein Skriptblock kann nicht ohne Eingabe ausgewertet werden.
In Zeile:2 Zeichen:26
+ $user_mail = (get-aduser {$_.Name.split('\')[1]}).EmailAddress  
+                          ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [Get-ADUser], ParameterBindingException
    + FullyQualifiedErrorId : ScriptBlockArgumentNoInput,Microsoft.ActiveDirectory.Management.Commands.GetADUser

Viele Grüße und nochmals Danke!
Timo
114757
114757 10.08.2015 um 16:42:09 Uhr
Goto Top
Sorry da hab ich gepennt, ist korrigiert ...
Baeckster
Baeckster 11.08.2015 aktualisiert um 10:29:37 Uhr
Goto Top
Hey jodel32,
nochmals vielen Dank für deine super Hilfe face-smile
Leider können wir das Skript nicht verwenden, da oft der Administratoraccount der Owner der Ordner und Dateien ist und nicht der eigentliche Benutzer. Daher kann logischerweise keine Benachrichtigung stattfinden.
Deshalb werden wir wohl wieder auf unser Anfangsskript zurückgreifen müssen, allerdings ohne die erste nicht funktionierende If-Abfrage.
Falls jemand noch eine Idee hat würden wir uns über jede Hilfe freuen! face-smile

Gruß Timo
114757
114757 11.08.2015 aktualisiert um 11:00:16 Uhr
Goto Top
Na dann könntest du stattdessen den Usernamen einfach aus dem Pfad zur Datei auslesen face-wink

Dazu einfach das Grouping so abändern:
....... | group {$_.Name.Split('\')[4]}