Powershell GUI

Ejemplo de un simple script con GUI.

En este tutorial, crearemos un script de PowerShell que proporciona una interfaz gráfica de usuario (GUI) para dividir un archivo CSV en varios archivos basados en un número especificado de filas.

Paso 1: Definir la Función para Dividir el Archivo

Primero, definimos una función que manejará la división del archivo CSV. Esta función requiere la ruta de origen, el número máximo de filas por archivo, la ruta de destino para los archivos de resultado y un patrón de nombre de archivo.

function splitthefile($path_source_csv, $max_number_rows, $path_result_files, $filename) {
    # Do something
}

Paso 2: Cargar las Asambleas Requeridas para la GUI

Luego cargamos las bibliotecas necesarias de .NET para crear la GUI.

Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase, System.Windows.Forms, System.Drawing

Paso 3: Personalizar el Tema y los Íconos de la GUI

La apariencia de la GUI se puede personalizar usando temas e íconos.

$ThemeFile = "$local_path\Themes\ExpressionDark.xaml"
$icon =  "$local_path\Themes\favicon.ico"

Paso 4: Crear el Diseño de la GUI Usando XAML

A continuación, definimos el diseño de la GUI con XAML. Puedes usar Visual Studio para generar el XAML de forma visual.

$inputXML = @"
<Window x:Class="csv.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"
        xmlns:local="clr-namespace:specialboackup"
        mc:Ignorable="d"
        Title="CSV Splitter" Height="300" Width="450" Icon="$icon">
        <Window.Resources>
        <ResourceDictionary>
           <ResourceDictionary.MergedDictionaries>
               <ResourceDictionary Source="$ThemeFile" />
           </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
   </Window.Resources>
   <Grid>
        <Canvas HorizontalAlignment="Left" Height="251" Margin="10,10,0,0" VerticalAlignment="Top" Width="424">
            <Button x:Name="get_source" Content="..." Canvas.Left="388" Canvas.Top="31" Width="26" Height="23" RenderTransformOrigin="-0.963,1.375"/>
            <Button x:Name="split" Content="Split" Canvas.Left="299" Canvas.Top="214" Width="74" Height="26"/>
            <TextBox x:Name="source" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="363" Canvas.Left="10" Canvas.Top="31" RenderTransformOrigin="0.5,1"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Source CSV File" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="10" Width="348" Foreground="Black"/>
            <Button x:Name="get_output" Content="..." Canvas.Left="388" Canvas.Top="82" Width="26" Height="23" RenderTransformOrigin="-0.963,1.375"/>
            <TextBox x:Name="dest" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="363" Canvas.Left="10" Canvas.Top="82" RenderTransformOrigin="0.5,1"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Output Folder" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="63" Width="348" Foreground="Black"/>
            <TextBox x:Name="rows" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="94" Canvas.Left="279" Canvas.Top="175" RenderTransformOrigin="0.5,1"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Number of rows per file" VerticalAlignment="Top" Canvas.Left="122" Canvas.Top="175" Width="137" Height="23" Foreground="Black"/>
            <TextBox x:Name="filename" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="94" Canvas.Left="279" Canvas.Top="138" RenderTransformOrigin="0.5,1"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="New File Name" VerticalAlignment="Top" Canvas.Left="122" Canvas.Top="138" Width="137" Height="23" Foreground="Black"/>
        </Canvas>
    </Grid>
</Window>
"@       

Paso 5: Analizar el XAML para Crear la GUI

La cadena XAML se procesa para crear los objetos de la GUI.

$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N'  -replace '^<Win.*', '<Window'

[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, with error: $($Error[0])`n Ensure that there are NO SelectionChanged properties (PowerShell cannot process them)"
   throw
}

Paso 6: Vincular Elementos de la GUI a Variables del Script

Localizamos todos los elementos nombrados en la GUI y los vinculamos a variables del script.

$xaml.SelectNodes("//*[@Name]") | %{"trying item $($_.Name)";
    try {Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name) -ErrorAction Stop}
    catch{throw}
    }
Function Get-FormVariables {
 if ($global:ReadmeDisplay -ne $true) {
   Write-host "If you need to reference this display again, run Get-  FormVariables" -ForegroundColor Yellow;$global:ReadmeDisplay=$true
 }
 write-host "Found the following interactable elements from our form" - ForegroundColor Cyan
 get-variable WPF*
}

Paso 7: Definir Controladores de Eventos para los Clics de Botones

Los controladores de eventos se asocian con los botones en la GUI para realizar acciones cuando se hacen clic.

$WPFget_source.Add_click({
    $WPFsource.Text=Get-File
})

$WPFget_output.Add_click({
    $WPFdest.Text=Get-Folder
})

$WPFsplit.Add_click({
    $number_rows=$WPFrows.Text.Trim() 
    $path_source=$WPFsource.Text.Trim() 
    $path_dest=$WPFdest.Text.Trim() 
    $wshell = New-Object -ComObject Wscript.Shell
    splitthefile -path_source_csv $path_source -max_number_rows $number_rows  -path_result_files $path_dest -filename $WPFfilename.text.Trim()
    $wshell.Popup("Split complete",0,"Messsage",0x1)
})

Paso 8: Mostrar la GUI

Finalmente, mostramos la GUI y esperamos a que el usuario interactúe con ella.

$Form.ShowDialog() | out-null

Script Completo de PowerShell

Aquí está el script completo de PowerShell como se describe en los pasos anteriores:


function splitthefile($path_source_csv, $max_number_rows, $path_result_files, $filename) {
 # Do something
}

Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase, System.Windows.Forms, System.Drawing 

$ThemeFile = "$local_path\Themes\ExpressionDark.xaml"
$icon =  "$local_path\Themes\favicon.ico"

$inputXML = @"
<Window x:Class="csv.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"
        xmlns:local="clr-namespace:specialboackup"
        mc:Ignorable="d"
        Title="CSV Splitter" Height="300" Width="450" Icon="$icon">
        <Window.Resources>
        <ResourceDictionary>
           <ResourceDictionary.MergedDictionaries>
               <ResourceDictionary Source="$ThemeFile" />
           </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
   </Window.Resources>
   <Grid>
        <Canvas HorizontalAlignment="Left" Height="251" Margin="10,10,0,0" VerticalAlignment="Top" Width="424">
            <Button x:Name="get_source" Content="..." Canvas.Left="388" Canvas.Top="31" Width="26" Height="23" RenderTransformOrigin="-0.963,1.375"/>
            <Button x:Name="split" Content="Split" Canvas.Left="299" Canvas.Top="214" Width="74" Height="26"/>
            <TextBox x:Name="source" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="363" Canvas.Left="10" Canvas.Top="31" RenderTransformOrigin="0.5,1"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Source CSV File" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="10" Width="348" Foreground="Black"/>
            <Button x:Name="get_output" Content="..." Canvas.Left="388" Canvas.Top="82" Width="26" Height="23" RenderTransformOrigin="-0.963,1.375"/>
            <TextBox x:Name="dest" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="363" Canvas.Left="10" Canvas.Top="82" RenderTransformOrigin="0.5,1"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Output Folder" VerticalAlignment="Top" Canvas.Left="10" Canvas.Top="63" Width="348" Foreground="Black"/>
            <TextBox x:Name="rows" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="94" Canvas.Left="279" Canvas.Top="175" RenderTransformOrigin="0.5,1"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Number of rows per file" VerticalAlignment="Top" Canvas.Left="122" Canvas.Top="175" Width="137" Height="23" Foreground="Black"/>
            <TextBox x:Name="filename" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="94" Canvas.Left="279" Canvas.Top="138" RenderTransformOrigin="0.5,1"/>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="New File Name" VerticalAlignment="Top" Canvas.Left="122" Canvas.Top="138" Width="137" Height="23" Foreground="Black"/>
        </Canvas>
    </Grid>
</Window>
"@       
 
$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N'  -replace '^<Win.*', '<Window'
 
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML

#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{
   $Form=[Windows.Markup.XamlReader]::Load( $reader )
} catch {
    Write-Warning "Unable to parse XML, with error: $($Error[0])`n Ensure that there are NO SelectionChanged properties (PowerShell cannot process them)"
    throw
}
 
$xaml.SelectNodes("//*[@Name]") | %{"trying item $($_.Name)";
    try {Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name) -ErrorAction Stop}
    catch{throw}
    }
Function Get-FormVariables {
 if ($global:ReadmeDisplay -ne $true) {
   Write-host "If you need to reference this display again, run Get-  FormVariables" -ForegroundColor Yellow;$global:ReadmeDisplay=$true
 }
 write-host "Found the following interactable elements from our form" - ForegroundColor Cyan
 get-variable WPF*
}

$WPFget_source.Add_click({
    $WPFsource.Text=Get-File
})

$WPFget_output.Add_click({
    $WPFdest.Text=Get-Folder
})

$WPFsplit.Add_click({
    $number_rows=$WPFrows.Text.Trim() 
    $path_source=$WPFsource.Text.Trim() 
    $path_dest=$WPFdest.Text.Trim() 
    $wshell = New-Object -ComObject Wscript.Shell
    splitthefile -path_source_csv $path_source -max_number_rows $number_rows  -path_result_files $path_dest -filename $WPFfilename.text.Trim()
    $wshell.Popup("Split complete",0,"Messsage",0x1)
})


$Form.ShowDialog() | out-null
Maximiliano Díaz Doglia
Últimas entradas de Maximiliano Díaz Doglia (ver todo)