netsapiens.ps1

<#
.SYNOPSIS
    Powershell management wrapper for the Netsapiens platform
.DESCRIPTION
    Upon running the script you will be prompted for your PBX credentials. Regardless of the functions in this script you will only be able to run commands available to your scope. I.e. Office Manager, Reseller, etc.
    You will also need to populate your config.json file and store it in the same folder as this script. Otherwise the script will not function. Contact OIT support for your client ID and secret.
.EXAMPLE
Get-LastBootTime -ComputerName localhost
.LINK
www.oitvoip.com
#>


## Trap any errors
trap [Net.WebException] { continue; }
#Add Web Assembly for URL encoding
Add-Type -AssemblyName System.Web

# Get authentication credentials
$Global:Creds = $host.ui.PromptForCredential("PBX Credentials", "Please enter your portal login and password.", "", "")
# Import configuration file
Try {
    $path = Join-Path -Path $PSScriptRoot "config.json"
    $global:Config = Get-Content -Path $path -Raw | ConvertFrom-Json
}
Catch {
    Write-Host "Unable to import configuration file. Verify it has been created and in the same folder as the script."
}
# Verify that you can authenticate against the API
Try {
    get-token
    Write-Host "You have been authenticated. Please continue."
}
Catch {
    Write-Host "Unable to authenticate. Please try again"
}
## Helper Functions
Function Get-Token() {
    ## Helper function to get an access token. Required to perform calls against the API
    ## Scopes: Any
    $nsapipassword = $Creds.GetNetworkCredential().Password
    $tokenURL = "https://" + $Config.NetSapiens.fqdn + "/ns-api/oauth2/token/?grant_type=password&client_id=" + $Config.NetSapiens.clientID + "&client_secret=" + $Config.NetSapiens.clientSecret + "&username=" + $creds.UserName + "&password=" + $nsapipassword

    $response = Invoke-RestMethod $tokenURL
    $currentdate = Get-Date

    $Global:apitoken = New-Object -TypeName psobject
    $apitoken | Add-Member NoteProperty -Name accesstoken -Value $response.access_token
    $apitoken | Add-Member NoteProperty -Name expiration -Value $currentdate.AddSeconds(3600)
}
Function Check-Domain {
    ## Checks if a domain exists
    ## Scopes: Any
    param (
        [Parameter(Mandatory = $true)][String]$domain
    )
    $payload = @{
        object = 'domain'
        action = 'count'
        domain = $domain
    }    
    $res = NS-Call $payload
    If ($res.total -eq 1) {
        return $res.total
    }
    else { 
        $res = 0
        Write-Host "Domain does not exist"
        return
    }    
}
Function NS-Call {
    ## Helper function to place API calls
    ## Scopes: Any
    param (
        [Parameter(Mandatory = $true)][Hashtable]$load,
        [Parameter(Mandatory = $false)][String]$type
    )
    # Check if payload submitted
    if (!$load) {
        Write-Host -ForegroundColor Red "Invalid or missing payload. Killing application"
        exit
    }
    # NS token expires in 1 hour. Check if token is still valid. If not, request a new one
    if ((!$apitoken) -or ((get-date) -lt $apitoken.expiration)) {
        Get-Token
    }

    # Check if request is POST or GET. Set GET by default
    if (!$type) { $type = "GET" }

    # Add format descriptor in case it's missing
    if (!$load.format) { $load.add('format', 'json') }

    # Set headers
    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add("Authorization", 'Bearer ' + $apitoken.accesstoken)

    # Set request URL
    $requrl = "https://" + $Config.NetSapiens.fqdn + "/ns-api/"

    $response = Invoke-RestMethod $requrl -Headers $headers -Method $type -Body $load
    return $response
}

############### Functions ###################


## Call Center Functions
Function Count-Agents {
    ## Counts agents in a queue.
    ## Scopes: Office Manager, Call Center Manager, Reseller, Super User
    param (
        [Parameter(Mandatory = $true)][String]$domain,
        [Parameter(Mandatory = $false)][String]$queue #extension number of queue
    )
    Check-Domain $domain
    $payload = @{
        object = 'agent'
        action = 'count'
        domain = $domain
    }
    if($queue){$payload.add('queue', $queue)}
    Try {
        $res = NS-Call $payload
        return $res
    }
    Catch {
        $res = "No data returned"
        return $res
    }
}

## Call Recording Functions
Function Get-CallRecording {
    ## Determine if call recording is enabled on a device
    ## Scopes: Office Manager, Reseller, Super User
    param (
        [Parameter(Mandatory = $true)][String]$domain
    )
    Check-Domain $domain
        $payload = @{
            object = 'device'
            action = 'read'
            domain = $domain
        }      
    Try {
        $res = NS-Call $payload
        $res = $res | Select-Object -Property subscriber_name, sub_fullname, call_processing_rule | Sort-Object subscriber_name | Where-Object{$_.call_processing_rule -match "Record"}
        $res | ForEach-Object {$_.call_processing_rule = "Enabled"}
        $newtblFormat = @{Expression={$_.subscriber_name};Label="User";},
                               @{Expression={$_.sub_fullname};Label="Name";},
                               @{Expression={$_.call_processing_rule};Label="Rec Enabled";}
        return $res | Format-Table $newtblFormat
    }
    Catch {
        $res = "No data returned"
        return $res
    }
}
## Domain Functions
Function Get-Domain {
    ## Reads the properties for a single domain
    ## Scopes: Reseller, Super User
    param (
        [Parameter(Mandatory = $true)][String]$domain
    )
    Check-Domain $domain
    $payload = @{
        object = 'domain'
        action = 'read'
        domain = $domain
    }    
    $res = NS-Call $payload
    If ($res) {
        return $res
    }
    else { 
        $res = "No data returned"
        return $res
    } 

}

## Device Functions
Function Get-Devices {
    ## Returns a list of devices per domain or user.
    ## Scopes: Any
    param (
        [Parameter(Mandatory = $true)][String]$domain,
        [Parameter(Mandatory = $false)][String]$user
    )
    Check-Domain $domain
    $payload = @{
        object = 'device'
        action = 'read'
        domain = $domain
    } 
    If ($user) { $payload.add('user', $user) }
    Try {
        $newtblFormat = @{Expression={$_.subscriber_name};Label="User";},
            @{Expression={$_.mode};Label="Status";},
            @{Expression={$_.aor};Label="Device";},
            @{Expression={$_.model};Label="Model";},
            @{Expression={$_.mac};Label="Mac";},
            @{Expression={$_.received_from};Label="Public IP";},
            @{Expression={$_.contact};Label="Contact IP (Private)";},
            @{Expression={$_.registration_time};Label="Last Registration";}
        $res = NS-Call $payload | Sort-Object "subscriber_name"
        $res | ForEach-Object {
            $_.aor = $_.aor.Substring(4)
            $_.aor = $_.aor -replace $domain
            $_.aor = $_.aor -replace "@"
            $_.aor = $_.aor -replace ".video.bridge"
            $_.aor = $_.aor -replace ".conference-bridge"
            # @TODO Filter Contact IP
            #$_.contact = "stuff"
            #$contact = $_.contact
            #$a = $contact.IndexOf("@")
            #$_.contact = $a
            #$contact = $contact.Substring($a+1)
            #$b = $contact.IndexOf(";")
            #$_.contact = $contact.Substring(0,$b)
        }
        $res = $res | Format-Table $newtblFormat
        return $res
    } Catch {
        $res = "No data returned"
        return $res
    }    
}
## Number functions
Function Get-e911 {
    ## Reads all e911 numbers registered to a domain. Returns list and count of numbers.
    ## Scopes: Office Manager, Reseller, Super User
    param (
        [Parameter(Mandatory = $true)][String]$domain
    )
    Check-Domain $domain
    $payload = @{
        object = 'callidemgr'
        action = 'read'
        domain = $domain
    }
    $res = NS-Call $payload
    $didlist = @()
    $didcount = 0
    Foreach ($num in $res) {
        $curDID = $num.callid
        If ($curDID.length -eq 11) {
            $didlist += $curDID.Substring(1)
        }
        else {
            $didlist += $curDID
        }
    }
    $didlist = $didlist | select -Unique | Sort-Object
    $didcount = $didlist.count
    $didtotals = New-Object -TypeName psobject
    $didtotals | Add-Member -NotePropertyName "e911 Count" -NotePropertyValue $didcount
    $didtotals | Add-Member -NotePropertyName "e911 List" -NotePropertyValue $didlist

    if ($didtotals) { return $didtotals }else {
        $res = "No e911 numbers assigned"
        return $res
    }
}
Function Get-DIDs {
    ## Reads all DIDs in a domain. Returns list of DIDs as well as counts
    ## Scopes: Office Manager, Reseller, Super User
    param (
        [Parameter(Mandatory = $true)][String]$domain
    )
    Check-Domain $domain
    $payload = @{
        object      = 'phonenumber'
        action      = 'read'
        dialplan    = 'DID Table'
        dest_domain = $domain
    }    
    $numlist = NS-Call $payload
    $numlist = $numlist | Select-Object -Property matchrule | Sort-Object matchrule
    $didcount = 0
    $tfncount = 0
    $didlist = @()
    $tfnlist = @()

    Foreach ($num in $numlist) {
        $curDID = $num.matchrule
        If ($curDID -match "sip:1833") {
            $tfncount = $tfncount + 1
            $tfnlist += $curDID.substring(5, 10)
        }
        elseIf ($curDID -match "sip:1844") {
            $tfncount = $tfncount + 1
            $tfnlist += $curDID.substring(5, 10)
        }
        elseIf ($curDID -match "sip:1855") {
            $tfncount = $tfncount + 1
            $tfnlist += $curDID.substring(5, 10)
        }
        elseIf ($curDID -match "sip:1866") {
            $tfncount = $tfncount + 1
            $tfnlist += $curDID.substring(5, 10)
        }
        elseIf ($curDID -match "sip:1877") {
            $tfncount = $tfncount + 1
            $tfnlist += $curDID.substring(5, 10)
        }
        elseIf ($curDID -match "sip:1888") {
            $tfncount = $tfncount + 1
            $tfnlist += $curDID.substring(5, 10)
        }
        elseIf ($curDID -match "sip:1800") {
            $tfncount = $tfncount + 1
            $tfnlist += $curDID.substring(5, 10)
        }
        elseIf ($curDID -match "sip:5555") { }
        elseif ($curDID -match "sip:Conf") { }
        else {
            $didcount = $didcount + 1
            $didlist += $curDID.substring(5, 10)
        }
    }

    $didtotals = New-Object -TypeName psobject
    $didtotals | Add-Member -NotePropertyName "DID" -NotePropertyValue $didcount
    $didtotals | Add-Member -NotePropertyName "TFN" -NotePropertyValue $tfncount
    $didtotals | Add-Member -NotePropertyName "DID List" -NotePropertyValue $didlist
    $didtotals | Add-Member -NotePropertyName "TFN List" -NotePropertyValue $tfnlist

    return $didtotals
}
Function Format-DID {
    ## Helper function to format DIDs into 10 digit format
    ## Scopes: N/A
    param (
        [Parameter(Mandatory = $true)][String]$did
    )
    # Remove special characters from DID
    $did = ($did.Trim()) -replace '[\s()-]', ''
    # Remove any preceeding 1 from DID
    if (($did.Length -eq 11) -and ($did[0] -eq "1")) { $did = $did.Substring(1) }
    # Check if DID is now 10 digits
    if ($did.Length -ne 10) {
        Write-Host "Your entered DID $did is not 10 characters. Please try again."
        return
    }
    return $did
}

## User Functions
Function Get-Users {
    ## Read list of users from domain. Includes various optional filters
    ## Scopes: Office Manager, Reseller, Super User
    param (
        [Parameter(Mandatory = $true)][String]$domain,
        [Parameter(Mandatory = $false)][String]$login,       
        [Parameter(Mandatory = $false)][String]$user,     
        [Parameter(Mandatory = $false)][String]$first_name,    
        [Parameter(Mandatory = $false)][String]$last_name,    
        [Parameter(Mandatory = $false)][String]$email
    )
    Check-Domain $domain
    $payload = @{
        object = 'subscriber'
        action = 'read'
        domain = $domain
    }
    # Check for the presence of additional filters. Add to payload if used
    If ($login) { $payload.Add('login', $login) }
    If ($user) { $payload.Add('user', $user) }
    If ($first_name) { $payload.Add('first_name', $first_name) }
    If ($last_name) { $payload.Add('last_name', $last_name) }
    If ($email) { $payload.Add('email', $email) }
    $res = NS-Call $payload | Format-Table -Property User, dial_policy, Scope, First_name, Last_name, Email, Vmail_enabled, Vmail_notify, Vmail_transcribe


    If ($res) {
        return $res
    }
    else { 
        $res = "No data returned"
        return $res
    }    
}
Function Get-Contacts {
    ## Description of what function accomplishes
    ## Scopes: Basic User, Office Manager, Reseller, Super User
    param (
        [Parameter(Mandatory = $true)][String]$domain,
        [Parameter(Mandatory = $true)][String]$user
    )
    Check-Domain $domain
    $payload = @{
        object = 'contact'
        action = 'read'
        domain = $domain
        user   = $user
    }
    Try {
        $res = NS-Call $payload -type "POST"
        $newtblFormat = @{Expression = { $_.tags }; Label = "Favorites"; },
        @{Expression = { $_.first_name }; Label = "First Name"; },
        @{Expression = { $_.last_name }; Label = "Last Name"; },
        @{Expression = { $_.company }; Label = "Company"; },
        @{Expression = { $_.work_phone }; Label = "Work"; },
        @{Expression = { $_.work_phone }; Label = "Work"; },
        @{Expression = { $_.cell_phone }; Label = "Cell"; },
        @{Expression = { $_.email }; Label = "Email"; }
        return $res | Format-Table $newtblFormat
    }
    Catch {
        $res = "No data returned"
        return $res
    } 
}
Function Get-Transcription {
    ## Returns list and a total number of users with voicemail transcription enabled
    ## Scopes: Office Manager, Reseller, Super User
    param (
        [Parameter(Mandatory = $true)][String]$domain,
        [Parameter(Mandatory = $false)][String]$user
    )
    Check-Domain $domain

    $payload = @{
        object = 'subscriber'
        action = 'read'
        domain = $domain
    }
    if($user){$payload.Add('user', $user)}
    Try {
        $res = NS-Call $payload
        $res = $res | Select-Object -Property user, vmail_transcribe, vmail_notify, srv_code | Sort-Object user | Where-Object{$_.srv_code -eq ""} | Where-Object{$_.vmail_transcribe -ne ""}  | Where-Object{$_.vmail_transcribe -ne "no"}
        $obj = New-Object -TypeName psobject
        $obj | Add-Member -NotePropertyName "Users" -NotePropertyValue $res
        $obj | Add-Member -NotePropertyName "Total" -NotePropertyValue $res.users.count 
        return $obj
    }
    Catch {
        $res = "No data returned"
        return $res
    }
}

## Template Function
Function Template {
    ## Description of what function accomplishes
    ## Scopes: Basic User, Office Manager, Reseller, Super User
    param (
        [Parameter(Mandatory = $true)][String]$domain,
        [Parameter(Mandatory = $false)][String]$var1,
        [Parameter(Mandatory = $false)][String]$var2,
        [Parameter(Mandatory = $false)][String]$var3
    )
    Check-Domain $domain
    $payload = @{
        object = 'domain'
        action = 'read'
        domain = $domain
    }    
    Try {
        $res = NS-Call $payload
        return $res
    }
    Catch {
        $res = "No data returned"
        return $res
    }
}