Search code examples
powershelllync

Getting unassigned phone numbers for Skype for Business in powershell


Has anyone ever done something like this in powershell? I'm automating new user creation and have to set up their skype for business accounts. Here's what I have so far:

<# set up skype for business #>
Enable-CsUser -Identity $FULLNAME `
 -RegistrarPool REDACTED
 -SipAddress $SIP
Set-CsUser $FULLNAME `
 -EnterpriseVoiceEnabled $true `
 -ExchangeArchivingPolicy Uninitialized `
 -LineURI $PHONENUMBER
# only for driver manager/managers
Grant-CsConferencingPolicy $FULLNAME `
 -PolicyName $ConferencingPolicy
Grant-CsExternalAccessPolicy -identity $FULLNAME `
 -PolicyName 'Allow external access'

All I have left is the to assign the LineURI, and I can't seem to find anything about how to do that. I did, however, find a script that does this, but it doesn't seem like it's specific to my needs. My question is this: how can I query Skype for Business in powershell to grab the first unassigned number and assign it as the LineURI? I have been using New-CSUnassignedNumber but cannot seem to make any headway.


Solution

  • SfB doesn't keep a record of your number ranges, so it doesn't know if you assigning 1299 is the last in a range, or if the range stretches into the 1300's

    Get-CsUser | ? LineUri | Select LineUri | Sort
    

    this will give you a sorted list of all assigned uri's in your organization, so you'll be able to pick out ones which may be assignable, regardless you can use a number of methods to find what you're looking for, but you may be interested in this for the longer-term approach, it's a script which takes in your number ranges, and outputs a list of the used and available ones in a nice Csv.

    #region Input
    $NumRangeKeyTable = @{
        #Make sure numbers are in the same format as they are in Skype,
        #Do not include any ';ext' or 'tel:' etc. formatting!
        #Put single numbers in the format:
        #    "+35313456789" = ""
        #Put number ranges in the format:
        #    "+35313456700" = "+35313456799"
    
        "+35313456789" = ""
        "+35313456700" = "+35313456799"
    }
    
    #Save Location, set to $null to be prompted for location.
    $FileName = $null 
    #endregion
    
    #region Code
    #region Helper Functions
    Function Get-CsAssignedURIs {
    $AllNumbers = @()
    $Users = Get-CsUser
    $Users | ? {$_.LineURI -ne ""} | %{ $AllNumbers += New-Object PSObject -Property @{Name = $_.DisplayName ; SipAddress = $_.SipAddress ; Number = $_.LineURI ; Type = "User" }}
    $Users | ? {$_.PrivateLine -ne ""} | %{ $AllNumbers += New-Object PSObject -Property @{Name = $_.DisplayName ; SipAddress = $_.SipAddress ; Number = $_.PrivateLine ; Type = "PrivateLine" }}
    Get-CsRgsWorkflow | Where-Object {$_.LineURI -ne ""} | Select Name,LineURI | %{$AllNumbers += New-Object PSObject -Property @{Name = $_.Name ; SipAddress = $_.PrimaryUri ; Number = $_.LineURI ; Type = "Workflow" }}
    Get-CsCommonAreaPhone -Filter {LineURI -ne $null} | %{ $AllNumbers += New-Object PSObject -Property @{Name = $_.DisplayName ; SipAddress = $_.SipAddress ; Number = $_.LineURI ; Type = "CommonArea" }}
    Get-CsAnalogDevice -Filter {LineURI -ne $null} | %{ $AllNumbers += New-Object PSObject -Property @{Name = $_.DisplayName ; SipAddress = $_.SipAddress ; Number = $_.LineURI ; Type = "AnalogDevice" }}
    Get-CsExUmContact -Filter {LineURI -ne $null} | %{ $AllNumbers += New-Object PSObject -Property @{Name = $_.DisplayName ; SipAddress = $_.SipAddress ; Number = $_.LineURI ; Type = "ExUmContact" }}
    Get-CsDialInConferencingAccessNumber -Filter {LineURI -ne $null} | %{ $AllNumbers += New-Object PSObject -Property @{Name = $_.DisplayName ; SipAddress = $_.PrimaryUri ; Number = $_.LineURI ; Type = "DialInAccess" }}
    Get-CsTrustedApplicationEndpoint -Filter {LineURI -ne $null} | %{ $AllNumbers += New-Object PSObject -Property @{Name = $_.DisplayName ; SipAddress = $_.SipAddress ; Number = $_.LineURI ; Type = "ApplicationEndpoint" }}
    Return $AllNumbers
    }
    
    function Get-UniqueExt {
        Param(
            [string]$Uri1,
            [string]$Uri2
        )
    
        $Reg = "^([0-9+])+$"
    
        if ([string]::IsNullOrEmpty($uri1) -and [string]::IsNullOrEmpty($Uri2)) { return "Two blank strings provided" }
        if ($Uri1 -eq $Uri2) { return $Uri1 }
        if ([string]::IsNullOrEmpty($uri1)) { return $Uri2 }
        if ([string]::IsNullOrEmpty($uri2)) { return $Uri1 }
        if ($Uri1.Length -ne $Uri2.Length) { return "Strings cannot be different lengths" }
        if (($Uri1 -notmatch $Reg) -or ($Uri2 -notmatch $Reg)) { return "Strings must be in the format '0123..' or '+123..'" }
    
        ($Uri1.Length-1)..0 | % {
            if ($Uri1[$_] -ne $Uri2[$_]) { $Diff = $_ }
        }
    
        $Start = $Uri1.Substring(0,$Diff)
        $Sub1 = $Uri2.Substring($Diff)
        $Sub2 = $Uri1.Substring($Diff)
    
        if ($Sub1 -lt $Sub2) {
            $Min = $Sub1 ; $Max = $Sub2
        } else {
            $Min = $Sub2 ; $Max = $Sub1
        }
    
        $FormatStr = "" ; 1..$Min.Length | % { $FormatStr += "0"}
        $Min..$Max | % { "$($Start)$($_.ToString($FormatStr))" }
    }
    
    function Save-ToFile {
        Param(
        [Parameter(ValueFromPipeline=$True)]
        $Item = $null,
        [switch]$ReturnName,
        $ExtFilter = "*",
        $WinTitle = "Select File",
        $FileTypeDisplay = $null
        )
    
        If ($FileTypeDisplay -eq $null) {
        If ($ExtFilter -eq "*") {
            $ExtName = "All"
        } Else {
            $ExtName = (Get-Culture).TextInfo.ToTitleCase($ExtFilter)
        }} Else {
            $ExtName = (Get-Culture).TextInfo.ToTitleCase($FileTypeDisplay) }
    
        [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
        $FolderDialog = New-Object System.Windows.Forms.SaveFileDialog
        $FolderDialog.Filter = "$($ExtName) files (*.$($ExtFilter.ToLowerInvariant()))| *.$($ExtFilter.ToLowerInvariant())"
        $FolderDialog.Title = $WinTitle
        $Result = $FolderDialog.ShowDialog()
    
        If ($Result -eq "OK"){
        $Item | Out-File $FolderDialog.FileName -Append
        If ($ReturnName) { return $FolderDialog.FileName }}
        Else {
        Write-Error "No file selected" }
    }
    #endregion
    
    Function Main {
    Param ( [Hashtable]$NumRanges )
    
    #region Process Data
    $AllNums = $NumRanges.Keys | % {
        Get-UniqueExt -Uri1 $_ -Uri2 $NumRanges[$_]
    }
    $S4BNums = Get-CsAssignedURIs
    $S4BNums | % { $_.Number = ($_.Number.Split(';')[0] -ireplace "tel:","") }
    
    $KT = @{}
    
    $S4BNums | % {
        $KT[$_.Number] = $_
    }
    
    $FullRecord = $AllNums | Sort | % {
        $Number = $_
        $Type = ""
        $Name = ""
    
        if ($KT[$_] -ne $null){
            $UseDetails = $KT[$_]
            $Name = $UseDetails.Name
            $Type = $UseDetails.Type
        }
    
        [PSCustomObject]@{
            Number = $Number
            Name = $Name
            Type = $Type
        }
    }
    #endregion
    
    return $FullRecord
    }
    
    $Results = Main $NumRangeKeyTable
    
    #region Output-Data
        if ($FileName -eq $null) {
        $FileName = (Save-ToFile -Item "" -ReturnName -ExtFilter "Csv")
        }
        if ($FileName -ne $null) {
        $Results | Export-Csv -Path $FileName -NoTypeInformation
        } else { $Results | Out-GridView }
    #endregion
    #endregion