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
Related
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
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:
I have developed a few internal Chocolatey Packages and the internal repository has no access to Internet. I'd like to have the icon of the packages I have developed to be included in the package itself. Is this possible in Chocolatey?
There is nothing currently in Chocolatey that would allow for the embedding on icons into the package. This would also require that the repository that you are using supported extracting the icon from within the package for display. In the interim, my suggestion would be to host the icons internally on your own website, and update the nupsec files with the internal location for the icons.
No idea if this is the sort of thing you need as I don't use Chocolatey but here's how to use Base64 so that you can embed images in your scripts...
Get the image data:
# Path to image file
$PathToSourceImage = 'c:\temp\image.jpg'
$PathToExe = 'c:\temp\example.exe'
# Convert image to Base64 and copy to clipboard - or there's several websites where you can do this.
[convert]::ToBase64String((get-content $PathToSourceImage -encoding byte)) | Clip
You can also extract from icon or executable:
$Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($PathtoExe)
$MemoryStream = New-Object System.IO.MemoryStream
$Icon.save($MemoryStream)
$Bytes = $MemoryStream.ToArray()
$MemoryStream.Flush()
$MemoryStream.Dispose()
[convert]::ToBase64String($Bytes) | Clip
Now use the image data in your script
# Paste the Base64 data here and assign to a variable.....
$IconBase64 = 'AAABAAEAICAQKAAAAADoAgAAFgAAACgAAAAgAAAAQAAAAAEABAAAAAAAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAA
AP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMzMAAAAAAAAAAAAAczMzM3MzMAAAAAAAAAAAd3M3iIu3dzAAAAAAAAA
Ad3eIi7u7szNwAAAAAAAAAHeIiLu7u7MzMAAAAAAAAACIiIi7u7uzMzAAAAAAAAAAiIiIu7u7szMwAAAAAAAAAIiIiIi7u7uzMAAAAAAAAACIiIiIi7u7u7AAAAAAAAAAiIiIiIi7u7uwAAAAAA
AAAIiIiIiIiLu7sAAAAAAAAACIiIiIiIiHu7AAAAAAAAAAiIiIiId3czdwAAAAAAAAAIiIh3iIiLiHMAAAAAAAAACIh4iLu3iDu4AAAAAAAAAAh4i7u7u4i7sAAAAAAAAAAIi3iLu7uIsAAAAAA
AAAAAC7uIi7u4iLAAAAAAAAAAAAAAuIsACIuwAAAAAAAAAAAAALiAAAiLsAAAAAAAAAAAAAC4sAAIi7AAAAAAAAAAAAAAuLAACIuwAAAAAAAAAAAAALiwAAiLsAAAAAAAAAAAAAC4uACIi7AAAA
AAAAAAAAAAiLsIiIsAAAAAAAAAAAAAAIiIuIi7AAAAAAAAAAAAAAAIiI+LsAAAAAAAAAAAAAAAAIiIuwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP/
/8AAf/8AAD/8AAD//AAB//wAAf/8AAH//AAB//wAAf/8AAH//AAB//wAAf/8AAH//AAB//wAAf/8AAP//AAP//wAD///hw///48P//+PD///jw///48P//+GD///hB///4Af///AP///4H////////////w=='
# Convert back to PS icon object
$iconBytes = [Convert]::FromBase64String($iconBase64)
$stream = New-Object IO.MemoryStream($iconBytes, 0, $iconBytes.Length)
$stream.Write($iconBytes, 0, $iconBytes.Length);
$MyIcon = [System.Drawing.Icon]::FromHandle((New-Object System.Drawing.Bitmap -Argument $stream).GetHIcon())
# You can also convert to bitmap etc for images
$Bytes = [Convert]::FromBase64String($iconBase64)
$stream = New-Object IO.MemoryStream($Bytes, 0, $Bytes.Length)
$stream.Write($Bytes, 0, $Bytes.Length);
$MyImg = New-Object System.Drawing.Bitmap -Argument $stream
# Example using Forms
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object System.Windows.Forms.Form
$form.Font = $DefaultFont
$form.Text = "Test"
$form.Size = '400,400'
$form.StartPosition = 'CenterScreen'
$form.FormBorderStyle = 'FixedSingle'
#
# Using the icon
$form.Icon = $MyIcon
$DASImage = New-Object System.Windows.Forms.PictureBox
$DASImage.Width = $MyImg.Width
$DASImage.Height = $MyImg.Height
$DASImage.Location = '10,10'
$DASImage.Image = $MyImg
$form.Controls.Add($DASImage)
# Show form
$form.ShowDialog() | Out-Null
$form.Dispose()
Ensure your icon images are a suitable size etc
I am trying to develop a lite app to run a set of powershell scripts. I have a small user base that will need to run the app. This app will have a few presentable options (scripts) that it can run from the start. The user needs to be able to click a button to run the script.
The issue I'm having is how to reference the file needed when I don't know the specific location that the user will be running the script from.
I need to be able to have a background image, and scripts stored in a small folder that will be included in the app. Is there a way to direct the script to look in the current directory for files?
Here is my code currently:
#Credit: Portions of this code were provided at the following URL:
http://blogs.technet.com/b/stephap/archive/2012/04/23/building-forms-with-powershell-part-1-the-form.aspx#pi47623=2
# LOAD WINDOWS FORMS
# Load the Winforms assembly
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
#Welcome Screen:
#code for welcome splash here. Haven't gotten that far yet.
# CREATE FORM
$Form = New-Object System.Windows.Forms.Form
$Form.Size = New-Object System.Drawing.Size(500,400)
# background. This is where I need help.
$Image = [system.drawing.image]::FromFile("C:\Users\zstewart\Pictures\script runner.png")
#this location is where my question arises. It won't work on another user's machine.
$Form.BackgroundImage = $Image
$Form.BackgroundImageLayout = "Center"
# None, Tile, Center, Stretch, Zoom
#SET FORM TITLE
$form.text = "ScriptRunner v.001"
#TEXT FIELD FOR PRINTING A RESULT
$outputBox = New-Object System.Windows.Forms.TextBox
$outputBox.Location = New-Object System.Drawing.Size(40,60)
$outputBox.Size = New-Object System.Drawing.Size(400,30)
$outputBox.MultiLine = $True
$outputBox.ScrollBars = "Vertical" #had horizontal here. Didn't work.
# BUTTON
# Create Button and set text and location
$button = New-Object Windows.Forms.Button
$button.Size = New-Object Drawing.Point 120,30
$button.text = "Select Script"
$button.Location = New-Object Drawing.Point 170, 100
# INPUT HANDLER BUTTON - ON CLICK IN THIS CASE
# Set up event handler to exit
$button.add_click({
Function Get-FileName($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "All files (*.*)| *.*"
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
$outputBox.text=$OpenFileDialog.filename
} #end function Get-FileName
Get-FileName -initialDirectory "c:\fso"
})
# Create Button and set text and location
$button2 = New-Object Windows.Forms.Button
$button2.text = "Run Script"
$button2.Size = New-Object Drawing.Point 120,30
$button2.Location = New-Object Drawing.Point 170,140
# INPUT HANDLER RUN BUTTON - RUN SCRIPT
# close button - on click close app
$button2.add_click({
$form.Close() #need to add code to run some included scripts.
})
# ADD CONTROLS TO FORM
$form.controls.add($button)
$form.controls.add($button2)
$Form.Controls.Add($outputBox)
# DISPLAY DIALOG
$form.ShowDialog()
I realize that this is a very VERY dirty code, but I am still trying to learn as I go along. Please excuse my code skills.
In PS v3.0 and above, you can reference the scripts directory with the $PSScriptRoot automatic variable:
$Image = [system.drawing.image]::FromFile("$PSScriptRoot\script runner.png")
To make your script PowerShell 2.0-friendly, you could do the following at the top of your script:
if(-not (Get-Variable -Name 'PSScriptRoot' -Scope 'Script')) {
$Script:PSScriptRoot = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
}
I'm trying to create a GUI for one of the scripts I'm running that is really just a fancy way to get input from a user and feed it into a variable that will be used later on in the script. However, when I enter anything into the text input field, it doesn't assign to the variable unless I go to the specific line in the code and run it by itself. What am I doing wrong?
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "File Path"
$objForm.Size = New-Object System.Drawing.Size(300,200)
$objForm.StartPosition = "CenterScreen"
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
{$x=$objTextBox.Text;$objForm.Close()}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
{$objForm.Close()}})
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "Go for gold!"
$OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close()})
$objForm.Controls.Add($OKButton)
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(100,23)
$CancelButton.Text = "Abort! It's a trap!"
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20)
$objLabel.Size = New-Object System.Drawing.Size(280,20)
$objLabel.Text = "Please enter the full file path:"
$objForm.Controls.Add($objLabel)
$objTextBox = New-Object System.Windows.Forms.TextBox
$objTextBox.Location = New-Object System.Drawing.Size(10,40)
$objTextBox.Size = New-Object System.Drawing.Size(260,20)
$objForm.Controls.Add($objTextBox)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
$x
I found a solution on here that suggested changing the variable to $global, but that did nothing. Any suggestions are appreciated.
You could always go with a standard VB InputBox:
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic")
[Microsoft.VisualBasic.Interaction]::InputBox("Please enter your name",$MyInvocation.MyCommand.Name)
It's dirty, but it's essentially what you're looking for I think, and it's far fewer lines of code than making your own Windows Form. If you want to hide the console output of loading Microsoft.VisualBasic, then you can do one of two things:
Prepend [System.Reflection.Assembly] with [void], which will tell the console to ignore the output
Pipe it in to Out-Null, and you'll achieve the same effect
One alternative is you can wait for the Windows Form to close (the code should stop until the window opened by $objForm.ShowDialog() has closed, too), and then grab the text out of $objTextBox.Text.
If all you really want is for someone to put in a folder path or file path, though, then this method is by far the easiest to implement and validate:
$vbShell = New-Object -ComObject Shell.Application
$folder = $vbShell.BrowseForFolder(0x00,"Enter your custom text here",0x01)
$path = $folder.Self.Path
Here's the documentation for the Shell object from Microsoft, too, so that you can get the BrowseForFolder method to work the way you want it to:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb774065%28v=vs.85%29.aspx
Hope this helps!
It's a very familiar window... Employed in more Windows applications than I care to count.