Untitled

mail@pastecode.io avatar
unknown
powershell
2 years ago
8.4 kB
12
Indexable
Never
using namespace System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$form1 = New-Object 'System.Windows.Forms.Form'
$buttonRunPS = New-Object 'System.Windows.Forms.Button'
$buttonRunC = New-Object 'System.Windows.Forms.Button'
$richtextbox2 = New-Object 'System.Windows.Forms.RichTextBox'
$richtextbox1 = New-Object 'System.Windows.Forms.RichTextBox'
$treeview1 = New-Object 'System.Windows.Forms.TreeView'
$InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState'

function Start-RunspaceTask {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory, Position = 0)][ScriptBlock]$ScriptBlock,
        [Parameter(Mandatory, Position = 1)][PSObject[]]$ProxyVars
    )
    
    $Runspace = [RunspaceFactory]::CreateRunspace($InitialSessionState)
    $Runspace.ApartmentState = 'STA'
    $Runspace.ThreadOptions = 'ReuseThread'
    $Runspace.Open()
    ForEach ($Var in $ProxyVars) { $Runspace.SessionStateProxy.SetVariable($Var.VariableName, $Var.VariableValue) }
    $Thread = [PowerShell]::Create()
    $Thread.AddScript($ScriptBlock, $True) | Out-Null
    $Thread.Runspace = $Runspace
    [Void]$jobList.Add([PSObject]@{ PowerShell = $Thread; Runspace = $Thread.BeginInvoke() })
}

#System.Collections.Concurrent is thread-safe
$global:SyncHash = [System.Collections.Concurrent.ConcurrentDictionary[string, object]]::new()
$global:jobList = [System.Collections.Concurrent.ConcurrentBag[object]]::new()

$initialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$SyncHash.form1 = $form1
$SyncHash.treeview1 = $treeview1
$SyncHash.richtextbox1 = $richtextbox1
$SyncHash.richtextbox2 = $richtextbox2

$buttonRunC_Click = {
#region Custom Types
    Add-Type -ReferencedAssemblies System.Windows.Forms, System.ComponentModel, System.ComponentModel.Primitives, System.Threading.Tasks -TypeDefinition @'
using System.Threading.Tasks;
using System.Windows.Forms;

public class TreeViewHelper
{
    public static void AddNode(TreeView TreeView, TreeNode TreeNode)
    {
        TreeView.Invoke((MethodInvoker)(() => TreeView.Nodes.Add(TreeNode)));
    }

    public static async void AddNodeAsync(TreeView TreeView, string Name)
    {
        await Task.Run(() =>
        {
            TreeView.Invoke((MethodInvoker)(() => TreeView.Nodes.Add(Name)));
        });
    }
}
'@
    
    Add-Type -ReferencedAssemblies System.Windows.Forms, System.ComponentModel, System.ComponentModel.Primitives, System.Threading.Tasks -TypeDefinition @'
using System.Threading.Tasks;
using System.Windows.Forms;

public class RichTextBoxHelper
{
    public static void AddText(RichTextBox RichTextBoxControl, string Text)
    {
        RichTextBoxControl.Invoke((MethodInvoker)(() => RichTextBoxControl.AppendText(Text)));
    }

    public static async void AddTextAsync(RichTextBox RichTextBoxControl, string Text)
    {
        await Task.Run(() =>
        {
            RichTextBoxControl.Invoke((MethodInvoker)(() => RichTextBoxControl.AppendText(Text)));
        });
    }
}
'@
#endregion 

    $ScriptBlock = {
        $treeview1.Nodes.Clear() | Out-Null
        
        Get-ChildItem Function: | Where-Object { $_.Name -NotLike "*:*" } | Select-Object -ExpandProperty Name | ForEach-Object {
            $Definition = Get-Content "function:$_" -ErrorAction Stop
            $SessionStateFunction = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList "$_", $Definition
            $InitialSessionState.Commands.Add($SessionStateFunction)
        }
        
        $TopLevelDir = 'C:\Windows\System32'
        
        foreach ($FilePath in [System.Io.Directory]::EnumerateFiles($TopLevelDir, "*.dll", [System.IO.SearchOption]::AllDirectories)) {
            $counter = 0
            
            $streamReader = [System.IO.StreamReader]::new($FilePath, [System.Text.Encoding]::Default)
            
            while ($null -ne ($line = $streamReader.ReadLine()) -and $counter -le 100) {
                #simulate read file work
                $counter++
            }
            
            $streamReader.Close()
            $streamReader.Dispose()
            
            [RichTextBoxHelper]::AddText($SyncHash.richtextbox2, $FilePath)
            [TreeViewHelper]::AddNode($SyncHash.treeview1, $FilePath) # works from Runspace
        }
    }
    
    Start-RunspaceTask $ScriptBlock -ProxyVars @([PSObject]@{ VariableName = 'SyncHash'; VariableValue = $SyncHash })
    #$ScriptBlock.invoke() #replace Start-RunspaceTask with this line if you want to debug code
}

$buttonRunPS_Click = {

    $ScriptBlock = {
        $treeview1.Nodes.Clear() | Out-Null
        
        Get-ChildItem Function: | Where-Object { $_.Name -NotLike "*:*" } | Select-Object -ExpandProperty Name | ForEach-Object {
            $Definition = Get-Content "function:$_" -ErrorAction Stop
            $SessionStateFunction = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList "$_", $Definition
            $InitialSessionState.Commands.Add($SessionStateFunction)
        }
        
        $TopLevelDir = 'C:\Windows\System32'
        
        foreach ($FilePath in [System.Io.Directory]::EnumerateFiles($TopLevelDir, "*.dll", [System.IO.SearchOption]::AllDirectories)) {
            $counter = 0
            
            $streamReader = [System.IO.StreamReader]::new($FilePath, [System.Text.Encoding]::Default)
            
            while ($null -ne ($line = $streamReader.ReadLine()) -and $counter -le 100) {
                #simulate read file work
                $counter++
            }
            
            $streamReader.Close()
            $streamReader.Dispose()
            
            $SyncHash.richtextbox2.Invoke([System.Windows.Forms.MethodInvoker]{ $SyncHash.richtextbox2.AppendText($FilePath + "`n") }) # works from Runspace but very slow
            $SyncHash.treeview1.Invoke([System.Windows.Forms.MethodInvoker]{ $SyncHash.treeview1.Nodes.Add($FilePath) }) # works from Runspace but very slow

        }
    }
    
    Start-RunspaceTask $ScriptBlock -ProxyVars @([PSObject]@{ VariableName = 'SyncHash'; VariableValue = $SyncHash })
    #$ScriptBlock.invoke() #replace Start-RunspaceTask with this line if you nwat to debug
}

#region Form Code
$form1.SuspendLayout()
$form1.Controls.Add($buttonRunPS)
$form1.Controls.Add($buttonRunC)
$form1.Controls.Add($richtextbox2)
$form1.Controls.Add($richtextbox1)
$form1.Controls.Add($treeview1)
$form1.AutoScaleDimensions = New-Object System.Drawing.SizeF(6, 13)
$form1.AutoScaleMode = 'Font'
$form1.ClientSize = New-Object System.Drawing.Size(548, 647)
$form1.Name = 'form1'
$form1.Text = 'Form'
$buttonRunPS.Anchor = 'Bottom, Right'
$buttonRunPS.Location = New-Object System.Drawing.Point(432, 612)
$buttonRunPS.Name = 'buttonRunPS'
$buttonRunPS.Size = New-Object System.Drawing.Size(104, 23)
$buttonRunPS.TabIndex = 4
$buttonRunPS.Text = 'Run PS'
$buttonRunPS.UseVisualStyleBackColor = $True
$buttonRunPS.add_Click($buttonRunPS_Click)
$buttonRunC.Anchor = 'Bottom, Left'
$buttonRunC.Location = New-Object System.Drawing.Point(304, 612)
$buttonRunC.Name = 'buttonRunC'
$buttonRunC.Size = New-Object System.Drawing.Size(122, 23)
$buttonRunC.TabIndex = 3
$buttonRunC.Text = 'Run C#'
$buttonRunC.UseVisualStyleBackColor = $True
$buttonRunC.add_Click($buttonRunC_Click)
$richtextbox2.Anchor = 'Top, Bottom, Left, Right'
$richtextbox2.Location = New-Object System.Drawing.Point(304, 295)
$richtextbox2.Name = 'richtextbox2'
$richtextbox2.Size = New-Object System.Drawing.Size(232, 311)
$richtextbox2.TabIndex = 2
$richtextbox2.Text = ''
$richtextbox1.Anchor = 'Top, Left, Right'
$richtextbox1.Location = New-Object System.Drawing.Point(303, 12)
$richtextbox1.Name = 'richtextbox1'
$richtextbox1.Size = New-Object System.Drawing.Size(233, 276)
$richtextbox1.TabIndex = 1
$richtextbox1.Text = ''
$treeview1.Anchor = 'Top, Bottom, Left'
$treeview1.Location = New-Object System.Drawing.Point(12, 12)
$treeview1.Name = 'treeview1'
$treeview1.Size = New-Object System.Drawing.Size(285, 623)
$treeview1.TabIndex = 0
$form1.ResumeLayout()
#endregion

$form1.ShowDialog()