Search code examples
powershelluser-interfacenestedfreezescriptblock

Need help gui background-job double-hop issue and script freezing


I'm having an issue with double hopping scriptblock for background job that either does nothing or freezes the script. Explenation below. The idea for the script is to get a list of files (very large count, ~200k) and then process them in three individual ways (get hashcodes and get true duplicates, compare filenames and get pseudo duplicates, get zero length files). At this moment I'm working on hashes. The result of $job1 is a string (array?) that cannot be piped to get-filehash. This results in $job2 looping through each string in order to get hashes. As background-jobs work on scriptblocks and foreach loop has scriptblock component a double hop is created. I've worked around that by using invoke-command combined with [scriptblock]::Create() method inside job scriptblock. That unfortunately freezes the form. My question to you is as follows. How do I force $job1 result to be of system.io.fileinfo type OR how do I unfreeze script while Invoke-command is in progress?

Add-Type -AssemblyName System.Windows.Forms
add-type -AssemblyName system.drawing

[System.Windows.Forms.Application]::EnableVisualStyles()
$path = "C:\"

$window = New-Object system.Windows.Forms.Form
$window.Size = New-Object system.Drawing.Size @(400,400)
$window.StartPosition = "CenterScreen"
$window.Font = New-Object System.Drawing.Font("Calibri",11,[System.Drawing.FontStyle]::Bold)
$window.Text = "STARTING UP"



$ProgressBar1 = New-Object System.Windows.Forms.ProgressBar
$ProgressBar1.Location = New-Object System.Drawing.Point(10, 10)
$ProgressBar1.Size = New-Object System.Drawing.Size(365, 20)
$ProgressBar1.Style = "Marquee"
$ProgressBar1.MarqueeAnimationSpeed = 20
$ProgressBar1.UseWaitCursor = $true
$ProgressBar1.Visible = $false


$button = New-Object System.Windows.Forms.Button
$button.size = New-Object system.drawing.size @(50,50)
$button.Location = New-Object System.Drawing.Point(20, 70)
$button.Text = "TEST"
$window.Controls.add($button)

$label = New-Object System.Windows.Forms.Label
$label.Size = New-Object System.Drawing.Size @(100, 50)
$label.Location = New-Object System.Drawing.Point (80, 70)
$label.BorderStyle = 'Fixed3D'
$label.ForeColor = 'green'
$label.TextAlign = 'middlecenter'
$window.Controls.Add($label)


$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000

$timer.add_Tick({$script:time2 =((get-date)-$script:time1).ToString("hh\:mm\:ss")
$label2.text = $script:time2
})

$button.add_Click(
{$1 = Get-Date
$Script:time1 = Get-Date
$timer.start()
$ProgressBar1.BringToFront()
$ProgressBar1.Show()
    $this.Enabled = $false
    $job = Start-Job -ScriptBlock  {
        Get-ChildItem -File -recurse $HOME -ErrorAction SilentlyContinue|select -ExpandProperty FullName

            }
    while($job.State -eq 'Running') {
        [System.Windows.Forms.Application]::DoEvents()
    }
    $script:asd = $job | Receive-Job #-AutoRemoveJob -Wait
    $ProgressBar1.Hide()
    $this.Enabled = $true
    $2 = ((get-date) - $1).ToString("hh\:mm\:ss")
    $label.text = $2
    $timer.stop()
}
)



$button2 = New-Object System.Windows.Forms.Button
$button2.Size = New-Object System.Drawing.Size @(50, 50)
$button2.Location = New-Object System.Drawing.Point (200, 70)
$button2.Text = 'Exit'
$window.Controls.Add($button2)


$button2.add_Click({$window.Close()})


$button3 = new-object System.Windows.Forms.Button
$button3.Size = New-Object System.Drawing.Size @(50, 50)
$button3.Location = New-Object System.Drawing.Point (20, 200)
$button3.Text = "Start"
$window.Controls.Add($button3)



$button3.add_Click({
$sb = foreach ($qwe in $Script:asd){Get-FileHash $qwe -Algorithm MD5|select -ExpandProperty Hash -OutVariable +Script:tester}
$ProgressBar2.BringToFront()
$ProgressBar2.Show()
$this.Enabled = $false
$job2 = start-job -Name 'asd' -scriptblock {
 param($sb) 
 $sb = [scriptblock]::Create($sb)
 Invoke-command -ScriptBlock $sb
                                            }
 while($job2.State -eq 'Running') {
        [System.Windows.Forms.Application]::DoEvents()
    }
Write-Host $Script:tester
$ProgressBar2.Hide()
$this.Enabled = $true
 })



$label2 = New-Object System.Windows.Forms.Label
$label2.size = New-Object System.Drawing.Size @(100, 50)
$label2.Location = New-Object System.Drawing.Point (80, 200)
$label2.BorderStyle = 'Fixed3D'
$label2.ForeColor = 'green'
$label2.TextAlign = 'middlecenter'
$window.Controls.Add($label2)

$ProgressBar2 = New-Object System.Windows.Forms.ProgressBar
$ProgressBar2.Location = New-Object System.Drawing.Point(10, 330)
$ProgressBar2.Size = New-Object System.Drawing.Size(365, 20)
$ProgressBar2.Style = "Marquee"
$ProgressBar2.MarqueeAnimationSpeed = 20
$ProgressBar2.UseWaitCursor = $true
$ProgressBar2.Visible = $false
$window.Controls.Add($ProgressBar2)

$groupbox = New-Object System.Windows.Forms.GroupBox
$groupbox.size = New-Object system.drawing.size @(377, 365)
$groupbox.Location = New-Object System.Drawing.point (4, -5) 
$window.Controls.Add($groupbox)




$window.Controls.Add($ProgressBar1)

$window.ShowDialog()|out-null

Solution

  • For anyone interested. The answer was piping $job results to set-variable - $job|Wait-job|Receive-Job|Set-Variable -Name JOB_RESULT -Scope Script.

    Then using $using: scope in $job2 scriptblock - $job2 = start-job -scriptblock { $using:JOB_RESULT|Get-FileHash -Algorithm MD5}