Category: PowerShell

Second-hop PowerShell remoting with Skype for Business/Lync cmdlets

I have faced a huge issue trying to run mutliple commands via remote PowerShell on different Front End servers, but apparently if the cmdlet needs to access resources from the Back End database – the command fails with this:

Active Directory error "-2147016672" occurred while searching for domain controllers

which is a very frustrating error.

For example running Get-CsCertificate will work, as the information is saved locally on the Front End, however Test-CsDatabase -LocalService will fail with this error, because executing this from your machine (in my case in a different domain) first jumps on the Front End, then requires a token from the Front End’s AD to send to the 3rd server for authentication – the SQL Back End where the connection breaks.

I also experimented with Get-CsConnections.ps1 script, and got the same problem.

So I came up with a bit ugly, but working solution for this. It is simple – Scheduled tasks.

$trigger = New-ScheduledTaskTrigger -AtStartup
$action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument 'Import-Module SkypeForBusiness; Test-CsDatabase -LocalService | convertto-csv -notypeinformation | out-file C:\temp\db.txt' 
$principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\NETWORK SERVICE" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal
Register-ScheduledTask Test-CsDatabaseOnce -InputObject $task
Start-ScheduledTask -TaskName Test-CsDatabaseOnce
do {
    $state = (Get-ScheduledTask -TaskName Test-CsDatabaseOnce).State
    Start-Sleep -Milliseconds 200
} while ($state -eq "Running")
Get-Content C:\temp\db.txt | select -skip 1
Unregister-ScheduledTask -TaskName Test-CsDatabaseOnce -Confirm:$false

Here I create a simple task with the Network Service account and the name Test-CsDatabaseOnce, then run it, wait for the task to complete, which exports my results in csv in C:\temp\db.txt, and finally I get my results and work with them further.

Did the same thing with Get-CsConnections.ps1, however before that I had to deploy the script locally on each Front End with the simple code below:

$local_file = "C:\temp\Get-CsConnections.ps1"
$content = []::ReadAllBytes($local_file)
$remote_file = "C:\temp\Get-CsConnections.ps1"
Invoke-Command -Session $session -ScriptBlock { Param($path) [system.IO.file]::WriteAllBytes($path,$using:content) } -ArgumentList $remote_file

PowerShell get variable names from PSCustomObject

If you for example import a .csv file and loop trough it with with PowerShell, each entry is from the type PSCustomObject.

Recently I wanted to see an easy way to get the column names from the .csv file as well as the values, so I found out this very easy solution:

$csv | ForEach-Object {
 $row = $_;
 #give an array of columns for this item
 $columns = ($row.PSObject.Properties.Name);
 #gives an array of the values for this item
 $data = $row.psobject.Properties.Value;

I also wanted to do a comma separated list of the values, which I did with the following snippet:

 $commas_columns = $columns -join ",";
 $commas_data = "'{0}'" -f ($data -join "','");

Office 365 License Management for Skype for Business Online

So I had a customer recently that wanted to update licenses on multiple users but only for Skype for Business Online. As I was researching I found out that in the web panel there is no option to that in bulk. Also there is no easy option to do in the PowerShell too. So I had to come out with a simple and fast solution so that I could enable all users only for Skype for Business Online at once. Another special requirement was to ONLY enable the Skype for Business service and ONLY for users having the E3 license assigned.

As you might know, Office 365 License has multiple services in it, so you can have an E3 user with Skype enabled and another one with Skype disabled. Gets trickier because there is not option to just ‘enable’ or ‘disable’ a service for a user (as you have the option in the admin panel clicking with your mouse user after user…). The only provided way with PowerShell is to create license options, per license, specifying which services should be disabled, by default all remaining services are deemed as enabled.

First you need to get the account sku with the following command:


You will receive a table with fist collumn AccountSkuId, you need the text before the colon, so for example mytennant365:SOME_SERVICE.

I will explain how the script works first, then you can review it yourself below.

  1. I have a .csv file called files.csv with only 1 column, with the name WindowsEmailAddress, containing the SMTP addresses of the users that need to be updated
  2. Loop trough all users and and get the licenses assigned (you can have multiple licenses assigned to a user!)
  3. Loop trough all licenses and only filter the E3 one (ENTERPRISEPACK) and get all services with their status (being disabled, enabled, etc.)
  4. Create an empty array of disabled services (options)
  5. Loop trough all services and copy only the disabled plans to the new empty array with disabled options, but SKIP the Skype for Business Online one (MCOSTANDARD).
  6. Create a service license option with the disabled services (skipping the Skype for Business Online one)
  7. Assign the newly created license options to the user
$users = Import-Csv file.csv
$users | ForEach-Object {
	$upn = $_.WindowsEmailAddress;
	$l = (Get-MsolUser -UserPrincipalName $upn).Licenses;
	$l | ForEach-Object {
		if ($_.AccountSkuId -eq "mytennant365:ENTERPRISEPACK"){
			$p = $_.ServiceStatus;
			$DisabledOptions = @()
			$p | ForEach-Object {
				if ($_.ProvisioningStatus -eq "Disabled" -and $_.ServicePlan.ServiceName -ne "MCOSTANDARD"){
					$DisabledOptions += $_.ServicePlan.ServiceName
			$x = New-MsolLicenseOptions -AccountSkuId "mytennant365:ENTERPRISEPACK" -DisabledPlans $DisabledOptions
			Set-MsolUserLicense -UserPrincipalName $upn -LicenseOptions $x;