mabe12
Goto Top

Falsche Berechnung in Powershellscript

Hallo Zusammen,
seit kurzem beschäftige ich mich etwas mit Powershell und habe da (für mich) ein sehr interessantes Phänomen.
Das Script soll mir die Ordnergrößen mehrerer Ordner und zum Schluß die Summe ausgeben.
Solange wie ich das in der ISE teste ist alles so wie ich es haben möchte aber sobald ich entweder die xx.ps1 direkt aufrufe oder über eine Batch zeigt er als Summe nur noch den letzten abgefragten Wert an und da stehe ich etwas auf dem Schlauch und würde mich freuen wenn mir da jemand meinen Denkfehler zeigen könnte.

Das Script:

$Folders = @(
    "$env:USERPROFILE\Desktop"  
    "$env:USERPROFILE\Documents"  
    "$env:USERPROFILE\Downloads"  
        )

$total = 0
'Größe der Ordner:'  

#ForEach ($Folder in ($Folders)) {"$_      : {0:n3} GB" -f ((Get-ChildItem -Path $_ -Force -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).sum/1GB)} 

& {
ForEach ($_ in ($Folders))  
    {
        $sum1 = (Get-ChildItem -Path $_ -Force -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).sum
        New-Object psobject -Property @{
                    Pfad = $_
                    Größe = '{0:n3} GB' -f ($sum1/1GB)  
                } 
        $Global:total = $total + $sum1
        }
        } | Format-Table -auto Pfad,Größe

'Summe der Ordner: {0:n3} GB' -f (($Global:total)/1GB)  


Als Ergebnis erhalte ich dann (richtig):
Pfad Größe
-----
C:\Users\xyz\Desktop 0,004 GB
C:\Users\xyz\Documents 0,000 GB
C:\UserData\xyz\Downloads 6,926 GB

Summe der Ordner: 6,930 GB

Als Ergebnis erhalte ich dann (falsch):
Pfad Größe
-----
C:\Users\xyz\Desktop 0,004 GB
C:\Users\xyz\Documents 0,000 GB
C:\UserData\xyz\Downloads 6,926 GB

Summe der Ordner: 6,926 GB

Content-Key: 1821571299

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

Printed on: April 28, 2024 at 15:04 o'clock

Member: SeaStorm
SeaStorm Feb 03, 2022 updated at 15:03:45 (UTC)
Goto Top
Hi

du hantierst hier aus einer Mischung zwischen GLOBAL und LOCAL Variablen.
Global funktioniert in der ISE nicht wirklich, weil es im Grunde Zeile für Zeile einzeln ausführt und damit Global und Local das gleiche ist.

Das wird deutlich wenn du dein Script mal um 2 Ausgaben erweiterst:

       $Global:total = $total + $sum1
        Write-Host "Total im FE: $($Global:total/1GB)"  
        }
        Write-Host "Total NACH FE: $($Global:total/1GB)"  
        $result | Format-Table -auto Pfad,Größe

Ausgabe in der ISE:
Größe der Ordner:
Total im FE: 0.0578269734978676
Total im FE: 0.0697913477197289
Total im FE: 36.6269341837615
Total NACH FE: 36.6269341837615

Pfad                      Größe    
----                      -----    
C:\Users\SeaStorm\Desktop   0,058 GB 
C:\Users\SeaStorm\Documents 0,012 GB 
C:\Users\SeaStorm\Downloads 36,557 GB


Summe der Ordner: 36,627 GB

Ausgabe als PS1:
Größe der Ordner:
Total im FE: 0.0578269734978676
Total im FE: 0.0119643742218614
Total im FE: 36.5571428360417
Total NACH FE: 36.5571428360417

Pfad                      Größe
----                      -----
C:\Users\SeaStorm\Desktop   0,058 GB
C:\Users\SeaStorm\Documents 0,012 GB
C:\Users\SeaStorm\Downloads 36,557 GB


Summe der Ordner: 36,557 GB

Du siehst im ISE das die Größen aufeinander addiert werden
und im PS1 das einzelnen größen einfach aufgelistet werden.


Das liegt daran das in der .ps1 deine Zeile
$Global:total = $total + $sum1
Dafür Sorgt das immer ausgeführt wird:
$Global:total ist Jetzt: 0 + Grösse
und nicht
$Global:total ist Jetzt: $Global:total + Grösse

Einfach weil du Local und Global vermischt. deine Variable $total ist immer 0, weil sie nie verändert wird
Du solltest also schreiben:
$Global:total = 0
....
$Global:total = $Global:total + $sum1


oder besser den Quatsch mit dem manuellen summieren lassen und dein CustomObject auch nutzen.
Für was du da den call einbaust erschliesst sich mir allerdings überhaupt nicht.

Ich würde eher sowas basteln:
$Folders = @(
    "$env:USERPROFILE\Desktop"  
    "$env:USERPROFILE\Documents"  
    "$env:USERPROFILE\Downloads"  
        )

'Größe der Ordner:'  

$FolderResult = ForEach ($_ in ($Folders))  
    {
        $sum1 = (Get-ChildItem -Path $_ -Force -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).sum
        New-Object psobject -Property @{
                    Pfad = $_
                    Größe = $sum1/1GB
                } 
    } 
    
 $FolderResult | Format-Table -auto Pfad, @{name=’Größssse’ ; expression={"{0:n3}" -f $_.Größe}}   

'Summe der Ordner: {0:n3} GB' -f (( ($FolderResult.Größe | Measure -Sum).Sum))  
Member: mbehrens
mbehrens Feb 03, 2022 at 20:37:09 (UTC)
Goto Top
Zitat von @mabe12:

$Folders = @(
    "$env:USERPROFILE\Desktop"  
    "$env:USERPROFILE\Documents"  
    "$env:USERPROFILE\Downloads"  
        )

Sollte zur Bestimmung dieser Ordner nicht eher
GetFolderPath
genutzt werden, z. B. via
[Environment]::GetFolderPath("Desktop")  
Member: mabe12
mabe12 Feb 04, 2022 at 11:26:16 (UTC)
Goto Top
Hallo,
vielen Dank für die sehr hilfreichen Antworten, das hat mich doch sehr viel weiter gebracht.

@SeaStorm
Mit der globalen Variable hatte ich angefangen weil ich die lokale nicht aus dem foreach raus bekommen hatte und mit der globalen hatte es funktioniert.
Mit dem CustomObject meinst du "$FolderResult.Größe " nehme ich an?
Soweit bin ich noch nicht das ich das jetzt zu 100% verstehe, das muss ich mir nochmal genauer anschauen.
Auf jeden Fall macht es was ich gern haben wollte und ich habe das Script entsprechend angepasst.
Ich fürchte auch folgendes verstehe ich nicht richtig:
Zitat von @SeaStorm:
Für was du da den call einbaust erschliesst sich mir allerdings überhaupt nicht.
Was genau meinst du damit?

@mbehrens
das kannte ich so noch nicht und was ich nicht verstehe ist wenn ich das so aufrufe bekomme ich den Pfad, genau so wie er benötigt wird.
Wenn ich Get-ChildItem env: aufrufe erhalte ich keinen "Desktop" - woher wird das dann genommen?
Was genau ist der Unterschied bzw Vor- und Nachteile von
"$env:USERPROFILE\Desktop" und [Environment]::GetFolderPath("Desktop")


Ich wollte das Script gern noch dahin weiter entwickeln das ich mir auch die Netzwerkgeschwindigkeit zwischen dem localhost und einem bestimmten Server und dann daraus folgend die vermutliche Uploadzeit anzeigen lasse.
Vermutlich ist es richtiger dazu ein neues Thema anzufangen?
Member: SeaStorm
SeaStorm Feb 04, 2022 at 16:28:48 (UTC)
Goto Top
Zitat von @mabe12:
@SeaStorm
Mit dem CustomObject meinst du "$FolderResult.Größe " nehme ich an?
Jain. $FolderResult kommt ja von mir. Du hast ein Object mit
New-Object psobject -Property ....
erstellt, machst aber nichts damit, ausser es in das Format-Table zu pipen.
Für was du da den call einbaust erschliesst sich mir allerdings überhaupt nicht.
Was genau meinst du damit?
Deine Zeile 12 : "& {"
& ist hier ein Call Operator. Also "& { SCRIPT BLOCK }" um den Scriptblock auszuführen. Ergibt hier einfach keinen Sinn, außer das du das Ergebnis jetzt halt pipen kannst. Dann lieber in eine Variable packen damit man das ganze auch verwenden kann. Ausserdem ist's super hässlich zu lesen face-smile
Member: mbehrens
mbehrens Feb 04, 2022 at 17:05:22 (UTC)
Goto Top
Zitat von @mabe12:

@mbehrens
das kannte ich so noch nicht und was ich nicht verstehe ist wenn ich das so aufrufe bekomme ich den Pfad, genau so wie er benötigt wird.
Wenn ich Get-ChildItem env: aufrufe erhalte ich keinen "Desktop" - woher wird das dann genommen?
Was genau ist der Unterschied bzw Vor- und Nachteile von
"$env:USERPROFILE\Desktop" und [Environment]::GetFolderPath("Desktop")

Dier erste Version benutzt einen Pfad, der auf Umgebungsvariable Userprofile basiert. Dort wird einfach "\Desktop" angehängt. Dieses Verzeichnis (C:\Users\meinBenutzer\Desktop) muss es nicht zwangsläufig geben, z. B. wenn der Desktop umgeleitet ist. Die zweite Version liefert dann den richtigen Pfad (\\meinServer\meineFreigabe\meinBenuzter\Desktop).
Member: mabe12
mabe12 Feb 07, 2022 at 08:44:57 (UTC)
Goto Top
Zitat von @SeaStorm:
Jain. $FolderResult kommt ja von mir. Du hast ein Object mit
New-Object psobject -Property ....
erstellt, machst aber nichts damit, ausser es in das Format-Table zu pipen.
ich meinte mit Object das ".Größe" hinter FolderResult, also ob das das Object ist?
In deinem Vorschlag ist ja auch das New-Object psobject -Property drin und ich vermute das dann Pfad und Größe Teile dieses psobject sind und der Teil Größe dann in der Variable FolderResult verwendet wird?
Oh, ich glaub das wirft gerade mehr Rätsel auf face-plain
Deine Zeile 12 : "& {"
das hatte ich reingemacht weil der Teil sonst nicht gelaufen ist und ich hatte es irgendwo so gesehen - aber gut zu wissen das das dann besser über eine Variable läuft und ich dadurch nicht mit einer globalen hantieren muss