PowerScript: System.Windows.Forms.FolderBrowserDialog opening in the background - powershell

PowerScript Noob here.
I've found a snippet of code that lets the user select a folder thru a Folder Browser Dialog, instead of having enter the path to the folder manually.
Works as expected, except the Folder Browser Dialog often opens behind other windows on the screen, which is getting tiresome.
Here is the code:
Function Get-Folder($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")|Out-Null
$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.Description = "Select a folder"
$foldername.rootfolder = "MyComputer"
$foldername.SelectedPath = $initialDirectory
if($foldername.ShowDialog() -eq "OK")
{
$folder += $foldername.SelectedPath
}
return $folder
}
$FolderNavn = Get-Folder($StartFolder)
How do I get the Folder Browser Dialog to open 'on top of' all other Windows?
Thanks.

To set the BrowseForFolder dialog TopMost, you need to use the ShowDialog() overloaded method with a parameter that specifies the dialogs owner (parent) form.
The easiest I think it to just create a new Form with property Topmost set to $true and use that as owner form:
function Get-Folder {
[CmdletBinding()]
param (
[Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
[string]$Message = "Please select a directory.",
[Parameter(Mandatory=$false, Position=1)]
[string]$InitialDirectory,
[Parameter(Mandatory=$false)]
[System.Environment+SpecialFolder]$RootFolder = [System.Environment+SpecialFolder]::Desktop,
[switch]$ShowNewFolderButton
)
Add-Type -AssemblyName System.Windows.Forms
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
$dialog.Description = $Message
$dialog.SelectedPath = $InitialDirectory
$dialog.RootFolder = $RootFolder
$dialog.ShowNewFolderButton = if ($ShowNewFolderButton) { $true } else { $false }
$selected = $null
# force the dialog TopMost
# Since the owning window will not be used after the dialog has been
# closed we can just create a new form on the fly within the method call
$result = $dialog.ShowDialog((New-Object System.Windows.Forms.Form -Property #{TopMost = $true }))
if ($result -eq [Windows.Forms.DialogResult]::OK){
$selected = $dialog.SelectedPath
}
# clear the FolderBrowserDialog from memory
$dialog.Dispose()
# return the selected folder
$selected
}

Related

I need to build a powershell that creates a url shortcut and opens to google chrome

I have very basic knowledge in creating scripts and self taught.
I need to build a powershell that creates a url shortcut and opens to google chrome
The Website has some features that currently only work in chrome
I have created a foundation for creating the icon but need help telling it to open only through Chrome and not the default browser
$new_object = New-Object -ComObject WScript.Shell
$destination = $new_object.SpecialFolders.Item("AllUsersDesktop")
$source_path = Join-Path -Path $destination -ChildPath "\\Procore Login.url"
$source = $new_object.CreateShortcut($source_path)
$source.TargetPath = "https://login.procore.com/"
$source.Save()
As commented, if you create a .url internet shortcut, this wil open in whatever the user has set to be the default browser.
If you want to always have that url open in chrome, you need to create a .lnk shortcut where you set it to start chrome.exe with the wanted url as target to open.
For that you can use below helper function:
function New-Shortcut {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$TargetPath, # the path to the executable
# the rest is all optional
[string]$ShortcutPath = (Join-Path -Path ([Environment]::GetFolderPath("Desktop")) -ChildPath 'New Shortcut.lnk'),
[string[]]$Arguments = $null, # a string or string array holding the optional arguments.
[string[]]$HotKey = $null, # a string like "CTRL+SHIFT+F" or an array like 'CTRL','SHIFT','F'
[string]$WorkingDirectory = $null,
[string]$Description = $null,
[string]$IconLocation = $null, # a string like "notepad.exe, 0"
[ValidateSet('Default','Maximized','Minimized')]
[string]$WindowStyle = 'Default',
[switch]$RunAsAdmin
)
switch ($WindowStyle) {
'Default' { $style = 1; break }
'Maximized' { $style = 3; break }
'Minimized' { $style = 7 }
}
$WshShell = New-Object -ComObject WScript.Shell
# create a new shortcut
$shortcut = $WshShell.CreateShortcut($ShortcutPath)
$shortcut.TargetPath = $TargetPath
$shortcut.WindowStyle = $style
if ($Arguments) { $shortcut.Arguments = $Arguments -join ' ' }
if ($HotKey) { $shortcut.Hotkey = ($HotKey -join '+').ToUpperInvariant() }
if ($IconLocation) { $shortcut.IconLocation = $IconLocation }
if ($Description) { $shortcut.Description = $Description }
if ($WorkingDirectory) { $shortcut.WorkingDirectory = $WorkingDirectory }
# save the link file
$shortcut.Save()
if ($RunAsAdmin) {
# read the shortcut file we have just created as [byte[]]
[byte[]]$bytes = [System.IO.File]::ReadAllBytes($ShortcutPath)
# set bit 6 of byte 21 ON
# ([math]::Pow(2,5) or 1 -shl 5 --> 32)
# see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/16cb4ca1-9339-4d0c-a68d-bf1d6cc0f943
# page 13
$bytes[21] = $bytes[21] -bor 32
[System.IO.File]::WriteAllBytes($ShortcutPath, $bytes)
}
# clean up the COM objects
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($shortcut) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($WshShell) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
And use it like this:
$chromePath = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe').'(Default)'
$props = #{
'ShortcutPath' = Join-Path -Path ([Environment]::GetFolderPath("Desktop")) -ChildPath 'Procore Login.lnk'
'TargetPath' = $chromePath
'Arguments' = 'https://login.procore.com/'
}
New-Shortcut #props

BrowseForFolders doesn't display on top

I'm writing PS Script and following block of code shows dialogbox below windows forms gui.
$btn1 = New-Object Windows.Forms.Button
$btn1.Text = "Wybierz folder projektowy"
$btn1.Location = New-Object System.Drawing.Point(170,140)
$btn1.Size = New-Object System.Drawing.Size(160,20)
$btn1.add_Click({
function Select-Folder($message='Select a folder', $path = 0) {
$object = New-Object -comObject Shell.Application
$object.topmost=$true
$folder = $object.BrowseForFolder(0, $message, 0, $path)
if ($folder -ne $null) {
$folder.self.Path
}
}
$folderPath = Select-Folder 'Select the folder where the move scripts reside'
If ($folderPath) {
Set-Content -Path "C:\Projekty\logs\temp_path.txt" -Value $folderPath.ToString() -Encoding Unicode
write-host $folderPath
get-content -Path "C:\Projekty\logs\temp_path.txt"
}
Else { Write-Host 'I do not have a folder path' }
})
$form_acl.Controls.Add($btn1)
Is there any way to make it display on top?
Here's screenshot of a problem:
You can try this alternative instead:
function Select-Folder {
[CmdletBinding()]
param (
# sets the descriptive text displayed above the tree view control in the dialog box
[Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
[string]$Message = "Please select a directory.",
# sets the (pre)selected path
[Parameter(Mandatory=$false, Position=1)]
[string]$InitialDirectory,
# sets the root folder where the browsing starts from
[Parameter(Mandatory=$false)]
[System.Environment+SpecialFolder]$RootFolder = [System.Environment+SpecialFolder]::Desktop,
# sets a value indicating whether the 'New Folder' button appears in the folder browser dialog box
[switch]$ShowNewFolderButton
)
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
$dialog.Description = $Message
$dialog.SelectedPath = $InitialDirectory
$dialog.RootFolder = $RootFolder
$dialog.ShowNewFolderButton = $ShowNewFolderButton.IsPresent
$selected = $null
# force the dialog TopMost:
# because the owning window will not be used after the dialog has been closed,
# you can simply create a new form inside the method call.
$result = $dialog.ShowDialog((New-Object System.Windows.Forms.Form -Property #{TopMost = $true; TopLevel = $true}))
if ($result -eq [Windows.Forms.DialogResult]::OK){
$selected = $dialog.SelectedPath
}
# clear the FolderBrowserDialog from memory
$dialog.Dispose()
# return the selected folder
$selected
}
Select-Folder -Message 'Select the folder where the move scripts reside' -ShowNewFolderButton
Theo's helpful answer shows an alternative, WinForms-based way to invoke a folder-browsing dialog, via the System.Windows.Forms.FolderBrowserDialog class.
However, it seems that all that is missing from your original approach is to pass your form's window handle (hWND, .Handle) as the first argument to the Shell.Application COM object's .BrowseForFolder() method, which makes it the dialog's owner window and therefore shows the dialog on top of it - even if the form itself has the .TopMost property set:
$folder = (New-Object -ComObject Shell.Application).BrowseForFolder(
$form_acl.Handle, # Pass your form's window handle to make it the owner window
$message,
0,
$path)
Here's a simplified, self-contained example (requires PSv5+, but can be adapted to earlier versions):
using namespace System.Windows.Forms
using namespace System.Drawing
Add-Type -AssemblyName System.Windows.Forms
# Create a sample topmost form with a single
# button that invokes a folder-browsing dialog.
($form = [Form] #{
Text = "Topmost Form"
Size = [Size]::new(300, 100)
TopMost = $true # Make the form topmost.
StartPosition = 'CenterScreen'
}).Controls.AddRange(#(
($folderBrowseButton = [Button] #{
Location = [Point]::new(70, 20)
Size = [Size]::new(160,30)
Text = 'Browse for Folder'
})
))
$folderBrowseButton.add_Click({
$path = 'C:\'
# IMPORTANT: Pass $form.Handle, the form's window handle (HWND) as the first argument, which
# makes the form the owning window, ensuring that the dialog is displayed on
# top - even if the form itself is set to topmost.
$folder = (New-Object -ComObject Shell.Application).BrowseForFolder(
$form.Handle,
'Pick a target folder:',
0, # Options
$path # Starting directory path.
)
if ($null -ne $folder) {
Write-Verbose -vb ('Folder picked: ' + $folder.self.Path)
} else {
Write-Verbose -vb 'Folder browsing canceled.'
}
})
$null = $form.ShowDialog()

OpenFileDialog in PowerShell - Can the icon of the dialog be changed?

I have this code that will invoke the OpenFileDialog class.
There doesn't seem to be a property to change the icon of the dialog that's shown at the top left corner of the dialog.
Is there a way to hack a change this?
Here's the code:
Function Invoke-OpenFileDialog {
Param (
[Parameter(Mandatory=$true, Position=0)] [string] $Title,
[Parameter(Mandatory=$true, Position=1)] [string] $InitialDirectory,
[Parameter(Mandatory=$true, Position=2)] [string] $Filter
)
Add-Type -AssemblyName System.Windows.Forms
if ($InitialDirectory -ne "") {
if (!(Test-Path -LiteralPath $InitialDirectory -PathType Container)) {
$InitialDirectory = ([System.IO.FileInfo]$InitialDirectory).DirectoryName
}
}
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.Filter = $Filter
$OpenFileDialog.InitialDirectory = $InitialDirectory
$OpenFileDialog.Title = $Title
$result = $OpenFileDialog.ShowDialog()
$OpenFileDialog.Dispose()
if ($result -eq 'OK') {
return $OpenFileDialog.FileName
}
else { return "" }
}
$title = 'OpenFileDialog Title'
$initialDirectory = ([System.IO.FileInfo]"C:\Users\").DirectoryName
$filter = 'All files (*.*)| *.*'
$filePicked = Invoke-OpenFileDialog -Title $title -InitialDirectory $initialDirectory -Filter $filter
# Then use this to check if the picker has done its job.
if ($filePicked -ne "") {
$filePicked
Write-Host 'File Picked...'
}
else {
Write-Host 'File Not Picked...'
}
The icon in question:
Found it!
Create your form and use my code from here to give that form your own icon.
Then, from a button for example on the form, you open the OpenFile dialog, using your function. The dialog will then have the icon used in your form.
# start the code with your own function to show the OpenFile dialog
function Invoke-OpenFileDialog {
Param (
[Parameter(Mandatory=$true, Position=0)] [string] $Title,
[Parameter(Mandatory=$true, Position=1)] [string] $InitialDirectory,
[Parameter(Mandatory=$true, Position=2)] [string] $Filter
)
if ($InitialDirectory -ne "") {
if (!(Test-Path -LiteralPath $InitialDirectory -PathType Container)) {
$InitialDirectory = ([System.IO.FileInfo]$InitialDirectory).DirectoryName
}
}
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.Filter = $Filter
$OpenFileDialog.InitialDirectory = $InitialDirectory
$OpenFileDialog.Title = $Title
$result = $OpenFileDialog.ShowDialog()
$OpenFileDialog.Dispose()
if ($result -eq 'OK') {
return $OpenFileDialog.FileName
}
else { return "" }
}
# next, create your form (just a simple demo below) and from there show the dialog
# (I'm using a button on the form to do this)
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$form = New-Object system.Windows.Forms.Form
$form.ClientSize = '400,230'
$form.text = "Test"
$form.TopMost = $false
# This base64 string holds the bytes that make up the 16x16 StackOverflow icon
$iconBase64 = #'
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB
tUlEQVQ4y5WSTUtUYRzFf/d6r00FMQPCFG3yUsyYH6BCooUv5ZeoIImEghauMojqAwQu3QSSZEEt
KmozgwVGYC+EFGTGtcHc1DgSjI339bQwJsaZUeesHv7PeQ7nf85jSBLbQJXfgDB2J+vuTHYA78Ew
/pNRiILWBPRnFYD206OEC9MEsxMNSM0QVLR256S857ekOJL/5q7Kt7OKlj7U0Jo7sBK0D1wj/PSU
9alhrO5BrOwA3uMRVC5uvUL84yPxyiLW0TMkzt0j/jnP+sRZ7BMXkGL8Z9erXKNRC96jq4SfX2Bl
+7F7LmIkD+I9vEz86xt2zxBmx2HaMr3NBUBEX6cJZsaJlt7TdugY9vHzhF9yWNn+6uOGIUbLc4qW
56SgIkkKC29VmRxS+eYR+a/H67Kuc+BNXSKcz4NpYXZ0Yqa7MPd3gWFidQ9i7DtQ49WQpEXXxXVd
evv60FqRuOiiUoG4VEAr34lXC6hUYM/ILPlXMziOQ6fjbJS1efvw3f3/6tYujHQGM53ZGNiJ+rY3
D/yXY02/hn3qyvYCe28s0ApqBPK5HK3CAkimUjj/QtkJkqlU9fwXBBkCP6jNZvAAAAAASUVORK5C
YII=
'#
$iconBytes = [Convert]::FromBase64String($iconBase64)
$stream = New-Object IO.MemoryStream($iconBytes, 0, $iconBytes.Length)
$stream.Write($iconBytes, 0, $iconBytes.Length)
$form.Icon = [System.Drawing.Icon]::FromHandle((New-Object System.Drawing.Bitmap -Argument $stream).GetHIcon())
$button = New-Object System.Windows.Forms.Button
$button.Size = New-Object System.Drawing.Size(90,24)
$button.Left = $form.Width - $button.Width - 40
$button.Top = $form.Height - $button.Height * 3
$button.Text = 'Open File'
$button.Add_Click({
# in here, we use your function
$title = 'OpenFileDialog Title'
$initialDirectory = ([System.IO.FileInfo]"C:\Users\").DirectoryName
$filter = 'All files (*.*)| *.*'
$filePicked = Invoke-OpenFileDialog -Title $title -InitialDirectory $initialDirectory -Filter $filter
# Then use this to check if the picker has done its job.
if ($filePicked -ne "") {
$filePicked
Write-Host 'File Picked...'
}
else {
Write-Host 'File Not Picked...'
}
})
$form.Controls.Add($button)
[void]$form.ShowDialog()
# when done, dispose of the form
$form.Dispose()
Now, if you run this, you'll see the form:
and if you click the button, the dialog shows up, including your forms icon:
You can do this for a WPF UI aswell, although setting a WPF form with an embedded icon is slightly different:
# start the code with your own function to show the OpenFile dialog
function Invoke-OpenFileDialog {
Param (
[Parameter(Mandatory=$true, Position=0)] [string] $Title,
[Parameter(Mandatory=$true, Position=1)] [string] $InitialDirectory,
[Parameter(Mandatory=$true, Position=2)] [string] $Filter
)
if ($InitialDirectory -ne "") {
if (!(Test-Path -LiteralPath $InitialDirectory -PathType Container)) {
$InitialDirectory = ([System.IO.FileInfo]$InitialDirectory).DirectoryName
}
}
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.Filter = $Filter
$OpenFileDialog.InitialDirectory = $InitialDirectory
$OpenFileDialog.Title = $Title
$result = $OpenFileDialog.ShowDialog()
$OpenFileDialog.Dispose()
if ($result -eq 'OK') {
return $OpenFileDialog.FileName
}
else { return "" }
}
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName System.Windows.Forms
[xml]$xaml = #"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="Initial Window" WindowStartupLocation = "CenterScreen"
Width = "400" Height = "230" ShowInTaskbar = "True">
<Button x:Name = "Button" Height = "24" Width = "90" Content = 'Open File' />
</Window>
"#
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load( $reader )
# This base64 string holds the bytes that make up the 16x16 StackOverflow icon
$iconBase64 = #'
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB
tUlEQVQ4y5WSTUtUYRzFf/d6r00FMQPCFG3yUsyYH6BCooUv5ZeoIImEghauMojqAwQu3QSSZEEt
KmozgwVGYC+EFGTGtcHc1DgSjI339bQwJsaZUeesHv7PeQ7nf85jSBLbQJXfgDB2J+vuTHYA78Ew
/pNRiILWBPRnFYD206OEC9MEsxMNSM0QVLR256S857ekOJL/5q7Kt7OKlj7U0Jo7sBK0D1wj/PSU
9alhrO5BrOwA3uMRVC5uvUL84yPxyiLW0TMkzt0j/jnP+sRZ7BMXkGL8Z9erXKNRC96jq4SfX2Bl
+7F7LmIkD+I9vEz86xt2zxBmx2HaMr3NBUBEX6cJZsaJlt7TdugY9vHzhF9yWNn+6uOGIUbLc4qW
56SgIkkKC29VmRxS+eYR+a/H67Kuc+BNXSKcz4NpYXZ0Yqa7MPd3gWFidQ9i7DtQ49WQpEXXxXVd
evv60FqRuOiiUoG4VEAr34lXC6hUYM/ILPlXMziOQ6fjbJS1efvw3f3/6tYujHQGM53ZGNiJ+rY3
D/yXY02/hn3qyvYCe28s0ApqBPK5HK3CAkimUjj/QtkJkqlU9fwXBBkCP6jNZvAAAAAASUVORK5C
YII=
'#
$iconBytes = [Convert]::FromBase64String($iconBase64)
$stream = New-Object IO.MemoryStream($iconBytes, 0, $iconBytes.Length)
$stream.Write($iconBytes, 0, $iconBytes.Length)
# set the form's icon
$Window.Icon = [System.Windows.Media.Imaging.BitmapFrame]::Create($stream)
# connect to the button
$button = $Window.FindName("Button")
$button.Add_Click({
# in here, we use your function
$title = 'OpenFileDialog Title'
$initialDirectory = ([System.IO.FileInfo]"C:\Users\").DirectoryName
$filter = 'All files (*.*)| *.*'
$filePicked = Invoke-OpenFileDialog -Title $title -InitialDirectory $initialDirectory -Filter $filter
# Then use this to check if the picker has done its job.
if ($filePicked -ne "") {
$filePicked
Write-Host 'File Picked...'
}
else {
Write-Host 'File Not Picked...'
}
})
$null = $Window.ShowDialog()
I found a way to set the icon independently from any UI by setting up:
$OpenFileDialogForm = New-Object System.Windows.Forms.Form
and passing a base64 string to the icon property of the $OpenFileDialogForm.
Then pass the $OpenFileDialogForm to:
$userClicked = $OpenFileDialog.ShowDialog($OpenFileDialogForm),
Some comments in the Invoke-OpenFileDialog function explaining this.
The IconBase64 parameter in the function is where this can be set.
Here's the code for this:
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
Function Get-LastValidDirectory {
Param
(
[Parameter(Mandatory = $true, HelpMessage = 'The literal path where the folder you want to check is, which will return the last valid folder.')]
[Array]$LiteralPath
)
if (Test-Path -LiteralPath $LiteralPath -PathType Container) {
# Returns the path passed to the function if it has been found.'
return $LiteralPath
}
# Increment the input folder
$lastDir = Split-Path -LiteralPath $LiteralPath
# Test that folder for it not existing and check if it's doesn't exist and in the
# while loop increment the $lastDir variable.
while (!(Test-Path -LiteralPath $lastDir -PathType Container)) {
$lastDir = Split-Path -LiteralPath $lastDir
}
return $lastDir
}
function Invoke-OpenFileDialog {
Param (
[Parameter(Mandatory=$true, Position=0)] [string] $Title,
[Parameter(Mandatory=$true, Position=1)] [string] $InitialDirectory,
[Parameter(Mandatory=$true, Position=2)] [string] $Filter,
[Parameter(Mandatory=$true, Position=3)] [string] $IconBase64,
[Parameter(Mandatory=$true, Position=4)] [boolean] $TopMost
)
if ($InitialDirectory -ne "") {
if (!(Test-Path -LiteralPath $InitialDirectory -PathType Container)) {
$InitialDirectory = ([System.IO.FileInfo]$InitialDirectory).DirectoryName
}
}
# Create a streaming image by streaming the base64 string to a bitmap stream source.
$IconBase64 = $IconBase64
$iconBytes = [Convert]::FromBase64String($IconBase64)
$stream = New-Object IO.MemoryStream($iconBytes, 0, $iconBytes.Length)
$stream.Write($iconBytes, 0, $iconBytes.Length)
# Create a new form to hold the object and set it properties for the main
# OpenFileDialog form.
$OpenFileDialogForm = New-Object System.Windows.Forms.Form
$OpenFileDialogForm.Icon = [System.Drawing.Icon]::FromHandle((New-Object System.Drawing.Bitmap -Argument $stream).GetHIcon())
$OpenFileDialogForm.TopMost = $TopMost
# Set the properties of the main OpenFileDialog along with using the
# OpenFileDialogForm properties from above.
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.Filter = $Filter
$OpenFileDialog.InitialDirectory = $InitialDirectory
$OpenFileDialog.Title = $Title
$userClicked = $OpenFileDialog.ShowDialog($OpenFileDialogForm)
$OpenFileDialog.Dispose()
if ($userClicked -eq 'OK') { return $OpenFileDialog.FileName } else { return "" }
}
$title = 'OpenFileDialog Title'
$initialDirectory = ([System.IO.FileInfo]"C:\Users\").DirectoryName + '\no folder here'
$filter = 'Application (*.exe)|*.exe|SpreadSheet (*.xlsx)|*.xlsx'
$filter = 'All files (*.*)| *.*'
$iconBase64OpenFileDialog = "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGkmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIwLTEyLTI2VDIxOjQxOjA0WiIgeG1wOk1vZGlmeURhdGU9IjIwMjAtMTItMjZUMjE6NDc6MjZaIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIwLTEyLTI2VDIxOjQ3OjI2WiIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpkODAwODQwYy0yN2JiLTI3NDItYjVjOS0yNjY5NjI4ZjE1NGEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N2Y4MTY1YTYtZmVkYi02MDRkLThkNjgtYjM3YjBiN2RmMWRlIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6N2Y4MTY1YTYtZmVkYi02MDRkLThkNjgtYjM3YjBiN2RmMWRlIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo3ZjgxNjVhNi1mZWRiLTYwNGQtOGQ2OC1iMzdiMGI3ZGYxZGUiIHN0RXZ0OndoZW49IjIwMjAtMTItMjZUMjE6NDE6MDRaIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmJhODk5YWVjLTA4ZDAtYjQ0Yi1hYzU3LWM0NGFmZGU1MDY1MiIgc3RFdnQ6d2hlbj0iMjAyMC0xMi0yNlQyMTo0Njo0MloiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4wIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ZDgwMDg0MGMtMjdiYi0yNzQyLWI1YzktMjY2OTYyOGYxNTRhIiBzdEV2dDp3aGVuPSIyMDIwLTEyLTI2VDIxOjQ3OjI2WiIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjAgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjkLPFQAABG3SURBVHic5Zt7rGxXXcc/a7/fM3NrkVeqlaZiMZYmJQKlBQ3gjaEGFLC1EQxIytwS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"
$filePicked = Invoke-OpenFileDialog -Title $title -InitialDirectory $initialDirectory -Filter $filter -IconBase64 $iconBase64OpenFileDialog -TopMost $true
# Then use this to check if the picker has done its job.
if ($filePicked -ne "") {
$filePicked
Write-Host 'File Picked...'
}
else {
Write-Host 'File Not Picked...'
}

PowerShell popup in form

Is there a way to bring a PoweR Shell popup to the front of the screen?
i use this command to show the popup
$wshell = New-Object -ComObject Wscript.Shell
$Output = $wshell.Popup("text" ,0,"header",0+64)
but when i use form and a button in the form bis supposed to bring up the popup it shows in the back behind the form
the form itself opens in the center and not bringing to front as shows here
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$Form = New-Object system.Windows.Forms.Form
$Form.ClientSize = '1370,720'
$Form.text = "Chame Wizard"
$Form.TopMost = $true
$Form.icon = "c:\script\chame.ico"
$FormImage = [system.drawing.image]::FromFile("c:\script\back2.jpg")
$Form.BackgroundImage = $FormImage
$Form.StartPosition = "CenterScreen"
i know i can use balloon popup but i want the user to press OK before the script continues.
Thanks :-)
You can also use one of the overloaded methods of [System.Windows.Forms.MessageBox]::Show() which allows you to add the owner window in order to have the messagebox be topmost to that.
By using $null there, your messagebox will be topmost to all opened windows:
function Show-MessageBox {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $false)]
[string]$Title = 'MessageBox in PowerShell',
[Parameter(Mandatory = $true)]
[string]$Message,
[Parameter(Mandatory = $false)]
[ValidateSet('OK', 'OKCancel', 'AbortRetryIgnore', 'YesNoCancel', 'YesNo', 'RetryCancel')]
[string]$Buttons = 'OKCancel',
[Parameter(Mandatory = $false)]
[ValidateSet('Error', 'Warning', 'Information', 'None', 'Question')]
[string]$Icon = 'Information',
[Parameter(Mandatory = $false)]
[ValidateRange(1,3)]
[int]$DefaultButton = 1
)
# determine the possible default button
if ($Buttons -eq 'OK') {
$Default = 'Button1'
}
elseif (#('AbortRetryIgnore', 'YesNoCancel') -contains $Buttons) {
$Default = 'Button{0}' -f [math]::Max([math]::Min($DefaultButton, 3), 1)
}
else {
$Default = 'Button{0}' -f [math]::Max([math]::Min($DefaultButton, 2), 1)
}
Add-Type -AssemblyName System.Windows.Forms
# added from tip by [Ste](https://stackoverflow.com/users/8262102/ste) so the
# button gets highlighted when the mouse hovers over it.
[void][System.Windows.Forms.Application]::EnableVisualStyles()
# Setting the first parameter 'owner' to $null lets he messagebox become topmost
[System.Windows.Forms.MessageBox]::Show($null, $Message, $Title,
[Windows.Forms.MessageBoxButtons]::$Buttons,
[Windows.Forms.MessageBoxIcon]::$Icon,
[Windows.Forms.MessageBoxDefaultButton]::$Default)
}
With this function in place, you call it like:
Show-MessageBox -Title 'Important message' -Message 'Hi there!' -Icon Information -Buttons OK
Edit
As asked by Ste, the above function shows the messagebox TopMost. That however does not mean it is Modal. It only means the box is shown on top when first displayed, but can be pushed to the background by activating other windows.
For a real Modal messagebox that cannot be pushed to the background, I use this:
function Show-MessageBox {
[CmdletBinding()]
param(
[parameter(Mandatory = $true, Position = 0)]
[string]$Message,
[parameter(Mandatory = $false)]
[string]$Title = 'MessageBox in PowerShell',
[ValidateSet("OKOnly", "OKCancel", "AbortRetryIgnore", "YesNoCancel", "YesNo", "RetryCancel")]
[string]$Buttons = "OKCancel",
[ValidateSet("Critical", "Question", "Exclamation", "Information")]
[string]$Icon = "Information"
)
Add-Type -AssemblyName Microsoft.VisualBasic
[Microsoft.VisualBasic.Interaction]::MsgBox($Message, "$Buttons,SystemModal,$Icon", $Title)
}
Show-MessageBox -Title 'Important message' -Message 'Hi there!' -Icon Information -Buttons OKOnly
Theos' answer is great but if you want the MessageBox to be modal and not allow any more interaction with the $Form then this is the way to go about it.
I've updated this to show how to show a modal messagebox with a $Form.Add_Load event handler should you need a modal message box on execution of the script.
Comments in the code on how to achieve this:
# I've added this as an answer here:
# Edit added the $Form.Add_Load event handler.
# https://stackoverflow.com/questions/59371640/powershell-popup-in-form/67368911#67368911
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$Form = New-Object system.Windows.Forms.Form
$Form.ClientSize = '444,55'
$Form.StartPosition = "CenterScreen"
$Form.Text = "..."
$Form.TopMost = $true
$Btn = New-Object System.Windows.Forms.Button
$Btn.Height = $Form.Height-39
$Btn.Text = "DO NOT PRESS..."
$Btn.Width = $Form.Width-15
$Form.Controls.Add($Btn)
$Btn.Add_Click({
# To have a modal messagebox you need to have it called from a form and use: $this.ActiveForm as shown below.
[System.Windows.Forms.MessageBox]::Show($this.ActiveForm, 'Not to!!', 'I Told You..', [Windows.Forms.MessageBoxButtons]::"OK", [Windows.Forms.MessageBoxIcon]::"Warning")
})
# Here you can do an if statement and then fire the message box when the Form loads which will be modal also.
$Form.Add_Load({
[System.Windows.Forms.MessageBox]::Show($this.ActiveForm, 'You can add the message box as an event handler to show a message when the form is loaded...', 'A Message on Form Load Event!!', [Windows.Forms.MessageBoxButtons]::"OK", [Windows.Forms.MessageBoxIcon]::"Warning")
})
# This below needs to be added to focus the dialog when it opens after the $Form.
$Form.Add_Shown({$Form.Activate(); $Btn.Focus()})
$Form.ShowDialog()
Theos great function modified to accept a -Modal switch.
# Mod of Theos' answer here: https://stackoverflow.com/a/59378301/8262102
# Edit by Ste: Can now be shown modal to the parent form with the usage of the
# -Modal switch.
# Mod of Theos' answer here: https://stackoverflow.com/a/59378301/8262102
# Edit by Ste: Can now be shown modal to the parent form with the usage of the
# -Modal switch.
Function Show-MessageBox {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $false)]
[string]$Title = 'MessageBox in PowerShell',
[Parameter(Mandatory = $true)]
[string]$Message,
[Parameter(Mandatory = $false)]
[ValidateSet('OK', 'OKCancel', 'AbortRetryIgnore', 'YesNoCancel', 'YesNo', 'RetryCancel')]
[string]$Buttons = 'OKCancel',
[Parameter(Mandatory = $false)]
[ValidateSet('Error', 'Warning', 'Information', 'None', 'Question')]
[string]$Icon = 'Information',
[Parameter(Mandatory = $false)]
[ValidateRange(1,3)]
[int]$DefaultButton = 1,
[Parameter(Mandatory = $false)]
[Switch]$Modal = $false
)
# Determine the possible default button.
if ($Buttons -eq 'OK') {
$Default = 'Button1'
}
elseif (#('AbortRetryIgnore', 'YesNoCancel') -contains $Buttons) {
$Default = 'Button{0}' -f [math]::Max([math]::Min($DefaultButton, 3), 1)
}
else {
$Default = 'Button{0}' -f [math]::Max([math]::Min($DefaultButton, 2), 1)
}
# Create a new form to hold the object and set it properties for the main
# FolderBrowserDialog form.
Add-Type -AssemblyName System.Windows.Forms
$MessageBoxParentForm = New-Object System.Windows.Forms.Form
$MessageBoxParentForm.TopMost = $Modal
Add-Type -AssemblyName System.Windows.Forms
[void][System.Windows.Forms.Application]::EnableVisualStyles()
[System.Windows.Forms.MessageBox]::Show(($MessageBoxParentForm), $Message, $Title,
[Windows.Forms.MessageBoxButtons]::$Buttons,
[Windows.Forms.MessageBoxIcon]::$Icon,
[Windows.Forms.MessageBoxDefaultButton]::$Default)
}
# Non-modal example.
# Show-MessageBox -Title 'Important message' -Message 'Hi there!' -Icon None -Buttons OKCancel
# Modal example.
Show-MessageBox -Modal -Title 'Important message' -Message 'Hi there!' -Icon Warning -Buttons OK

Ask user for file path to save

This is what I was going for
$x = Get-Process
$y = Get-Date -Format yyyy-MM-dd_hh.mmtt
$SelPath = Read-Host -Prompt "Choose a location to save the file?"
$Path = $SelPath + 'Running Process' + ' ' + $FixedDate + '.txt'
$x | Out-File $Path
"Read-Host". For example:
$folder = Read-Host "Folder location"
While the links provided in the comments show the use of the FolderBrowserDialog, all of these fail to show it as a Topmost form and also do not dispose of the form when done.
Here's two functions that ensure the dialog gets displayed on top.
The first one uses the Shell.Application Com object:
# Show an Open Folder Dialog and return the directory selected by the user.
function Get-FolderName {
[CmdletBinding()]
param (
[Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
[string]$Message = "Select a directory.",
[string]$InitialDirectory = [System.Environment+SpecialFolder]::MyDocuments,
[switch]$ShowNewFolderButton
)
$browserForFolderOptions = 0x00000041 # BIF_RETURNONLYFSDIRS -bor BIF_NEWDIALOGSTYLE
if (!$ShowNewFolderButton) { $browserForFolderOptions += 0x00000200 } # BIF_NONEWFOLDERBUTTON
$browser = New-Object -ComObject Shell.Application
# To make the dialog topmost, you need to supply the Window handle of the current process
[intPtr]$handle = [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle
# see: https://msdn.microsoft.com/en-us/library/windows/desktop/bb773205(v=vs.85).aspx
$folder = $browser.BrowseForFolder($handle, $Message, $browserForFolderOptions, $InitialDirectory)
$result = $null
if ($folder) {
$result = $folder.Self.Path
}
# Release and remove the used Com object from memory
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($browser) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
return $result
}
$folder = Get-FolderName
if ($folder) { Write-Host "You selected the directory: $folder" }
else { "You did not select a directory." }
The second one uses a bit of C# code for the 'Topmost' feature and System.Windows.Forms
function Get-FolderName {
[CmdletBinding()]
param (
[Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
[string]$Message = "Please select a directory.",
[System.Environment+SpecialFolder]$InitialDirectory = [System.Environment+SpecialFolder]::MyDocuments,
[switch]$ShowNewFolderButton
)
# To ensure the dialog window shows in the foreground, you need to get a Window Handle from the owner process.
# This handle must implement System.Windows.Forms.IWin32Window
# Create a wrapper class that implements IWin32Window.
# The IWin32Window interface contains only a single property that must be implemented to expose the underlying handle.
$code = #"
using System;
using System.Windows.Forms;
public class Win32Window : IWin32Window
{
public Win32Window(IntPtr handle)
{
Handle = handle;
}
public IntPtr Handle { get; private set; }
}
"#
if (-not ([System.Management.Automation.PSTypeName]'Win32Window').Type) {
Add-Type -TypeDefinition $code -ReferencedAssemblies System.Windows.Forms.dll -Language CSharp
}
# Get the window handle from the current process
# $owner = New-Object Win32Window -ArgumentList ([System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle)
# Or write like this:
$owner = [Win32Window]::new([System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle)
# Or use the the window handle from the desktop
# $owner = New-Object Win32Window -ArgumentList (Get-Process -Name explorer).MainWindowHandle
# Or write like this:
# $owner = [Win32Window]::new((Get-Process -Name explorer).MainWindowHandle)
Add-Type -AssemblyName System.Windows.Forms
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
$dialog.Description = $Message
$dialog.RootFolder = $InitialDirectory
# $dialog.SelectedPath = '' # a folder within the RootFolder to pre-select
$dialog.ShowNewFolderButton = if ($ShowNewFolderButton) { $true } else { $false }
$result = $null
if ($dialog.ShowDialog($owner).ToString() -eq 'OK') {
$result = $dialog.SelectedPath
}
# clear the FolderBrowserDialog from memory
$dialog.Dispose()
return $result
}
$folder = Get-FolderName -InitialDirectory MyPictures
if ($folder) { Write-Host "You selected the directory: $folder" }
else { "You did not select a directory." }
Hope that helps
p.s. See Environment.SpecialFolder Enum for the [System.Environment+SpecialFolder] enumeration values