|
| 1 | +--- |
| 2 | +title: "AnyBox" |
| 3 | +output: |
| 4 | + md_document: |
| 5 | + toc: true |
| 6 | + toc_depth: 3 |
| 7 | + variant: markdown_strict+backtick_code_blocks |
| 8 | + pandoc_args: ["--atx-headers"] |
| 9 | +--- |
| 10 | + |
| 11 | +```{r setup, include=FALSE} |
| 12 | +knitr::opts_chunk$set(echo = TRUE, eval=FALSE, engine='bash', |
| 13 | + engine.path = list('bash'="C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe")) |
| 14 | +``` |
| 15 | + |
| 16 | +# *Message Box, Input Box*, <u>AnyBox</u> |
| 17 | + |
| 18 | +Read this on [GitHub](https://github.com/dm3ll3n/AnyBox) or [my site](https://www.donaldmellenbruch.com/project/AnyBox/). |
| 19 | + |
| 20 | +## Overview |
| 21 | + |
| 22 | +Creating forms in Powershell can be tedious, from aligning the content just right to wiring up events. Thankfully, when it comes to GUIs for Powershell scripts, a simple message box or input box usually does the trick. The problem is that the not-so-built-in offerings for Powershell are extremely limited in (1) features and (2) customization. |
| 23 | + |
| 24 | +Message box: |
| 25 | + |
| 26 | +```{powershell, eval=FALSE} |
| 27 | +Add-Type -AssemblyName PresentationFramework |
| 28 | +
|
| 29 | +[System.Windows.MessageBox]::Show('hello world', 'MessageBoxDemo') |
| 30 | +``` |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | +Input box: |
| 35 | + |
| 36 | +```{powershell, eval=FALSE} |
| 37 | +[Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') |
| 38 | +
|
| 39 | +[Microsoft.VisualBasic.Interaction]::InputBox('interesting input', 'InputBoxDemo') |
| 40 | +``` |
| 41 | + |
| 42 | + |
| 43 | + |
| 44 | +Neither of these approaches are customizable beyond the essentials; they are focused purely on their limited functional. They're also not very Powershell-esque. If you want anything more, you'll have to create it yourself. A few options exist to make the creation of a custom form simpler (form designers), but the learning curve can be steep for a non-developer Powershell users (e.g., engineers, admins), and it is a tedious task even for the Powershell experts. |
| 45 | + |
| 46 | +AnyBox was developed to satisfy both the need for simplicity and advanced customization when creating appealing WPF forms in Windows Powershell. |
| 47 | + |
| 48 | +## How to get it |
| 49 | + |
| 50 | +Install AnyBox from the [Powershell Gallery](https://www.powershellgallery.com/packages/AnyBox) with: |
| 51 | + |
| 52 | +```{powershell, eval=FALSE} |
| 53 | +Install-Module -Name 'AnyBox' |
| 54 | +``` |
| 55 | + |
| 56 | +Then, load it with: |
| 57 | + |
| 58 | +```{powershell} |
| 59 | +Import-Module AnyBox |
| 60 | +``` |
| 61 | + |
| 62 | +## Message Box |
| 63 | + |
| 64 | +Simple message box with AnyBox: |
| 65 | + |
| 66 | +```{powershell} |
| 67 | +Show-AnyBox -Title 'MessageBoxDemo' -Message 'hello world' -Buttons 'OK' |
| 68 | +``` |
| 69 | + |
| 70 | + |
| 71 | + |
| 72 | +Center the content and increase font size: |
| 73 | + |
| 74 | +```{powershell} |
| 75 | +Show-AnyBox -Title 'MessageBoxDemo' -Message 'hello world' -FontSize 14 -ContentAlignment 'Center' -Buttons 'OK' |
| 76 | +``` |
| 77 | + |
| 78 | + |
| 79 | + |
| 80 | +Add more buttons: |
| 81 | + |
| 82 | +```{powershell} |
| 83 | +Show-AnyBox -Title 'MessageBoxDemo' -Message 'hello world' -FontSize 14 -ContentAlignment 'Center' -Buttons 'Yes','No','Maybe?' |
| 84 | +``` |
| 85 | + |
| 86 | + |
| 87 | + |
| 88 | +Change the modal frame and set the window topmost: |
| 89 | + |
| 90 | +```{powershell} |
| 91 | +Show-AnyBox -Title 'MessageBoxDemo' -Message 'hello world' -FontSize 14 -ContentAlignment 'Center' -Buttons 'Yes','No','Maybe?' -WindowStyle 'ToolWindow' -Topmost |
| 92 | +``` |
| 93 | + |
| 94 | + |
| 95 | + |
| 96 | +Make it gnarly: |
| 97 | + |
| 98 | +```{powershell} |
| 99 | +Show-AnyBox -Title 'MessageBoxDemo' -Message 'hello world' -FontSize 14 -ContentAlignment 'Center' -Buttons 'Yes','No','Maybe?' -Topmost ` |
| 100 | + -Icon 'Warning' -BackgroundColor 'Black' -FontColor 'Orange' -FontFamily 'Comic Sans MS' |
| 101 | +``` |
| 102 | + |
| 103 | + |
| 104 | + |
| 105 | +## Input Box |
| 106 | + |
| 107 | +Simple input box with AnyBox: |
| 108 | + |
| 109 | +```{powershell} |
| 110 | +Show-AnyBox -Title 'InputBoxDemo' -Prompt "what's your name?" -Buttons 'Cancel','Submit' |
| 111 | +``` |
| 112 | + |
| 113 | + |
| 114 | + |
| 115 | +Add more prompts and a comment: |
| 116 | + |
| 117 | +```{powershell} |
| 118 | +Show-AnyBox -Title 'InputBoxDemo' -Prompts "what's your name?","what's your number?" -Buttons 'Cancel','Submit' -Comment '* responses are confidential' |
| 119 | +``` |
| 120 | + |
| 121 | + |
| 122 | + |
| 123 | +> The next couple of examples jump ahead a bit, but to give you an idea of what's possible... |
| 124 | +
|
| 125 | +Multi-line input: |
| 126 | + |
| 127 | +```{powershell} |
| 128 | +Show-AnyBox -Title 'InputBoxDemo' -Buttons 'Cancel','Submit' -Prompts @( |
| 129 | + New-AnyBoxPrompt -Message 'Query:' -LineHeight 5 |
| 130 | +) |
| 131 | +``` |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | +Grouped prompts and collapsible prompts: |
| 136 | + |
| 137 | +```{powershell} |
| 138 | +Show-AnyBox -Title 'InputBoxDemo' -Buttons 'Cancel','Submit' -MinWidth 100 -Prompts @( |
| 139 | + New-AnyBoxPrompt -Group 'Connection Info' -Message 'SQL Instance:' |
| 140 | + New-AnyBoxPrompt -Group 'Connection Info' -Message 'User Name:' |
| 141 | + New-AnyBoxPrompt -Group 'Connection Info' -Message 'Password:' -InputType Password |
| 142 | + New-AnyBoxPrompt -Group 'Query' -LineHeight 5 -Collapsible |
| 143 | +) |
| 144 | +``` |
| 145 | + |
| 146 | + |
| 147 | + |
| 148 | +## AnyBox |
| 149 | + |
| 150 | +AnyBox makes a fine replacement for your typical message box and input box, and it can do a lot more. So much so that, given a long list of parameters, it may be more intuitive to "build" the AnyBox top-down rather than calling the function with a long list of parameters. For example, the two functions below produce the same AnyBox: |
| 151 | + |
| 152 | +```{powershell} |
| 153 | +Show-AnyBox -Icon 'Question' -Title 'AnyBoxDemo' -Prompts "what's your name?","what's your number?" -FontSize 14 -ContentAlignment 'Center' -Buttons 'Yes','No','Maybe?' -DefaultButton 'Yes' -CancelButton 'No' -ButtonRows 2 -Topmost |
| 154 | +``` |
| 155 | + |
| 156 | +*or* |
| 157 | + |
| 158 | +```{powershell} |
| 159 | +Import-Module AnyBox |
| 160 | +
|
| 161 | +$anybox = New-Object AnyBox.AnyBox |
| 162 | +
|
| 163 | +$anybox.Icon = 'Question' |
| 164 | +$anybox.Title = 'AnyBoxDemo' |
| 165 | +$anybox.Prompts = 'what''s your name?','what''s your number?' |
| 166 | +$anybox.FontSize = 14 |
| 167 | +$anybox.ContentAlignment = 'Center' |
| 168 | +$anybox.Buttons = 'Yes','No','Maybe?' |
| 169 | +$anybox.DefaultButton = 'Yes' |
| 170 | +$anybox.CancelButton = 'No' |
| 171 | +$anybox.ButtonRows = 2 |
| 172 | +$anybox.Topmost = $true |
| 173 | +
|
| 174 | +$anybox | Show-AnyBox |
| 175 | +``` |
| 176 | + |
| 177 | + |
| 178 | + |
| 179 | +> Note: the later syntax was introduced in AnyBox v0.3.4. |
| 180 | +
|
| 181 | +### Prompts |
| 182 | + |
| 183 | +AnyBox offers many different prompt types. The typical prompt `Text`, shown in the examples above, is used when the value for "-Prompts" is a string. As you'll see, `Text` can be represented as a text box, combo box, or set of radio buttons. To use other prompt types and make customizations to individual prompts, use `New-AnyBoxPrompt`. |
| 184 | + |
| 185 | +```{powershell} |
| 186 | +Import-Module AnyBox |
| 187 | +
|
| 188 | +$anybox = New-Object AnyBox.AnyBox |
| 189 | +
|
| 190 | +$anybox.Prompts = @( |
| 191 | + # typical text prompt, but with default value. |
| 192 | + New-AnyBoxPrompt -InputType Text -Message "what's your name?" -DefaultValue 'donald' |
| 193 | + # typical text prompt, but with validation (must be all numeric). |
| 194 | + New-AnyBoxPrompt -InputType Text -Message "what's your number?" -ValidateScript { $_ -match '^[0-9]+$' } |
| 195 | + # sets are shown as drop-down lists. |
| 196 | + New-AnyBoxPrompt -InputType Text -Message "what's your favorite color?" -ValidateSet 'red','blue','green' -DefaultValue 'blue' |
| 197 | + # or sets of radio buttons. |
| 198 | + New-AnyBoxPrompt -InputType Text -Message "what's your favorite fruit?" -ValidateSet 'apple','banana','tomato?' -DefaultValue 'banana' -ShowSetAs Radio |
| 199 | + # date input. |
| 200 | + New-AnyBoxPrompt -InputType Date -Message "what's your birthday?" -DefaultValue '1970-01-01' |
| 201 | + # secure string input. |
| 202 | + New-AnyBoxPrompt -InputType Password -Message "what's your SSN?" |
| 203 | + # file input |
| 204 | + New-AnyBoxPrompt -InputType FileOpen -Message "Upload supporting documents:" |
| 205 | + # link input |
| 206 | + New-AnyBoxPrompt -InputType Link -Message "Terms & Conditions" -DefaultValue 'www.donaldmellenbruch.com' |
| 207 | + # checkbox (boolean) input. |
| 208 | + New-AnyBoxPrompt -InputType Checkbox -Message "I have read the terms & conditions" -DefaultValue $false |
| 209 | +) |
| 210 | +
|
| 211 | +$anybox.ContentAlignment = 'Center' |
| 212 | +$anybox.Buttons = 'Cancel','Submit' |
| 213 | +$anybox.Icon = 'Question' |
| 214 | +
|
| 215 | +$anybox | Show-AnyBox |
| 216 | +``` |
| 217 | + |
| 218 | + |
| 219 | + |
| 220 | +### Buttons |
| 221 | + |
| 222 | +To create a customized button, use `New-AnyBoxButton`. There are a few pre-made action buttons that can be created from a template, such as `'CopyMessage'`, which will copy the displayed message to the clipboard. |
| 223 | + |
| 224 | +```{powershell} |
| 225 | +Import-Module AnyBox |
| 226 | +
|
| 227 | +$anybox = New-Object AnyBox.AnyBox |
| 228 | +
|
| 229 | +$anybox.Icon = 'Error' |
| 230 | +$anybox.Message = 'Process.exe exited with code -1.' |
| 231 | +
|
| 232 | +$anybox.Buttons = @( |
| 233 | + New-AnyBoxButton -Text 'Close' -IsCancel |
| 234 | + New-AnyBoxButton -Template 'CopyMessage' |
| 235 | + New-AnyBoxButton -Text 'Retry' -IsDefault |
| 236 | +) |
| 237 | +
|
| 238 | +$anybox | Show-AnyBox |
| 239 | +``` |
| 240 | + |
| 241 | + |
| 242 | + |
| 243 | +### Data Grid |
| 244 | + |
| 245 | +In addition to messages, prompts, and buttons, AnyBox can present a data grid, complete with a search bar. |
| 246 | + |
| 247 | +```{powershell} |
| 248 | +Import-Module AnyBox |
| 249 | +
|
| 250 | +$anybox = New-Object AnyBox.AnyBox |
| 251 | +
|
| 252 | +$anybox.Title = 'Windows Services' |
| 253 | +$anybox.ContentAlignment = 'Center' |
| 254 | +$anybox.MaxHeight = 600 |
| 255 | +
|
| 256 | +$anybox.GridData = Get-Service | Select-Object Status, Name, DisplayName |
| 257 | +
|
| 258 | +$anybox.Buttons = @( |
| 259 | + New-AnyBoxButton -Text 'Close' |
| 260 | + New-AnyBoxButton -Template 'ExploreGrid' |
| 261 | + New-AnyBoxButton -Template 'SaveGrid' |
| 262 | +) |
| 263 | +
|
| 264 | +$anybox | Show-AnyBox |
| 265 | +``` |
| 266 | + |
| 267 | + |
| 268 | + |
| 269 | +> Suppress the grid search bar by setting `$anybox.NoGridSearch=$true` |
| 270 | +
|
| 271 | +### Handling Input |
| 272 | + |
| 273 | +Getting a message to users is only half the battle. Handling their responses is the other half, and AnyBox makes that easier too. |
| 274 | + |
| 275 | +After an AnyBox window closes, it returns a hashtable of user inputs (if any). The hashtable will contain a key for each prompt and each button. By default, prompt keys are named "Input_#", where `#` is index of the prompt in the order they were defined (starting from 0). Buttons, by default, are named by their text. To override the corresponding key name, specify a `-Name` for the prompt/button when defining it with `New-AnyBoxPrompt`/`New-AnyBoxButton`. Names cannot contain spaces. |
| 276 | + |
| 277 | +```{powershell} |
| 278 | +Import-Module AnyBox |
| 279 | +
|
| 280 | +$anybox = New-Object AnyBox.AnyBox |
| 281 | +
|
| 282 | +$anybox.Prompts = 1..3 | ForEach-Object { New-AnyBoxPrompt -Message "Prompt $_" -Name "Prompt_$_" } |
| 283 | +$anybox.Buttons = 1..3 | ForEach-Object { New-AnyBoxButton -Text "Button $_" -Name "Button_$_" } |
| 284 | +
|
| 285 | +$response = $anybox | Show-AnyBox |
| 286 | +
|
| 287 | +$response |
| 288 | +``` |
| 289 | + |
| 290 | + |
| 291 | + |
| 292 | + ## |
| 293 | + ## Name Value |
| 294 | + ## ---- ----- |
| 295 | + ## Prompt_3 also, text |
| 296 | + ## Button_1 False |
| 297 | + ## Prompt_2 moar text |
| 298 | + ## Prompt_1 some text |
| 299 | + ## Button_3 True |
| 300 | + ## Button_2 False |
| 301 | + |
| 302 | +To examine the output for a specific prompt/button (here, `Prompt_1`): |
| 303 | + |
| 304 | +```{powershell, eval=FALSE} |
| 305 | +$response['Prompt_1'] |
| 306 | +``` |
| 307 | + |
| 308 | +To see which button was clicked, iterate over the hashtable. |
| 309 | + |
| 310 | +```{powershell, eval=FALSE} |
| 311 | +$response.Keys | Where-Object { $_ -like 'Button_*' -and $response[$_] -eq $true } |
| 312 | +``` |
| 313 | + |
| 314 | +A similar method of iterating over the responses, which will return an array of key-value pairs that match a condition. |
| 315 | + |
| 316 | +```{powershell, eval=FALSE} |
| 317 | +$response.GetEnumerator() | Where-Object { $_.Name -like 'Prompt_*' -and $_.Value -like '*' } |
| 318 | +``` |
| 319 | + |
| 320 | +So, a simple AnyBox workflow could look something like: |
| 321 | + |
| 322 | +```{powershell} |
| 323 | +Import-Module AnyBox |
| 324 | +
|
| 325 | +# build the AnyBox |
| 326 | +$anybox = New-Object AnyBox.AnyBox |
| 327 | +
|
| 328 | +$anybox.Prompts = New-AnyBoxPrompt -Name 'name' -Message "what's your name?" -ValidateNotEmpty |
| 329 | +
|
| 330 | +$anybox.Buttons = @( |
| 331 | + New-AnyBoxButton -Name 'cancel' -Text 'Cancel' -IsCancel |
| 332 | + New-AnyBoxButton -Name 'submit' -Text 'Submit' -IsDefault |
| 333 | +) |
| 334 | +
|
| 335 | +# show the AnyBox; collect responses. |
| 336 | +$response = $anybox | Show-AnyBox |
| 337 | +
|
| 338 | +# act on responses. |
| 339 | +if ($response['submit'] -eq $true) { |
| 340 | + $name = $response['name'] |
| 341 | + Show-AnyBox -Message "Hello $name!" -Buttons 'OK' |
| 342 | +} |
| 343 | +else { |
| 344 | + Show-AnyBox -Message "Ouch!" -Buttons 'OK' |
| 345 | +} |
| 346 | +``` |
| 347 | + |
| 348 | + ----->  |
| 349 | + |
| 350 | +## More resources |
| 351 | + |
| 352 | +This guide was reworked as of AnyBox v0.3.4. More extensive docs exist at: |
| 353 | + |
| 354 | +https://www.donaldmellenbruch.com/doc/anybox/ |
| 355 | + |
| 356 | +Cheers! |
0 commit comments