PowerShell Form: Sometimes starts in the background - winforms

I wrote a little GUI for a script that I use on daily basis. Sometimes the window starts in the background behind all other windows I have opened. In this case there will even be no icon in the task bar. This phenomenon looks like the script is not started. When I minimize all other windows I can see the script GUI and after clicking into it the icon on the task bar appears.
Here is how I defined the PowerShell form:
[void] [system.reflection.assembly]::loadwithpartialname("system.windows.forms")
[void] [system.reflection.assembly]::loadwithpartialname("system.drawing")
$window = New-Object System.Windows.Forms.Form
$window.StartPosition = "CenterScreen"
$window.AutoSize = $False
$window.MinimizeBox = $False
$window.MaximizeBox = $False
$window.FormBorderStyle = "FixedToolWindow"
[...]
$window.ShowDialog() | Out-Null
Does anyone know what I can do to ensure that the GUI is always started on top?

Related

Add text to TextBox during ShowDialog and Add_ContentRendered

When loading my PowerShell WPF script, I want some information shown to the user that the script is loading multiple things from Active Directory.
As my script is now, the Window is unresponsive during the loading (which takes aprox 20 seconds), and then when everything is done, the TextBox is updated with the four lines that adds text to the TextBox. I want it to do task 1, update TextBox, then Task 2, update the TextBox and so on. How can I accomplish this?
In the Add_ContentRendered block I have four $WPFlogTxtBox.AddText("Some text"), but these are displayed in the $WPFlogTxtBox all at once when the Add_ContentRendered block is finished, not when they show up in the script.
XAML contains:
<TextBox x:Name="logTxtBox" HorizontalAlignment="Left" Height="112" Margin="10,290,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="496" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>
Rest of the script condensed:
$Form.Add_ContentRendered({
$WPFlogTxtBox.AddText("Getting OUs")
$OUs = Get-ADOrganizationalUnit -Filter '*' | sort Name
$WPFlogTxtBox.AddText("Getting users")
$users = Get-ADUser -Filter * | sort Name
$WPFlogTxtBox.AddText("Getting groups")
$groups = Get-ADGroup -Filter '*' | sort Name
})
$Form.ShowDialog()
This works, besides that the text is added to TextBox when everything in Add-ContentRendered is done.
I want the AddText-method to add the text when the command is run, not when the whole invoking block (Add_ContentRendered) is done.
Basically, you need to yield the thread to let the window repaint ...
$WPFlogTxtBox.Dispatcher.Yield("ApplicationIdle");
A better solution would be to do the work on a different thread, and call into the control's dispatcher to update it. Show-UI does this sort of thing for you 😉 but you can do it yourself by spinning up another PowerShell runspace -- that's a bit much to get into here. Look at the ShowUI code on github, or at blog posts from Boe Prox or Stephen Owen

How to style Windows Form Labels

I am writing a (purely) PowerShell app to display numbers in a table using Windows Forms
My thought is to create rows of fixed-size labels (or text boxes), which works out just fine. What I am having trouble with is figuring how to make those numbers right-justified within each label field. I see that using XAML there is a "HorizontalContentAlignment" but I can't seem to see the equivalent property in PowerShell. I see there is TextAlign property but that seems to be for Vertical alignment, rather than Horizontal.
Of course, I am open to doing something else (other than table of labels) that'll do the same thing.
Thanks.
Well, You can use the enumerations from System.Drawing.ContentAlignment
$Label = New-Object -TypeName System.Windows.Forms.Label
$Label.Text = 'SomeText'
$Label.TextAlign = [System.Drawing.ContentAlignment]::MiddleRight
How did I find the peroperty ?
$Label | Get-Member -MemberType Property | Where-Object -FilterScript {$_.name -like "*ali*"}
Since you are writing an app only with Powershell, I'd think it would be a little weird using Win Forms just for displaying information.
I'd suggest checking out POSHGUI (https://poshgui.com/Editor) which helps you generate win forms style GUI for you're Powershell code.
In addition, Powershell has Out-Gridview, which could be sufficient to your need if I got the idea of what you're trying to do.

Is it possible or practical to change the drfault look of WinForm control items?

I am working on a flat style user interface and many parts can work autonomously as widgets or smaller tools. For some of those, it would add an extra level of customizability and desktop appeal if i could change the basic look and feel of the CIs.
For instance, could I change the basic WinForm form ([Windows.Forms.Form]) appearance to resemble the outline of a dog-eared piece of paper? I would want to do different ones, so, a permanent change to the static method isn't what I'm looking for.
How about changing a button ([Windows.Forms.Button]) so that it has rounded edges? What about making it a circle?
I know that with many other things like this, the solution would be to create a completely new object that acts exactly like the object you want it to be and make it take on your intended appearance and behaviours. That is much more than I would like to do (I think).
So, barring the above-mentioned, is this possible in PowerShell? If it is, could someone point me in the right direction or maybe give me a rough explanation? It would be greatly appreciated!
Yep there are some modifications you can do.
For Example:
$Button = New-Object System.Windows.Forms.Button
$Button.UseVisualStyleBackColor = $true
$Button.BackColor = [System.Drawing.Color]::FromArgb(0,0,0,0)
$Button.ForeColor = "Tomato"
$Button.Font = New-Object System.Drawing.Font("Arial", 9.25)
I'm not shure about the border, but I now a cool tool.
AdminScriptEditor
Install and run ASE.
Create a new Powershell File. Then go to "Tools" in the menubar and open the Script Form Designer.
There you can "draw" / build your Form. When you select an Item, on the right side of the Script Form Designer you can easily Change the attributes, like Background Color, ForeColor etc.
After building the form you can easily klick on "File" --> Save to ASE.
And then you have the Form in $PS Code. There you can see how to manipulate the Form.
Greetz Eldo.Ob

What is the difference between using System.Drawing.Size and $button.Top & $button.Left in Windows Forms?

I have been designing a GUI in Powershell (never thought I'd use that sentence) and, while looking at different sources online, there are different methods for positioning Control Items withing a form.
When I first starting familiarizing myself with the basic framework on how to build a simple form, it shows this:
[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
$form = New-Object System.Windows.Forms.Form
$button = New-Object System.Windows.Forms.Button
$button.Top = 30
$button.Left = 30
$form.Controls.Add($button)
However, looking around, I have seen most places use this method:
[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
[System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')
$form = New-Object System.Windows.Forms.Form
$button = New-Object System.Windows.Forms.Button
$button.Location = New-Object System.Drawing.Size(30,30)
$form.Controls.Add($button)
It appears to accomplish the exact same thing.
Different ways to do the same thing is what makes programming interesting (to me, anyway). What I would like to know is if there is a reason why the latter is more commonly demonstrated and if there is a reason why.
Thanks.
Yes you are right. At the end it is exactly the same. All three properties are derived from system.windows.forms.control.
The documentation from Microsoft says:
Control.Left: Gets or sets the distance, in pixels, between the left edge of the control and the left edge of its container's client area [...]
The Left property value is equivalent to the Point.X property of the Location property value of the control.
Control.Top: Gets or sets the distance, in pixels, between the top edge of the control and the top edge of its container's client area. [...] The Top property value is equivalent to the Point.Y property of the Location property value of the control.
It's up to you what you'd like to use in a specific scenario. The only real difference I see, is that for setting the Location you need a new object (value type). For just setting top or left you only need an [int].

Add text to Rich Textbox in Powershell

I am working on a GUI for our office and I have run across an issue, the GUI works wonderfully if you don't have to output text to the GUI. I currently have a Rich Textbox to take the output and display it but it isn't displaying.
$WPFbtnDisk.Add_Click({
start-sleep -Milliseconds 840
write-host "Disk Clicked"
$WPFRichtextbox =gwmi win32_service -ComputerName ($WPFtxtServerName.Text) | sort DisplayName | select-object SystemName,DisplayName,StartMode,State,PathName | Out-String
})
This is the code that I have right now that according to what I read should load the box but it doesn't, if I change it to just a normal textbox it outputs but it just doesn't have any formatting so it is next to impossible to read.
Any help is appreciated.
The RichTextBox control does not have a Text field like a normal textbox, but a Document property which contains a reference to a FlowDocument that makes up the contents of the RichTextBox.
In lieu of creating and maintaining a FlowDocument, you can add text to the existing empty document with the RichTextBox.AppendText() method:
$WmiOutputTable = Get-WmiObject Win32_Service -ComputerName $WPFtxtServerName.Text |Select-Object SystemName,DisplayName,StartMode,State,PathName |Sort-Object DisplayName |Out-String
$WPFRichtextbox.AppendText($WmiOutputTable)

Resources