PowerShell Ausgabe von mehreren Rückgabewerten

ntloader

Commander
Registriert
Juni 2004
Beiträge
2.475
Hallo,

ich möchte ein Skript schreiben, dass über alle Laufwerke verteilt nach einem bestimmten Dateityp sucht und die gefundenen Dateien inkl. Dateigröße dann ausgibt. So sieht es aktuell aus:

PowerShell:
$volumes = Get-Volume | where Size -GT 1gb
$volumes = $volumes.driveletter
foreach ($driveletter in $volumes)
    {

    
    
     $driveletter = $driveletter + ":\"
     $vhdxfiles = Get-ChildItem $driveletter -Recurse -Filter *.vhdx -ErrorAction SilentlyContinue
     $vhdxfiles = $vhdxfiles.name
     $vhdxdirectory = $vhdxfiles.Directory
     $vhdxsize = $vhdxfiles.Length
     $vhdxlastwrite = $vhdxfiles.LastWriteTime

     $OutputObj  = New-Object -Type PSObject
     $OutputObj | Add-Member -MemberType NoteProperty -Name VHD -Value $vhdxfiles <----
    
     }

Mein Problem ist nun die letzte Zeile (da sollen noch mehr so Zeilen zur Ausgabe für andere Infos (Dateigröße, Pfad, etc) folgen.
In der Variable $vhdxfiles sind die gefundenen Dateien über mehrere Verzeichnisse / Festplatten verteilt. Anscheinend kommt meine Ausgabe nicht dabei klar, dass mehrere Objekte in der Variablen stecken. Ist nur ein Objekt darin, scheints zu gehen.

Hat mir jemand eine Idee, wie ich das gelöst bekomme?

Danke, ntloader
 
Du musst die Einträge halt in nem Array, ner Liste o.ä. sammeln und dort drauf pushen. Quick'n'Dirty einfach das Objekt ausgeben, die PowerShell sammelt die Objekte dann selbst und gibt sie entsprechend aus.

Wundert mich aber dass es "funktioniert", denn du überschreibst $vhdxfiles prompt mit dem einen/ersten Dateinamen, nachdem du alle auf dem Laufwerk gefunden hast. Normalerweise solltest du da ebenso drüber iterieren.
 
zweite schleife?
Code:
foreach ($file in $vhdxfiles){
    $OutputObj | Add-Member -MemberType NoteProperty -Name VHD -Value $file
}
 
LuAmRaTeu schrieb:
zweite schleife?
Code:
foreach ($file in $vhdxfiles){
    $OutputObj | Add-Member -MemberType NoteProperty -Name VHD -Value $file
}

Nope, schon versucht. Bekomme ich damit nicht hin.
Add-Member : Cannot add a member with the name "VHD" because a member with that name already exists. To overwrite the member anyway, add the Force parameter to your
command.
 
Wenn du in jeder Schleife $OutputObj neu erstellst, kann das gar nicht funktionieren. Erstelle das einfach vor der Schleife.

Das ganze geht auch viel einfacher:



$volumes = Get-Volume | where Size -GT 1gb
$volumes = $volumes.driveletter
$OutputObj = New-Object -Type PSObject
foreach ($driveletter in $volumes)
{
$driveletter = $driveletter + ":\"
$OutputObj = Get-ChildItem $driveletter -Recurse -Filter *.vhdx -ErrorAction SilentlyContinue
}
foreach ($FOO in $OutputObj)
{
echo $FOO.Name #Oder was auch immer man haben will
}
 
Ich glaube du hast nicht ganz verstanden, was ich möchte. Ich hätte gerne eine tabellarische Darstellung von sagen wir einfach mal dem Dateinamen und der Größe der Datei. Wie wäre das zu bewerkstelligen?

Danke, ntloader
 
Du kannst Add-Member einfach ein -PassThru mitgeben und weitere Add-Members anhängen, immer mit dem -Passthru. Ausnahme: das letzte Add-Member.

Oder, was auch geht:
PowerShell:
$obj = '' | select FeldA, FeldB, FeldC
$obj.FeldA = $wert1
$obj.FeldB = $wert2
# etc.

Alternativ wie vorgeschlagen in einer Hashtable sammeln. Die kann man dann auch in ein Objekt mit den fraglichen Feldern konvertieren.

Wichtig bei PS: Das Teil arbeitet bereits mit Listen. Öfter als nicht braucht man foreach oder sowas nicht oder nicht so oft.

An der Stelle kann man das auch verschachteln und dann jedes Ergebnis bei Fund ausgeben lassen. Kein Grund, erst alles zusammenzusammeln.
 
Ich glaube irgendwie wir reden aneinander vorbei.
Wie würde denn deine Lösung für mein Problem dann aussehen?
 
Sowas in der Art sollte funktionieren (natürlich noch entsprechend anpassen):

PowerShell:
using namespace System.IO

[ciminstance[]] $volumes = Get-Volume | Where-Object { $_.Size -GT 1gb  -and $_.DriveLetter -ne $null}

foreach ($volume in $volumes)
{   
  [string] $driveletter = '{0}:\' -f $volume.DriveLetter
   Write-Warning -Message ('Scanning Drive [{0}]' -f  $DriveLetter)
  Get-ChildItem -Path $driveletter -Recurse -Filter *.vhdx -ErrorAction SilentlyContinue |
  ForEach-Object {
    [FileInfo] $thisVHDX = $_   

    New-Object -Type PSObject |
    Add-Member -NotePropertyMembers @{
      VHD       = $thisVHDX.Name
      Location  = $thisVHDX.Directory
      Size      = $thisVHDX.Length
      LastWrite = $thisVHDX.LastWriteTime
    }   -PassThru
  }
}

Notes:

--- Dies umgeht das Problem des ursprünglichen Ansatzes nicht, daß Volumes nur durchsucht werden, wenn sie auch einen LW-Buchstaben haben; irgendwo im Dateisystem gemountete Volumes werden nicht durchsucht. Allerdings wurde dieser Fall per Filter ausgeschlossen, um Fehler während der Laufzeit zu vermeiden.

--- Verwendet PS5+ Syntax, insbesondere using namespace.

--- Retypisierung von Variablen ist nach Möglichkeit zu vermeiden. Entweder $vhdxfiles ist (object[]) Datei oder es ist (string[]) Dateiname. Beides zusammen sorgt nur dafür, daß das Script oben im OP nicht funktionieren kann.

--- Ich schlage außerdem vor, statt eines PSObjects für die Ausgabe einfach das stinknormale Dateiobjekt zu speichern (wenn es während des Durchlaufs überhaupt gespeichert wird). Einzelne Felder kann man hinterher immer noch ansprechen und für den Speicherbedarf nimmt das Objekt (Referenz) sehr viel weniger Platz weg als seine kopierten Eigenschaften (Werte).

--- Eine Weile wird das Script auch brauchen. Es ist daher zu überlegen, hier und da Statusmeldungen einzufügen (wo sinnvoll) damit man sieht, daß da was passiert. Das wäre dann aber schon Option Fortgeschritten(tm), da man dann mit Jobs oder Threads arbeiten muß.

Anders geht natürlich immer, und einen Anspruch darauf, daß dieser Ansatz der bessere wäre, gibt es natürlich nicht. :lol:
 
Zuletzt bearbeitet von einem Moderator:
Besten Dank für deine Antwort.
Da deine Powershell Skills meinen offenbar weit überlegen sind: Hast du irgendeine Buchempfehlung oder so für mich? Ich habe zwar schon ein paar PS-Bücher mir angeschaut, allerdings zu so Problemen wie ich sie z.B. im initialen Beitrag dieses Threads hatte, findet man in den Büchern in die ich bisher geschaut habe auch keine Lösungsansätze.
 
Ich bin da eher der theoretische Typ. Mir reichen Bücher aus allen Ecken, solange darin nur Probleme auftauchen und wie mit ihnen umgegangen wird.
Ob das für Dich reicht, weiß ich nicht.

Im Zweifel Dotnet Ressourcen mitnutzen und in PS die Autovervollständigen-Funktion mißbrauchen. Plus, Visual Studio und Intellisense. Einfach drauflos tippen und sagen wir ein neues FileInfo Objekt erstellen, nur zu Übungszwecken, nichts Richtiges.
Dann gucken, was VS so anbietet. Oft kommt man so recht schnell irgendwohin.
 
Zurück
Oben