by  Pavlo Vedilin

Skype Automation: Bulk Renaming of Contacts with PowerShell

clock-icon-white  10 min read

Struggling with Skype contacts? Wondering how to turn a boring and time-consuming task into an automated process? Here’s a solution with PowerShell and a small additional library.

Test automation is one of the prime topics to discuss among IT-guys. And this is no surprise: test automation tools and services have improved to the point where they are recognized by companies all over the world as a highly reliable and cost-effective means to improve quality control.

Imagine that you have a boring and time-consuming task that you do not want to do manually. Will you overcome your reluctance, or will you have a go at advanced automation tools already incorporated in Windows, accomplishing your task without buying and installing a ton of software, but just adding a pinch of the IT-magic? We all know you’d opt for the latter option. So let me show you hocus-pocus with PowerShell and a small additional library.

Suppose you were adding your co-workers to your skype account with a “MyWorkCollea gues:” prefix, but suddenly you found out that “CoWorkers:” functions much better. Now you have to rename a few hundred contacts in your skype account. Everyone hates this nitpicking task and the first thing that comes into your mind is to use some kind of API. Now, here comes the tragic part: Skype Kit (that’s how its API used to be called) was discontinued in mid-2013 and is no longer accessible. Looks like the only way out is the UI interaction. And that’s what we pin our hopes on.

Tools Used

First things first: let’s select the tools:

  • UI Automation PowerShell Extensions – a module based on the MS UI Automation Library that allows GUI interaction from PowerShell
  • UI Automation Verify (UIA Verify) – a framework for testing MS UI Automation Provider controls. It contains Visual UI Automation Verify (Visual UIA Verify), the graphical user interface tool that will be used for control identification
  • .NET v.3.5, PowerShell – if you are running a Windows7 or later these have to be already installed on your device

Laying the Groundwork

Tools

The first step is to download all the necessary software. What we need is to navigate to any tool page from the above, and then click the ‘Downloads’ tab. For PowerShell Extensions select a ‘Recommended Download’: ‘UIAutomation 0.8.7 Beta 3 .NET35’. Since for UIA Verify ‘there is no recommended release’, choose ‘First check-in for UIA Verify’, and download the ‘UIAVerify_x86.zip’. Note that you can also try the ‘Latest version’, but it does not contain any download link because t his tool was moved to a Windows Software Development Kit, which should be downloaded and installed if you want to use its latest version. We are OK with the existing UIA Verify download.

PowerShell

For security reasons, launching unsigned scripts is not allowed in Windows by default, so in order to use PowerShell for UI automation, some initial preparations are required. As long as we are planning to write a PowerShell script, it would be good to use some sort of Integrated Development Environment (IDE), in this case PowerShell ISE. Launch it with administrative privileges:

Next, allow it to run local unsigned scripts by executing the command ‘Set-ExecutionPolicy RemoteSigned’ (read more on execution policies here):

Finally, start scripting from telling PowerShell what libraries to use. The first line of the script will contain an ‘ipmo’ command followed by the path to a ‘UIAutomation.dll’ from an unzipped ‘PowerShell Extensions’ folder:

Developing Script

For those impatient, here is a full script:


ipmo C:\UIAutomation.0.8.7B3.NET35\UIAutomation.dll

$lookFor = Read-Host 'What are we looking for? (Regular expressions are allowed)'
$replaceWith = Read-Host 'Replace it with? (Regular expressions are allowed)'

Start-Process skype;
$mainWin = Get-UIAWindow -ProcessName 'skype';
$contactsLink = $mainWin.Descendants.Hyperlinks['CONTACTS'][0];
if ($contactsLink -ne $null){
    $contactsLink.Control.Click();
}
$contactsList = $mainWin.Descendants.Lists['Contacts'][0];
$contacts = $contactsList.Descendants.ListItems;

ForEach ($contact In $contacts) {
    $contact.Select();
    $contactNameValue = $contact.Current.Name.Split("{,}")[0];
    $newContactNameValue = $contactNameValue -replace $lookFor,$replaceWith
    $renameMenuItem = $contact.Control.InvokeContextMenu().Descendants.MenuItems[10] | Invoke-UIAButtonClick;
    $editNameInbox = $mainWin.Descendants.Edits[$contactNameValue][0];
    $editNameInbox.Value = $newContactNameValue;
    Write-Host "'$($contactNameValue)' renamed to '$($newContactNameValue)'`n"
}
$contacts[0].Select();

 
 

Now, let’s have a look at how we came up with this. ‘PowerShell Extensions’ allow us to query and interact with user interfaces through custom cmdlets and object wrappers. In this case, I was coding with ‘Object model’ known to people acquainted with one or more OOP languages, but some cmdlets with 'pipelining' were still required.

The first line of the script in the preparation part was described, and here are the next two lines:


    $lookFor = Read-Host 'What are we looking for? (Regular expressions are allowed)'
    $replaceWith = Read-Host 'Replace it with? (Regular expressions are allowed)'

 
 

Their role is to ask a user to enter two strings: the same as in in ‘Find and Replace’ function of text editors. It searches for the first line and th en replaces it with the second one. Note that it’s possible to change the message as you see fit.

The next line ‘Start-Process skype’ is rather self-explanatory: it performs the same function as a double click on Skype icon. At this point, if skype is already running and a needed user is logged in, move focus to the Skype window (it won’t work as expected if the user is not logged in).

The next mini-goal is to get a variable that represents the main window and checks if ‘Contacts’ list is displayed:


    $mainWin = Get-UIAWindow -ProcessName 'skype';
    $contactsLink = $mainWin.Descendants.Hyperlinks['CONTACTS'][0];

 
 

To get the main window variable, call a ‘Get-UIAWindow’ cmdlet and order it to return a variable representing the ‘Skype’ window. At the second line, query the main window: take all its descendants and return the first hyperlink with the name 'CONTACTS'. The trick is that if such a link exists, the ‘RECENT’ list is displayed, and we have to switch it back to 'CONTACTS'. The following lines perform the exact trick: if the contacts link is not null (was found), then click it:


    if ($contactsLink -ne $null){
        $contactsLink.Control.Click();
    }

 
 

At this point, you can pr obably ask: ‘Ok, it is clear why its name is 'CONTACTS', but how do you know that this is a hyperlink, and not a button or any other type of control?’ The answer is simple: we have checked this with ‘UIA Verify’ tool. Unzip it and launch the ‘VisualUIAVerify.exe’, then click ‘Focus Tracking’ button and move the cursor above the control you want to check. As you can see, on the screen below, it is highlighted and shown in the control hierarchy tree. Plus, there is a table that shows various properties: the name is 'CONTACTS' and the control type is ‘hyperlink’. So keep calm 

All right, we’ve got the contacts list, so the only thing left is to iterate through all the contacts and rename them. Again, we are querying the main window variable, but this time we are looking for the first list with the ‘Contacts’ name. Afterwards, we are getting all the list items from it in the same manner, and saving the results into a variable:


    $contactsList = $mainWin.Descendants.Lists['Contacts'][0];
    $contacts = $contactsList.Descendants.ListItems;

 
 

We will iterate through them with ‘ForEach’ loop:

 

ForEach ($contact In $contacts) {
    $contact.Select();
    $contactNameValue = $contact.Current.Name.Split("{,}")[0];
    $newContactNameValue = $contactNameValue -replace $lookFor,$replaceWith
    $renameMenuItem = $contact.Control.InvokeContextMenu().Descendants.MenuItems[10] | Invoke-UIAButtonClick;
    $editNameInbox = $mainWin.Descendants.Edits[$contactNameValue][0];
    $editNameInbox.Value = $newContactNameValue;
    Write-Host "'$($contactNameValue)' renamed to '$($newContactNameValue)'`n"
}

 
 

Now let see what is going on in this loop: firstly, at the top line of the loop, select the contact, scrolling it into view. The next task is to get the contacts name – and it requires some magic: the thing is that the ‘UIA Verify’ tool sees it as a combination of your name, skype name, online status and status all in one line, separated with commas. So in order to get the actual name, split it by commas and consider only the first result. This is done with ‘.Split("{,}")’ command:


&nb sp;   $contactNameValue = $contact.Current.Name.Split("{,}")[0];
 
 

Our next step is to obtain a new, modified, version of the current contact name. To achieve this, simply use a ‘-replace’ function provided by PowerShell:


    $newContactNameValue = $contactNameValue -replace $lookFor,$replaceWith
 
 

It takes two arguments: the first initial variable indicates what to look for, and then gets replaced with the second one, if found in the contact name. This function facilitates usage of regular expressions, and if you are familiar with them, you will be able to do more than just find/replace. Keep in mind that some characters (like quotes, dollar sign, square brackets, etc.) in those lines have to be ‘escaped’ (PowerShell escape symbol is the grave accent: `)

Next thing we do is to select the ‘Rename…’ menu item through clicking with the right mouse button on the current contact. It is 10th from the top. We could address it by its name, but this approach does not always work, so we assume that selecting 10th is OK in our case:


    $contact.Control.InvokeContextMenu().Descendants.MenuItems[10] | Invoke-UIAButtonClick;
 
 

Afterwards query the main window for an ‘edit inbox’ (it has the same name as our current contact), and when it is found, set its value to a new contact name. Then write a m essage to the console to figure out what was renamed and how:


    $editNameInbox = $mainWin.Descendants.Edits[$contactNameValue][0];
    $editNameInbox.Value = $newContactNameValue;
    Write-Host "'$($contactNameValue)' renamed to '$($newContactNameValue)'`n"

 
 

When these operations are complete for every contact in the contacts list, congratulations, you’re done: all the contacts in your skype account have been renamed. The last line of the script simply selects the first element of the list to return UI to its initial state indicating that the script is finished.

Conclusions

Despite the long description, this is not a complicated task to do, and you may get it done within a few hours. So if you are not a fan of handicrafts and don’t get kicks from tackling blow-by-blow manual tasks, why not trying to automate them? Get a blast while scripting!

Also, here are some useful links: