I was looking for an answer to how to create a custom dialog that can be displayed by a script, and allows multiple values to be specified by a user in a single dialog, rather than prompting them with multiple InputBoxes one after the other, and came across this old post:
https://sparxsystems.com/forums/smf/index.php?topic=44685.0, which describes a similar problem to what I was encountering, but points out that one of the suggested solutions for creating custom dialogs (using HTML Applications) is no longer possible in Windows 10. I wanted to share another (not particularly elegant, but functional) solution, in addition to those already suggested in the previous thread, in case it's useful to anyone else searching the forum.
This script uses the capability of Powershell to be able to create and use .Net objects - which includes the ability to use the System.Windows.Forms objects, to create simple dialogs that include any of the Windows Forms controls. One of the specific use-cases I had was a need to be able to display combo boxes with pre-set lists of values, so they could pick from those values. The Powershell script is executed using "WScript.Shell": and, to get back each of the multiple output values from the dialog, the PowerShell script writes the values as separate lines to the console, and the Sparx script scrapes those from STDOUT, and pops them into a custom Class, so they're easier to utilize as an object by subsequent script operations. The dialog example was taken from Microsoft's Documentation on creating Forms in Powershell, here:
https://learn.microsoft.com/en-us/powershell/scripting/samples/creating-a-custom-input-box?view=powershell-7.4' Create a custom class / object type, that we can use to return the results to the calling method
class DeviceDetails
public Name
public Domain_Name
public Description
public Environment
public IP_Address
public Server_Type
end class
'This method creates the dialog (in this example, passing 2 arrays as parameters, which have the lists of items used in combo boxes)
function getDeviceDetailsDialog(environments, server_types)
dim shell, ps_script, response, array, device, executor, env_def, env, st_def, st
'set the values that will be going into combo boxes (passed to function as arrays, extracted from t_propertytypes)
for each env in environments
env_def = env_def & "[void] $comboBox3.Items.Add('" & env &"');"
next
for each st in server_types
st_def = st_def & "[void] $comboBox5.Items.Add('" & st &"');"
next
'Powershell script to create the dialog box and print its output to stdout
ps_script = "Add-Type -AssemblyName System.Windows.Forms;" &_
"Add-Type -AssemblyName System.Drawing;" &_
"$form = New-Object System.Windows.Forms.Form;" &_
"$form.Text = 'Create Device';" &_
"$form.Size = New-Object System.Drawing.Size(300,420);" &_
"$form.StartPosition = 'CenterScreen';" &_
"$form.ShowIcon = $false; " &_
"$form.ControlBox= $false;" &_
"$form.FormBorderStyle = 'FixedDialog';" &_
"$okButton = New-Object System.Windows.Forms.Button;" &_
"$okButton.Location = New-Object System.Drawing.Point(75,345);" &_
"$okButton.Size = New-Object System.Drawing.Size(75,23);" &_
"$okButton.Text = 'OK';" &_
"$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK;" &_
"$form.AcceptButton = $okButton;$form.Controls.Add($okButton);" &_
"$cancelButton = New-Object System.Windows.Forms.Button;" &_
"$cancelButton.Location = New-Object System.Drawing.Point(150,345);" &_
"$cancelButton.Size = New-Object System.Drawing.Size(75,23);" &_
"$cancelButton.Text = 'Cancel';" &_
"$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel;" &_
"$form.CancelButton = $cancelButton;$form.Controls.Add($cancelButton);" &_
"$label1 = New-Object System.Windows.Forms.Label;" &_
"$label1.Location = New-Object System.Drawing.Point(10,20);" &_
"$label1.Size = New-Object System.Drawing.Size(280,20);" &_
"$label1.Text = 'Device Name'; " &_
"$form.Controls.Add($label1);" &_
"$textBox1 = New-Object System.Windows.Forms.TextBox;" &_
"$textBox1.Location = New-Object System.Drawing.Point(10,40);" &_
"$textBox1.Size = New-Object System.Drawing.Size(260,20);" &_
"$form.Controls.Add($textBox1);" &_
"$label2 = New-Object System.Windows.Forms.Label;" &_
"$label2.Location = New-Object System.Drawing.Point(10,60);" &_
"$label2.Size = New-Object System.Drawing.Size(280,20);" &_
"$label2.Text = 'Device Description:';" &_
"$form.Controls.Add($label2);" &_
"$textBox2 = New-Object System.Windows.Forms.TextBox;" &_
"$textBox2.Multiline = $true;" &_
"$textBox2.Location = New-Object System.Drawing.Point(10,80);" &_
"$textBox2.Size = New-Object System.Drawing.Size(260,80);" &_
"$form.Controls.Add($textBox2);" &_
"$label3 = New-Object System.Windows.Forms.Label;" &_
"$label3.Location = New-Object System.Drawing.Point(10,160);" &_
"$label3.Size = New-Object System.Drawing.Size(280,20);" &_
"$label3.Text = 'Environment:';$form.Controls.Add($label3);" &_
"$comboBox3 = New-Object System.Windows.Forms.ComboBox;" &_
"$comboBox3.Location = New-Object System.Drawing.Point(10,180);" &_
"$comboBox3.Size = New-Object System.Drawing.Size(260,20);" & env_def &_
"$form.Controls.Add($comboBox3);" &_
"$label4 = New-Object System.Windows.Forms.Label;" &_
"$label4.Location = New-Object System.Drawing.Point(10,200);" &_
"$label4.Size = New-Object System.Drawing.Size(280,20);" &_
"$label4.Text = 'Device IP Address:';$form.Controls.Add($label4);" &_
"$textBox4 = New-Object System.Windows.Forms.TextBox;" &_
"$textBox4.Multiline = $true;" &_
"$textBox4.Location = New-Object System.Drawing.Point(10,220);" &_
"$textBox4.Size = New-Object System.Drawing.Size(260,20);" &_
"$form.Controls.Add($textBox4);" &_
"$label5 = New-Object System.Windows.Forms.Label;" &_
"$label5.Location = New-Object System.Drawing.Point(10,240);" &_
"$label5.Size = New-Object System.Drawing.Size(280,20);" &_
"$label5.Text = 'Device Type:';$form.Controls.Add($label5);" &_
"$comboBox5 = New-Object System.Windows.Forms.ComboBox;" &_
"$comboBox5.Location = New-Object System.Drawing.Point(10,260);" &_
"$comboBox5.Size = New-Object System.Drawing.Size(260,20);" & st_def &_
"$form.Controls.Add($comboBox5);" &_
"$label6 = New-Object System.Windows.Forms.Label;" &_
"$label6.Location = New-Object System.Drawing.Point(10,280);" &_
"$label6.Size = New-Object System.Drawing.Size(280,20);" &_
"$label6.Text = 'Domain Name:';$form.Controls.Add($label6);" &_
"$textBox6 = New-Object System.Windows.Forms.TextBox;" &_
"$textBox6.Multiline = $true;" &_
"$textBox6.Location = New-Object System.Drawing.Point(10,300);" &_
"$textBox6.Size = New-Object System.Drawing.Size(260,20);" &_
"$form.Controls.Add($textBox6);$form.Topmost = $true;" &_
"$form.Add_Shown({$textBox1.Select()});" &_
"$result = $form.ShowDialog();" &_
"if ($result -eq [System.Windows.Forms.DialogResult]::OK)" &_
"{ Write-Host $textBox1.Text; Write-Host $textBox2.Text; Write-Host $comboBox3.Text; " &_
"Write-Host $textBox4.Text; Write-Host $comboBox5.Text;Write-Host $textBox6.Text;}"
Set shell = CreateObject("WScript.Shell")
Set executor = shell.Exec("powershell.exe -windowstyle hidden -noprofile -command " & ps_script)
executor.StdIn.Close
'extract the text that the Powershell script wrote to the console (Write-Host)
response = executor.StdOut.ReadAll
array = split(response, vblf)
'create response object
set device = new DeviceDetails
with device
.Name = array(0)
.Description = array(1)
.Environment = array(2)
.IP_Address = array(3)
.Server_Type = array(4)
.Domain_Name = array(5)
End with
set getDeviceDetailsDialog = device
end function
'usage example:
'dim device
'set device = getDeviceDetailsDialog(array("prod","dev","test"), array("AppServer","WebServer"))
'MsgBox(device.Description & " - " & device.Environment)
The big lump of Powershell script code in the middle is, admittedly, ugly: you could make the script cleaner by saving the PowerShell script as a .ps1 file to disk, but that adds a dependency for all users to have the script in the same place on their workstations: I preferred the idea of keeping this all in the model / database, so there's no individual user set up for new users for my use-case.
Anyhow, I hope someone finds this useful!