master b30bc361bc84 cached
17 files
29.5 KB
8.0k tokens
1 requests
Download .txt
Repository: dan-osull/PowerShell-Script-Menu-Gui
Branch: master
Commit: b30bc361bc84
Files: 17
Total size: 29.5 KB

Directory structure:
gitextract_c2swp2db/

├── .gitignore
├── LICENSE
├── PSScriptMenuGui/
│   ├── PSScriptMenuGui.psd1
│   ├── PSScriptMenuGui.psm1
│   ├── examples/
│   │   ├── PSScriptMenuGui.ps1
│   │   ├── PSScriptMenuGui_all_options.ps1
│   │   ├── example_data.csv
│   │   ├── example_target.cmd
│   │   ├── example_target.ps1
│   │   └── example_text_file.txt
│   ├── private/
│   │   └── functions.ps1
│   ├── public/
│   │   └── functions.ps1
│   └── xaml/
│       ├── end.xaml
│       ├── heading.xaml
│       ├── item.xaml
│       └── start.xaml
└── README.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.vscode/


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Dan O'Sullivan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: PSScriptMenuGui/PSScriptMenuGui.psd1
================================================
#
# Module manifest for module 'PSScriptMenuGui'
#
# Generated by: Dan O'Sullivan
#
# Generated on: 10/7/2019
#

@{

# Script module or binary module file associated with this manifest.
RootModule = 'PSScriptMenuGui.psm1'

# Version number of this module.
ModuleVersion = '1.0.1'

# Supported PSEditions
# CompatiblePSEditions = @()

# ID used to uniquely identify this module
GUID = '103460b8-4f8b-471c-8f70-41e493070656'

# Author of this module
Author = "Dan O'Sullivan"

# Company or vendor of this module
# CompanyName = ''

# Copyright statement for this module
Copyright = "(c) Dan O'Sullivan. Released under the MIT License."

# Description of the functionality provided by this module
Description = 'Use a CSV file to make a graphical menu of PowerShell scripts. Easy to customise and fast to launch.

You can also add Windows programs and files to the menu.

See the Project Site on GitHub for full documentation.'

# Minimum version of the PowerShell engine required by this module
PowerShellVersion = '5.1'

# Name of the PowerShell host required by this module
# PowerShellHostName = ''

# Minimum version of the PowerShell host required by this module
# PowerShellHostVersion = ''

# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# DotNetFrameworkVersion = ''

# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# CLRVersion = ''

# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''

# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()

# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()

# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# ScriptsToProcess = @()

# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()

# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
# NestedModules = @()

# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = @(
    'Show-ScriptMenuGui',
    'New-ScriptMenuGuiExample'
)

# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @()

# Variables to export from this module
VariablesToExport = '*'

# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = @()

# DSC resources to export from this module
# DscResourcesToExport = @()

# List of all modules packaged with this module
# ModuleList = @()

# List of all files packaged with this module
# FileList = @()

# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{

    PSData = @{

        # Tags applied to this module. These help with module discovery in online galleries.
        Tags = @('PSEdition_Desktop','PSEdition_Core','Windows')

        # A URL to the license for this module.
        LicenseUri = 'https://github.com/weebsnore/PowerShell-Script-Menu-Gui/blob/master/LICENSE'

        # A URL to the main website for this project.
        ProjectUri = 'https://github.com/weebsnore/PowerShell-Script-Menu-Gui'

        # A URL to an icon representing this module.
        # IconUri = ''

        # ReleaseNotes of this module
        # ReleaseNotes = ''

        # Prerelease string of this module
        # Prerelease = ''

        # Flag to indicate whether the module requires explicit user acceptance for install/update/save
        RequireLicenseAcceptance = $false

        # External dependent modules of this module
        # ExternalModuleDependencies = @()

    } # End of PSData hashtable

} # End of PrivateData hashtable

# HelpInfo URI of this module
# HelpInfoURI = ''

# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''

}



================================================
FILE: PSScriptMenuGui/PSScriptMenuGui.psm1
================================================
if ($PSEdition -eq 'Core') {
    if (-not $IsWindows) {
        throw 'This module only runs on Windows'
    }
    if ($PSVersionTable.PSVersion.Major -eq 6) {
        throw 'This module is not compatible with PowerShell Core 6'
    }
}

# Get public and private function definition files
# Based on: https://github.com/RamblingCookieMonster/PSStackExchange/blob/db1277453374cb16684b35cf93a8f5c97288c41f/PSStackExchange/PSStackExchange.psm1
$scripts = @()
$scripts += Get-ChildItem -Path $PSScriptRoot\public\*.ps1 -ErrorAction SilentlyContinue
$scripts += Get-ChildItem -Path $PSScriptRoot\private\*.ps1 -ErrorAction SilentlyContinue

# Dot source the files
ForEach ($script in $scripts) {
    try {
        . $script.FullName
    }
    catch {
        throw
    }
}

# Used to get files from xaml and examples subfolders
$moduleRoot = $PSScriptRoot

================================================
FILE: PSScriptMenuGui/examples/PSScriptMenuGui.ps1
================================================
#region Setup
Set-Location $PSScriptRoot
Remove-Module PSScriptMenuGui -ErrorAction SilentlyContinue
try {
    Import-Module PSScriptMenuGui -ErrorAction Stop
}
catch {
    Write-Warning $_
    Write-Verbose 'Attempting to import from parent directory...' -Verbose
    Import-Module '..\'
}
#endregion

Show-ScriptMenuGui -csvPath '.\example_data.csv' -Verbose

================================================
FILE: PSScriptMenuGui/examples/PSScriptMenuGui_all_options.ps1
================================================
#region Setup
Set-Location $PSScriptRoot
Remove-Module PSScriptMenuGui -ErrorAction SilentlyContinue
try {
    Import-Module PSScriptMenuGui -ErrorAction Stop
}
catch {
    Write-Warning $_
    Write-Verbose 'Attempting to import from parent directory...' -Verbose
    Import-Module '..\'
}
#endregion

$params = @{
    csvPath = '.\example_data.csv'
    windowTitle = 'Example with all options'
    buttonForegroundColor = 'Azure'
    buttonBackgroundColor = '#C00077'
    iconPath = '.\pwsh7.ico'
    hideConsole = $true
    noExit = $true
    Verbose = $true
}
Show-ScriptMenuGui @params

================================================
FILE: PSScriptMenuGui/examples/example_data.csv
================================================
Section,Method,Command,Arguments,Name,Description
Old school,cmd,.\example_target.cmd,,Example 1:<LineBreak />cmd,.cmd file
Old school,cmd,taskmgr.exe,,Example 2:<LineBreak />cmd,External executable
Old school,cmd,notepad.exe,example_text_file,Example 3:<LineBreak />cmd,External executable with arguments
Less old,powershell_file,.\example_target.ps1,,Example 4:<LineBreak />powershell_file,.ps1 file called with powershell.exe
Less old,powershell_inline,"""Inline script"";$PSVersionTable;Read-Host ""Press Enter to continue""",,Example 5:<LineBreak />powershell_inline,Inline script called with powershell.exe
Less old,powershell_inline,$PSVersionTable, -NoExit -WindowStyle Maximized,Example 6:<LineBreak />powershell_inline,Additional powershell.exe arguments
The future,pwsh_file,.\example_target.ps1,,Example 7:<LineBreak />pwsh_file,.ps1 file called with pwsh.exe
The future,pwsh_inline,"""Inline script"";$PSVersionTable;Read-Host ""Press Enter to continue""",,Example 8:<LineBreak />pwsh_inline,Inline script called with pwsh.exe
The future,pwsh_inline,"& .\example_target.ps1 -Message ""passed in via param""",,Example 9:<LineBreak />pwsh_inline,.ps1 file called with parameter


================================================
FILE: PSScriptMenuGui/examples/example_target.cmd
================================================
@echo off
echo CMD script called from PSScriptMenuGui.ps1
pause

================================================
FILE: PSScriptMenuGui/examples/example_target.ps1
================================================
param ($message)
"PowerShell script called from PSScriptMenuGui.ps1"
if ($message) {
    "`$message = $message"
}
$PSVersionTable
Read-Host "Press Enter to continue"

================================================
FILE: PSScriptMenuGui/examples/example_text_file.txt
================================================
hello world

================================================
FILE: PSScriptMenuGui/private/functions.ps1
================================================
function Hide-Console {
    Write-Verbose 'Hiding PowerShell console...'
    # .NET method for hiding the PowerShell console window
    # https://stackoverflow.com/questions/40617800/opening-powershell-script-and-hide-command-prompt-but-not-the-gui
    Add-Type -Name Window -Namespace Console -MemberDefinition '
    [DllImport("Kernel32.dll")]
    public static extern IntPtr GetConsoleWindow();

    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
    '
    $consolePtr = [Console.Window]::GetConsoleWindow()
    [Console.Window]::ShowWindow($consolePtr, 0) # 0 = hide
}

Function New-GuiHeading {
    param(
        [Parameter(Mandatory)][string]$name
    )
    $string = Get-Content "$moduleRoot\xaml\heading.xaml"
    $string = $string.Replace('INSERT_SECTION_HEADING',(Get-XamlSafeString $name) )
    $string = $string.Replace('INSERT_ROW',$row)
    $script:row++

    return $string
}

Function New-GuiRow {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][PSCustomObject]$item
    )
    Write-Verbose $item

    $string = Get-Content "$moduleRoot\xaml\item.xaml"
    $string = $string.Replace('INSERT_BACKGROUND_COLOR',$buttonBackgroundColor)
    $string = $string.Replace('INSERT_FOREGROUND_COLOR',$buttonForegroundColor)
    $string = $string.Replace('INSERT_BUTTON_TEXT',(Get-XamlSafeString $item.Name) )
    # Description is optional
    if ($item.Description) {
        $string = $string.Replace('INSERT_DESCRIPTION',(Get-XamlSafeString $item.Description) )
    }
    else {
        $string = $string.Replace('INSERT_DESCRIPTION','')
    }
    $string = $string.Replace('INSERT_BUTTON_NAME',$item.Reference)
    $string = $string.Replace('INSERT_ROW',$row)
    $script:row++

    return $string
}

Function Get-XamlSafeString {
    param(
        [Parameter(Mandatory)][string]$string
    )
    # https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/how-to-use-special-characters-in-xaml
    # Order matters: &amp first
    $string = $string.Replace('&','&amp;').Replace('<','&lt;').Replace('>','&gt;').Replace('"','&quot;')
    # Restore line breaks
    $string = $string -replace '&lt;\s*?LineBreak\s*?\/\s*?&gt;','<LineBreak />'

    return $string
}

Function New-GuiForm {
    # Based on: https://foxdeploy.com/2015/05/14/part-iii-using-advanced-gui-elements-in-powershell/
    param (
        [Parameter(Mandatory)][array]$inputXml # XML has not been converted to object yet
    )
    # Process raw XML
    $inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*','<Window'

    # Read XAML
    [void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
    [xml]$xaml = $inputXML
    $reader = (New-Object System.Xml.XmlNodeReader $xaml)
    try {
        $form = [Windows.Markup.XamlReader]::Load($reader)
    }
    catch {
        Write-Warning "Unable to parse XML!
Ensure that there are NO SelectionChanged or TextChanged properties in your textboxes (PowerShell cannot process them).
Note that this module does not currently work with PowerShell 7-preview and the VS Code integrated console."
        throw
    }

    # Load XAML button objects in PowerShell
    $script:buttons = @()
    $xaml.SelectNodes("//*[@Name]") | ForEach-Object {
        try {
            $script:buttons += $Form.FindName($_.Name)
        }
        catch {
            throw
        }
    }

    return $form
}

Function Invoke-ButtonAction {
    param(
        [Parameter(Mandatory)][string]$buttonName
    )
    Write-Verbose "$buttonName clicked"

    # Get relevant CSV row
    $csvMatch = $csvData | Where-Object {$_.Reference -eq $buttonName}
    Write-Verbose $csvMatch

    # Pipe match to Start-Script function
    # Lets us check CSV data via parameter validation
    try {
        $csvMatch | Start-Script -ErrorAction Stop
    }
    catch {
        Write-Error $_
    }
}

Function Start-Script {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ValueFromPipelineByPropertyName)]
        [ValidateSet('cmd','powershell_file','powershell_inline','pwsh_file','pwsh_inline')]
        [string]$method,

        [Parameter(Mandatory,ValueFromPipelineByPropertyName)][string]$command,

        [Parameter(ValueFromPipelineByPropertyName)][string]$arguments
    )

    # Handle cmd first
    if ($method -eq 'cmd') {
        if ($arguments) {
            # Using .NET directly, as Start-Process adds a trailing space to arguments
            # https://social.technet.microsoft.com/Forums/en-US/97be1de5-f31e-416e-9752-ed60c39c0383/powershell-40-startprocess-adds-extra-space-to-commandline
            $process = New-Object System.Diagnostics.Process
            $process.StartInfo.FileName = $command
            $process.StartInfo.Arguments = $arguments
            # Set process working directory to PowerShell working directory
            # Mimics behaviour of exe called from cmd prompt
            $process.StartInfo.WorkingDirectory = $PWD
            $process.Start()
        }
        else {
            Start-Process -FilePath $command -Verbose:$verbose
        }
        return
    }

    # Begin constructing PowerShell arguments
    $psArguments = @()
    $psArguments += '-ExecutionPolicy Bypass'
    $psArguments += '-NoLogo'
    if ($noExit) {
        # Global -NoExit switch
        $psArguments += '-NoExit'
    }
    if ($arguments) {
        # Additional PS arguments from CSV
        # PowerShell doesn't seem to care if it gets the same argument twice
        $psArguments += $arguments
    }

    # Set Start-Process params according to CSV method
    $splitMethod = $method.Split('_')
    $encodedCommand = [Convert]::ToBase64String( [System.Text.Encoding]::Unicode.GetBytes($command) )
    switch ($splitMethod[0]) {
        powershell {
            $filePath = 'powershell.exe'
        }
        pwsh {
            $filePath = 'pwsh.exe'
        }
    }
    switch ($splitMethod[1]) {
        file {
            $psArguments += "-File `"$command`""
        }
        inline {
            $psArguments += "-EncodedCommand `"$encodedCommand`""
        }
    }

    # Launch process
    $psArguments | ForEach-Object { Write-Verbose $_ }
    Start-Process -FilePath $filePath -ArgumentList $psArguments -Verbose:$verbose
}

================================================
FILE: PSScriptMenuGui/public/functions.ps1
================================================
Function Show-ScriptMenuGui {
    <#
    .SYNOPSIS
        Use a CSV file to make a graphical menu of PowerShell scripts. Easy to customise and fast to launch.
    .DESCRIPTION
        Do you have favourite scripts that go forgotten?

        Does your organisation have scripts that would be useful to frontline staff who are not comfortable with the command line?

        This module uses a CSV file to make a graphical menu of PowerShell scripts.

        You can also add Windows programs and files to the menu.
    .PARAMETER csvPath
        Path to CSV file that defines the menu.

        See CSV reference: https://github.com/weebsnore/PowerShell-Script-Menu-Gui
    .PARAMETER windowTitle
        Custom title for the menu window.
    .PARAMETER buttonForegroundColor
        Custom button foreground (text) color.

        Hex codes (e.g. #C00077) and color names (e.g. Azure) are valid.

        See .NET Color Class: https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.colors
    .PARAMETER buttonBackgroundColor
        Custom button background color.
    .PARAMETER iconPath
        Path to .ico file for use in menu.
    .PARAMETER hideConsole
        Hide the PowerShell console that the menu is called from.

        Note: This means you won't be able to see any errors from button clicks. If things aren't working, this should be the first thing you stop using.
    .PARAMETER noExit
        Start all PowerShell instances with -NoExit ("Does not exit after running startup commands.")

        Note: You can set -NoExit on individual menu items by using the Arguments column.

        See CSV reference: https://github.com/weebsnore/PowerShell-Script-Menu-Gui
    .EXAMPLE
        Show-ScriptMenuGui -csvPath '.\example_data.csv' -Verbose
    .NOTES
        Run New-ScriptMenuGuiExample to get some example files
    .LINK
        https://github.com/weebsnore/PowerShell-Script-Menu-Gui
    #>
    [CmdletBinding()]
    param(
        [string][Parameter(Mandatory)]$csvPath,
        [string]$windowTitle = 'PowerShell Script Menu',
        [string]$buttonForegroundColor = 'White',
        [string]$buttonBackgroundColor = '#366EE8',
        [string]$iconPath,
        [switch]$hideConsole,
        [switch]$noExit
    )
    Write-Verbose 'Show-ScriptMenuGui started'

    # -Verbose value, to pass to select cmdlets
    $verbose = $false
    try {
        if ($PSBoundParameters['Verbose'].ToString() -eq 'True') {
            $verbose = $true
        }
    }
    catch {}

    $csvData = Import-CSV -Path $csvPath -ErrorAction Stop
    Write-Verbose "Got $($csvData.Count) CSV rows"

    # Add unique Reference to each item
    # Used as x:Name of button and to look up action on click
    $i = 0
    $csvData | ForEach-Object {
        $_ | Add-Member -Name Reference -MemberType NoteProperty -Value "button$i"
        $i++
    }

    # Begin constructing XAML
    $xaml = Get-Content "$moduleRoot\xaml\start.xaml"
    $xaml = $xaml.Replace('INSERT_WINDOW_TITLE',$windowTitle)
    if ($iconPath) {
        # TODO: change taskbar icon?
        # WPF wants the absolute path
        $iconPath = (Resolve-Path $iconPath).Path
        $xaml = $xaml.Replace('INSERT_ICON_PATH',$iconPath)
    }
    else {
        # No icon specified
        $xaml = $xaml.Replace('Icon="INSERT_ICON_PATH" ','')
    }

    # Add CSV data to XAML
    # Row counter
    $script:row = 0
    # Not using Group-Object as PS7-preview4 does not preserve original order
    $sections = $csvData.Section | Where-Object {-not [string]::IsNullOrEmpty($_) } | Get-Unique
    # Generate GUI rows
    ForEach ($section in $sections) {
        Write-Verbose "Adding GUI Section: $section..."
        # Section Heading
        $xaml += New-GuiHeading $section
        $csvData | Where-Object {$_.Section -eq $section} | ForEach-Object {
            # Add items
            $xaml += New-GuiRow $_
        }
    }
    Write-Verbose 'Adding any items with blank Section...'
    $csvData | Where-Object { [string]::IsNullOrEmpty($_.Section) } | ForEach-Object {
        $xaml += New-GuiRow $_
        # TODO: spacing at top of window is untidy with no Sections (minor)
    }
    Write-Verbose "Added $($row) GUI rows"

    # Finish constructing XAML
    $xaml += Get-Content "$moduleRoot\xaml\end.xaml"

    Write-Verbose 'Creating XAML objects...'
    $form = New-GuiForm -inputXml $xaml

    Write-Verbose "Found $($buttons.Count) buttons"
    Write-Verbose 'Adding click actions...'
    ForEach ($button in $buttons) {
        $button.Add_Click( {
            # Use object in pipeline to identify script to run
            Invoke-ButtonAction $_.Source.Name
        } )
    }

    if ($hideConsole) {
        if ($global:error[0].Exception.CommandInvocation.MyCommand.ModuleName -ne 'PSScriptMenuGui') {
            # Do not hide console if there have been errors
            Hide-Console | Out-Null
        }
    }

    Write-Verbose 'Showing dialog...'
    $Form.ShowDialog() | Out-Null
}

Function New-ScriptMenuGuiExample {
    <#
    .SYNOPSIS
        Creates an example set of files for PSScriptMenuGui
    .PARAMETER path
        Path of output folder
    .EXAMPLE
        New-ScriptMenuGuiExample -path 'PSScriptMenuGui_example'
    .LINK
        https://github.com/weebsnore/PowerShell-Script-Menu-Gui
    #>
    [CmdletBinding()]
    param (
        [string]$path = 'PSScriptMenuGui_example'
    )

    # Ensure folder exists
    if (-not (Test-Path -Path $path -PathType Container) ) {
        New-Item -Path $path -ItemType 'directory' -Verbose | Out-Null
    }

    Write-Verbose "Copying example files to $path..." -Verbose
    Copy-Item -Path "$moduleRoot\examples\*" -Destination $path
}

================================================
FILE: PSScriptMenuGui/xaml/end.xaml
================================================
        </Grid>
    </ScrollViewer>
</Window>


================================================
FILE: PSScriptMenuGui/xaml/heading.xaml
================================================
<TextBlock Text="INSERT_SECTION_HEADING" TextWrapping="Wrap" Grid.Row="INSERT_ROW" Grid.ColumnSpan="2" FontSize="25" Padding="5,10,0,5" />

================================================
FILE: PSScriptMenuGui/xaml/item.xaml
================================================
            <Button x:Name="INSERT_BUTTON_NAME" Grid.Row="INSERT_ROW" Grid.Column="0" Background="INSERT_BACKGROUND_COLOR" Foreground="INSERT_FOREGROUND_COLOR" MinHeight="50" VerticalAlignment="Top" Padding="10" Margin="0,5,0,5" >
                <TextBlock TextWrapping="Wrap" TextAlignment="Center">INSERT_BUTTON_TEXT</TextBlock>
            </Button>
            <TextBlock TextWrapping="Wrap" Grid.Row="INSERT_ROW" Grid.Column="1" Padding="10,5,0,5" VerticalAlignment="Center">INSERT_DESCRIPTION</TextBlock>

================================================
FILE: PSScriptMenuGui/xaml/start.xaml
================================================
<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="INSERT_WINDOW_TITLE" Icon="INSERT_ICON_PATH" SizeToContent="WidthAndHeight" MaxHeight="800" MinHeight="200" MaxWidth="600" WindowStartupLocation="CenterScreen">
    <ScrollViewer Padding="10,0,10,10">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <!-- TODO: very hacky way to set maximum rows! -->
                <RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/>
            </Grid.RowDefinitions>

================================================
FILE: README.md
================================================
# PSScriptMenuGui

[![PSGallery Version](https://img.shields.io/powershellgallery/v/PSScriptMenuGui.png?style=for-the-badge&logo=powershell&label=PowerShell%20Gallery)](https://www.powershellgallery.com/packages/PSScriptMenuGui/) [![PSGallery Downloads](https://img.shields.io/powershellgallery/dt/PSScriptMenuGui.png?style=for-the-badge&label=Downloads)](https://www.powershellgallery.com/packages/PSScriptMenuGui/) [![PSGallery Platform](https://img.shields.io/powershellgallery/p/PSScriptMenuGui.png?style=for-the-badge&label=Platform)](https://www.powershellgallery.com/packages/PSScriptMenuGui/)

Do you have favourite scripts that go forgotten?

Does your organisation have scripts that would be useful to frontline staff who are not comfortable with the command line?

This module uses a CSV file to make a graphical menu of PowerShell scripts.

It's easy to customise and fast to launch.

You can also add Windows programs and files to the menu.

Just a few minutes to setup and - *click! click!* - you're away!

![](demo.gif)

## Try it out

### Tutorial

Looking for a step-by-step introduction? [**See this blog post.**](https://blog.osull.com/2019/11/06/tutorial-use-a-csv-file-to-make-a-graphical-menu-of-powershell-scripts/)

### Install from the PowerShell Gallery

    Install-Module PSScriptMenuGui -Scope CurrentUser
    New-ScriptMenuGuiExample
    cd PSScriptMenuGui_example
    .\PSScriptMenuGui.ps1

### Clone from GitHub

    git clone https://github.com/weebsnore/PowerShell-Script-Menu-Gui
    cd PowerShell-Script-Menu-Gui\PSScriptMenuGui\examples
    .\PSScriptMenuGui.ps1

## Problems and feedback

How are you finding the module? Is it useful? *(Please share a screenshot!)*

Are you stuck? Do you want a feature?

Please [open a GitHub issue](https://github.com/weebsnore/PowerShell-Script-Menu-Gui/issues) or get in touch.

[@dan_osull.com](https://twitter.com/dan_osull_com/) *- follow me for updates!*  
https://blog.osull.com  
powershell@osull.com

## Compatibility

Tested with **PowerShell 5.1 x64** and **PowerShell 7 x64** on Windows 10.

## Basic usage

    Show-ScriptMenuGui -csvPath '.\example_data.csv' -Verbose

## Show-ScriptMenuGui options

Parameter | What is it?
:--- |:---
`-csvPath` | Path to CSV file that defines the menu. See [CSV reference](#csv-reference), below.
`-windowTitle` *(optional)* | Custom title for the menu window
`-buttonForegroundColor` *(optional)* | Custom button foreground (text) color. Hex codes (e.g. `#C00077`) and color names (e.g. `Azure`) are valid. See [.NET Color Class](https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.colors).
`-buttonBackgroundColor` *(optional)* | Custom button background color
`-iconPath` *(optional)* | Path to .ico file for use in menu
`-hideConsole` *(optional)* | Hide the PowerShell console that the menu is called from. **Note:** This means you won't be able to see any errors from button clicks. If things aren't working, this should be the first thing you stop using.
`-noExit` *(optional)* | Start all PowerShell instances with `-NoExit` *("Does not exit after running startup commands.")*. **Note:** You can set `-NoExit` on individual menu items by using the *Arguments* column. See [CSV reference](#csv-reference), below.

See [`PSScriptMenuGui_all_options.ps1`](PSScriptMenuGui/examples/PSScriptMenuGui_all_options.ps1) for an example using every option.

## CSV reference

This table details how to lay out the CSV file for your menu.

The top row of your CSV should contain the column headers. Each row after this defines a menu item.

Column header | What is it?
:--- |:---
Section *(optional)* | Text for heading
Method | What happens when you click the button? Valid options: `cmd` \| `powershell_file` \| `powershell_inline` \| `pwsh_file` \| `pwsh_inline`
Command | Path to target script/executable (`cmd` or `_file` methods) ***or*** PowerShell commands (`_inline` methods)
Arguments *(optional)* | Arguments to pass to target executable (`cmd` method) ***or*** to the PowerShell exe (other methods)
Name | Text for button
Description *(optional)* | Text for description 

### Some examples

Section | Method | Command | Arguments | Name | Description
:---|:---|:---|:---|:---|:---
Old school | `cmd` | `taskmgr.exe` | | Example 2: cmd | External executable
Old school | `cmd` | `notepad.exe` | `example_text_file` | Example 3: cmd | External executable with arguments
Less old | `powershell_file` | `example_target.ps1` | | Example 4: powershell_file | .ps1 file called with powershell.exe
Less old | `powershell_inline` | `$PSVersionTable` | `-NoExit -WindowStyle Maximized` | Example 6: powershell_inline | Additional powershell.exe arguments
The future | `pwsh_file` | `example_target.ps1` | | Example 7: pwsh_file | .ps1 file called with pwsh.exe
The future | `pwsh_inline` | `& .\example_target.ps1 -Message "passed in via param"` | |Example 9: pwsh_inline | .ps1 file called with parameter

See [`example_data.csv`](PSScriptMenuGui/examples/example_data.csv) for further examples in CSV format.

### Tips

- Relative paths, network paths and paths in your environment should work.
- `<LineBreak />` is supported in text fields.
- You can add multiple `_inline` commands by separating with a semi-colon (`;`)
- Excel makes a good editor!
- But watch out for Excel turning e.g. `-NoExit` into a formula. Best workaround is to prefix with a space.

![](excel.png)
Download .txt
gitextract_c2swp2db/

├── .gitignore
├── LICENSE
├── PSScriptMenuGui/
│   ├── PSScriptMenuGui.psd1
│   ├── PSScriptMenuGui.psm1
│   ├── examples/
│   │   ├── PSScriptMenuGui.ps1
│   │   ├── PSScriptMenuGui_all_options.ps1
│   │   ├── example_data.csv
│   │   ├── example_target.cmd
│   │   ├── example_target.ps1
│   │   └── example_text_file.txt
│   ├── private/
│   │   └── functions.ps1
│   ├── public/
│   │   └── functions.ps1
│   └── xaml/
│       ├── end.xaml
│       ├── heading.xaml
│       ├── item.xaml
│       └── start.xaml
└── README.md
Condensed preview — 17 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (32K chars).
[
  {
    "path": ".gitignore",
    "chars": 9,
    "preview": ".vscode/\n"
  },
  {
    "path": "LICENSE",
    "chars": 1071,
    "preview": "MIT License\n\nCopyright (c) 2019 Dan O'Sullivan\n\nPermission is hereby granted, free of charge, to any person obtaining a "
  },
  {
    "path": "PSScriptMenuGui/PSScriptMenuGui.psd1",
    "chars": 4514,
    "preview": "#\n# Module manifest for module 'PSScriptMenuGui'\n#\n# Generated by: Dan O'Sullivan\n#\n# Generated on: 10/7/2019\n#\n\n@{\n\n# S"
  },
  {
    "path": "PSScriptMenuGui/PSScriptMenuGui.psm1",
    "chars": 850,
    "preview": "if ($PSEdition -eq 'Core') {\n    if (-not $IsWindows) {\n        throw 'This module only runs on Windows'\n    }\n    if ($"
  },
  {
    "path": "PSScriptMenuGui/examples/PSScriptMenuGui.ps1",
    "chars": 360,
    "preview": "#region Setup\nSet-Location $PSScriptRoot\nRemove-Module PSScriptMenuGui -ErrorAction SilentlyContinue\ntry {\n    Import-Mo"
  },
  {
    "path": "PSScriptMenuGui/examples/PSScriptMenuGui_all_options.ps1",
    "chars": 590,
    "preview": "#region Setup\nSet-Location $PSScriptRoot\nRemove-Module PSScriptMenuGui -ErrorAction SilentlyContinue\ntry {\n    Import-Mo"
  },
  {
    "path": "PSScriptMenuGui/examples/example_data.csv",
    "chars": 1189,
    "preview": "Section,Method,Command,Arguments,Name,Description\nOld school,cmd,.\\example_target.cmd,,Example 1:<LineBreak />cmd,.cmd f"
  },
  {
    "path": "PSScriptMenuGui/examples/example_target.cmd",
    "chars": 63,
    "preview": "@echo off\necho CMD script called from PSScriptMenuGui.ps1\npause"
  },
  {
    "path": "PSScriptMenuGui/examples/example_target.ps1",
    "chars": 165,
    "preview": "param ($message)\n\"PowerShell script called from PSScriptMenuGui.ps1\"\nif ($message) {\n    \"`$message = $message\"\n}\n$PSVer"
  },
  {
    "path": "PSScriptMenuGui/examples/example_text_file.txt",
    "chars": 11,
    "preview": "hello world"
  },
  {
    "path": "PSScriptMenuGui/private/functions.ps1",
    "chars": 6298,
    "preview": "function Hide-Console {\n    Write-Verbose 'Hiding PowerShell console...'\n    # .NET method for hiding the PowerShell con"
  },
  {
    "path": "PSScriptMenuGui/public/functions.ps1",
    "chars": 5699,
    "preview": "Function Show-ScriptMenuGui {\n    <#\n    .SYNOPSIS\n        Use a CSV file to make a graphical menu of PowerShell scripts"
  },
  {
    "path": "PSScriptMenuGui/xaml/end.xaml",
    "chars": 46,
    "preview": "        </Grid>\n    </ScrollViewer>\n</Window>\n"
  },
  {
    "path": "PSScriptMenuGui/xaml/heading.xaml",
    "chars": 138,
    "preview": "<TextBlock Text=\"INSERT_SECTION_HEADING\" TextWrapping=\"Wrap\" Grid.Row=\"INSERT_ROW\" Grid.ColumnSpan=\"2\" FontSize=\"25\" Pad"
  },
  {
    "path": "PSScriptMenuGui/xaml/item.xaml",
    "chars": 511,
    "preview": "            <Button x:Name=\"INSERT_BUTTON_NAME\" Grid.Row=\"INSERT_ROW\" Grid.Column=\"0\" Background=\"INSERT_BACKGROUND_COLO"
  },
  {
    "path": "PSScriptMenuGui/xaml/start.xaml",
    "chars": 3298,
    "preview": "<Window x:Class=\"WpfApp.MainWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xm"
  },
  {
    "path": "README.md",
    "chars": 5411,
    "preview": "# PSScriptMenuGui\n\n[![PSGallery Version](https://img.shields.io/powershellgallery/v/PSScriptMenuGui.png?style=for-the-ba"
  }
]

About this extraction

This page contains the full source code of the dan-osull/PowerShell-Script-Menu-Gui GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 17 files (29.5 KB), approximately 8.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!