PowerShell In GUI Blog

PowerShell GUI Box Just In A Few Clicks

Archive for the ‘System.Windows.Forms.ToolStripItem’ Category

WordPress inspired me with ‘Copy a Post’ tool (StatusStrip + ProgressBar)

leave a comment »

Today’s update announced by WordPress motivated me to add a ProgressBar to the same post that is about a StatusStrip. Why? One of two today’s new features is ‘Copy a Post’. What is it? In spite of the availability of that page, I’ll say a little about blogger’s work.

Usually, the PowerShell (or of any programming environment) blogger needs an idea, a time, a code that will be put out and a description. Also, categories and/or tags to make a post visible throughout the Internet.

WordPress provided such a very simple, even boring feature as a copying of existing post. But imagine that on May, 1st I bought a brand new, lightweight Android 2.2 netbook. A great thing for blogging, skyping and facebooking, it was brought to Finland on 2nd and used on the way to see Google maps. How long did I manage not to write a post? I wrote one today, not a post, but a pleasantry great deal of code. Great under these unusual circumstances as a non-Windows/Linux keyboard layout and lack of habitual tools support.

I used some RDP application (demo with no more one host at a time) to connect to my home Windows 7 with Script Editor and ISE. Some key sequences on an Android’s are not habitual, there aren’t such keys as Insert, Home (to a beginning of text string I mean), Del, all Fs (it’s really pity if you use Far or Unreal Commander). The right shift worked as Tab, the left one went weird from time to time, but the vast majority o code was written on Android’s keyboard!

When I was ready to save me first draft accomplished on an Android device, I noticed these features. How do you think whether I was glad or excited after all that fighting with Android OS? The post will be put out later, maybe tomorrow.

And now, this Copy a Post feature again helps me: I thought that there isn’t a reason not to all System.Windows.Forms.ProgressBar example to the very similar StatusBar code. No doubts, Copy a Post is the first I did.

After this long introduction, let’s turn to a sample. I added a progress bar, three radio buttons, two group boxes (to split up radio buttons to two groups) and added some additional code. Should I add more details? If so, please write request in comments.

I’ll simply describe the functions until questions arrived:

– setStatusStrip used for labels and a bar of the $script:stStrip control

– setProgressBar is the same but for a ProgressBar

– createRadioButton creates radio buttons and adds a handler to enable the user set a style to the StatusStrip and ProgressBar

cls
Set-StrictMode -Version Latest
#region $form1
[System.Windows.Forms.Form]$form1 = New-Object System.Windows.Forms.Form;
$form1.Width = 500;
$form1.Height = 500;
[System.Windows.Forms.Button]$btnDirC = New-Object System.Windows.Forms.Button;
$btnDirC.Text = 'dir c:\';
$btnDirC.Left = 300;
$btnDirC.Top = 100;
$btnDirC.add_Click(([System.EventHandler]$handler =
	{
		processDirC;
	}));
$form1.Controls.Add($btnDirC);
[System.Windows.Forms.GroupBox]$script:groupProgressBar = `
	New-Object System.Windows.Forms.GroupBox;
$script:groupProgressBar.Left = 20;
$script:groupProgressBar.Top = 20;
$script:groupProgressBar.Width = 250;
$script:groupProgressBar.Height = 100;
$script:groupProgressBar.Text = "ProgressBar";
[System.Windows.Forms.GroupBox]$script:groupStatusStrip = `
	New-Object System.Windows.Forms.GroupBox;
$script:groupStatusStrip.Left = 20;
$script:groupStatusStrip.Top = 200;
$script:groupStatusStrip.Width = 250;
$script:groupStatusStrip.Height = 150;
$script:groupStatusStrip.Text = "StatusStrip";
$form1.Controls.AddRange(@($script:groupProgressBar, $script:groupStatusStrip));
function processDirC
{
	[int]$maxNumber = (dir c:\).Length;
	setStatusStrip -OperationName $null `
		-OperationProgress $null `
		-ProgressBarMinimum 1 `
		-ProgressBarMaximum $maxNumber `
		-ProgressBarValue 1;
	setProgressBar -ProgressBarMinimum 1 `
		-ProgressBarMaximum $maxNumber `
		-ProgressBarValue 1;
	[int]$counter = 1;
	dir c:\ | `
		%{
          setStatusStrip -OperationName $_ `
			-OperationProgress "$($counter) of $($maxNumber)" `
			-ProgressBarMinimum $null `
			-ProgressBarMaximum $null `
			-ProgressBarValue $counter;
		  setProgressBar  -ProgressBarMinimum $null `
			-ProgressBarMaximum $null `
			-ProgressBarValue $counter;
          [System.Windows.Forms.Application]::DoEvents();
		  sleep -Milliseconds 500;
		  $counter++;
		  }
}
#endregion $form1
#region StatusBar
$form1.Controls.Add(
	(([System.Windows.Forms.StatusStrip]$script:stStrip = `
	#region StatusBar properties
	New-Object System.Windows.Forms.StatusStrip) `
	| %{#at the bottom of the window
		$script:stStrip.Dock = [System.Windows.Forms.DockStyle]::Bottom;
		$script:stStrip.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor `
			[System.Windows.Forms.AnchorStyles]::Left;
		#layout style by default
		$script:stStrip.LayoutStyle = [System.Windows.Forms.ToolStripLayoutStyle]::Table;
		#operation name
		[System.Windows.Forms.ToolStripLabel]$script:stStripLabelOperation = `
			New-Object System.Windows.Forms.ToolStripLabel;
		$script:stStripLabelOperation.Text = "Write the operation name here";
		#which item is being processed
		[System.Windows.Forms.ToolStripLabel]$script:stStripLabelProgress = `
			New-Object System.Windows.Forms.ToolStripLabel;
		$script:stStripLabelProgress.Text = "Write the item number here";
		#the progress bar
		[System.Windows.Forms.ToolStripProgressBar]$script:stStripProgressBar = `
			New-Object System.Windows.Forms.ToolStripProgressBar;
		$script:stStrip.Items.AddRange([System.Windows.Forms.ToolStripItem[]]@(
									$script:stStripLabelOperation,
									$script:stStripLabelProgress,
									$script:stStripProgressBar
									));
		$script:stStrip.Name = "stStrip";
		$script:stStrip.AutoSize = $true;
		$script:stStrip.Left = 0;
		$script:stStrip.Visible = $true;
		$script:stStrip.Enabled = $true;
		$script:stStripLabelOperation.Width = 50;
		$script:stStripLabelProgress.Width = 50;
		$script:stStripProgressBar.Width = 50;
		$script:stStripProgressBar.Visible = $false;
	#endregion StatusBar properties
	$script:stStrip;}
)	);
#endregion StatusBar
#region ToolStripLayoutStyle
	#region function createRadioButton
function createRadioButton
{
	param([string]$ControlName,
		  [ref]$Top
		  )
	$rb = $null;
	[System.Windows.Forms.RadioButton]$private:rb = `
		New-Object System.Windows.Forms.RadioButton;
	$private:rb.Name = $ControlName;
	$private:rb.Text = $ControlName;
	$private:rb.Left = 20;
	$private:rb.Top = ($Top.Value += 20);
	$private:rb.Width = 200;
	$private:rb.add_CheckedChanged(([System.EventHandler]$handler =
	{
		param($sender)
		if ($sender.Checked){
			if ($sender.Parent -eq $script:groupStatusStrip)
			{
				$script:stStrip.LayoutStyle = `
					([System.Windows.Forms.ToolStripLayoutStyle]($sender.Name));
			}
			else
			{
				$script:pgBar.Style = `
					([System.Windows.Forms.ProgressBarStyle]($sender.Name));
			}
		}
	}));
	return $private:rb;
}
	#endregion function createRadioButton
[int]$top = 0;
$script:groupStatusStrip.Controls.AddRange(
	[System.Windows.Forms.Control[]]@(
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::Flow.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::HorizontalStackWithOverflow.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::StackWithOverflow.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::Table.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::VerticalStackWithOverflow.ToString()) ([ref]$top))
	));
$script:groupStatusStrip.Controls[([System.Windows.Forms.ToolStripLayoutStyle]::Table.ToString())].Checked = $true;
#endregion ToolStripLayoutStyle
#region ProgressBarStyle
[int]$top = 0;
$script:groupProgressBar.Controls.AddRange(
	[System.Windows.Forms.Control[]]@(
	(createRadioButton ([System.Windows.Forms.ProgressBarStyle]::Blocks.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ProgressBarStyle]::Continuous.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ProgressBarStyle]::Marquee.ToString()) ([ref]$top))
	));
$script:groupProgressBar.Controls[([System.Windows.Forms.ProgressBarStyle]::Blocks.ToString())].Checked = $true;
#endregion ProgressBarStyle
#region function setStatusStrip
function setStatusStrip
{
	param($OperationName = "",
		  $OperationProgress = "",
		  $ProgressBarMinimum = 0,
		  $ProgressBarMaximum = 0,
		  $ProgressBarValue = 0
		  )
		try{$null = $script:stStrip;
			if ($OperationName -ne $null -and `
				$script:stStripLabelOperation -ne $null)
				{
					$script:stStripLabelOperation.Text = $OperationName;
					$script:stStripLabelOperation.Width = 200;
				}
			if ($OperationProgress -ne $null -and `
				$script:stStripLabelProgress -ne $null)
				{
					$script:stStripLabelProgress.Text = $OperationProgress;
					$script:stStripLabelProgress.Width = 100;
				}
			if ($script:stStripProgressBar -ne $null){
				if ($ProgressBarMinimum -ne $null)
					{$script:stStripProgressBar.Minimum = $ProgressBarMinimum;}
				if ($ProgressBarMaximum -ne $null)
					{$script:stStripProgressBar.Maximum = $ProgressBarMaximum;}
				if ($ProgressBarValue -ne $null)
					{$script:stStripProgressBar.Value = $ProgressBarValue;}
				if ($script:stStripProgressBar.Minimum -eq `
					$script:stStripProgressBar.Maximum)
					{$script:stStripProgressBar.Visible = $false;}
				else
					{$script:stStripProgressBar.Visible = $true;}
			}
		}
		catch{}
}
#endregion function setStatusStrip
#region ProgressBar
[System.Windows.Forms.ProgressBar]$script:pgBar = New-Object System.Windows.Forms.ProgressBar;
$script:pgBar.Left = 100;
$script:pgBar.Top = 150;
$script:pgBar.Visible = $true;
$script:pgBar.Minimum = 1;
$form1.Controls.Add($script:pgBar);
	#region function setProgressBar
function setProgressBar
{
	param($ProgressBarMinimum = 0,
		  $ProgressBarMaximum = 0,
		  $ProgressBarValue = 0
		  )
		try{$null = $script:pgBar;
			if ($script:pgBar -ne $null){
				if ($ProgressBarMinimum -ne $null)
					{$script:pgBar.Minimum = $ProgressBarMinimum;}
				if ($ProgressBarMaximum -ne $null)
					{$script:pgBar.Maximum = $ProgressBarMaximum;}
				if ($ProgressBarValue -ne $null)
					{$script:pgBar.Value = $ProgressBarValue;}
				if ($script:pgBar.Minimum -eq `
					$script:pgBar.Maximum)
					{$script:pgBar.Visible = $false;}
				else
					{$script:pgBar.Visible = $true;}
			}
		}
		catch{}
}
	#endregion function setProgressBar
#endregion ProgressBar
$form1.ShowDialog() | Out-Null;

The code is downloadable as a script from here.

StatusStrip. An easy way

leave a comment »

Long operations are among things annoying most. To prevent users from getting bored with application that is mining data or doing multi-change, it’s common to use a kind of progressbar.

Let’s take a StatusStrip control. It’s relatively new control, firstly introduced in .NET 2.0 (or like) and it’s container. This container allows you to add a label, a progress bar and a couple of other controls.

Below is a typical function working with a statusstrip that contains two label and one progress bar. For our purposes, the first label is operation name (the name of an action performed now) and the second is a counter like ‘3 of 87’.

cls
Set-StrictMode -Version Latest
#region $form1
[System.Windows.Forms.Form]$form1 = New-Object System.Windows.Forms.Form;
$form1.Width = 500;
[System.Windows.Forms.Button]$btnDirC = New-Object System.Windows.Forms.Button;
$btnDirC.Text = 'dir c:\';
$btnDirC.Left = 300;
$btnDirC.Top = 100;
$btnDirC.add_Click(([System.EventHandler]$handler = 
	{
		processDirC;
	}));
$form1.Controls.Add($btnDirC);
function processDirC
{
	[int]$maxNumber = (dir c:\).Length;
	setStatusStrip -OperationName $null `
		-OperationProgress $null `
		-ProgressBarMinimum 1 `
		-ProgressBarMaximum $maxNumber `
		-ProgressBarValue 1;
	[int]$counter = 1;
	dir c:\ | `
		%{
          setStatusStrip -OperationName $_ `
			-OperationProgress "$($counter) of $($maxNumber)" `
			-ProgressBarMinimum $null `
			-ProgressBarMaximum $null `
			-ProgressBarValue $counter;
          [System.Windows.Forms.Application]::DoEvents();
		  sleep -Milliseconds 500;
		  $counter++;
		  }
}
#endregion $form1
#region StatusBar
$form1.Controls.Add(
	(([System.Windows.Forms.StatusStrip]$script:stStrip = `
	#region StatusBar properties
	New-Object System.Windows.Forms.StatusStrip) `
	| %{#at the bottom of the window
		$script:stStrip.Dock = [System.Windows.Forms.DockStyle]::Bottom;
		$script:stStrip.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor `
			[System.Windows.Forms.AnchorStyles]::Left;
		#layout style by default
		$script:stStrip.LayoutStyle = [System.Windows.Forms.ToolStripLayoutStyle]::Table;
		#operation name
		[System.Windows.Forms.ToolStripLabel]$script:stStripLabelOperation = `
			New-Object System.Windows.Forms.ToolStripLabel;
		$script:stStripLabelOperation.Text = "Write the operation name here";
		#which item is being processed
		[System.Windows.Forms.ToolStripLabel]$script:stStripLabelProgress = `
			New-Object System.Windows.Forms.ToolStripLabel;	
		$script:stStripLabelProgress.Text = "Write the item number here";
		#the progress bar
		[System.Windows.Forms.ToolStripProgressBar]$script:stStripProgressBar = `
			New-Object System.Windows.Forms.ToolStripProgressBar;
		$script:stStrip.Items.AddRange([System.Windows.Forms.ToolStripItem[]]@(
									$script:stStripLabelOperation,
									$script:stStripLabelProgress,
									$script:stStripProgressBar
									));					
		$script:stStrip.Name = "stStrip";							
		$script:stStrip.AutoSize = $true;
		$script:stStrip.Left = 0;
		$script:stStrip.Visible = $true;
		$script:stStrip.Enabled = $true;
		$script:stStripLabelOperation.Width = 50;
		$script:stStripLabelProgress.Width = 50;
		$script:stStripProgressBar.Width = 50;
		$script:stStripProgressBar.Visible = $false;
	#endregion StatusBar properties
	$script:stStrip;}
)	);
#endregion StatusBar
#region ToolStripLayoutStyle
	#region function createRadioButton
function createRadioButton
{
	param([string]$ControlName,
		  [ref]$Top
		  )
	$rb = $null;
	[System.Windows.Forms.RadioButton]$private:rb = `
		New-Object System.Windows.Forms.RadioButton;
	$private:rb.Name = $ControlName;
	$private:rb.Text = $ControlName;
	$private:rb.Left = 20;
	$private:rb.Top = ($Top.Value += 20);
	$private:rb.add_CheckedChanged(([System.EventHandler]$handler = 
	{
		param($sender)
		if ($sender.Checked){
		$script:stStrip.LayoutStyle = `
			([System.Windows.Forms.ToolStripLayoutStyle]($sender.Name));
		}
	}));
	return $private:rb;
}
	#endregion function createRadioButton
[int]$top = 0;
$form1.Controls.AddRange(
	[System.Windows.Forms.Control[]]@(
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::Flow.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::HorizontalStackWithOverflow.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::StackWithOverflow.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::Table.ToString()) ([ref]$top)),
	(createRadioButton ([System.Windows.Forms.ToolStripLayoutStyle]::VerticalStackWithOverflow.ToString()) ([ref]$top))
	));
$form1.Controls[([System.Windows.Forms.ToolStripLayoutStyle]::Table.ToString())].Checked = $true;
#endregion ToolStripLayoutStyle
#region function setStatusStrip
function setStatusStrip
{
	param($OperationName = "",
		  $OperationProgress = "",
		  $ProgressBarMinimum = 0,
		  $ProgressBarMaximum = 0,
		  $ProgressBarValue = 0
		  )
		try{$null = $script:stStrip;
			if ($OperationName -ne $null -and `
				$script:stStripLabelOperation -ne $null)
				{
					$script:stStripLabelOperation.Text = $OperationName;
					$script:stStripLabelOperation.Width = 200;
				}
			if ($OperationProgress -ne $null -and `
				$script:stStripLabelProgress -ne $null)
				{
					$script:stStripLabelProgress.Text = $OperationProgress;
					$script:stStripLabelProgress.Width = 100;
				}
			if ($script:stStripProgressBar -ne $null){
				if ($ProgressBarMinimum -ne $null)
					{$script:stStripProgressBar.Minimum = $ProgressBarMinimum;}
				if ($ProgressBarMaximum -ne $null)
					{$script:stStripProgressBar.Maximum = $ProgressBarMaximum;}
				if ($ProgressBarValue -ne $null)
					{$script:stStripProgressBar.Value = $ProgressBarValue;}
				if ($script:stStripProgressBar.Minimum -eq `
					$script:stStripProgressBar.Maximum)
					{$script:stStripProgressBar.Visible = $false;}
				else
					{$script:stStripProgressBar.Visible = $true;}
			}
		}
		catch{}
}
#endregion function setStatusStrip
$form1.ShowDialog() | Out-Null;

In short, the sample consists of a form $form1, a button that demonstrates a comparatively long operation, the status bar itself and five radio buttons showing how the style can be changed.

The setStatusBar function sets texts for the first label (the name of each file), the second label (the counter), minimum and maximum of the progress bar (can be set once), the current progress bar value (in my sample is the same as value used for the second label).

The code is downloadable as a script from here.

Adding a MenuStrip to a Form. Hands Only

leave a comment »

As can be clearly seen from the survey Ravikanth conducted here http://www.ravichaganti.com/blog/?p=2111 , the great majority of powershellers do write GUI. Moreover, there is no common universal tool. Every powersheller chooses the way one creates user interface.

Well, why don’t we create a small example by using just bare hands. Let’s do our preparation. A recipe is simple: a bit of text editor (Intellisense-enabled is preferable), a piece of rich text or even a text file, and a keyboard.

Supposedly, we need a form with a menu (two-level one, not to be considered as a simpleton), a label and a textbox. The user should be able to manage content of textbox using menu.

There is two ways to create a form:

1.1 by using PrimalForms:

#Generated Form Function
function GenerateForm { 
########################################################################
 # Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.10.0
 # Generated On: 26/04/2011 09:43 p.m.
 # Generated By: apetrovskiy
 ########################################################################

#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
$textBox1=New-Object System.Windows.Forms.TextBox
$label1=New-Object System.Windows.Forms.Label
$InitialFormWindowState=New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects 
#region Generated Form Code 
$System_Drawing_Size=New-Object System.Drawing.Size
$System_Drawing_Size.Height =262
$System_Drawing_Size.Width =284
$form1.ClientSize=$System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode=0
$form1.Name="form1"
$form1.Text="Primal Form"
$textBox1.DataBindings.DefaultDataSourceUpdateMode=0
$System_Drawing_Point=New-Object System.Drawing.Point
$System_Drawing_Point.X =34
$System_Drawing_Point.Y =82
$textBox1.Location=$System_Drawing_Point
$textBox1.Name="textBox1"
$System_Drawing_Size=New-Object System.Drawing.Size
$System_Drawing_Size.Height =20
$System_Drawing_Size.Width =195
$textBox1.Size=$System_Drawing_Size
$textBox1.TabIndex=1
$form1.Controls.Add($textBox1
$label1.DataBindings.DefaultDataSourceUpdateMode=0
$System_Drawing_Point=New-Object System.Drawing.Point
$System_Drawing_Point.X =36
$System_Drawing_Point.Y =45
$label1.Location=$System_Drawing_Point
$label1.Name="label1"
$System_Drawing_Size=New-Object System.Drawing.Size
$System_Drawing_Size.Height =22
$System_Drawing_Size.Width =177
$label1.Size=$System_Drawing_Size
$label1.TabIndex=0
$label1.Text="label1"
$form1.Controls.Add($label1
#endregion Generated Form Code 
#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 the Form
$form1.ShowDialog() | Out-Null
#End Function
#Call the Function
GenerateForm

1.2 by typing the following code:

[System.Windows.Forms.Form]$form1=`
New-Object System.Windows.Forms.Form
[System.Windows.Forms.Label]$label1=`
New-Object System.Windows.Forms.Label
$label1.Name="label1"
$label1.Text="label1"
$label1.Left=20; 
$label1.Top=50
[System.Windows.Forms.TextBox]$textbox1=`
New-Object System.Windows.Forms.TextBox
$textbox1.Name="textbox1"
$textbox1.Left=20
$textbox1.Top=100
$form1.Name="form1"
$form1.Controls.Add($label1); 
$form1.Controls.Add($textbox1); 
$form1.ShowDialog() | Out-Null;

All our further actions are insertions to be written above the string  $form1.ShowDialog()

2. Now we add the following simple function:

function addMenuItem 

param([ref]$ParentItem
[string]$ItemName=''
[string]$ItemText=''
[scriptblock]$ScriptBlock=$null 

[System.Windows.Forms.ToolStripMenuItem]$private:menuItem=`
New-Object System.Windows.Forms.ToolStripMenuItem
$private:menuItem.Name =$ItemName
$private:menuItem.Text =$ItemText
if ($ScriptBlock -ne $null
{ $private:menuItem.add_Click(([System.EventHandler]$handler=`
$ScriptBlock)); } 
if (($ParentItem.Value) -is [System.Windows.Forms.MenuStrip]) 
{ ($ParentItem.Value).Items.Add($private:menuItem); } 
if (($ParentItem.Value) -is [System.Windows.Forms.ToolStripItem]) 
{ ($ParentItem.Value).DropDownItems.Add($private:menuItem); } 
return $private:menuItem
}

The function receives a reference to the parent menu item, the name and the label chosen for a new menu element, and, if nesessary, scriptblock. Don’t pass a scriptblock to menuitems that are not at the lowest leel of your menu hierarhy.

3. After that it’s time to add a MenuStrip:

[System.Windows.Forms.MenuStrip]$mainMenu=New-Object System.Windows.Forms.MenuStrip
$form1.Controls.Add($mainMenu);

If we run our form now, we can see a hardly visible (depending on your color schema) strip at the top of the $form1.

4. Now we can add handlers form menu items. To simplify the example, our handlers are scriptblocks. I wrote one, crischening it as $sb1. Undoubtedly, by searching for $mainMenu in ObjectBrowser untidy code you may find more examples.

[scriptblock]$sb1=
#your code
}

5. Finally, we add menu items (see sample code for more details):

#region File 
(addMenuItem -ParentItem ([ref]$mainMenu) -ItemName 'mnuFile' -ItemText 'File' -ScriptBlock $null) | %
$null=addMenuItem -ParentItem ([ref]$_) -ItemName 'mnuFileOpen' -ItemText 'Open' -ScriptBlock $sb1
$null=addMenuItem -ParentItem ([ref]$_) -ItemName 'mnuFileSave' -ItemText 'Save' -ScriptBlock $null
$null=addMenuItem -ParentItem ([ref]$_) -ItemName 'mnuFileExit' -ItemText 'Exit' -ScriptBlock $null;} | Out-Null
#endregion File

Today’s code attached here.