petergyger
Goto Top

Powershell: Verzeichnis ohne Datei x

Hallo

Ausgangslage
Verzeichnis mit 2 Unterverzeichnisebenen:
[root]
¦__[Leve1]
¦______[Level2]

In den Verzeichnissen von [Level2] hat es Dateien.
Ich benötige eine Liste aller Verzeichnisse, welche die Datei "weekday.xml" nicht enthalten.

Entwurf
Get-ChildItem -Path "t:\Kalender\an" -Recurse -Directory | ForEach-Object {  
    $directory = $_
    $containsFile = Get-ChildItem -Path $directory.FullName -Filter "metadata.opf" -File -ErrorAction SilentlyContinue  

    if (-not $containsFile) {
        [PSCustomObject]@{
            Directory = $directory.FullName
        }
    }
} | Format-Table

Dieser Entwurf zeigt alle Verzeichnisse der Ebene2 an. Egal ob weekday.xml vorhanden ist.
Hinweis auf meinen Denkfehler erwünscht...

Beste Grüsse

Content-ID: 7886732637

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

Ausgedruckt am: 23.11.2024 um 20:11 Uhr

Kraemer
Lösung Kraemer 18.07.2023 aktualisiert um 12:49:24 Uhr
Goto Top
Moin,

Test-Path ist dein Freund.

Gruß
6376382705
Lösung 6376382705 18.07.2023 aktualisiert um 12:49:24 Uhr
Goto Top
Hi.

# Gib hier den Pfad des übergeordneten Verzeichnisses ein, in dem du suchen möchtest.
$baseDirectory = "C:\Pfad\Zum\Übergeordneten\Verzeichnis"  

# Liste aller Verzeichnisse im übergeordneten Verzeichnis abrufen und nach Verzeichnissen ohne "weekday.xml" filtern. 
$directoriesWithoutWeekdayXml = Get-ChildItem -Path $baseDirectory -Directory |
    Where-Object { -Not (Test-Path (Join-Path $_.FullName "weekday.xml")) }  

# Die Liste der Verzeichnisse ohne "weekday.xml" ausgeben. 
$directoriesWithoutWeekdayXml | ForEach-Object { $_.FullName }

ungetestet.

Gruß
PeterGyger
PeterGyger 18.07.2023 aktualisiert um 12:49:24 Uhr
Goto Top

# Gib hier den Pfad des übergeordneten Verzeichnisses ein, in dem du suchen möchtest.
$baseDirectory = "C:\Pfad\Zum\Übergeordneten\Verzeichnis"  

# Liste aller Verzeichnisse im übergeordneten Verzeichnis abrufen und nach Verzeichnissen ohne "weekday.xml" filtern. 
$directoriesWithoutWeekdayXml = Get-ChildItem -Path $baseDirectory -Directory |
    Where-Object { -Not (Test-Path (Join-Path $_.FullName "weekday.xml")) }  

# Die Liste der Verzeichnisse ohne "weekday.xml" ausgeben. 
$directoriesWithoutWeekdayXml | ForEach-Object { $_.FullName }

Hallo emm386

Erster Test mit Deinem Snippet durchgelaufen. Sieht gut aus. Wenn ich noch Fehler finde, dokumentiere ich das hier.
Einen extra Punkt für die ausführliche Dokumentation.

Beste Grüsse



Test-Path ist dein Freund.

Gruß
Hallo erik

Exakt. Das war mir entfallen.

Beste Grüsse
7426148943
7426148943 18.07.2023 aktualisiert um 12:56:55 Uhr
Goto Top
Moin.
Es geht auch ohne Test-Path
$baseDirectory = "C:\Pfad\Zum\Übergeordneten\Verzeichnis"   
Get-ChildItem $baseDirectory -Directory | ?{!$_.GetFiles("weekday.xml")} | select -Expand Fullname  

Zeppel
PeterGyger
PeterGyger 18.07.2023 um 12:58:37 Uhr
Goto Top
$baseDirectory = "C:\Pfad\Zum\Übergeordneten\Verzeichnis"   
Get-ChildItem $baseDirectory -Directory | ?{!$_.GetFiles("weekday.xml")} | select -Expand Fullname  

Hallo Zeppel

Das ist definitiv smart! Eine K.O. Lösung - effizienter geht es nicht - IMHO.

Aber...

Alle Lösungen haben einen Designfehler. D.h. ich habe die Aufgabe nicht klar genug geschildert.
Es sollen nur die Verzeichnisse der Ebene2 nach dieser Datei durchsucht werden.
Die Ebene1 hat nur Verzeichnisse.

Ich editiere /teste gerade die Lösung. Mal sehen, ob ich zum Ziel komme.

Beste Grüsse
7426148943
Lösung 7426148943 18.07.2023 aktualisiert um 13:05:32 Uhr
Goto Top
lle Lösungen haben einen Designfehler. D.h. ich habe die Aufgabe nicht klar genug geschildert.
Es sollen nur die Verzeichnisse der Ebene2 nach dieser Datei durchsucht werden.
Die Ebene1 hat nur Verzeichnisse.
In dem Fall liefert dir das hier das Gewünschte, einfach noch ein "\*\*" an die Variable pappen, feddisch.
$baseDirectory = "C:\Pfad\Zum\Übergeordneten\Verzeichnis"     
Get-ChildItem "$baseDirectory\*\*" -Directory | ?{!$_.GetFiles("weekday.xml")} | select -Expand Fullname    
PeterGyger
PeterGyger 18.07.2023 um 13:19:29 Uhr
Goto Top
Hallo Zeppel

Gerade 2x erfolgreich getestet. Noch dazu mit einem nano kleinen Snippet. Pokal verdient

...
Und sie laufen! Naß und nässer
wirds im Saal und auf den Stufen.
Welch entsetzliches Gewässer!
Herr und Meister! hör mich rufen! –
Ach, da kommt der Meister!
Herr, die Not ist groß!
Die ich rief, die Geister
werd ich nun nicht los.

»In die Ecke,
Besen, Besen!
Seids gewesen.
Denn als Geister
ruft euch nur zu seinem Zwecke,
erst hervor der alte Meister.«


Beste Grüsse
7426148943
7426148943 18.07.2023 aktualisiert um 13:25:53 Uhr
Goto Top
Naja kürzer geht hier auch noch ist dann aber für einen Laien der das lesen muss schwer interpretierbar
(ls "$baseDirectory\*\*" -Dir | ?{!$_.GetFiles("weekday.xml")}).Fullname  
PeterGyger
PeterGyger 18.07.2023 um 14:50:16 Uhr
Goto Top
Hallo Zeppel

Da lerne ich wieder extrem viel über PS.

$baseDirectory = "d:\temp"       
(ls "$baseDirectory\*\*" -Dir | ?{!$_.GetFiles("weekday.xml")}).Fullname    

Analyse:
- Code in der Klammer kapselt - d.h. das Resultat wird als Ausdruck behandelt. In diesem soll das Property "Fullname" angezeigt werden, wenn der Ausdruck ein Objekt schickt.
-
ls "$baseDirectory\*\*"  
-- Erstellt eine Liste der Objekte im Dateisystem im Pfad ls "$baseDirectory\*\*"
-
-DIR 
-- jetzt wird es unlogisch. "ls" als auch "dir" sind vorgegebe Aliase von GCI (Get-Alias -Definition Get-ChildItem)
-- d.h. ich kann in der PS den Befehl
ls D:\bibliothek.bak -dir
absetzen. "-DIR" zeigt jedoch keinen Effekt. Wenn ich aber
ls D:\bibliothek.bak -ls
eingebe erhalte ich einen Fehler:
Get-ChildItem : Es wurde kein Parameter gefunden, der dem Parameternamen "ls" entspricht.  

A: Welchen Zweck hat der Parameter "-ls"? 🚧
B: Weshalb erhalte ich bei Dir einen Fehler? 🚧
C: Wenn den Parameter "-ls" weglasse, funktioniert das Skript dennoch 🤔🤔🤔

$baseDirectory = "D:\temp"       
(ls "$baseDirectory\*\*" | ?{!$_.GetFiles("weekday.xml")}).Fullname    

Pipe
-
?
-- Alias für das "where-object"
-
!
-- negiert (NOT) die nachfolgende Funktion
-
$_
-- Variable für das aktuelle Element im Durchgang
-
$_.GetFiles("weekday.xml")  
-- Zugriff auf Datei Attribute von $_
Zusammengefasst überprüft der Filter nach Pipe, ob die aktuelle Datei in der Liste kein Property mit dem Wert "weekday.xml" hat. Wenn ja, wird der Wert des Property Fullname angezeigt.

Abgesehen von den zwei Baustellen oben, verstehe ich diese Zeile.
Danke für die Lektion.

Beste Grüsse
Kraemer
Kraemer 18.07.2023 um 15:10:25 Uhr
Goto Top
Ich versuchs mal face-wink

 Get-Alias dir

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           dir -> Get-ChildItem

Get-Alias ls

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           ls -> Get-ChildItem

Bei dem -dir bin ich mir auch unsicher. Es ist schon mal kein Parameteralias von Get-Childitem
(Get-Command Get-ChildItem).Parameters.Values.aliases

und auch kein Alias von -Directory obwohl genau das ersetzt wurde
(Get-Command Get-ChildItem).Parameters["Directory"].Aliases  
ad
d
7426148943
7426148943 18.07.2023 aktualisiert um 16:50:10 Uhr
Goto Top
Zitat von @PeterGyger:
-
-DIR 
-- jetzt wird es unlogisch. "ls" als auch "dir" sind vorgegebe Aliase von GCI (Get-Alias -Definition Get-ChildItem)
ls ist ein Alias für Get-ChildItem korrejt, aber -Dir ist ein Parameter von Get-Childitem und zwar die Abkürzung von -Directory! Das es kein Alias ist erkennst du an dem Dash vor dem Namen somit ist es ein Parameter der Funktion Get-ChildItem.

A: Welchen Zweck hat der Parameter "-ls"? 🚧
ls ist kein Parameter sonder ein Alias von Get-ChildItem.
B: Weshalb erhalte ich bei Dir einen Fehler? 🚧
C: Wenn den Parameter "-ls" weglasse, funktioniert das Skript dennoch 🤔🤔🤔
Du wirfst CMDLet(bzw. Alias) und Parameter durcheinander ganz einfach.
Es gibt Funktionen (CMDLets) diese lassen sich mit Aliasen aufrufen sofern angelegt , die Funktionen selbst haben Parameter die mit dem Dash(-) eingeleitet werden, aber auch unbenannte Parameter haben können die man direkt angeben kann wie hier bspw. der Pfad. Für die Parameternamen selbst gibt es ebenfalls Abkürzungen wie das -Dir hier bspw. Die Abkürzung von -Directory ist.
Nun klar?

Wenn nicht hier zum nachlesen
https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/ ...

Vielleicht mal von der Pike auf lernen, an einem verregneten Wochenende hat man das durch ...

Powershell Leitfaden für Anfänger
PeterGyger
PeterGyger 19.07.2023 um 17:05:24 Uhr
Goto Top
Hallo 7426148943

Punkt "-dir"
Das habe ich inzwischen über SS64.com herausgefunden.
Da Du diese Info fett hervorgehoben hast, hast Du Dich wahrscheinlich genervt. Mein Glück, dass es auch anderen Teilnehmern wie Kraemer nicht klar war...

Punkt "-ls"
Das habe ich bereits früher festgehalten.
ps-dir

Das Du nicht nachvollziehen kannst, dass wenn man links "ls" liest und rechts "-Dir" sieht, automatisch an den Alias denkt, ist schade. In der Psychologie nennt man das einen Anker Effekt. Zu diesen Basiskenntnissen kann ich Dir gerne ein Buch empfehlen.

Was sagt ein Profi wie Du zu diesem Konstrukt?
"$baseDirectory\*\*"

Die Bücher die ich über PS als OO Sprache gelesen habe, müsste man jede Verzeichnisebene als Objekte einlesen. Und am Schluss die Funktion einsetzen. Nur weil es "geht", heisst es ja nicht das es ein guter bzw. effizienter Stil ist.
Auch als Praktiker bin ich offen für strategische Konzepte einer Sprache.

Beste Grüsse