Script to find Unused Numbers in Lync

Ståle Hansen has published a great PowerShell script that digs through the Lync CsUnassignedNumber list and mashes it against all of the possible uses of a number (including CsAnalogDevices, CommonAreaPhones, RGS, UMContacts and more) to report what numbers in a given number range are currently spare. It fills a yawning (and frustrating gap) in the Lync administrator’s toolkit.

We tend not to use the Unassigned Numbers feature here in Oz. Generally speaking, we’re happier letting you receive a free supervisory message from the carrier if you’ve dialled a vacant number, rather than charging you for the privilege of receiving a recorded announcement, a menu, or transferring you to an already overburdened reception.

foreach ($Serie in (Get-CsUnassignedNumber))

The real meat of Ståle’s script runs inside a loop that iterates through each entry in the Unassigned Numbers list, so it dawned on me that I could quite easily replace that with an array of my own, and then add a front-end menu so you could choose just what range you were interested in.

This is the result. All I’ve done is replace the top of the script (down to and including the line captured above), with this code. I’ve left a marker in there to show where Ståle’s original script resumes:

####################################################################################################
# List-UnusedNumbers.ps1
#
# v10 April 2011 by Ståle Hansen, Lync MVP (http://msunified.net)
#
# Thanks to Marjus Sirvinsks (http://marjuss.wordpress.com) for pointing me in the right direction
#
####################################################################################################
[System.Console]::ForegroundColor = [System.ConsoleColor]::White
clear-host

Write-Host
Write-Host "Script for finding unused numbers in Lync Server 2010, by Ståle Hansen"
Write-Host "- With menu front-end by Greig Sheridan, 2012. https://greiginsydney.com"
Write-Host
Write-Host


$Ranges = @()

#Copy and repeat the 5 lines below for each number range you have in use:
#---------------------------------------------------------------------------
$NumberRange = New-Object Object
$NumberRange | Add-Member -Type NoteProperty -name "Identity" -value "Sydney" 
$NumberRange | Add-Member -Type NoteProperty -name "NumberRangeStart" -value "tel:+61281234500"
$NumberRange | Add-Member -Type NoteProperty -name "NumberRangeEnd" -value "tel:+61281234599"
$Ranges += $NumberRange
#---------------------------------------------------------------------------

$NumberRange = New-Object Object
$NumberRange | Add-Member -Type NoteProperty -name "Identity" -value "Melbourne" 
$NumberRange | Add-Member -Type NoteProperty -name "NumberRangeStart" -value "tel:+61370001200" 
$NumberRange | Add-Member -Type NoteProperty -name "NumberRangeEnd" -value "tel:+61370001299"
$Ranges += $NumberRange


#First figure out the maximum width of the site's name (for the tabular menu):
$width=0
foreach ($Serie in ($Ranges)) {
	if ($Serie.Identity.Length -gt $width) {
		$width = $Serie.Identity.Length
	}
}

#Provide an on-screen menu of indial ranges for the user to choose from:
$index = 0
foreach ($Serie in ($Ranges)) {
	write-host ($index.ToString()).PadRight(3," "), $Serie.Identity.Padright($width+1," "), $Serie.NumberRangeStart, $Serie.NumberRangeEnd
	$index++
}
$index--	#Undo that last increment
Write-Host
write-host "Choose the range you're interested in"
$chosen = read-host "Or any other value to quit: "

if ($chosen -notmatch '^\d$') {Exit}
if ([int]$chosen -lt 0) {Exit}
if ([int]$chosen -gt $index) {Exit}

Write-Host
Write-Host "Wait while I search the entire database. This could take a while..."
Write-Host

$Selected = $Ranges[$chosen]


foreach ($Serie in ($Selected)) {


#---- Greig's note: Ståle's original script resumes from here untouched ----


#The CountryCodeLength is the length of you countrycode. For Norway this is 47 so the length is 2.
#If you want to remove more than 2 digits, change the $CountryCodeLength
$CountryCodeLength=2
#The "tel:+" string is the +5 lenght that is added in the next line
$CountryCodeLength=$CountryCodeLength+5

#Now we get the replace string so that all numbers can be converted to an int
#In the norwegian case this value becomes tel:+47
$ReplaceValue=($Serie.NumberRangeStart).Substring(0,$CountryCodeLength)

#Check to see if Unassigned Numbers are in E.164 format, if its not, continue to the next number serie
if (($ReplaceValue.Substring(0,5)) -ne "tel:+"){
Write-Host "The script requires that Unassigned Numbers are populated in E.164 format" -Foregroundcolor Yellow
Write-Host "It appears that the number range " -nonewline
Write-Host $Serie.Identity -nonewline -Foregroundcolor Green
Write-Host " is not in this format"
Write-Host
Continue
}

#To see what your $ReplaceValue is, untag the next line
#Write-Host Value to be replaced is $ReplaceValue

$NumberStart=$Serie.NumberRangeStart | ForEach-Object {$_.Replace($ReplaceValue, "")}
$NumberEnd=$Serie.NumberRangeEnd | ForEach-Object {$_.Replace($ReplaceValue, "")}

$Ser=$NumberStart..$NumberEnd

$ErrorActionPreference = 'SilentlyContinue'

$Used=Get-CsUser -Filter {LineURI -ne $Null} | Select-Object LineURI | out-string -stream
$Used+=Get-CsUser -Filter {PrivateLine -ne $Null} | Select-Object PrivateLine | out-string -stream
$Used+=Get-CsAnalogDevice -Filter {LineURI -ne $Null} | Select-Object LineURI | out-string -stream
$Used+=Get-CsCommonAreaPhone -Filter {LineURI -ne $Null} | Select-Object LineURI | out-string -stream
$Used+=Get-CsExUmContact -Filter {LineURI -ne $Null} | Select-Object LineURI | out-string -stream
$Used+=Get-CsDialInConferencingAccessNumber -Filter {LineURI -ne $Null} | Select-Object LineURI | out-string -stream
$Used+=Get-CsTrustedApplicationEndpoint -Filter {LineURI -ne $Null} | Select-Object LineURI | out-string -stream
$Used+=Get-CsRgsWorkflow | Select-Object LineURI | out-string -stream
$Used=$Used | ForEach-Object {$_.ToLower()}
$Used=$Used | ForEach-Object {$_.Replace($ReplaceValue, "")}
$Used=$Used | ForEach-Object {$_.split(';')[0]}

$ErrorActionPreference = 'Continue'

$AllUsed=@()
foreach($Series in $Ser){foreach($UsedNumber in $Used){
if($Series -eq $UsedNumber){$AllUsed+=$UsedNumber}
}
}

$ListUnUsed=@()
$ComparisonResult=compare-object $Ser $AllUsed
foreach($UnUsed in $ComparisonResult){
if($UnUsed.SideIndicator -eq '<='){$ListUnUsed+=$UnUsed.InputObject;$FreeSize++}
}

$RangeSize=($NumberEnd-$NumberStart)+1
$TotalUsed = $RangeSize-$FreeSize
$TotalFree = $RangeSize-$TotalUsed

Write-Host "Total free numbers in number range " -nonewline
Write-Host $Serie.Identity -NoNewLine -Foregroundcolor Green
Write-Host ", " -NoNewLine
Write-Host $TotalFree -NoNewLine
Write-Host " of"$RangeSize
Write-Host "This range start with " -NoNewLine
Write-Host $NumberStart -NoNewLine -Foregroundcolor Green
Write-Host " and ends with " -NoNewLine
Write-Host $NumberEnd -Foregroundcolor Green
Write-Host "To list available numbers, press "-NoNewLine
Write-Host "L" -NoNewLine -Foregroundcolor Green
$opt = Read-Host " else press Enter"

if($opt -eq "L"){$ListUnUsed}

Write-Host

$FreeSize=0
$ListUnUsed=$NULL
$UsedNumbers=$NULL
}

[System.Console]::ForegroundColor = [System.ConsoleColor]::Gray

If you’re feeling so inclined, Download this version of the script.

This is what it looks like on-screen:


Script for finding unused numbers in Lync Server 2010, by Ståle Hansen
- With menu front-end by Greig Sheridan, 2012. https://greiginsydney.com


0   Sydney     tel:+61281234500 tel:+61281234599
1   Melbourne  tel:+61370001200 tel:+61370001299

Choose the range you're interested in
Or any other value to quit: : 1

Wait while I search the entire database. This could take a while...

Total free numbers in number range Melbourne, 100 of 100
This range start with 370001200 and ends with 370001299
To list available numbers, press L else press Enter:

 

- G.

9 Comments

  1. Hi Adam.

    In the past I’ve just created multiple entries per site if the ranges aren’t contiguous. Even if they are you’ll often want to see what’s free in a given range rather than across the entire site, so I think it’s better to split them up anyway.

    This sample would create one entry for a 400-number indial range:
    —————————————————————————
    $NumberRange = New-Object Object
    $NumberRange | Add-Member -Type NoteProperty -name “Identity” -value “Sydney”
    $NumberRange | Add-Member -Type NoteProperty -name “NumberRangeStart” -value “tel:+61281234500”
    $NumberRange | Add-Member -Type NoteProperty -name “NumberRangeEnd” -value “tel:+61281234899”
    $Ranges += $NumberRange
    #—————————————————————————

    – Greig.

  2. In most cases I would tend to agree with you, however some of our dialing ranges due to a variety of issues and “special numbers” are split into 4 or 5 ranges, and that starts to get tedious to search for numbers. Another example might be our Davis center, which has 2 ranges but is only about 100 numbers in total. It would be nice to be able to consolidate.

    I figure i can either figure out how to define a range that contains multiple non contiguous blocks, be able to also define a blacklist of numbers NOT to use in a defined range, or what might be simpler is some manner to select a menu item that then runs the script multiple times for multiple defined ranges.

    Ill also run this question by the Powershell guru i know, and if he has a solution Ill fwd it to you just in case you are curious.

  3. Thanks Greig
    Yours and Stales scripts were very helpful in my rework for OnBoarding Automation.

    .\Get-NextAvailableSFBNumber.ps1 Vic
    tel:+61*****25701;ext=25701

    .\Get-NextAvailableSFBNumber.ps1 NSW
    tel:+61****47002;ext=47002

    .\Get-NextAvailableSFBNumber.ps1 SA
    tel:+61****37801;ext=37801

Leave a Reply

Your email address will not be published. Required fields are marked *

... and please just confirm for me that you're not a bot first: Time limit is exhausted. Please reload the CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.