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.
So for a US number, would it be:
$CountryCodeLength=1
#The “tel:+” string is the +5 lenght that is added in the next line
$CountryCodeLength=$CountryCodeLength+10
?
Correct!
Awesome!
Can this deal with a situation where an office has numbers in two ranges or a split range?
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.
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.
Check out Stale & Lasse’s site devoted to number management:
https://lyncnumbers.net/
That might be just what you need.
– Greig.
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
Nice one!
I’m interested in the Get-NextAvailableSFBNumber script.
Is it possible you could share the script?