1. I've got a PowerShell
Secret: Putting a
GUI on your scripts
Microsoft Services
Premier Field
Engineering
Welcome.
Microsoft Services
helps businesses
around the world
maximize their
investment in
Microsoft products
and technologies.
5. Tooling Up Scripting with Windows PowerShell
http://technet.microsoft.com/en-us/library/bb978526.aspx
Understanding Event Driven Programming - 23
http://channel9.msdn.com/Series/C-Sharp-Fundamentals-
Development-for-Absolute-Beginners/Understanding-Event-
Driven-Programming-23
XPath Tutorial
http://www.w3schools.com/xpath/default.asp
6. WPF & XAML
6
Windows Presentation Foundation (WPF) is a next-
generation presentation system for building
Windows client applications.
Extensible Application Markup Language (XAML) is
an XML-based markup language that is used to
implement an application's appearance declaratively.
It is typically used to create windows, dialog boxes,
pages, and user controls, and to fill them with
controls, shapes, and graphics…
10. Loading the
Dialog
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$XamlPath
)
[xml]$Global:xmlWPF = Get-Content -Path $XamlPath
#Add WPF and Windows Forms assemblies
try{
Add-Type -AssemblyName
PresentationCore,PresentationFramework,WindowsBase,system.windows.forms
} catch {
Throw "Failed to load Windows Presentation Framework assemblies."
}
#Create the XAML reader using a new XML node reader
$Global:xamGUI = [Windows.Markup.XamlReader]::Load((new-object
System.Xml.XmlNodeReader $xmlWPF))
#Create hooks to each named object in the XAML
$xmlWPF.SelectNodes("//*[@Name]") | %{
Set-Variable -Name ($_.Name) -Value $xamGUI.FindName($_.Name) -Scope Global
}
11. What’s in a
Name?
11
<Label Name="Label1" Content="Label"
HorizontalAlignment="Left" Margin="68,38,0,0"
VerticalAlignment="Top" Width="197"/>
<Button Name="Button1" Content="Button"
HorizontalAlignment="Left" Margin="307,41,0,0"
VerticalAlignment="Top" Width="75"/>
15. Fire the Script Set-ExecutionPolicy -ExecutionPolicy Unrestricted
Set-ExecutionPolicy : Access to the registry key
'HKEY_LOCAL_MACHINESOFTWAREMicrosoftPowerShell1Sh
ellIdsMicrosoft.PowerShell' is denied. To change the
execution policy for the default (LocalMachine) scope,
start Windows PowerShell with the "Run as
administrator" option. To change the execution policy
for the current user, run "Set-ExecutionPolicy -Scope
CurrentUser".
Kick off your HelloWorld script: .HelloWorld.ps1
** Logistics and Rules:
Cell Phones to Vibrate.
Show the BathRoom.
Set the Tone
Windows Server Admins have a lot of choices for automating routine tasks, but for those looking stay up-to-date, the lingua franca is certainly PowerShell. PowerShell is great, it allows you to deal with objects instead of just strings, has a syntax that C# and JavaScript programmers can easily relate to, and with Microsoft's heavy investments in propagating this awesome language throughout the ecosystem, you can be sure it's not going away soon.
So its settled…right? Learn PowerShell and thrive. But honestly, I didn't get in Windows to work from the Command-Line. I'm what you call a "GUI Guy". I love Windows, and as a developer I have spent more than my share of time designing beautiful interfaces for the web. I believe that good design can have a huge influence on the success or failure of the underlying code. Don't get me wrong, I love the power and speed of scripted tasks. But that's why this "secret" is so special. You don't lose anything PowerShell has to offer.
So, what do you get when you mix XML, XPath, XAML, WPF, PowerShell and a little creativity? Well, I say it's nothing short of magic. Even after you understand how it works, I hope you still get that little twinkle in your eyes that keeps the inner-Geek excited.
In order to follow along, you'll need to get a few tools. You've probably got these lying around.
What You'll need
.NET Framework 4
PowerShell (and ISE)
Visual Studio 2013 (or Visual Studio Express 2013)
Microsoft .NET Framework 4 (Web Installer)
http://www.microsoft.com/en-us/download/details.aspx?id=17851
PowerShell ISE
Windows PowerShell ISE is an optional feature and requires .Net Framework 3.51 to be installed. To install Windows PowerShell ISE on Windows Server 2008 R2, use the Add Features Wizard or run the following Powershell command:
Import-Module ServerManager; Add-WindowsFeature PowerShell-ISE
Visual Studio Express 2013 for Windows Desktop
Visual Studio Express for Windows Desktop lets you take full advantage of Windows with XAML designers, a productive IDE, and a variety of programming languages
http://www.visualstudio.com/en-us/products/visual-studio-express-vs.aspx
I'm going to presume a lot here. I'm going to assume you've got modern Windows Server Admin skills and are a proficient PowerShell scripter. I'm also going to assume you've heard of XML/Xpath, event-driven programming, and some basics about Object-Oriented Programming. If not, please get started with these resources. (Note: The mention of these resources is NOT an endorsement)
WPF Interface Fundamentals
WPF and XAML are important concepts to grasp for this methodology. To begin, let's review a bit about WPF and XAML (from the documentation) Here are some significant pieces of the documentation that should help you understand a bit more about why we are using them.
Introduction to WPF
http://msdn.microsoft.com/en-us/library/aa970268(v=vs.110).aspx
Windows Presentation Foundation (WPF) is a next-generation presentation system for building Windows client applications… a resolution-independent and vector-based rendering engine…WPF extends the core with a comprehensive set of application-development features that include Extensible Application Markup Language (XAML), WPF is included in the Microsoft .NET Framework, so you can build applications that incorporate other elements of the .NET Framework class library.
WPF exists as a subset of .NET Framework types that are for the most part located in the System.Windows namespace… you instantiate classes, set properties, call methods, and handle events, all using your favorite .NET Framework programming language. [WPF Offers] the ability to develop an application using both markup and code-behind, an experience that ASP.NET developers should be familiar with. You generally use Extensible Application Markup Language (XAML) markup to implement the appearance of an application while using managed programming languages (code-behind) to implement its behavior
XAML Overview (WPF)
http://msdn.microsoft.com/en-us/library/ms752059(v=vs.110).aspx
XAML is an XML-based markup language that is used to implement an application's appearance declaratively. It is typically used to create windows, dialog boxes, pages, and user controls, and to fill them with controls, shapes, and graphics….Since XAML is XML-based, the UI that you compose with it is assembled in a hierarchy of nested elements known as an element tree.
Once the project loads, you will see a pre-built Window. Simply Drag-N-Drop controls onto the canvas from Common WPF Controls. In the screenshot below, I've added a textbox and a button. Notice the Handles that surround the control. You are welcome to use these handles to re-size the control.
Notice the XAML in the window below the design canvas. You can see a Label and Button control added to the Grid Element. Use the XAML resource documentation if you want to get fancy, but you now have all the XAML you need to continue. Simply copy and XAML and paste it into a Notepad Window. Remove the x:Class attribute from the Window element. Leave the XML NameSpace elements (xmlns and xmlns:x), Title, Height and Width. Save the file with the .XAML extension. (ie. MyForml.XAML)
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Label Content="Label" HorizontalAlignment="Left" Margin="68,38,0,0" VerticalAlignment="Top" Width="197"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="307,41,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
To make this easier (but admittedly more complex to understand), you'll need the following helper cmdlet to load and interpret the XAML. Simply save the following text as loadDialog.ps1
LoadDialog Walkthrough
This loadDialog helper cmdlet is extremely important, so let's break it down. This cmdlet accepts one parameter. The FileName and Path of the XAML file. The contents are loaded into a Global variable (typed as XML) using the following line:
[xml]$Global:xmlWPF = Get-Content -Path $XamlPath
Next, WPF and Windows Forms Assemblies are loaded from the Framework. These allow use to make sense of the XAML to display the dialog.
Add-Type -AssemblyName PresentationCore,PresentationFramework,WindowsBase,system.windows.forms
With the power of our loaded assemblies, we load the XML variable xmlWPF as a parameter into a XmlNodeReader method, and subsequently a XamlReader. The results is loaded into a Global XAML-typed variable. Thanks to our loaded assemblies, our code now "understands" how to interpret this XAML (more in this later).
Last, we wire the XAML notes in the tree to PowerShell variables. Using the power of XPath, we scan through all the XAML tree nodes, extracting the Name Attribute. This name is passed down the pipe and turned into a Global Variable.
$xmlWPF.SelectNodes("//*[@Name]") | %{
Set-Variable -Name ($_.Name) -Value $xamGUI.FindName($_.Name) -Scope Global
}
For those of you following intently, you'll have noticed that there isn't a NAME attribute by default using Visual Studio. You'll need to add this manually. Simply enough. Simply edit the XAML file and add NAME attribute in the elements that you want to control via PowerShell. Continuing with our example, I have added name "Label1" to our label element and "Button1" to the button element in the XAML.
So, we've finally arrived. You're ready to build your HelloWorld.ps1 Of course by now, you've realized to make this work, there are actually three files involved. This may seem like a lot, but as you build multiple scripts this will make sense. So, you have your primary script named "HelloWorld.ps1", the loadDialog.ps1 helper cmdlet, and your XAML form (MyForm.XAML)
For clean separation, I recommend you store your .ps1 files in a Scripts Folder and the XAML forms in a Forms folder
To review what's going on, your original PowerShell scripts calls the loadDialog.ps1 helper cmdlet, which in turn, loads XAML form into a variable and creates matching PowerShell variables for all the elements int the tree based on the Name attribute. So, near the top of your HelloWorld.ps1 script should be a line like this:
#Required to load the XAML form and create the PowerShell Variables
.\loadDialog.ps1 -XamlPath '..\Forms\MyForm.xaml'
After this line successfully executes, we now have access to the form via PowerShell Variables
$Label1
$Button1
The properties to set and get are a matter of research on websites like MSDN, or exploring the properties window inside of Visual Studio. For example, here is an example of the button Class:
http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.button.aspx
Remember when I mentioned Event-Driven programming? At this point, you'll want to wire-up an event to the button. Here's how.
So, once the button is clicked, the code is setting the Content Property of our Label1 PowerShell variable with "Hello World". Since this wired directly to the WPF form, we get to actually see the results on our screen.
Lastly, with everything set, we are finally able to load the Window, using the ShowDialog() method of our XAML object.
This must be the last statement in you script. From that point forward, everything is controlled via the events you have configured.
Lastly, with everything set, we are finally able to load the Window, using the ShowDialog() method of our XAML object.
This must be the last statement in you script. From that point forward, everything is controlled via the events you have configured.
Methods like this don’t come along by chance. This mountain top of PowerShell GUI is viewed on the shoulders of giant minds. My heartfelt thanks go to the engineering rock stars who made this possible, Microsoft Senior Premier Field Engineers Mike Melone and Don Scott.
The methodology to create a PowerShell GUI is somewhat advanced, but not beyond the reach of those who spend a great deal of time coding PowerShell solutions for others to use. I have personally used this method to create input validation and control the choices of input from my users. This is a very basic example, but WPF forms can be very sophisticated, that's the fun part, the creativity you bring that will help empower and guide others to be successful, without getting 'stuck' at the command-line.