Powershell GUI bleibt während einer While schleife hängen...
Hallo alle zusammen!
Ich habe zuzeit ein Powershellproblem wo ich einfach nicht mehr weiterkomme. Ich hoffe ihr könnt mir hier helfen.
Vorgeschichte:
Ich schreibe ein kleines Powershell Backupporgramm mit GUI für unsere Kunden.
Das Programm besteht aus 3 Scripten und einer XML-Datei für die Einstellungen.
Einstellungen.ps1 -> Hier werden die Ziel und Quellpfade eingestellt und in der XML Datei gespeichert.
BackupAufExternenDatenträger.ps1 -> In diesem Script befindet sich die GUI (mit Prograssbar für die Fortschrittsanzeige) und der Backupjob
BackupAufInternenDatenträger.ps1 -> Das gleiche wie BackupAufExternenDatenträger.ps1 nur mit andernen Pfaden
Das Backup erfolgt mit Robocopy über den Befehl Start-Job:
$BackupJob = start-job -Name RIS-Backup -ArgumentList $SicherungsQuelle,$sicherungsPfad,$LogPath -scriptblock{
$LogPath = $args[2]
$Robocopy = robocopy $args $args[1] /mir /V /LOG:$Logpath}
Nachdem der Job gestartet wurde gehts an die Fortschrittsberechnung.
Das habe ich einfach mit einer While-Schleife erledigt, die guckt wie groß sind die zu kopierenden Daten und wieviel wurde schon Kopiert das ganze wird dann noch in Prozent um gerechnet und in einer Progressbar angezeigt.
while ($BackupJob.State -eq "Running")
{
$Kopiert = (Get-ChildItem $sicherungsPfad -Recurse | Measure-Object -property length -sum)
$Kopiert = "{0:N2}" -f ($Kopiert.sum / 1GB) | % {$_ -replace ",","."}
$Prozentanzeiger = 0
$Prozentanzeiger = $Kopiert/$GesamtGrBackup*100
"{0:n1}" -f $Prozentanzeiger
$progressBar1.Value = $prozentanzeiger
### 2 Sekunden warten ###
ping -n 2 localhost | out-null
}
Das ganze Funktioniert wunderbar nur habe ich das Problem, dass solange die While schleife am laufen ist, ich nichts mehr in der GUI machen kann (z.b. den Button "Backup Stoppen" drücken oder das Fenster verschieben )
Ich hatte dann noch die Idee die Schleife auch einfach in einen eigenen Job zu packen dann allerdings wird die Progressbar nicht mehr aktualisiert.
Jetzt zu meiner Frage:
Wie schaffe ich es das die Progressbar durch die schleife aktualisiert wird (Mir also der Fortschritt in der GUI angezeigt wird) und ich gleichzeitig die GUI weiterbenutzen kann?
Ich habe zuzeit ein Powershellproblem wo ich einfach nicht mehr weiterkomme. Ich hoffe ihr könnt mir hier helfen.
Vorgeschichte:
Ich schreibe ein kleines Powershell Backupporgramm mit GUI für unsere Kunden.
Das Programm besteht aus 3 Scripten und einer XML-Datei für die Einstellungen.
Einstellungen.ps1 -> Hier werden die Ziel und Quellpfade eingestellt und in der XML Datei gespeichert.
BackupAufExternenDatenträger.ps1 -> In diesem Script befindet sich die GUI (mit Prograssbar für die Fortschrittsanzeige) und der Backupjob
BackupAufInternenDatenträger.ps1 -> Das gleiche wie BackupAufExternenDatenträger.ps1 nur mit andernen Pfaden
Das Backup erfolgt mit Robocopy über den Befehl Start-Job:
$BackupJob = start-job -Name RIS-Backup -ArgumentList $SicherungsQuelle,$sicherungsPfad,$LogPath -scriptblock{
$LogPath = $args[2]
$Robocopy = robocopy $args $args[1] /mir /V /LOG:$Logpath}
Nachdem der Job gestartet wurde gehts an die Fortschrittsberechnung.
Das habe ich einfach mit einer While-Schleife erledigt, die guckt wie groß sind die zu kopierenden Daten und wieviel wurde schon Kopiert das ganze wird dann noch in Prozent um gerechnet und in einer Progressbar angezeigt.
while ($BackupJob.State -eq "Running")
{
$Kopiert = (Get-ChildItem $sicherungsPfad -Recurse | Measure-Object -property length -sum)
$Kopiert = "{0:N2}" -f ($Kopiert.sum / 1GB) | % {$_ -replace ",","."}
$Prozentanzeiger = 0
$Prozentanzeiger = $Kopiert/$GesamtGrBackup*100
"{0:n1}" -f $Prozentanzeiger
$progressBar1.Value = $prozentanzeiger
### 2 Sekunden warten ###
ping -n 2 localhost | out-null
}
Das ganze Funktioniert wunderbar nur habe ich das Problem, dass solange die While schleife am laufen ist, ich nichts mehr in der GUI machen kann (z.b. den Button "Backup Stoppen" drücken oder das Fenster verschieben )
Ich hatte dann noch die Idee die Schleife auch einfach in einen eigenen Job zu packen dann allerdings wird die Progressbar nicht mehr aktualisiert.
Jetzt zu meiner Frage:
Wie schaffe ich es das die Progressbar durch die schleife aktualisiert wird (Mir also der Fortschritt in der GUI angezeigt wird) und ich gleichzeitig die GUI weiterbenutzen kann?
Please also mark the comments that contributed to the solution of the article
Content-ID: 223797
Url: https://administrator.de/contentid/223797
Printed on: November 10, 2024 at 07:11 o'clock
6 Comments
Latest comment
Hallo Lennyy,
da sei dir das Asynchrone Event-Handling der Powershell ans Herz gelegt:
http://blogs.technet.com/b/heyscriptingguy/archive/2011/06/16/use-async ...
Da du hier aber zusätzlich mit einer GUI arbeitest musst du dafür auch mit Delegates oder Runspaces via BeginInvoke arbeiten damit die GUI von einem anderen Thread aus "upgedated" werden kann.
Ein Beispiel kannst du hier sehen:
http://stackoverflow.com/questions/14401704/update-winforms-not-wpf-ui- ...
Du siehst das ganze ist nicht so simpel, les dich aber bitte erst mal ein ...
Grüße Uwe
da sei dir das Asynchrone Event-Handling der Powershell ans Herz gelegt:
http://blogs.technet.com/b/heyscriptingguy/archive/2011/06/16/use-async ...
Da du hier aber zusätzlich mit einer GUI arbeitest musst du dafür auch mit Delegates oder Runspaces via BeginInvoke arbeiten damit die GUI von einem anderen Thread aus "upgedated" werden kann.
Ein Beispiel kannst du hier sehen:
http://stackoverflow.com/questions/14401704/update-winforms-not-wpf-ui- ...
Du siehst das ganze ist nicht so simpel, les dich aber bitte erst mal ein ...
Grüße Uwe
Hallo Lennyy,
da das ganze doch etwas Zeit zur Einarbeitung benötigt habe ich dir hier mal ein Beispiel mit einer Demo-Form zusammen gestellt bei der eine Progress-Bar durch einen parallelen RunSpace(Thread) aktualisiert wird:
Grüße Uwe
da das ganze doch etwas Zeit zur Einarbeitung benötigt habe ich dir hier mal ein Beispiel mit einer Demo-Form zusammen gestellt bei der eine Progress-Bar durch einen parallelen RunSpace(Thread) aktualisiert wird:
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion
#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$button1 = New-Object System.Windows.Forms.Button
$progress = New-Object System.Windows.Forms.ProgressBar
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects
#Create synchronized Hashtable-Object for communication between sub-thread and form
$syncHash = [hashtable]::Synchronized(@{})
#set the controls in the hashtable we wish to manipulate
$syncHash.progress = $progress
# initialize second Powershell runspace
$psCmd = [powershell]::Create()
#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
$handler_button1_Click=
{
if ($button1.Text -eq "Start"){
# create new runspace to run our sub-thread in
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$psCmd.AddScript({
# in this expample we set the progress-bar value every 500 ms
for ($i = 1;$i -le 10;$i++){
sleep -Milliseconds 500
$syncHash.progress.Value = $i * 10
}
})
$psCmd.Runspace = $newRunspace
#start the runspace
$data = $psCmd.BeginInvoke()
$button1.Text = "Stop"
}else{
$psCmd.Stop()
$button1.Text = "Start"
}
}
$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
$form1.WindowState = $InitialFormWindowState
}
#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 74
$System_Drawing_Size.Width = 292
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.MaximizeBox = $False
$form1.Name = "form1"
$form1.Text = "ProgressForm"
$button1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 41
$button1.Location = $System_Drawing_Point
$button1.Name = "button1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 268
$button1.Size = $System_Drawing_Size
$button1.TabIndex = 1
$button1.Text = "Start"
$button1.UseVisualStyleBackColor = $True
$button1.add_Click($handler_button1_Click)
$form1.Controls.Add($button1)
$progress.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 12
$progress.Location = $System_Drawing_Point
$progress.Name = "progress"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 268
$progress.Size = $System_Drawing_Size
$progress.TabIndex = 0
$form1.Controls.Add($progress)
#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#----- Show Form
$form1.ShowDialog() | out-null
Zitat von @Lennyy:
Ich verstehe einfach nicht wo der Fehler liegt nach meinem Verständnis ist alles richtig (Ich bin allerdings auch noch
grün hinter den Ohren was Powershell betrifft)
sieh dir mal das Beispiel genauer an, das ich dir erstellt habe, bei Dir fehlt ja die Hälfte davon...Ich verstehe einfach nicht wo der Fehler liegt nach meinem Verständnis ist alles richtig (Ich bin allerdings auch noch
grün hinter den Ohren was Powershell betrifft)
Ach ja und noch eine Frage habe ich: Wie bette ich den Quellcode hier so schön ein wie colinardo das oben gemacht hat?
das machst du mit Tags zur Codeformatierung.Grüße Uwe