none
Powershell - Continiue on"Error" or "Access denied" bei - System.IO.Directory Klasse GetFiles Methode RRS feed

  • Frage

  • Hi,

    ich habe da ein Problem mit Powershell.

    Ich suche einen Weg eine Datei im Benutzerprofil C:\Users\Username auf über 1000 Windows 7 Computern zu finden.

    Get-ChildItem ist viel zu langsam. Bin bei meinen recherchen hierrauf gestoßen:

    [System.IO.Directory]::GetFiles

    Leider bekomme ich immer den untestehenden Fehler.

    Beim Versuch den Fehler mit try{} catch{} zu umgehen bekomme ich gar keine Ausgabe mehr zu sehen.

    Wie bringe ich meinem Script bei das es einfach weitermachen soll, auch wenn es Fehler erzeugt?

    Ich suche ein: -ErrorAction SilentlyContinue

    Befehl:

    [System.IO.Directory]::GetFiles("\\Computername\c$\Users\Username" , "MobaXterm.ini" , "ALLDIRECTORIES")

    Ausgabe:

    Exception calling "GetFiles" with "3" argument(s): "Access to the path '\\Computername\c$\Users\Username\AppData\Local\Application Data' is denied."
    At line:1 char:1
    + [System.IO.Directory]::GetFiles("\\vm-barakise-7\c$\Users\barakise" , ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : UnauthorizedAccessException

    Dienstag, 31. Juli 2018 13:26

Antworten

  • Moin,

    ich muss meinen Vorrednern aufs Vehementeste in dem Punkt zustimmen, dass eine Remote-Pull-Abfrage nicht optimal ist. Mein Favorit wäre in dem Fall die Software-Verteilung (SCCM kann übrigens von Hause aus Dateien inventarisieren, vermutlich können die Konkurrenzprodukte das auch).

    Wenn es aber remote sein soll, wäre ich für so etwas wie

    $comps = (Get-ADComputer -Filter <Filter Deiner Wahl>).DNSHostName
    $sessions = New-CIMSession -ComputerName $comps
    $sess = New-CIMSession -ComputerName localhost
    Get-CIMInstance CIM_DataFile -Filter "(Drive='C:') AND (Path LIKE '\\Users\\%) AND (FileName='MobaXTerm') AND (Extension='ini')" -CIMSession $sessions | ft Name, PSComputerName
    Da wird die Suche immerhin lokal durch den CIM-Provider ausgeführt.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.




    Dienstag, 31. Juli 2018 21:08
  • Try/Catch kann man auch für die Get-Childitem-Variante anwenden und wirkt quasi wie die ErrorAction.
    Allerdings, und da ist das Missverständniss, wird eben für das ausgeführte cmdlet insgesamt ein Error ausgeworfen.
    Ein Fortsetzen innerhalb der tiefsten Ebene, auf der der Fehler gerade passiert, ist technisch nicht vorgesehen.

    Zum Verständnis:
    Ein Fehler wird an die erste Ebene über den Callstack gemeldet, die eine Try/Catch-Fehlerbehandlung durchführt. Und das ist nun mal leider dein Skript.

    Um also den Fehler zu umgehen und immer weiter zu machen, musst du das ganze selber rekursiv über eine Schleifen-Funktion je Verzeichnisebene ereldigen. Eine automatische Rekursion hilft dir da nicht.

    Wenn du mehrere PC's parallel abfragen willst, hilft dir u.U. das Threading weiter:
    http://www.get-blog.com/?p=189
    https://blogs.technet.microsoft.com/santhse/invokeall/

    Der Nachteil ist aber immer noch, dass alle Daten erst mal lokal von den Rechnern geholt werden müssen.
    Man kann aber die Remoterechner dies selber tun lassen:
    https://www.windowspro.de/wolfgang-sommergut/powershell-remote-ausfuehren-winrm-ueber-gpos-aktivieren

    Somit machst du 2 Dinge:
    a) Je computer ein Thread
    b) Je Thread ein Remote-Aufruf

    Damit hast du dann ParallelComputing über zig Rechner gelöst.


    Dienstag, 31. Juli 2018 15:47

Alle Antworten

  • Ist es wirklich eine gute Idee, auf diese Weise 1000 PCs direkt zu durchsuchen? .... ich bin skeptisch. Nach meiner Erfahrung hat man in Infrastrukturen solcher Größe ein AD und irgendeine Art Softwareverteilung, die für solche Aufgaben deutlich besser geeignet wären. Notfalls dann eben mittels GPOs.

    Wenn Du direkt .Net-Klassen benutzt, kannst Du Dir ein -ErrorAction sparen. Der Parameter funktioniert nur mit Powershell-cmdlets. Und ohne Deinen Code zu sehen, können wir auch schwer beurteilen, warum Dein Try-Catch nicht wie gewünscht funktioniert.

    Unabhängig davon nochmal: Bitte überdenk Deinen Ansatz nochmal. Es gibt vermutlich deutlich bessere (robustere) Ansätze, so eine Aufgabe zu lösen.


    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Dienstag, 31. Juli 2018 13:55
  • Hi,

    erst mal danke für die Antwort.

    Kurze Erklärung zum Code:

    Computername Name:   K3-FischerM-WS

    AD User Name:   FischerM

    UserProfilPfad:    C:\Users\FischerM\

    Deswegen die Codezeile

    $Username = ($computer.Split("-"))[1]

    um den Usernamen vom Computernamen zu trennen.

    Der Username wird gebraucht um auf das jeweilige Windows User Profil Verzeichniss zuzugreifen um eine bestimmte Datei   MobaXterm.ini   zu finden.

    Die Datei befindet sich an verschiedenen und immer unterschiedlichen Stellen im Userprofil.

    Ein weiteres Problem ist das auf ca. 50% der Computer das User Profil auf der D: Partition in D:\Data\Username gespeichert ist, und nicht wie üblich auf C:\User\Username

    Wie schon gesagt ist das cmdlet Get-ChildItem viel zu langsam. Und dauert mit unter viele Tage bis das Script durchgelaufen ist.

    Hier mein Code mit .NET Klassen

    foreach ($computer in Get-Content D:\VirtualMachines.txt)
    {
    $Username = ($computer.Split("-"))[1]
    
    Write-Host "Currently searching in $computer at Path $username"
    
    $PathC = "\\$computer\c$\Users\$username"
    $PathD = "\\$computer\d$\Data\$username"
    
    $filenameC = try {[System.IO.Directory]::GetFiles($PathC, "MobaXterm.ini", "ALLDIRECTORIES")}
    catch {continue}
    
    $filenameD = try {[System.IO.Directory]::GetFiles($PathD, "MobaXterm.ini", "ALLDIRECTORIES")}
    catch {continue}
    
    $filenameC
    $filenameD
    }

    Hier mein Code mit Get-ChildItem

    foreach ($computer in Get-Content D:\VirtualMachines.txt)
    {
    $Username = ($computer.Split("-"))[1]
    
    Write-Host "Currently searching in $computer at Path $username"
    
    Get-ChildItem -Recurse -Force \\$computer\c$\Users\$username -ErrorAction SilentlyContinue | 
    Where-Object { ($_.PSIsContainer -eq $false) -and  ( $_.Name -eq "MobaXterm.ini") } | 
    Select-Object Name,Directory | 
    Export-Csv D:\MobaXTermAtUserProfileC.csv -nti -append
    
    Get-ChildItem -Recurse -Force \\$computer\d$\data\$username -ErrorAction SilentlyContinue | 
    Where-Object { ($_.PSIsContainer -eq $false) -and  ( $_.Name -eq "MobaXterm.ini") } | 
    Select-Object Name,Directory | 
    Export-Csv D:\MobaXTermAtUserProfileD.csv -nti -append
    }

    Habt ihr andere Lösungsansätze?

    Ich brauche eine schnelle Lösung mit der ich Dateien mit einem bestimmten Namen auf allen Remote-Computern finden kann.

    Danke für eure Hilfe ;-)



    • Bearbeitet RoyalFlash Dienstag, 31. Juli 2018 15:10
    Dienstag, 31. Juli 2018 15:05
  • Deswegen die Codezeile

    $Username = ($computer.Split("-"))[1]

    um den Usernamen vom Computernamen zu trennen.

    omg :-))

    Der Username wird gebraucht um auf das jeweilige Windows User Profil Verzeichniss zuzugreifen um eine bestimmte Datei   MobaXterm.ini   zu finden.

    Warum? Steck die Suche in ein Logonskript, das unterhalb von %userprofile% bei der Anmeldung des Benutzers sucht. Das zeigt dann auch immer auf das richtige Verzeichnis. Und das Ergebnis speicherst auf einem Netzwerkshare...

    Viel einfacher, schneller und robuster als die Remote-Lösung von Dir.

    Oder mach's als Computerstartskript, das alle lokalen Profilverzeichnisse durchsucht (Registry -> ProfileList, da steht der Pfad aller vorhandenen Profile drin...).

    Dienstag, 31. Juli 2018 15:45
  • Try/Catch kann man auch für die Get-Childitem-Variante anwenden und wirkt quasi wie die ErrorAction.
    Allerdings, und da ist das Missverständniss, wird eben für das ausgeführte cmdlet insgesamt ein Error ausgeworfen.
    Ein Fortsetzen innerhalb der tiefsten Ebene, auf der der Fehler gerade passiert, ist technisch nicht vorgesehen.

    Zum Verständnis:
    Ein Fehler wird an die erste Ebene über den Callstack gemeldet, die eine Try/Catch-Fehlerbehandlung durchführt. Und das ist nun mal leider dein Skript.

    Um also den Fehler zu umgehen und immer weiter zu machen, musst du das ganze selber rekursiv über eine Schleifen-Funktion je Verzeichnisebene ereldigen. Eine automatische Rekursion hilft dir da nicht.

    Wenn du mehrere PC's parallel abfragen willst, hilft dir u.U. das Threading weiter:
    http://www.get-blog.com/?p=189
    https://blogs.technet.microsoft.com/santhse/invokeall/

    Der Nachteil ist aber immer noch, dass alle Daten erst mal lokal von den Rechnern geholt werden müssen.
    Man kann aber die Remoterechner dies selber tun lassen:
    https://www.windowspro.de/wolfgang-sommergut/powershell-remote-ausfuehren-winrm-ueber-gpos-aktivieren

    Somit machst du 2 Dinge:
    a) Je computer ein Thread
    b) Je Thread ein Remote-Aufruf

    Damit hast du dann ParallelComputing über zig Rechner gelöst.


    Dienstag, 31. Juli 2018 15:47
  • Moin,

    ich muss meinen Vorrednern aufs Vehementeste in dem Punkt zustimmen, dass eine Remote-Pull-Abfrage nicht optimal ist. Mein Favorit wäre in dem Fall die Software-Verteilung (SCCM kann übrigens von Hause aus Dateien inventarisieren, vermutlich können die Konkurrenzprodukte das auch).

    Wenn es aber remote sein soll, wäre ich für so etwas wie

    $comps = (Get-ADComputer -Filter <Filter Deiner Wahl>).DNSHostName
    $sessions = New-CIMSession -ComputerName $comps
    $sess = New-CIMSession -ComputerName localhost
    Get-CIMInstance CIM_DataFile -Filter "(Drive='C:') AND (Path LIKE '\\Users\\%) AND (FileName='MobaXTerm') AND (Extension='ini')" -CIMSession $sessions | ft Name, PSComputerName
    Da wird die Suche immerhin lokal durch den CIM-Provider ausgeführt.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.




    Dienstag, 31. Juli 2018 21:08
  • Deswegen die Codezeile

    $Username = ($computer.Split("-"))[1]

    um den Usernamen vom Computernamen zu trennen.

    omg :-))

    Der Username wird gebraucht um auf das jeweilige Windows User Profil Verzeichniss zuzugreifen um eine bestimmte Datei   MobaXterm.ini   zu finden.

    Warum? Steck die Suche in ein Logonskript, das unterhalb von %userprofile% bei der Anmeldung des Benutzers sucht. Das zeigt dann auch immer auf das richtige Verzeichnis. Und das Ergebnis speicherst auf einem Netzwerkshare...

    Viel einfacher, schneller und robuster als die Remote-Lösung von Dir.

    Oder mach's als Computerstartskript, das alle lokalen Profilverzeichnisse durchsucht (Registry -> ProfileList, da steht der Pfad aller vorhandenen Profile drin...).

    Guten Morgen,

    an das Logonskript hab ich auch schon gedacht. Leider sind das maschinen die rund um die Uhr laufen und sich User nicht einfach an und abmelden. Reboots erfolgen nur bei Windows Updates alle paar Wochen....

    Ich brauche aber eine schnelle Lösung.

    Mittwoch, 1. August 2018 06:40
  • Moin,

    ich muss meinen Vorrednern aufs Vehementeste in dem Punkt zustimmen, dass eine Remote-Pull-Abfrage nicht optimal ist. Mein Favorit wäre in dem Fall die Software-Verteilung (SCCM kann übrigens von Hause aus Dateien inventarisieren, vermutlich können die Konkurrenzprodukte das auch).

    Wenn es aber remote sein soll, wäre ich für so etwas wie

    $comps = (Get-ADComputer -Filter <Filter Deiner Wahl>).DNSHostName
    $sessions = New-CIMSession -ComputerName $comps
    $sess = New-CIMSession -ComputerName localhost
    Get-CIMInstance CIM_DataFile -Filter "(Drive='C:') AND (Path LIKE '\\Users\\%) AND (FileName='MobaXTerm') AND (Extension='ini')" -CIMSession $sessions | ft Name, PSComputerName
    Da wird die Suche immerhin lokal durch den CIM-Provider ausgeführt.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.




    Danke, ich werde es ausprobieren...
    Mittwoch, 1. August 2018 06:44
  • Danke, ich werde es ausprobieren...


    ...aber bitte nicht gleich gegen alle ;-)

    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Mittwoch, 1. August 2018 06:48
  • ...aber bitte nicht gleich gegen alle ;-)
    Schisser!  ;-)  :-D

    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Mittwoch, 1. August 2018 08:10
  • ...aber bitte nicht gleich gegen alle ;-)

    Schisser!  ;-)  :-D

    Kohschn iz ze mazer ov ze porselin kräht 

    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Mittwoch, 1. August 2018 08:52
  • > ....aber bitte nicht gleich gegen alle ;-)

    Doch, dann explodiert sein Admin-Rechner xd

    Mittwoch, 1. August 2018 09:22