Get-CSInstalledClient

By | February 27, 2016

While working on some slides for my upcoming session: Path to Skype for Business client deployment on The Skype Show: http://www.theskypeshow.com/episode-3-backing-up-desktop-client-and-security/ I wanted to come up with a few lines of code to list how the Skype for Business/Lync client was deployed to a computer. There’s quite a few options these days standalone, basic, part of Office, not to mention the versions and builds on top of that.

The most consistent way for detection is checking the registry for uninstall keys. These keys are located under:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
  • HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

The client edition formats are as follows:

  • Office 365 ProPlus (2013/2016): O365ProPlusRetail -en-us
  • Office 2016 Professional Plus: Office16.PROPLUS
  • Skype for Business 2016 Standalone: Office16.LYNC
  • Skype for Business 2016 Basic: Office16.LYNCENTRY
  • Office 2013 Professional Plus: Office15.PROPLUS
  • Lync 2013 Standalone: Office15.LYNC
  • Lync 2013 Basic: Office15.LYNCENTRY
  • Lync 2010: {81BE0B17-563B-45D4-B198-5721E6C665CD}
  • Office Communicator 2007 R2: {0D1CBBB9-F4A8-45B6-95E7-202BA61D7AF4}
  • Office Communicator 2005: {BE5AD430-9E0C-4243-AB3F-593835869855}
  • *Note Office 365 includes the language in the key name.

The following few lines of code creates an array of the key formats, excludes Office 2010 Pro Plus and checks both HKey local registry locations if present.

$clientcheck =  @(
"*Uninstall\Office*.lync*",
"*Uninstall\O*ProPlus*",
"*Uninstall\{81BE0B17-563B-45D4-B198-5721E6C665CD}",
"*Uninstall\{0D1CBBB9-F4A8-45B6-95E7-202BA61D7AF4}",
"*Uninstall\{BE5AD430-9E0C-4243-AB3F-593835869855}"
)

$clientignore = "*Office14*" #Lync not part of Office 2010 Pro Plus

Foreach($pattern in $clientcheck){
	Get-ChildItem -Path HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Get-Item | ?{$_.name -like $pattern -and $_.name -notlike $clientignore} | Get-itemproperty | Sort-Object -Property DisplayName | Select-Object -Property DisplayName, DisplayVersion
	if (Test-path HKLM:SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall) {
		Get-ChildItem -Path HKLM:SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-Item | ?{$_.name -like $pattern -and $_.name -notlike $clientignore} | Get-itemproperty | Sort-Object -Property DisplayName | Select-Object -Property DisplayName, DisplayVersion
	}
}

gsi1

The above works well when querying the local computer, slightly modified to report from a login script or even an uninstall old client routine. But that’s boring, so I wanted the ability to query on demand remotely.

The following script is a function that you can pass a list of computers and remotely check the installed client, generates a log of results and leaves an object to query on. I also added some code to attempt starting the Remote Registry services if unable to connect.

The script can be found on TechNet Gallery:
Script Download: Get-CSInstalledClient.ps1 https://gallery.technet.microsoft.com/Get-CSInstalledClient-687d0afe

Outside the script I generate a list of computer FQDNs, this can be created manually or use your favorite Active Directory computer query. Example:

$ComputerFile="C:\temp\computers.txt"
Import-Module ActiveDirectory
Get-ADComputer -SearchBase 'OU=Corporate,DC=domain,DC=com' -Filter 'ObjectClass -eq "Computer"' | Select -Expand DNSHostName | out-file $ComputerFile -append

I recommend reviewing the computer list and cleaning out items that are not expected to return results (decommissioned, non-windows, servers…). This will greatly decrease the script’s run time as it won’t be waiting for timeouts and attempting remote registry starts.

Get-CSInstalledClient log file:
gsi3

Get-CSInstalledClient console output:
gsi2

Script Download: Get-CSInstalledClient.ps1 https://gallery.technet.microsoft.com/Get-CSInstalledClient-687d0afe

Leave a Comment