This is the continuation of
Automate PowerDesigner Using Microsoft Powershell Script -- Part One
In this article we discuss how to automate Powerdesigner GUI using Microsoft UI Automation.
I am on Windows 7 64bit environment. PowerDesigner is on 16.5.5 64bit.
Preparation
First of all, we need obtain UI Automation assemblies and several tools.
In case you have not installed MicrosoftWindows SDK for Windows 7 and .NET Framework 4 or 4.5, click the link:
Once you install the SDK, go to Start->All Programs->Microsoft SDK v7.0->Tools. We'll use
to get GUI automation information. In addition, we'll use the followingassemblies:
UIAutomationClient.dll
UIAutomationTypes.dll
WindowsBase.dll
The files can be found at
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework.
I use .Net Framework 4.5 for my testing.
Secondly, we'll use Windows PowerShell ISE as primary editor.
To start the editor, click Start button. In Search programs and files, type
Windows PowerShell ISE and hit Return.
Note: I only test my code on 64bit PowerShell ISE.
Finally, let's get familiar with several UI Automation components.
System.Windows.Automation Contains all automation APIs and definitions
System.Windows.Automation.AutomationElement Defines a window object.
System.Windows.Automation.ControlType Defines an control object type. Example: Window, Button, Pane.
System.Windows.Automation.PropertyCondition Stores condition you want to apply to an object.
System.Windows.Automation.AndCondition You have two conditions and you want both them to be true.
System.Windows.Automation.OrCondition You have two conditions and you want one of them to be true.
System.Windows.Automation.TreeScope Use this structure to define how to find an object.
Get hand-on experience
Start PowerShell ISE. Click File->New to open a new file.
Copy and paste the following code and click Run
add-type -path "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\UIAutomationClient.dll"
add-type -path "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\UIAutomationTypes.dll"
$PowerDesigner = new-object -com powerdesigner.application
Start-Sleep -Seconds 4
# The following code searches for window with title PowerDesigner
$title='PowerDesigner'
# Declare control type as window
$type=[System.Windows.Automation.ControlType]::Window
# In order to use control type Window, we need set control type property
$controlProperty=[System.Windows.Automation.AutomationElement]::ControlTypeProperty
# To find name PowerDesigner, we need set name property
$nameProperty =[System.Windows.Automation.AutomationElement]::NameProperty
# Create condition with window as search object
$typeCondition = new-object System.Windows.Automation.PropertyCondition $controlProperty, $type
# Create another condition with name( PowerDesigner) as search object
$nameCondition = new-object System.Windows.Automation.PropertyCondition $nameProperty, $title
# Create AndConditon. Make both namecodition and typecodition to be true
$andCondition = new-object System.Windows.Automation.AndCondition $typeCondition, $nameCondition
# Define how to search specified object. You can use Descendants, Children, Subtree
$descendants = [System.Windows.Automation.TreeScope]::Descendants
# In UI Automation, Window is root object. Must use root element to find window object
# The code below means find the first object which is a window and its name is PowerDesigner
$handle=[System.Windows.Automation.AutomationElement]::RootElement.FindFirst($descendants, $andCondition)
# The code below is very similar to above. It define two properties. One for menu and another for menu name File
# Then use $handle above to find the correct object.
$title='File'
$type=[System.Windows.Automation.ControlType]::MenuItem
$controlProperty=[System.Windows.Automation.AutomationElement]::ControlTypeProperty
$nameProperty =[System.Windows.Automation.AutomationElement]::NameProperty
$typeCondition = new-object System.Windows.Automation.PropertyCondition $controlProperty, $type
$nameCondition = new-object System.Windows.Automation.PropertyCondition $nameProperty, $title
$andCondition = new-object System.Windows.Automation.AndCondition $typeCondition, $nameCondition
$descendants = [System.Windows.Automation.TreeScope]::Descendants
# Important.
# Use window handle we got from above to find menu
$menu=$handle.FindFirst($descendants, $andCondition)
$pattern=[System.Windows.Automation.ExpandCollapsePattern]::Pattern
# Click menu with name File
$menu=$menu.GetCurrentPattern($pattern)
$menu.Expand()
The code starts PowerDesigner and mimics mouse click on menu File.
Look at the code carefully, it consists of two blocks, each one starting from $title=... until $descendants=...
The blocks show how UI Automation deals with a specific GUI object.
For those who are not familiar with PowerShell Script, I'll demonstrate how to embed C# or Visual Basic code
into PowerShell Script. In fact, most developers adopt this approach.
Run C# or Visual Basic in PowerShell ISE
PowerShell can run C# or Visual Basic code on the fly. The following is an example in C#
$source= @'
using System;
using System.IO;
namespace PD
{
public static class Epoch
{
public static void HelloWorld()
{
Console.WriteLine("Hello World");
}
}
}
'@
Add-Type -TypeDefinition $source -Language 'CSharp'
[PD.Epoch]::HelloWorld()
This is the equivalent code in Visual Basic:
$source= @'
Imports System
Imports System.IO
Namespace PD
Public Class Epoch
Public Shared Sub HelloWorld()
Console.WriteLine("Hello World")
End Sub
End Class
End Namespace
'@
Add-Type -TypeDefinition $source -Language 'VisualBasic'
[PD.Epoch]::HelloWorld()
Run the code in Powershell ISE:
Get Automation Object Information
Automation process needs know GUI object's name or ID (In UI Automation, it is called AutomationID).
Inspect Objects provides this information.
Clicking Start Button. Go to All Programs->Microsoft Windows SDK v7.0->Tools->Inspect Objects.
When the application starts, select UI Automation in the dropdown.
Start Powerdesigner. Mouse hovers over the GUI. Inspect Objects shows detail on object property. See screenshot below.
The value of Name and AutomationId will be used frequently in our coding.
Develop an application
I present two examples in this article.
The code is in powershellscript_test.txt.zip, attached at bottom.
Unzip the file after download. It creates powershellscript_test.txt.
Rename powershellscript_test.txt to powershellscript_test.zip
Unzip the file.
.
UIautomationLibrary.ps1 contains C# library which can be used to access many Windows GUI objects.
.
The first example is reverse engineering a database.
Open reverseEng.ps1. Modify DBMS, database account. If you are not sure what DBMS name is, go to
File->Reverse Engineer->Database. Click DBMS dropdown. Write down the name.
Close Powerdesigner instance if there is one.
Start PowerShell ISE. Execute UIautomationLibrary.ps1. Execute reverseEng.ps1
Remark:The application keeps using function find andfindById to obtain GUI object handle.
The value of the second parameter in both functions can be got from Inspect Objects.
Functions such as InvokeButton mimics mouse click on Button. All these functions belong to class
Robot under namespace PD. The definition of the class is in UIautomationLibrary.ps1
The second example is convert a LDM to PDM.
It creates an empty PDM. Open given LDM. Then mimics mouse click Tools->Generate Physical Data Model...
Executeproper pre-transformation. Generate a brand new PDM.
Then execute proper post-transformation to rename foreign key in the PDM.
Find a folder to store the following files:
project.ldm
PDMtest.xem
LDMtest.xem
Open ldm2pdm.ps1. Modify variable $workingPlace so it points to correct location.
Execute UIautomationLibrary.ps1 if you haven't done.
Execute ldm2pdm.ps1
Remark: System.windows.Forms.SendKeys belongs to Windows .Net Forms. It mimics keyboard typing.
SetFocus() and leftClick() are not part of UIAutomation. They inherit from user32.dll
Send-MailMessage , a very useful function fromPowerShell.
LDMtest.xem creates an extended attribute called ALIAS in entity level. We assign alias for each
entity and store it in ALIAS. For example, we have an entity called Customer, its alias is CUST.
We then run pre-transformation collectAliasFromLdm. It adds alias to entity name in format
entityname:alias ( example: Customer:CUST)
After PDM gets generated, PDMtest.xem will run post-transformation RenameFK to find alias from table name field.
And use alias to generate foreign key name. The screenshot below shows the final result:
Use third party product
UI Automation PowerShell Extensions is an Open Source product. It contains far more features
than my library does. For those who does GUI automation testing in daily base, this is a wonderful tool.
It can be downloaded from
http://uiautomation.codeplex.com/
This site also has good document on how to use the extension.
reverseEng2.ps1 demonstrates how to call API in the extension.
I am using UI Automation 0.8.7 Beta 3 .NET35
Open the file, we need change DBMS and database account. We also need specify the location of
UIAutomation.dll.
Develop C# project to run automation
Some programmer prefer C# or Visual Basic as develop tool. Attached is a project sample.
I use Microsoft Visual Studio Express 2012 to create the project.
Download CSharpAutomation.txt.zip.
Unzip the file. It creates CSharpAutomation.txt.
Rename file CSharpAutomation.txt to CSharpAutomation.zip.
Unzip the file.
This is C# version of reverse engineer. You need modify DBMS and database account information in the code.
Start Powerdesigner first.
Run the code.