Sunday, January 12, 2025

WPF GUI Using C# or PowerShell

C# and WPF (XAML) GUI


For displaying the output of Get-Process | Format-Table | Out-String in a WPF window, you have a few good options, each with its own strengths:

1. TextBox:

  • Pros: Simple to use, readily available. Handles scrolling automatically.
  • Cons: Limited formatting options. Might not preserve the table structure perfectly, especially if it involves complex formatting.

2. RichTextBox:

  • Pros: Offers more control over formatting. You can potentially retain some of the table-like structure by using tabs or other formatting.
  • Cons: Can be slightly more complex to work with than a TextBox.

3. DataGrid:

  • Pros: Excellent for displaying tabular data. If you can convert the output of Get-Process into objects, DataGrid will present them clearly in a structured grid.
  • Cons: Requires restructuring the PowerShell output into objects that the DataGrid can bind to.

4. ListView with GridView:

  • Pros: Provides a flexible way to display data in a grid-like format with customizable columns.
  • Cons: Like the DataGrid, it requires processing the output of Get-Process to fit the ListView structure.

Recommendation:

If you need to preserve the exact table formatting from Format-Table, RichTextBox might be the best choice. However, if you prioritize clear, structured presentation and are willing to convert the PowerShell output into objects, DataGrid is generally the most suitable option for displaying tabular data in WPF.

Example using DataGrid:

C#

using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Windows;

public partial class MainWindow : Window
{
   
public ObservableCollection<ProcessInfo> Processes { get; set; }

   
public MainWindow()
   {
       InitializeComponent();
       Processes =
new ObservableCollection<ProcessInfo>();
       DataContext =
this;
       LoadProcesses();
   }

   
private void LoadProcesses()
   {
       
using (PowerShell ps = PowerShell.Create())
       {
           ps.AddCommand(
"Get-Process");
           
foreach (PSObject result in ps.Invoke())
           {
               Processes.Add(
new ProcessInfo
               {
                   ProcessName = result.Properties[
"ProcessName"].Value.ToString(),
                   Id =
int.Parse(result.Properties["Id"].Value.ToString()),
                   
// Add other properties as needed
               });
           }
       }
   }
}

public class ProcessInfo
{
   
public string ProcessName { get; set; }
   
public int Id { get; set; }
   
// Add other properties as needed
}


XAML:

<Window ... >
   
<Grid>
       
<DataGrid ItemsSource="{Binding Processes}" AutoGenerateColumns="True" />
   
</Grid>
</Window>


This example demonstrates how to use DataGrid to display process information. You'll need to adjust the properties in ProcessInfo to match the ones you want to show from Get-Process.

PowerShell and XAML Script


So, the first example was using C# as a back-end language to invoke PowerShell and pass the “Get-Process” command via a string in ps.AddCommand property of the PowerShell object.  But, we can also use PowerShell as the language to load the XAML in a PowerShell session and iterate and create PSCustomObject’s for each invocation that finds each process one by one.  

Add-Type -AssemblyName PresentationFramework

# Create the XAML for the window
$xaml = @'
<Window
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="Process Viewer" Height="300" Width="500">
   <Grid>
       <DataGrid x:Name="dataGrid" AutoGenerateColumns="True" />
   </Grid>
</Window>
'@


# Create the WPF window

$window = [Windows.Markup.XamlReader]::Parse($xaml)

# Function to get process information
function Get-ProcessInfo {
   
Get-Process | ForEach-Object {
       [PSCustomObject]@{
           ProcessName =
$_.ProcessName
           Id           =
$_.Id
           
# Add other properties as needed
       }
   }
}

# Get process data
$processes = Get-ProcessInfo

# Bind the data to the DataGrid
$window.FindName("dataGrid").ItemsSource = $processes

# Show the window
$window.ShowDialog()

Step Details:

  1. Add WPF Assembly: Add-Type -AssemblyName PresentationFramework imports the necessary WPF libraries.
  2. Define XAML: The $xaml variable holds the XAML code for a simple window with a DataGrid.
  3. Create Window: [Windows.Markup.XamlReader]::Parse($xaml) creates the WPF window object from the XAML string.
  4. Get-ProcessInfo Function: This function fetches process information using Get-Process and formats it into custom objects with properties like ProcessName and Id. You can add more properties as needed.
  5. Bind Data: $window.FindName("dataGrid").ItemsSource = $processes finds the DataGrid in the window and sets its ItemsSource to the $processes collection, populating the grid.
  6. Show Window: $window.ShowDialog() displays the WPF window.

To run this code:

  1. Save it as a .ps1 file (e.g., process_viewer.ps1).
  2. Run the script from PowerShell: .\process_viewer.ps1

This will open a WPF window with a DataGrid displaying the process information.

This approach keeps the core logic in PowerShell, leveraging its capabilities for data retrieval and manipulation, while using WPF for the user interface.

Saturday, January 11, 2025

Using Visual Studio Snippets and ReSharper Options

Resolving Visual Studio Snippets Conflict with ReSharper Templates 🔧🔨

ReSharper can indeed override or conflict with Visual Studio's built-in snippet functionality because its template system takes priority. Here's how you can manage this situation and use both effectively:


✔️ Option 1: Prioritize Visual Studio Snippets

If you prefer using Visual Studio's snippets over ReSharper's templates, you can adjust the ReSharper settings:

  1. Disable ReSharper Templates Temporarily:
  • Go to ReSharper > Options.
  • Navigate to Code Editing > Templates > Live Templates.
  • Uncheck the templates that conflict with Visual Studio snippets, such as prop, for, etc.
  1. Use Explicit Visual Studio Snippet Insertion:
  • Type the snippet shortcut (e.g., prop) and press Tab twice to trigger the Visual Studio snippet explicitly.
  • Alternatively, right-click in the editor, select Insert Snippet, and choose the desired snippet.

✔️ Option 2: Customize ReSharper Templates to Mimic VS Snippets

If you like ReSharper's template system but miss certain Visual Studio snippets, you can add similar functionality to ReSharper:

  1. Create a New ReSharper Template:
  • Go to ReSharper > Tools > Templates Explorer.
  • Click the New Template button.
  • Define a template name, shortcut (e.g., prop), and the desired code.
  1. Example: Create a Property Template:
  • Template Shortcut: prop

Code template example:

private $TYPE$ $fieldName$;
public $TYPE$ $PropertyName$ {
   
get { return $fieldName$; }
   
set { $fieldName$ = value; }
}

  • Add template parameters ($TYPE$, $fieldName$, $PropertyName$) as required.
  • Save and test it in your editor.

✔️ Option 3: Use Both Snippets and Templates

If you want to keep both ReSharper and Visual Studio snippets functional, use specific shortcuts to separate their behavior:

  1. Unique Shortcuts for Snippets and Templates:
  • Change Visual Studio snippet shortcuts to something unique:
  • Open Tools > Code Snippets Manager.
  • Select a snippet and update its shortcut to avoid conflicts (e.g., change prop to vsprop).
  • Now you can use vsprop for Visual Studio snippets and prop for ReSharper templates.
  1. Invoke Snippets Explicitly via Menus:
  • Right-click and choose Insert Snippet or use the menu shortcut for Visual Studio snippets.
  • Use ReSharper's shortcuts for its templates.

✔️ Option 4: Temporarily Disable ReSharper

If you frequently need Visual Studio snippets in certain projects:

  • Disable ReSharper for Specific Sessions:
  • Go to Tools > Options > Environment > Keyboard.
  • Assign a shortcut to the command ReSharper_Suspend and ReSharper_Resume.
  • Use these shortcuts to toggle ReSharper when you need Visual Studio snippets.

This balance lets you enjoy the best of both worlds: ReSharper's advanced templates and Visual Studio's snippets. 🚀

Thursday, January 09, 2025

Basic steps to create a project workspace in Visual Studio Code

Creating a Workspace in Visual Studio Code

1. Open VS Code and Create a Folder

  • Launch Visual Studio Code.
  • Create a new folder on your computer where you'll house your project. You can do this within VS Code or using your operating system's file explorer.

2. Open the Folder in VS Code

  • File > Open Folder... Navigate to and select the folder you just created.

3. (Optional) Add More Folders to the Workspace

  • If your project involves multiple separate folders, you can add them:
  • In the VS Code Explorer (the file navigator pane on the left side), right-click in an empty area.
  • Select Add Folder to Workspace... and choose the folder you want to include.

4. Create Files

  • In the VS Code Explorer, you'll see your project folder(s).
  • To create new files:
  • Right-click on a folder and select New File.
  • Give your file a name (including the appropriate file extension, like .html, .js, .css, .py, etc.).

5. Save Your Workspace (Recommended)

  • This step is important for organizing larger projects.
  • File > Save Workspace As...
  • Choose a location and give your workspace a name (e.g., my-project.code-workspace). This creates a .code-workspace file that stores the configuration of your workspace.

Key Concepts

  • Workspace: In VS Code, a workspace is the environment where you manage your project files and folders. It can be a single folder or multiple folders.
  • .code-workspace file: This file saves the workspace configuration (folders, settings) so you can easily reopen the same project setup later.

Example: Basic Web Project

Let's say you're starting a simple website. Here's how you might set up your workspace:

  1. Create a folder named my-website.
  2. Open this folder in VS Code.
  3. Create these files within the my-website folder:
  • index.html
  • style.css
  • script.js
  1. Save the workspace as my-website.code-workspace.

Now you have a basic workspace to start building your website!

Saturday, January 04, 2025

How To Write a PowerShell Portable Function

There are a few ways to write reusable PowerShell functions:

1. Script Modules (.psm1)

*   **Create a module file:** Create a new file with a `.psm1` extension (e.g., `MyFunctions.psm1`).

*   **Write your function:** Inside this file, define your function:

```powershell
function Get-MyThing {
   # Function code here
}

```

*   **Save the module:** Save the file in a directory that PowerShell can find. Common locations include:
   *   `$env:USERPROFILE\Documents\WindowsPowerShell\Modules\`
   *   `$env:PSModulePath` (system-wide modules)
*   **Import the module:** In your other scripts, import the module using:

```powershell
Import-Module MyFunctions
```

*   **Use the function:** You can now call `Get-MyThing` in your scripts.


2. Script Files (.ps1)

*   **Create a script file:** Create a new file with a `.ps1` extension (e.g., `MyFunctions.ps1`).

*   **Write your function:** Define your function within this script file.
*   **Dot source the script:** In your other scripts, use the dot sourcing operator (`.`) to load the functions:

```powershell
. .\MyFunctions.ps1
```

*   **Use the function:** You can now call your function.


3. Module Manifests (.psd1)

*   For more complex modules with multiple functions and dependencies, use a module manifest. This is a file with a `.psd1` extension that describes the module's contents, version, and other metadata.

*   You can use the `New-ModuleManifest` cmdlet to generate a basic manifest file.

Best Practices

  • Verb-Noun Naming: Use approved verbs (get, set, new, etc.) and descriptive nouns for your function names (e.g., Get-DiskSpace).
  • Parameters: Use parameters to make your functions flexible and reusable in different situations.
  • Comment-Based Help: Add comment-based help to your functions to provide documentation.
  • Error Handling: Include error handling with try-catch blocks to make your functions robust.
  • Output: Consider what your function will output. Raw data is generally preferred for functions, so it can be piped to other commands.

Example with Parameters and Help:

PowerShell

<#

.SYNOPSIS
Gets the free disk space on a computer.

.PARAMETER ComputerName
The name of the computer to check.

.EXAMPLE
Get-FreeDiskSpace -ComputerName "MyServer"
#>

function Get-FreeDiskSpace {
   
param(
       [
string]$ComputerName = "localhost"
   )

   
try {
       
Get-WmiObject Win32_LogicalDisk -ComputerName $ComputerName |
           
Where-Object {$_.DriveType -eq 3} |
           
Select-Object DeviceID, @{Name="FreeSpaceGB";Expression={$_.FreeSpace / 1GB}}
   }
   
catch {
       
Write-Error "Failed to get disk space: $_"

   }
}


By following these guidelines, you can create well-structured, reusable PowerShell functions that will improve the efficiency and maintainability of your scripts.