Windows Forms - Randomize BackColor - Powershell - windows

I'm making a GUI using Windows Forms and I'd like to add a feature where you can randomize the background color of the form. Please be noted that I intend to keep the code fully written in Powershell.
Here's a snippet of the code:
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$objForm = New-Object System.Windows.Forms.Form
$choochoo = New-Object System.Windows.Forms.Button
And here is the code that I need help with:
$choochoo.Add_Click({$objForm.BackColor = Random})
Obviously 'Random' does not work in this example and is only being used as a placeholder.
I suppose I need to generate random values using the time but would appreciate a more concrete code. Thanks in advance.

Been learning Powershell recently. Playing around came up with a solution for this today if anyone wants to do all possible random colors (I know this thread is old).
Add-Type -AssemblyName System.Windows.Forms
$Form = New-Object system.Windows.Forms.Form
$Form.Text = "Sample Form"
$Label = New-Object System.Windows.Forms.Label
$Label.Text = "This is a Form."
$Form.Controls.Add($Label)
function colorful{
$c1 = '';
$c2 = '';
foreach( $digit in (1..6 | foreach{ '{0:X}' -f (Get-Random -Max 16) })){
$c1 = "$c1"+"$digit";}
foreach( $digit in (1..6 | foreach{ '{0:X}' -f (Get-Random -Max 16) })){
$c2 = "$c2"+"$digit";}
$Form.BackColor = "#FF"+$c1;
$Form.ForeColor = "#FF"+$c2;
};
colorful;
$Form.ShowDialog();

You'll want to be using an instance of System.Random to select from the possible static properties of System.Drawing.Color.

Got it to work with this if someone needs this too:
function RandomBacklight {`
$random = New-Object System.Random
switch ($random.Next(9)) {
0 {$objForm.BackColor = "LightBlue"}
1 {$objForm.BackColor = "LightGreen"}
2 {$objForm.BackColor = "LightPink"}
3 {$objForm.BackColor = "Yellow"}
4 {$objForm.BackColor = "Orange"}
5 {$objForm.BackColor = "Brown"}
6 {$objForm.BackColor = "Magenta"}
7 {$objForm.BackColor = "White"}
8 {$objForm.BackColor = "Gray"}
}
}
$choochoo.Add_Click({RandomBacklight})

Related

Powershell GUI PictureBox not able to change photos

I am new to Powershell.
I am trying to create picture box that will load a lot of images in a folder.
I have a folder that contain 10 images. but i want my picturebox to display it dynamically every second or 3 seconds
here is my code so far.
####################################### Form settings ##############################################
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$Form = New-Object System.Windows.Forms.Form
$Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog
$Form.Anchor = "Top,Bottom,Left,Right"
$Form.Size = New-Object System.Drawing.Size(1920,1600)
$Form.AutoScale = $True
$Form.StartPosition = "CenterScreen" #loads the window in the center of the screen
$Form.BackgroundImageLayout = "Zoom"
$Form.MinimizeBox = $True
$Form.MaximizeBox = $False
$Form.WindowState = "Normal"
$Form.SizeGripStyle = "Auto"
$Form.AutoSizeMode = New-Object System.Windows.Forms.AutoSizeMode
$Form.SizeGripStyle = "Show"
$Form.BackColor = "LightGray"
###################################################################################################
###################################################################################################
######################################### Image Folder ############################################
$ImagePreview = New-Object System.Windows.Forms.PictureBox
$ImagePreview.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::StretchImage
$ImagePreview.Location = New-Object System.Drawing.Size(965,110)
$ImagePreview.Size = New-Object System.Drawing.Size(295,370)
$ImagePreview.BackColor = "White"
$Form.Controls.Add($ImagePreview)
Function ImageFolder($ImagePreview)
{
$ImageItem = Get-Item "C:\Newfolder"
$ImagePreview.ImageLocation = $ImageItem
}
$TimerImageFolder = New-Object System.Windows.Forms.Timer
$TimerImageFolder.Interval = 3000
$TimerImageFolder.Add_Tick({$ImageFolder $ImagePreview})
$TimerImageFolder.Enabled = $True
$ImageGroupBox = New-Object System.Windows.Forms.GroupBox
$ImageGroupBox.Location = New-Object System.Drawing.Size(940,70)
$ImageGroupBox.size = New-Object System.Drawing.Size(350,440)
$ImageGroupBox.text = "Preview"
$ImageGroupBox.BackColor = "DimGray"
$ImageGroupBox.ForeColor = "White"
$Form.Controls.Add($ImageGroupBox)
####################################### Result ##############################################
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
I don't know which part is wrong.
Thank You so much for the help Guys
What you're attempting to do is a cumbersome task from PowerShell. As you may note, it requires the instantiation of a powershell instance where initialize the Forms.Timer, this is needed because we need the .Tick event to happen on a separate thread, otherwise, the form would freeze on each triggering of this event.
The code shared below is, as a minimal reproduction of what you're trying to achieve, I have tried to simplified as much as possible but, as stated before, this is no easy task from PowerShell.
Below example as well as another example using an API to load the pictures from the Internet instead of from Disk can be found on this Gist. There is also a gif demo there.
using namespace System.Windows.Forms
using namespace System.Drawing
using namespace System.Management.Automation.Runspaces
Add-Type -AssemblyName System.Drawing, System.Windows.Forms
[Application]::EnableVisualStyles()
$event = #{}
# Get the paths of all the pictures in the `pictures` folder
$pictures = (Get-ChildItem .\pictures -Filter *.png).FullName
# basic form
$form = [Form]#{
ClientSize = [Size]::new(1280, 720)
StartPosition = 'CenterScreen'
}
# basic picturebox, note it includes a `Name` so it's easier to find
# from inside the `powershell` instance
$pictureBox = [PictureBox]#{
Name = 'myPictureBox'
Anchor = 'top, left'
SizeMode = [PictureBoxSizeMode]::StretchImage
Location = [Point]::new(20, 20)
Size = [Size]::new($form.Width - 60, $form.Height - 80)
Image = [Drawing.Image]::FromFile($pictures[0])
}
$form.Controls.Add($pictureBox)
# event to resize the picturebox when the form is resized
$form.Add_Resize({
$pictureBox.Size = [Size]::new($this.Width - 60, $this.Height - 80)
})
# initialize a `powershell` instance where we can handle the the Slide Show
# in PowerShell we require to perform this action from a different thread,
# else the form will freeze every 3000 milliseconds
$ps = [powershell]::Create().AddScript({
param($pictures, $form)
[ref] $ref = 1
$timer = [Windows.Forms.Timer]#{
Interval = 3000
}
# find the pictureBox in the Form controls
$pictureBox = $form.Controls.Find('myPictureBox', $false)[0]
# this Tick Event swaps the pictures when triggered
$timer.Add_Tick({
$pictureBox.Image = [Drawing.Image]::FromFile($pictures[$ref.Value++ % $pictures.Count])
})
# Start the Timer
$timer.Enabled = $true
# this `while` loop keeps this thread running until the form is closed
while($form.DialogResult -eq 'None') {
# we perform `Application.DoEvents()` so the form is updated on each loop iteration,
# without it we wouldn't see the picturebox updated
[Windows.Forms.Application]::DoEvents()
}
$form.DialogResult
# here we pass the list of paths and the form instance itself to this thread
}).AddParameters(#{ pictures = $pictures; form = $form })
# when the form is shown
$form.Add_Shown({
# bring it to front
$this.Activate()
# and add this AsyncResult to the `$events` hashtable
$event['AsyncResult'] = $ps.BeginInvoke()
})
# display the form (this blocks the current thread)
$null = $form.ShowDialog()
# when the form is closed, stop the runspace
$ps.EndInvoke($event['AsyncResult'])
# and dispose everything
$form, $ps | ForEach-Object Dispose

Powershell gui textbox with multiple color lines

Im having trouble with powershell textbox
here is the definition of it:
$ResultsTextBox = New-Object System.Windows.Forms.TextBox
$ResultsTextBox.Location = New-Object System.Drawing.Size(780,40)
$ResultsTextBox.Size = New-Object System.Drawing.Size(450,340)
i would like to create a function which output text to this text box but i would like to generate the text either red or green
depending of my choice..
but when i do this:
function LinkFn {
$ResultsTextBox.clear()
$SWITCH = Get-ADOrganizationalUnit -filter * -Property CanonicalName | Where-Object {$_.CanonicalName -eq $listBox2.SelectedItem}
forEach ($line in $listBox1.selecteditems){
try {
$ResultsTextBox.ForeColor ='green'
New-GPlink -name $line -target $SWITCH -ErrorAction STOP | Out-null
$ResultsTextBox.AppendText("`n GPO: $line HAVE BEEN LINKED Successfully.`n")
}
catch{
$ResultsTextBox.ForeColor ='red'
$ResultsTextBox.AppendText("`n COULDN NOT LINK GPO: $line `n")
}
}
it changes all the lines, when the result i wanted could be 1 line in red 2 lines in green for example
You need to use a RichTextBox control for this instead of a regular TextBox.
For demo here's a small form that fills lines in different colors to a RichTextBox:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
# helper function to write text in a given color
# to the specified RichTextBox control
function Append-ColoredLine {
param(
[Parameter(Mandatory = $true, Position = 0)]
[System.Windows.Forms.RichTextBox]$box,
[Parameter(Mandatory = $true, Position = 1)]
[System.Drawing.Color]$color,
[Parameter(Mandatory = $true, Position = 2)]
[string]$text
)
$box.SelectionStart = $box.TextLength
$box.SelectionLength = 0
$box.SelectionColor = $color
$box.AppendText($text)
$box.AppendText([Environment]::NewLine)
}
$form = New-Object System.Windows.Forms.Form
$form.Width = 400
$form.Height = 500
$richText = New-Object System.Windows.Forms.RichTextBox
$richText.Location = [System.Drawing.Point]::new(10,10)
$richText.Size = [System.Drawing.Size]::new(364,350)
$richText.Font = [System.Drawing.Font]::new('Calibri', 14)
$richText.Anchor = 'Top','Right','Bottom','Left'
$form.Controls.Add($richText)
$button = New-Object System.Windows.Forms.Button
$button.Location = [System.Drawing.Point]::new(10,400)
$button.Size = [System.Drawing.Size]::new(80,30)
$button.Text = 'Test'
$button.Anchor = 'Bottom','Left'
$button.Add_Click({
$richText.Clear()
# write green lines
Append-ColoredLine $richText Green "GPO: 'gpo_A' has been linked Successfully"
Append-ColoredLine $richText Green "GPO: 'gpo_B' has been linked Successfully"
# write red line
Append-ColoredLine $richText Red "Could not link GPO: 'gpo_C'"
# insert blank line
$richText.AppendText([Environment]::NewLine)
# write various lines in different colors
'Blue','DarkGoldenrod','DarkCyan','OliveDrab','Chocolate','Crimson' | ForEach-Object {
Append-ColoredLine $richText $_ "Some text using color '$_'"
}
})
$form.Controls.Add($button)
[void] $form.ShowDialog()
$form.Dispose()
When pressing the Test button on this form, colored lines are written
Hope that helps

creating a button function BEFORE selected items on gui

Im creating a form and something dont seems to work here. at the beginning of the script i declaring $button1_click as so:
#Link Button
$Button1_Click = {
Write-Host "link button"
$listBox.SelectedItems
$listBox2.SelectedItem}
i then continute to build to gui with 2 item lists
$button1 = New-Object System.Windows.Forms.Button
$button1.Location = New-Object System.Drawing.Point(10,430)
$button1.Size = New-Object System.Drawing.Size(75,23)
$button1.Text = 'Link'
$Button1.Add_Click($Button1_Click)
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(260,20)
$listBox.Height = 350
$listbox.SelectionMode = 'MultiExtended'
$listBox2 = New-Object System.Windows.Forms.ListBox
$listBox2.Location = New-Object System.Drawing.Point(300,40)
$listBox2.Size = New-Object System.Drawing.Size(450,20)
$listBox2.Height = 350
but when i hit button 1 i dont seem to have anything in the $listbox variable, maybe it got something to do it was declared before that other piece of code?
See my answer you accepted in another post you submitted about GUI and PowerShell with List boxes (which seems to be just a longer one of this one.):
Im having promlen with button functions in gui powershell
And this one as well.
Powershell output in color

Transparent background of Winform in powershell

Here I have a form with a PictureBox in it. I removed borders and now I want to make the background of the form transparent, so when I launch the script we just see the image nothing else.
I am making a splash screen kind of project with an unusual png shape. I tried the "TransperancyKey = Color" thing from .Net but it doesn't work. I want it to run in PowerShell.
# Importing Assembly for Windows Forms
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
# Main form/SplashScreen Object
$SScreen = New-Object system.Windows.Forms.Form
$SScreen.BackColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
#$SScreen.BackColor = Color.Lime
$SScreen.StartPosition = 1
$SScreen.FormBorderStyle = 0
$img = [System.Drawing.Image]::Fromfile('./1.png')
$pictureBox = new-object Windows.Forms.PictureBox
$pictureBox.Width = $img.Size.Width
$pictureBox.Height = $img.Size.Height
$pictureBox.Image = $img
$SScreen.controls.add($pictureBox)
$SScreen.Width = $pictureBox.Width
$SScreen.Height = $pictureBox.Height
# Open the main form
Start-Process -FilePath "C:\Windows\system32\WindowsPowerShell\v1.0\powershell_ise.exe"
$SScreen.TopMost = $true
$SScreen.Show()
Start-Sleep -seconds 5
$SScreen.Close()```
You can do this without adding a picturebox to the form and simply use the forms own BackgroundImage property for this.
Make sure your image has transparency of course.
For this, I took your image and made all black transparent.
Because I copied from the web page, it won't be as crisp as yours, but it's the idea that counts.
Try:
# Importing Assembly for Windows Forms
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$img = [System.Drawing.Image]::Fromfile('./1.png')
# Main form/SplashScreen Object
$SScreen = New-Object system.Windows.Forms.Form
$SScreen.Width = $img.Width
$SScreen.Height = $img.Height
$SScreen.TopMost = $true
$SScreen.BackgroundImage = $img
$SScreen.AllowTransparency = $true
$SScreen.TransparencyKey = $SScreen.BackColor
$SScreen.StartPosition = 1
$SScreen.FormBorderStyle = 0
# Open the main form
Start-Process -FilePath "C:\Windows\system32\WindowsPowerShell\v1.0\powershell_ise.exe"
$SScreen.Show()
Start-Sleep -Seconds 5
$SScreen.Close()
# tell Windows it can be removed from memory
$SScreen.Dispose()
Result:

powershell + PS2EXE-v0.5.0.0 + windows forms

I need to compile ps1 to exe. It works fine, but when i've added some windows.forms elements (open file dialog and select dir) it is still compiling but forms are not showing. Then I noticed, that forms are not showing even when I start script with RMB -> Exec with Powershell. But everything works fine in ISE.
Does anybody have similar problem?
Function Get-OpenFile($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "Text files (*.txt)|*.txt"
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
$OpenFileDialog.ShowHelp = $true
}
function Select-Folder($message='Folder to save', $path = 0) {
$object = New-Object -comObject Shell.Application
$folder = $object.BrowseForFolder(0, $message, 0, $path)
if ($folder -ne $null) {
$folder.self.Path
}
}
The rest of the code is just parser and renamer.
UPD - Problem is exactly with windows.forms, when I've comment #get-openfile(myDir) , select-folder dialog has been shown. And shows up, after compiling to exe.
ok, nevermind, i just refused open-file dialog.

Resources