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...'
}
Related
My code is below. I'd like to get the item/text selected from the notify icon context menu and also trigger an event from it. I can't figure out how to obtain which menu item was clicked and am not able to trigger any events. I have read and reread the stackoverflow link in the Powershell comment and have not had success. Thanks.
As a note, you'll need to specify an ico file twice at the top to see the icon in the system tray.
<#
https://stackoverflow.com/questions/54649456/powershell-notifyicon-context-menu
#>
cls;
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$form1 = New-Object System.Windows.Forms.Form;
$notifyIcon= New-Object System.Windows.Forms.NotifyIcon;
$iconOK = New-Object System.Drawing.Icon([you'll need to find an icon for this using get-childitem -Recurse -Filter "*.ico" -File -Path c:\ -ErrorAction SilentlyContinue);
$iconWarn = New-Object System.Drawing.Icon([you'll need to find an icon for this using get-childitem -Recurse -Filter "*.ico" -File -Path c:\ -ErrorAction SilentlyContinue);
$menuItem1 = New-Object System.Windows.Forms.MenuItem;
$menuItem1.Text = "Menu Item 1";
$menuItem1.Name = "MenuItem1";
$menuItem1.Tag = "MenuItem1";
$menuItem2 = New-Object System.Windows.Forms.MenuItem;
$menuItem2.Text = "Menu Item 2";
$menuItem2.Name = "MenuItem2";
$menuItem2.Tag = "MenuItem2";
$menuItem3 = New-Object System.Windows.Forms.MenuItem;
$menuItem3.Text = "Menu Item 3";
$menuItem3.Name = "MenuItem3";
$menuItem3.Tag = "MenuItem3";
$contextMenu = New-Object System.Windows.Forms.ContextMenu;
$contextMenu.Name = "Context menu name";
$contextMenu.Tag = "Context menu tag";
$contextMenu.MenuItems.Add($menuItem1) | Out-Null;
$contextMenu.MenuItems.Add($menuItem2) | Out-Null;
$contextMenu.MenuItems.Add($menuItem3) | Out-Null;
$notifyIcon.Icon = $iconOK;
$notifyIcon.Visible = $True;
$menuItem1.add_Click
({
Write-Host "menuItem1.add_Click";
})
$menuItem2.add_Click
({
Write-Host "menuItem2.add_Click";
})
$menuItem3.add_Click
({
Write-Host "menuItem3.add_Click";
})
$contextMenu.add_Click
({
Write-Host "contextMenu.add_Click";
})
$notifyIcon.ContextMenu = $contextMenu;
$global:notifyIconContextMenu = $notifyIcon.ContextMenu.PSObject.Copy();
$notifyIconContextMenuMenuItems = $notifyIconContextMenu.MenuItems;
$notifyIcon.Add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderNotifyIconAddClick = $sender.PSObject.Copy();
$global:eventArgsNotifyIconAddClick = $e.PSObject.Copy();
$global:menuItemTest = $senderNotifyIconAddClick.ContextMenu;
$global:selectedContextItem = ([System.Windows.Forms.ContextMenu]$senderNotifyIconAddClick.ContextMenu)#.CommandParameter as User;
if ($_.Button -eq [Windows.Forms.MouseButtons]::Left)
{
#$form1.WindowStartupLocation = "CenterScreen"
$form1.Show();
$form1.Activate();
Write-Host "$notifyIcon.Add_Click left click";
}
elseif ($_.Button -eq [Windows.Forms.MouseButtons]::Right)
{
Write-Host "$notifyIcon.Add_Click right click";
}
})
$form1.add_Closing({
$notifyIcon.Dispose();
Write-Host "form.add_Closing completed";
return;
});
[void][System.Windows.Forms.Application]::Run($form1);
Here is a complete working example, the only thing needed will be to provide a file path to the icon files, otherwise this will allow someone to paste and modify to suit their own needs. The issue was that I should have been using a contextmenustrip and toolstripitem, rather than a contextmenu and menuitem.
cls;
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$form1 = New-Object System.Windows.Forms.Form;
$notifyIcon= New-Object System.Windows.Forms.NotifyIcon;
$iconOK = New-Object System.Drawing.Icon([you'll need to find an icon for this using get-childitem -Recurse -Filter "*.ico" -File -Path c:\ -ErrorAction SilentlyContinue);
$iconWarn = New-Object System.Drawing.Icon([you'll need to find an icon for this using get-childitem -Recurse -Filter "*.ico" -File -Path c:\ -ErrorAction SilentlyContinue);
$notifyIcon.Icon = $iconOK;
$notifyIcon.Visible = $True;
$toolStripItemOne = New-Object -TypeName Windows.Forms.ToolStripMenuItem -ArgumentList 'File'
$toolStripItemOne.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderToolStripItemOneAddClick = $sender.PSObject.Copy();
$global:eventArgsToolStripItemOneAddClick = $e.PSObject.Copy();
Write-Host "toolStripItemOne.add_Click - " $senderToolStripItemOneAddClick.Text;
});
$toolStripItemTwo = New-Object -TypeName Windows.Forms.ToolStripMenuItem -ArgumentList 'Edit'
$subMenuItemOne = New-Object -TypeName Windows.Forms.ToolStripMenuItem;
$subMenuItemOne.Text = "Copy";
$subMenuItemOne.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderSubMenuItemOneAddClick = $sender.PSObject.Copy();
$global:eventArgsSubMenuItemOneAddClick = $e.PSObject.Copy();
Write-Host "subMenuItemOne.add_Click - " $senderSubMenuItemOneAddClick.Text;
});
$toolStripItemTwo.DropDownItems.Add($subMenuItemOne) | Out-Null;
$subMenuItemTwo = New-Object -TypeName Windows.Forms.ToolStripMenuItem;
$subMenuItemTwo.Text = "Paste";
$subMenuItemTwo.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderSubMenuItemTwoAddClick = $sender.PSObject.Copy();
$global:eventArgsSubMenuItemTwoAddClick = $e.PSObject.Copy();
Write-Host "subMenuItemTwo.add_Click - " $senderSubMenuItemTwoAddClick.Text;
});
$toolStripItemTwo.DropDownItems.Add($subMenuItemTwo) | Out-Null;
$toolStripItemTwo.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderToolStripItemTwoAddClick = $sender.PSObject.Copy();
$global:eventArgsToolStripItemTwoAddClick = $e.PSObject.Copy();
Write-Host "toolStripItemTwo.add_Click - " $senderToolStripItemTwoAddClick.Text;
});
$toolStripItemThree = New-Object -TypeName Windows.Forms.ToolStripMenuItem -ArgumentList 'Save'
$toolStripItemThree.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderToolStripItemThreeAddClick = $sender.PSObject.Copy();
$global:eventArgsToolStripItemThreeAddClick = $e.PSObject.Copy();
Write-Host "toolStripItemThree.add_Click - " $senderToolStripItemThreeAddClick.Text;
});
$toolStripItemFour = New-Object -TypeName Windows.Forms.ToolStripMenuItem -ArgumentList 'Close'
$toolStripItemFour.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderToolStripItemFourAddClick = $sender.PSObject.Copy();
$global:eventArgsToolStripItemFourAddClick = $e.PSObject.Copy();
Write-Host "toolStripItemFour.add_Click - " $senderToolStripItemFourAddClick.Text;
$form1.Close();
});
$contextMenuStrip = New-Object System.Windows.Forms.ContextMenuStrip;
$contextMenuStrip.Name = "Context menu strip name";
$contextMenuStrip.Tag = "Context menu strip tag";
$contextMenuStrip.Items.AddRange($toolStripItemOne);
$contextMenuStrip.Items.AddRange($toolStripItemTwo);
$contextMenuStrip.Items.AddRange($toolStripItemThree);
$contextMenuStrip.Items.AddRange($toolStripItemFour);
$contextMenuStrip.Size = New-Object System.Drawing.Size(153, 70);
$notifyIcon.ContextMenuStrip = $contextMenuStrip;
$global:notifyIconContextMenuStrip = $notifyIcon.ContextMenuStrip.PSObject.Copy();
$notifyIconContextMenuMenuItems = $notifyIconContextMenu.MenuItems;
$notifyIcon.Add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderNotifyIconAddClick = $sender.PSObject.Copy();
$global:eventArgsNotifyIconAddClick = $e.PSObject.Copy();
$global:menuItemTest = $senderNotifyIconAddClick.ContextMenu;
$global:selectedContextItem = ([System.Windows.Forms.ContextMenu]$senderNotifyIconAddClick.ContextMenu);
if ($_.Button -eq [Windows.Forms.MouseButtons]::Left)
{
$form1.Show();
$form1.Activate();
Write-Host "$notifyIcon.Add_Click left click";
}
elseif ($_.Button -eq [Windows.Forms.MouseButtons]::Right)
{
Write-Host "$notifyIcon.Add_Click right click";
}
})
$form1.add_Closing({
$notifyIcon.Dispose();
Write-Host "form.add_Closing completed";
return;
});
[void][System.Windows.Forms.Application]::Run($form1);
and here is how to display a label as the icon, which can be dynamically updated within the code
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$form1 = New-Object System.Windows.Forms.Form;
$notifyIcon= New-Object System.Windows.Forms.NotifyIcon;
$iconOK = New-Object System.Drawing.Icon([you'll need to find an icon for this using get-childitem -Recurse -Filter "*.ico" -File -Path c:\ -ErrorAction SilentlyContinue);
$iconWarn = New-Object System.Drawing.Icon([you'll need to find an icon for this using get-childitem -Recurse -Filter "*.ico" -File -Path c:\ -ErrorAction SilentlyContinue);
$memoryStream = New-Object System.IO.MemoryStream;
$idleTimeBitmap = New-Object System.Drawing.Bitmap(40, 14);
$idleTimeFont = New-Object System.Drawing.Font("Microsoft San Serif",7,[System.Drawing.FontStyle]::Regular);
$idleTimeBrushForegroundColor = [System.Drawing.Brushes]::White;
$idleTimeBrushBackgroundColor = [System.Drawing.Brushes]::Black;
$idleTimeImageGraphics = [Drawing.Graphics]::FromImage($idleTimeBitmap);
$idleTimeImageGraphics.FillRectangle($idleTimeBrushBackgroundColor,0,0,$idleTimeBitmap.Width,$idleTimeBitmap.Height)
$idleTimeImageGraphics.DrawString("00:00:00", $idleTimeFont, $idleTimeBrushForegroundColor, 1, 1);
$idleTimeBitmap.Save($memoryStream, [System.Drawing.Imaging.ImageFormat]::Bmp);
$toolStripItemOne = New-Object -TypeName Windows.Forms.ToolStripMenuItem -ArgumentList 'File'
$toolStripItemOne.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderToolStripItemOneAddClick = $sender.PSObject.Copy();
$global:eventArgsToolStripItemOneAddClick = $e.PSObject.Copy();
Write-Host "toolStripItemOne.add_Click - " $senderToolStripItemOneAddClick.Text;
});
$toolStripItemTwo = New-Object -TypeName Windows.Forms.ToolStripMenuItem -ArgumentList 'Edit'
$subMenuItemOne = New-Object -TypeName Windows.Forms.ToolStripMenuItem;
$subMenuItemOne.Text = "Copy";
$subMenuItemOne.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderSubMenuItemOneAddClick = $sender.PSObject.Copy();
$global:eventArgsSubMenuItemOneAddClick = $e.PSObject.Copy();
Write-Host "subMenuItemOne.add_Click - " $senderSubMenuItemOneAddClick.Text;
});
$toolStripItemTwo.DropDownItems.Add($subMenuItemOne) | Out-Null;
$subMenuItemTwo = New-Object -TypeName Windows.Forms.ToolStripMenuItem;
$subMenuItemTwo.Text = "Paste";
$subMenuItemTwo.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderSubMenuItemTwoAddClick = $sender.PSObject.Copy();
$global:eventArgsSubMenuItemTwoAddClick = $e.PSObject.Copy();
Write-Host "subMenuItemTwo.add_Click - " $senderSubMenuItemTwoAddClick.Text;
});
$toolStripItemTwo.DropDownItems.Add($subMenuItemTwo) | Out-Null;
$toolStripItemTwo.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderToolStripItemTwoAddClick = $sender.PSObject.Copy();
$global:eventArgsToolStripItemTwoAddClick = $e.PSObject.Copy();
Write-Host "toolStripItemTwo.add_Click - " $senderToolStripItemTwoAddClick.Text;
});
$toolStripItemThree = New-Object -TypeName Windows.Forms.ToolStripMenuItem -ArgumentList 'Save'
$toolStripItemThree.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderToolStripItemThreeAddClick = $sender.PSObject.Copy();
$global:eventArgsToolStripItemThreeAddClick = $e.PSObject.Copy();
Write-Host "toolStripItemThree.add_Click - " $senderToolStripItemThreeAddClick.Text;
});
$toolStripItemFour = New-Object -TypeName Windows.Forms.ToolStripMenuItem -ArgumentList 'Close'
$toolStripItemFour.add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderToolStripItemFourAddClick = $sender.PSObject.Copy();
$global:eventArgsToolStripItemFourAddClick = $e.PSObject.Copy();
Write-Host "toolStripItemFour.add_Click - " $senderToolStripItemFourAddClick.Text;
$form1.Close();
});
$memoryStream = New-Object System.IO.MemoryStream;
$idleTimeBitmap = New-Object System.Drawing.Bitmap(32, 20);
$idleTimeFont = New-Object System.Drawing.Font("Microsoft San Serif",12,[System.Drawing.FontStyle]::Regular);
$idleTimeBrushForegroundColor = [System.Drawing.Brushes]::White;
$idleTimeBrushBackgroundColor = [System.Drawing.Brushes]::Black;
$idleTimeImageGraphics = [Drawing.Graphics]::FromImage($idleTimeBitmap);
$idleTimeImageGraphics.FillRectangle($idleTimeBrushBackgroundColor,0,0,$idleTimeBitmap.Width,$idleTimeBitmap.Height)
$idleTimeImageGraphics.DrawString("14", $idleTimeFont, $idleTimeBrushForegroundColor, 1, 1);
$idleTimeBitmap.Save($memoryStream, [System.Drawing.Imaging.ImageFormat]::Bmp);
$idleTimeIcon = [System.Drawing.Icon]::FromHandle($idleTimeBitmap.GetHicon());
$contextMenuStrip = New-Object System.Windows.Forms.ContextMenuStrip;
$contextMenuStrip.Name = "Context menu strip name";
$contextMenuStrip.Tag = "Context menu strip tag";
$contextMenuStripLabel = New-Object System.Windows.Forms.Label;
$contextMenuStripLabel.Text = "contextMenuStripLabel";
$toolStripItemLabel = New-Object -TypeName Windows.Forms.ToolStripMenuItem;
$toolStripControlHost = New-Object Windows.Forms.ToolStripControlHost($contextMenuStripLabel);
$contextMenuStrip.Items.Insert(0, $toolStripControlHost);
$contextMenuStrip.Items.Add($toolStripControlHost) | Out-Null;
$contextMenuStrip.Items.AddRange($toolStripItemOne);
$contextMenuStrip.Items.AddRange($toolStripItemTwo);
$contextMenuStrip.Items.AddRange($toolStripItemThree);
$contextMenuStrip.Items.AddRange($toolStripItemFour);
$contextMenuStrip.Size = New-Object System.Drawing.Size(153, 70);
#$notifyIcon.Icon = $iconOK;
$notifyIcon.Visible = $True;
$notifyIcon.Icon = $idleTimeIcon;
$notifyIcon.ContextMenuStrip = $contextMenuStrip;
$global:notifyIconContextMenuStrip = $notifyIcon.ContextMenuStrip.PSObject.Copy();
$notifyIconContextMenuMenuItems = $notifyIconContextMenu.MenuItems;
$notifyIcon.Add_Click({
param(
[System.Object] $sender,
[System.EventArgs] $e
)
$global:senderNotifyIconAddClick = $sender.PSObject.Copy();
$global:eventArgsNotifyIconAddClick = $e.PSObject.Copy();
$global:menuItemTest = $senderNotifyIconAddClick.ContextMenu;
$global:selectedContextItem = ([System.Windows.Forms.ContextMenu]$senderNotifyIconAddClick.ContextMenu);
if ($_.Button -eq [Windows.Forms.MouseButtons]::Left)
{
$form1.Show();
$form1.Activate();
Write-Host "$notifyIcon.Add_Click left click";
}
elseif ($_.Button -eq [Windows.Forms.MouseButtons]::Right)
{
Write-Host "$notifyIcon.Add_Click right click";
}
})
$form1.add_Closing({
$notifyIcon.Dispose();
Write-Host "form.add_Closing completed";
return;
});
[void][System.Windows.Forms.Application]::Run($form1);
I have one question. I don't understand what I am doing wrong, I wrote the following script to tell me if the folder exists to show a message, but it is now showing it.
If (Test-Path -path ($LabServer + $CaseName) -PathType Container){
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show('Folder name exists, please enter a new name')
The script is supposed to create multiple folders in a specific location. I want to check if the folder name (Case Name) already exists, and if it does, do not create the folder with the same name, but the script continues and creates the folder and sub-folders.
Here is the full script.
Thank you for all your help
# Load required assemblies
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
# Drawing form and controls
$CreateFolder = New-Object System.Windows.Forms.Form
$CreateFolder.Text = "Create Multiple Custodian Folders"
$CreateFolder.Size = New-Object System.Drawing.Size(350,415)
$CreateFolder.FormBorderStyle = "FixedDialog"
$CreateFolder.TopMost = $true
$CreateFolder.MaximizeBox = $false
$CreateFolder.MinimizeBox = $false
$CreateFolder.ControlBox = $true
$CreateFolder.StartPosition = "CenterScreen"
$CreateFolder.Font = "Segoe UI"
#======================== CASE NAME ========================#
# adding a label to my form
$label_message = New-Object System.Windows.Forms.Label
$label_message.Location = New-Object System.Drawing.Size(20,8)
$label_message.Size = New-Object System.Drawing.Size(100,15)
$label_message.Text = "Case Name"
$CreateFolder.Controls.Add($label_message)
# CaseName
$CaseName = New-Object System.Windows.Forms.TextBox
$CaseName.Location = New-Object System.Drawing.Size(20,30)
$CaseName.Size = New-Object System.Drawing.Size(300,25)
$CaseName.ScrollBars = "Vertical"
$CreateFolder.Controls.Add($CaseName)
#======================== DROPBOX ========================#
$label_messageCombobox = New-Object System.Windows.Forms.Label
$label_messageCombobox.Location = New-Object System.Drawing.Size(20,60)
$label_messageCombobox.Size = New-Object System.Drawing.Size(100,15)
$label_messageCombobox.Text = "Pick a Server"
$CreateFolder.Controls.Add($label_messageCombobox)
$DropdownBox = New-Object System.Windows.Forms.ComboBox
$DropdownBox.Location = New-Object System.Drawing.Size(20,80)
$DropdownBox.Size = New-Object System.Drawing.Size(300,15)
$DropdownBox.Height = 200
$Dropdownbox.DropDownStyle = "DropDownList"
$CreateFolder.Controls.Add($DropdownBox)
$Servers = #("Lab Machine 40","Lab Machine 45","Lab Machine 50","Lab Machine 55")
foreach($Server in $Servers){
$DropdownBox.Items.Add($Server) | Out-Null
}
#======================== FUNCTION TO GET SERVER ========================#
Function Get-Server(){
$SelectedServer = $DropdownBox.SelectedItem.ToString()
if($SelectedServer -eq "Lab Machine 50") {
$Script:LabServer = Set-Location "\\Server50\K$" -PassThru
}
elseif($SelectedServer -eq "Lab Machine 55") {
$Script:LabServer = Set-Location "\\Server55\K$" -PassThru
}
elseif($SelectedServer -eq "Lab Machine 40") {
$Script:LabServer = Set-Location "\\Server40\K$" -PassThru
}
elseif($SelectedServer -eq "Lab Machine 45") {
$Script:LabServer = Set-Location "\\Server45\K$" -PassThru
}
}
#======================== INPUTBOX ========================#
$label_message2 = New-Object System.Windows.Forms.Label
$label_message2.Location = New-Object System.Drawing.Size(20,110)
$label_message2.Size = New-Object System.Drawing.Size(100,15)
$label_message2.Text = "Custodian Names"
$CreateFolder.Controls.Add($label_message2)
# Inputbox
$Inputbox = New-Object System.Windows.Forms.TextBox
$Inputbox.Multiline = $True;
$Inputbox.Location = New-Object System.Drawing.Size(20,130)
$Inputbox.Size = New-Object System.Drawing.Size(300,200)
$Inputbox.ScrollBars = "Vertical"
$CreateFolder.Controls.Add($Inputbox)
#======================== BUTTON ========================#
# add a button ti create folder
$button_ClickMe = New-Object System.Windows.Forms.Button
$button_ClickMe.Location = New-Object System.Drawing.Size(45,340)
$button_ClickMe.Size = New-Object System.Drawing.Size(240,32)
$button_ClickMe.TextAlign = "MiddleCenter"
$button_ClickMe.Text = "Create Folders"
$button_ClickMe.Add_Click({
#$FolderExist = $LabServer.Text + $CaseName.Text
If ($CaseName.TextLength -eq 0){
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show('Please Enter a Case Name')
}
else {
If (Test-Path -path ($LabServer + $CaseName) -PathType Container){
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show('Folder name exists, please enter a new name')
}
else {
if ($Inputbox.TextLength -eq 0){
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show('Please enter 1 custodian name')
}
else {
Get-Server
Set-Location $LabServer
New-Item $CaseName.Text -type directory
Start-Sleep -Seconds 5
Set-Location ($LabServer.Text + $CaseName.Text)
ForEach ($Folder in $Inputbox.lines) {
New-Item $Folder -type directory
}
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show('Folders were created')
[System.Windows.Forms.Application]::Exit()
}
}
}
})
$CreateFolder.Controls.Add($button_ClickMe)
# show form
$CreateFolder.Add_Shown({$CreateFolder.Activate()})
[void] $CreateFolder.ShowDialog()
You almost answered your own question here:
#$FolderExist = $LabServer.Text + $CaseName.Text
Check out the comments in the code:
If ($CaseName.TextLength -eq 0)
{
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show('Please Enter a Case Name')
}
else
{
# If we are here $LabServer is not defined because Get-Server did not run yet
# You can take 2 different approaches, either use your function or
# Test-Path using the ComboBox
# Approach 1: Define $LabServer
Get-Server
# Now you can Test-Path
$path = Join-Path $LabServer -ChildPath $CaseName.Text
If (Test-Path -Path $path -PathType Container)
{
.....
}
# Approach 2:
$path = Join-Path ("\\{0}\K$" -f $DropdownBox.SelectedItem) -ChildPath $CaseName.Text
If (Test-Path -Path $path -PathType Container)
{
.....
}
.....
Edit
I think it's worth adding a few recommendations to reduce the number of nested conditions you have on your AddClick listener.
First, by default at the start of your form, disable the button:
$button_ClickMe.Enabled = $false
Now you can add 2 listeners on TextChanged for both TextBox:
$textChangedEvent = {
if($caseName.TextLength -and $DropdownBox.SelectedItem -and $Inputbox.TextLength)
{
$button_ClickMe.Enabled = $true
}
else
{
$button_ClickMe.Enabled = $false
}
}
$CaseName.Add_TextChanged($textChangedEvent)
$Inputbox.Add_TextChanged($textChangedEvent)
With this you can remove the 2 conditions you have on $CaseName.TextLength -eq 0 and $Inputbox.TextLength -eq 0.
Lastly, your AddClick event would look like this (Note that you wouldn't need the Get-Server function):
$buttonClickEvent = {
$path = "\\{0}\K$" -f $DropdownBox.SelectedItem
$path = Join-Path $path -ChildPath $CaseName.Text
if(Test-Path $path -PathType Container)
{
[System.Windows.Forms.MessageBox]::Show('Folder name exists, please enter a new name')
return
}
New-Item $path -Type Directory
Start-Sleep -Seconds 5
foreach($folder in $Inputbox.Lines)
{
$folder = $Folder.Trim()
$newFolder = Join-Path $path -ChildPath $folder
New-Item $newFolder -Type Directory
[System.Windows.Forms.MessageBox]::Show('Folders were created')
[System.Windows.Forms.Application]::Exit()
}
}
$button_ClickMe.Add_Click($buttonClickEvent)
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
}
I want to decide which folder that I need to choose based on my data, then if I can't find it, it will show the GUI for waiting and do looping to check it. I try this code, I can find the folder, but when I can't find it once I want to show the GUI it returns some error.
This is how I checking the folder
function FIND {
Write-Host "call the function that can call the GUI.ps1 script"
$Path = "D:\Process"
Write-Host "Starting Mapping SSID and Finding Job"
$SSID_Unit = "111dddddfafafesa"
Try{
$Path_Job = (Get-Item (Get-ChildItem "$Path\*\SSID_LST" | Select-String -Pattern "$SSID_Unit").Path).Directory.FullName
$global:Result = [PSCustomObject]#{
Exists = $true
FileName = $Path_Job.FullName
Attempts = 1
}
Write-Host "Job'$($global:Result.FileName)' Exists. Found after $($global:Result.Attempts) attempts." -ForegroundColor Green
Write-Host "Continue to Assigned Job"
Pause
} Catch {
Write-Host "Waiting for the jobss"
& D:\X\Wait_GUI.ps1 -Path $Path_Job -MaxAttempts 20
Write-Host "Job not found after $($global:Result.Attempts) attempts." -ForegroundColor Red
}
}
FIND
This is the GUI
Param (
[string]$Path = '*.*',
[string]$MaxAttempts = 5
)
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
# set things up for the timer
$script:nAttempts = 0
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000 # 1 second
$timer.Add_Tick({
$global:Result = $null
$script:nAttempts++
$Path_Job = Get-Item -Path $Path
if ($Path_Job) {
$global:Result = [PSCustomObject]#{
Exists = $true
FileName = $Path_Job.FullName
Attempts = $script:nAttempts
}
$timer.Dispose()
$Form.Close()
}
elseif ($script:nAttempts -ge $MaxAttempts) {
$global:Result = [PSCustomObject]#{
Exists = $false
FileName = ''
Attempts = $script:nAttempts
}
$timer.Dispose()
$Form.Close()
}
})
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$Form = New-Object system.Windows.Forms.Form
$Form.ClientSize = '617,418'
$Form.text = "AutoGM"
$Form.BackColor = "#8b572a"
$Form.TopMost = $false
$Form.WindowState = 'Maximized'
$Label1 = New-Object system.Windows.Forms.Label
$Label1.text = "UNDER AUTOMATION PROCESS"
$Label1.AutoSize = $true
$Label1.width = 25
$Label1.height = 10
$Label1.Anchor = 'top,right,bottom,left'
$Label1.ForeColor = "#ffffff"
$Label1.Anchor = "None"
$Label1.TextAlign = "MiddleCenter"
$Label2 = New-Object system.Windows.Forms.Label
$Label2.text = "Waiting for the job..."
$Label2.AutoSize = $true
$Label2.width = 25
$Label2.height = 10
$Label2.ForeColor = "#ffffff"
$Label2.Anchor = "None"
$Label2.TextAlign = "MiddleCenter"
$Form.controls.AddRange(#($Label1,$Label2))
[void]$Form.Show()
# Write-Host $Form.Height
# Write-Host $Form.Width
$Label1.location = New-Object System.Drawing.Point(($Form.Width*0.35), ($Form.Height*0.4))
$Label2.location = New-Object System.Drawing.Point(($form.Width*0.43), ($Form.Height*0.5))
$L_S = (($Form.Width/2) - ($Form.Height / 2)) / 15
$Label1.Font = "Microsoft Sans Serif, $L_S, style=Bold"
$Label2.Font = "Microsoft Sans Serif, $L_S, style=Bold"
$Form.controls.AddRange(#($Label1,$Label2))
# start the timer as soon as the dialog is visible
$Form.Add_Shown({ $timer.Start() })
$Form.Visible = $false
[void]$Form.ShowDialog()
# clean up when done
$Form.Dispose()
if not found, it return this
Waiting for the jobss
Job not found after 1 attempts.
and the GUI is not shown
Ok, first of all, you are using different tests for the file and/or directory in the code and in the GUI. Furthermore, you call the GUI.ps1 file with a path set to a $null value.
I would change your code to something like this:
$Path = "D:\Process\*\SSID_LST\*" # the path to look for files
$SSID_Unit = "111dddddfafafesa" # the Search pattern to look for inside the files
function Test-FileWithGui {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$Path,
[Parameter(Mandatory = $true, Position = 2)]
[string]$Pattern,
[int]$MaxAttempts = 5
)
Write-Host "Starting Mapping SSID and Finding Job"
# set up an 'empty' $global:Result object to return on failure
$global:Result = '' | Select-Object #{Name = 'Exists'; Expression = {$false}}, FileName, Directory, #{Name = 'Attempts'; Expression = {1}}
# test if the given path is valid. If not, exit the function
if (!(Test-Path -Path $Path -PathType Container)) {
Write-Warning "Path '$Path' does not exist."
return
}
# try and find the first file that contains your search pattern
$file = Select-String -Path $Path -Pattern $Pattern -SimpleMatch -ErrorAction SilentlyContinue | Select-Object -First 1
if ($file) {
$file = Get-Item -Path $file.Path
$global:Result = [PSCustomObject]#{
Exists = $true
FileName = $file.FullName
Directory = $file.DirectoryName
Attempts = 1
}
}
else {
& "D:\GUI.ps1" -Path $Path -Pattern $Pattern -MaxAttempts $MaxAttempts
}
}
# call the function that can call the GUI.ps1 script
Test-FileWithGui -Path $Path -Pattern $SSID_Unit -MaxAttempts 20
# show the $global:Result object with all properties
$global:Result | Format-List
# check the Global result object
if ($global:Result.Exists) {
Write-Host "File '$($global:Result.FileName)' Exists. Found after $($global:Result.Attempts) attempts." -ForegroundColor Green
}
else {
Write-Host "File not found after $($global:Result.Attempts) attempts." -ForegroundColor Red
}
Next the GUI file.
As you are now searching for a file that contains some text, you need a third parameter to call this named Pattern.
Inside the GUI file we perform the exact same test as we did in the code above, using the parameter $Pattern as search string:
Param (
[string]$Path,
[string]$Pattern,
[int]$MaxAttempts = 5
)
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
# set things up for the timer
$script:nAttempts = 0
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000 # 1 second
$timer.Add_Tick({
$global:Result = $null
$script:nAttempts++
# use the same test as you did outside of the GUI
# try and find the first file that contains your search pattern
$file = Select-String -Path $Path -Pattern $Pattern -SimpleMatch -ErrorAction SilentlyContinue | Select-Object -First 1
if ($file) {
$file = Get-Item -Path $file.Path
$global:Result = [PSCustomObject]#{
Exists = $true
FileName = $file.FullName
Directory = $file.DirectoryName
Attempts = $script:nAttempts
}
$timer.Dispose()
$Form.Close()
}
elseif ($script:nAttempts -ge $MaxAttempts) {
$global:Result = [PSCustomObject]#{
Exists = $false
FileName = $null
Directory = $null
Attempts = $script:nAttempts
}
$script:nAttempts = 0
$timer.Dispose()
$Form.Close()
}
})
$Form = New-Object system.Windows.Forms.Form
$Form.ClientSize = '617,418'
$Form.Text = "AutoGM"
$Form.BackColor = "#8b572a"
$Form.TopMost = $true
$Form.WindowState = 'Maximized'
# I have removed $Label2 because it is easier to use
# just one label here and Dock it to Fill.
$Label1 = New-Object system.Windows.Forms.Label
$Label1.Text = "UNDER AUTOMATION PROCESS`r`n`r`nWaiting for the job..."
$Label1.AutoSize = $false
$Label1.Dock = 'Fill'
$Label1.TextAlign = "MiddleCenter"
$Label1.ForeColor = "#ffffff"
$L_S = (($Form.Width/2) - ($Form.Height / 2)) / 10
$Label1.Font = "Microsoft Sans Serif, $L_S, style=Bold"
$Form.controls.Add($Label1)
# start the timer as soon as the dialog is visible
$Form.Add_Shown({ $timer.Start() })
[void]$Form.ShowDialog()
# clean up when done
$Form.Dispose()
The results during testing came out like below
If the file was found within the set MaxAttempts tries:
Starting Mapping SSID and Finding Job
Exists : True
FileName : D:\Process\test\SSID_LST\blah.txt
Directory : D:\Process\test\SSID_LST
Attempts : 7
File 'D:\Process\test\SSID_LST\blah.txt' Exists. Found after 7 attempts.
When the file was NOT found:
Starting Mapping SSID and Finding Job
Exists : False
FileName :
Directory :
Attempts : 20
File not found after 20 attempts.
If even the folder $Path was not found, the output is
Starting Mapping SSID and Finding Job
WARNING: Path 'D:\Process\*\SSID_LST\*' does not exist.
Exists : False
FileName :
Directory :
Attempts : 1
File not found after 1 attempts.
Hope that helps
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