PowerShell & WPF: Marry Them For Reusable Scripts & Beautiful GUI!

This post is just to give you an idea of what is possible with PowerShell and WPF. It is not a complete solution that is ready to use. I do give you the key functions necessary to make it all work for your scenario and choices you want to make.

As an Admin and an avid PowerShell enthusiast who has developed libraries for some time, I have had situations where a GUI around a set of related scripts might help the end-user better than the scripts themselves no matter the amount of help/documentation in your scripts (like Helpdesk/Support). You still want the scripts to be independently functional for automation purposes and to help the pure command-line only user. There are also those times you just don’t have the energy to type it all out!

WPF (and Winforms to a certain extent) has traditionally been that amalgam that bridged the gap. Also, Sapien (our PowerShell User Group sponsor) has PowerShell Studio that helps you with the GUI or .exe building process around PowerShell scripts.

There are so many ways to do this but if you know C#, the easiest way to do this is to do it in Visual Studio itself with pure C# & WPF with the underlying reusable functionality powered by your own PowerShell scripts or scripts already in existing modules. Here is the GUI that I recently built for managing SQL Server logins (we manage SQL Logins with Active Directory Groups) using PowerShell scripts underneath. I cannot share this program itself for obvious reasons but can share all the ideas behind it and the XAML for this UI!

PowerShell_And_WPF_v3

What do you need?

You need a few basic things. If you are not familiar with one or more of these, please take the time to learn them. You will never regret the time you put into it! I can help you by answering basic questions or provide resource links for you on these.

  1. Visual Studio 2019 (use the free community edition if you qualify)
  2. Basic C# knowledge (recommend this YouTube series)
  3. Basic WPF knowledge (highly recommend this YouTube series)
  4. PowerShell knowledge (recommend this Stairway series or this great book)
  5. System.Management.Automation library from NuGet
  6. Entity Framework (if you plan to store data/log in SQL Server. Tutorial link)
  7. Use MVVM. Optional but recommended. (IPropertyChanged Automatic Impl.)

The GUI shown was completely built as I have outlined below using MVVM.

How to do it?

#1. Develop your PowerShell scripts

Don’t think about the UI yet. Just develop your PowerShell script library as if you would never need an GUI for it. This PowerShell script is one of the actual scripts used underneath the UI shown above to do intelligent matching and get AD Usernames from regular FirstName/LastName’s. In fact, 75% of the left half of the screen is powered by that script. In addition, some of the standard commands from the PowerShell ActiveDirectory Module are also used to get group memberships for example.

#2. Develop the GUI with WPF

Develop the GUI in WPF as if you will never use PowerShell but rather regular C# functions. The tutorial I referenced above by AngelSix is the best you can find. You will learn a lot about WPF in a few hours just like I did. In the end, you simply have to get good at nesting Grids and StackPanels effectively with the right margin spaces and alignment. You can use MVVM optionally but I recommend using it. MVVM simplifies development after the initial ramp-up. The XAML for the GUI Window shown in the screenshot above is in this post. For now, I have created a GIT gist and referenced the link to embed GitHub code later in this blog post as Listing 1.

#3. Add functions to talk to PowerShell from C#

These two static functions are the key. Let us say they are in a class called PowerShellHelper.

  1. A function to pass your PowerShell call which returns the results as a collection of PSObject objects
    • public static Collection ExecuteString(string command)
  2. A function to convert the results from #1 (PSObject collection) into a .NET DataTable
    • public static DataTable ToDataTable(Collection object data)

Both of these functions will be included later in the post (Listing 2) to not break the flow. The ToDataTable function is to make the process of working with the results easier. DataTables are very versatile. They can be bound directly to a DataGrid or you can loop through them and convert them to C# objects quite easily.

#4. Build the PowerShell calls using WPF input values and run

Now that you have the GUI and the PowerShell scripts that can run with inputs from the GUI, you just need to piece the command together and call the two functions in the previous step.

For example, let us say given the name of an AD Group input into a TextBox, you want to get and display all the members of the group using the PowerShell ActiveDirectory Module function Get-ADGroupMember. Your C# function which calls the helper functions from the previous step may look like this. Note that you don’t have to do an “Import-Module ActiveDirectory” in your call.

public static DataTable GetADGroupMembers(string adGroupName)
{
	DataTable returnValue = new DataTable();

	string command = @"
		$groupName = ""AD_GROUP_NAME"";
		Get-ADGroupMember $groupName  | Select-Object name, SamAccountName, objectClass, distinguishedName;
	";

	command = command.Replace("AD_GROUP_NAME", adGroupName);
	command = command.Replace(@"EU\", "");

	//Get the results and convert the results into a DataTable
	Collection results = PowerShellHelper.ExecuteString(command);
	DataTable dataTable = PowerShellHelper.ToDataTable(results);

	returnValue = dataTable;
	return returnValue;
}

The call to pass the TextBox input value collected in a TextBox named adGroupNameTextBox and display output in a DataGrid named adGroupMembersDataGrid, it would look like this:

public void DisplayADGroupMembers()
{
	//This is the call to PowerShell to get the AD group members
	DataTable returnVal = GetADGroupMembers(adGroupNameTextBox.text);

	//Bind the DataTable to the DataGrid
	adGroupMembersDataGrid.DataContext = returnVal.DefaultView;
}

If this was a call to your own script for example, you would have to dot-source the script in your PowerShell command and would look something like this for example

string command = @"
	. \\Path\To\My\Script\Get-ADUserNames.ps1;
	. \\Path\To\My\Script\Get-CleanADUserNames.ps1;

	#This is a simple list of full names of users to lookup the AD account for
	$userNames = ""CLEAN_USER_NAMES"";

	#Do the matching with our function and get the results back
	Get-ADUserNames -UserNames (Get-CleanADUserNames `
					-UserNamesString $userNames `
					-Separator ""`n"");
";

command = command.Replace("CLEAN_USER_NAMES", String.Join(Environment.NewLine, cleanedNames));

//Get the results and convert the results into a DataTable
Collection results = _powerShellHelper.ExecuteString(command);
DataTable dataTable = PowerShellHelper.ToDataTable(results);

#5. Fetch/Save the results to a Database

Once you get data back from PowerShell, you can also take the DataTable results and move them to C# objects which can then be persisted to the database using Entity Framework quite easily.

Let us say want to save the list of usernames we looked up using name search to a log table. It would look somewhat like this using Entity Framework

public void SaveADGroupLookedUp(DataTable adUserDataTable)
{
	//Use the EntityFramework database context already setup
	using (var context = new SQLADHelperContext())
	{
		//Loop through the rows in the DataTable
		foreach (DataRow row in adUserDataTable)
		{
			//Convert DataTable.DataRow to object of type ADUser
			//	whose structure matches the Database table with the same name
			ADUser adUserLookupLog = new ADUser(0, row.LastADUserNameLookupLogID, row.StringToMatch, row.FullName, row.Status, row.StatusMessage, row.ADUser, row.ADUserName, Environment.UserName, DateTime.Now));
		}

		context.ADUser.Add(adUserLookupLog);
		context.SaveChanges();
	}
}

Conclusion

The complexity of the C# code and XAML as well as the technologies used like MVVM may depend on the level of comfort you have. Initially you can keep it simple by doing direct code-behind (double click on button and write code). Later you can enhance it to follow best practices. As you get comfortable, you can log things to the database for audit. The references I have included in the main bullet list of requirements are some of the best resources. I have used the WPF tutorials by AngelSix and found them to be awesome. At the end of the day, it is not very complicated and as you do it, you will get it!

Listing 1: WPF XAML for GUI pictured at the top (On Git Gist)

Listing 2: PowerShell Helper (On Git Gist)

 

One thought on “PowerShell & WPF: Marry Them For Reusable Scripts & Beautiful GUI!

  1. This has been on my to-do list for over a year. Thanks for the great start!!!

    Curtis~

    Sent from Mail for Windows 10

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s