xtrudeIoT.psm1

function Connect-XiIoT()
{
    <#
    .SYNOPSIS
        version 0.1 - Written by Dave Hocking, Nutanix SE, Jan 2019.
        Created to make PowerShell API Calls into the Nutanix Xi IoT RestAPI.

    .DESCRIPTION
        Requires:
        - A local account, created in the Xi IoT portal, at the time of writing, there was an issue with MyNutanix logins via API
        - some body (as JSON)
        - URL/URI for the call
        - method
        - some variables/switches are optional

    .EXAMPLE
    To be interactively prompted for the Xi IoT Credentials, and then return a value to be used as $token in further commands to Xi IoT
    
    Connect-XiIoT
    #>


    # Allow advanced parameter functions
    [CmdletBinding()]

    # Define the Parameters to pass the to function
    Param(
        [ValidateSet('v1.0')]
        [Parameter(Mandatory=$false)]
        [string]$apiVer="v1.0"
    )

    $header = @{"Accept" = "application/json"}
    $contentType = "application/json"

    # Check for the presence of creds, optionally capture them, saves you having to keep re-entering them
    if (!$xiIotCreds) {$global:xiIotCreds = Get-Credential -Message "Enter your Xi IoT Credentials (eMail and Password)"}

    # Construct the auth body
    $body = 
@"
    {
        "email": "$($xiIotCreds.username)",
        "password": "$($xiIotCreds.GetNetworkCredential().password)"
    }
"@

    
    # Start building the API URI
    $baseURL = "https://iot.nutanix.com/"

    # Check for the appropriate API version and handle the URI's accordingly
    if ($apiVer -eq "v1.0")
    {
        $baseURL = $baseURL+"v1.0/login"
    }

    # Test for PowerShell Core (where this was developed)
    if ($PSVersionTable.PSEdition -eq "Core")
    {
        # Insert test here for correct auth, if not clean up the creds and try again
        # Create a loop with three attempts before breaking out, cleaning up the creds on the way out!

        $response = Invoke-WebRequest -Uri $baseURL -Method POST -Headers $header -ContentType $contentType -UseBasicParsing -Body $body
    }
    else
    {
        Write-Host "Not tested for Desktop edition of PowerShell as yet..."    
    }

    # Create the global scoped var "token" that contains the auth needed
    "Bearer $(($response|ConvertFrom-Json).token)"
}

function Get-XiIotEdgeSerial()
{
    <#
    .SYNOPSIS
        version 0.1 - Written by Dave Hocking, Nutanix SE, Jan 2019.
        Created to collect the Serial Number of a deployed Xi IoT Edge.

    .DESCRIPTION
        Requires:
        - an online Xi IoT Edge, deployed and connected to the network
        - the ability to route to the deployed edge, this command uses HTTP to read the serial number

    .EXAMPLE
    Will grab the serial from the Edge VM on IP 10.21.86.1
    
    Get-XiIotEdgeSerial -edge 10.21.86.1
    #>


    # Allow advanced parameter functions
    [CmdletBinding()]

    # Define the Parameters to pass the to function
    Param(
    [Parameter(Mandatory=$true)]
    [string]$edge
    )
    
    # use the Edge's API to return it's serial number
    (Invoke-WebRequest -Uri "http://$($edge):8080/v1/sn").content
}

function Get-XiIotEdge()
{
    <#
    .SYNOPSIS
        version 0.1 - Written by Dave Hocking, Nutanix SE, Jan 2019.
        Created to make PowerShell API Calls into the Nutanix Xi IoT RestAPI.

    .DESCRIPTION
        This commandlet will fetch the Xi IoT Edge objects that a user has access to

        Requires:
        - A token for auth, from Connect-XiIot

        Optional:
        - An edge name to filter for
        - An edge ID to filter for

        Limitations:
        - Need to work on parameter set validation, to prevent BOTH id and name being specified as filters

    .EXAMPLE
    Lists all data from all Edges accessible to the logged on user
    
    Get-XiIotEdge
    

    .EXAMPLE
    Lists all the data for the Edge with the name "Sherlock_01"
    
    Get-XiIotEdge -name "Sherlock_01"


    .EXAMPLE
    Lists all the data for the Edge with the id "abcdefghijklmnopq"
    
    Get-XiIotEdge -id "abcdefghijklmnopq"

    #>


    # Allow advanced parameter functions
    [CmdletBinding()]

    # Define the Parameters to pass the to function
    Param(
        [Parameter(Mandatory=$false)]
        [string]$name,
        [Parameter(Mandatory=$false)]
        [string]$id
    )

    $body =
@"
    {
    }
"@

    
        # Set the Method for this API Call
        $method = "GET"
    
        # Create the URLs for this call
        $baseURL = "https://iot.nutanix.com/"
        $apiurl = "v1.0/edges"
        $url = "$baseURL"+"$apiurl"
    
        # Set the ContentType
        $contentType = "application/json"
    
        # Set the header, using the Connect-XiIot function
        $token = Connect-XiIoT
        $header = @{
                    "Accept" = "application/json"
                    "Authorization" = $($token)
                    }
        
        # Send the API Call
        $result = Invoke-WebRequest -Uri $url -Method $method -Headers $header -ContentType $contentType -UseBasicParsing -Body $body
        
        # Process the JSON response
        $result = ($result | ConvertFrom-Json).result

        # if no options were specified as the filter
        if(!$PSBoundParameters.ContainsKey("id") -and !$PSBoundParameters.ContainsKey("name"))
        {
            $result
        }

        # if the id was specified in the params, filter the results
        if($PSBoundParameters.ContainsKey("id"))
        {
            $result | Where-Object {$_.id -eq $id}
        }
                    
        # if the name was specified in the params, filter the results
        if($PSBoundParameters.ContainsKey("name"))
        {
            $result | Where-Object {$_.name -eq $name}
        }
}

function Get-XiIotCategories()
{
     <#
    .SYNOPSIS
        version 0.1 - Written by Dave Hocking, Nutanix SE, Jan 2019.
        Created to make PowerShell API Calls into the Nutanix Xi IoT RestAPI.

    .DESCRIPTION
        This commandlet will fetch the Xi IoT Categories that a user has access to

        Requires:
        - A token for auth, from Connect-XiIot

        Optional:
        - An category name to filter for
        - An category ID to filter for

        Limitations:
        - Need to work on parameter set validation, to prevent BOTH id and name being specified as filters

    .EXAMPLE
    Lists all data from all Categories accessible to the logged on user
    
    Get-XiIotCategories
    

    .EXAMPLE
    Lists all the data for the Category with the name "Category_01"
    
    Get-XiIotCategories -name "Category_01"

    #>


    # Allow advanced parameter functions
    [CmdletBinding()]

    # Define the Parameters to pass the to function
    Param(
        [Parameter(Mandatory=$false)]
        [string]$name,
        [Parameter(Mandatory=$false)]
        [string]$id
    )
    $body =
@"
    {
    }
"@

        
    # Set the Method for this API Call
    $method = "GET"

    # Create the URLs for this call
    $baseURL = "https://iot.nutanix.com/"
    $apiurl = "v1.0/categories"
    $url = "$baseURL"+"$apiurl"

    # Set the ContentType
    $contentType = "application/json"

    # Set the header, using the Connect-XiIot function
    $token = Connect-XiIoT
    $header = @{
                "Accept" = "application/json"
                "Authorization" = $($token)
                }
    
    # Send the API Call
    $result = Invoke-WebRequest -Uri $url -Method $method -Headers $header -ContentType $contentType -UseBasicParsing -Body $body
    
    # Process the JSON response
    $result = ($result | ConvertFrom-Json).result

    # if no options were specified as the filter
    if(!$PSBoundParameters.ContainsKey("id") -and !$PSBoundParameters.ContainsKey("name"))
    {
        $result
    }

    # if the id was specified in the params, filter the results
    if($PSBoundParameters.ContainsKey("id"))
    {
        $result | Where-Object {$_.id -eq $id}
    }
                
    # if the name was specified in the params, filter the results
    if($PSBoundParameters.ContainsKey("name"))
    {
        $result | Where-Object {$_.name -eq $name}
    }
}

function New-XiIotDataSource()
{
    <#
    .SYNOPSIS
        version 0.1 - Written by Dave Hocking, Nutanix SE, Jan 2019.
        Created to make PowerShell API Calls into the Nutanix Xi IoT RestAPI.

    .DESCRIPTION

        Requires:
        - A token for auth, from Connect-XiIot
        - A Name for the Data Source
            e.g. "Warehouse Cameras"
        - An Edge ID to associate with, from (Get-XiIotEdge).id
        - A DataSource IP address
        - A Protocol selection of RTSP or MQTT (see caveats)
        - A "Data Type" Category, with full TenantID from (Get-XiIotCategories -name "Data Type").id
            e.g. "tid-dave.hocking-cat-data-type"
        - A Field Name (Could be the same as the Name for the Data Source, if there's only one sensor/device)
            e.g. "Camera01"
        - A Field Topic (or the path in RTSP)
            e.g. rtsp://10.0.0.12/path-to-the-camera
                 "field topic" here is "path-to-the-camera"

        Optional:
        - An RTSP port number (e.g. RTSP://blah:7447)
        - A DataType Value for the source from (Get-XiIotCategories -name "Data Type").values
             e.g. "Custom","Image","Proximity", etc...
             If no option is chosen, we'll use "Custom" instead for now

        Limitations:
        - Doesn't set any username/password for the source, this must be done in the UI afterwards
        - Doesn't create datasources with Certificate Based Auth
        - Doesn't create datasources with Token Based Auth
        - Only creates Password Based Auth Data Sources
        - Only one fieldname/topic can be specified, further extractions need to be done in the UI
        - There is no validation on the Category Type specified, or that the port number is valid
        - Data Sources must be RTSP or MQTT based
        - GigeVision based data sources haven't yet been coded
        - MQTT Based sources that want to exchange certs for authentication, must currently be "finished off" in the UI
        - Only works for Sensors, not Gateways, for now
    

    .EXAMPLE
    Creates a new DataSource for a Camera "Camera01", with the description "Warehouse Camera", on 10.0.0.10
    Associated to the Edge's with the ID "abcdefghijklmnopqrstu", uses RTSP over a non-standard port (7447)
    
    New-XiIotDataSource -name "Warehouse Cams" -desc "Warehouse Cameras" -IP 10.0.0.10 -edgeID "abcdefghijklmnopqrstu"
                            -proto rtsp -port 7447 -dataTypeCategory "tid-dave.hocking-cat-data-type" -dataType "Image"
                            -fieldName "WareHouse01" -fieldTopic "aA70w5LkULbAtEVY"
    #>


    # Allow advanced parameter functions
    [CmdletBinding()]

    # Define the Parameters to pass the to function
    Param(
        [Parameter(Mandatory=$true)]
        [string]$name,
        [Parameter(Mandatory=$false)]
        [string]$desc,
        [Parameter(Mandatory=$true)]
        [string]$ip,
        [Parameter(Mandatory=$true)]
        [string]$edgeID,
        [ValidateSet('RTSP','MQTT')]
        [Parameter(Mandatory=$true)]
        [string]$proto,
        [Parameter(Mandatory=$true)]
        [string]$dataTypeCategory,
        [Parameter(Mandatory=$false)]
        [string]$port,
        [Parameter(Mandatory=$false)]
        [string]$dataType="Custom",
        [Parameter(Mandatory=$true)]
        [string]$fieldName,
        [Parameter(Mandatory=$true)]
        [string]$fieldTopic
    )

    # Conditional check for a port number, if so, concatenate with the : symbol
    if ($PSBoundParameters.ContainsKey('port'))
    {
        $port = ":$($port)"
    }

    # Define the body to send
    $body =
@"
    {
        `"edgeId`": `"$($edgeID)`",
        `"name`": `"$($name)`",
        `"type`": `"Sensor`",
        `"connection`": `"Unsecure`",
        `"selectors`": [
            {
            `"id`": `"$($dataTypeCategory)`",
            `"value`": `"$($dataType)`",
            `"scope`": [
                `"__ALL__`"
            ]
            }
        ],
        `"protocol`": `"$($proto)`",
        `"authType`": `"PASSWORD`",
        `"fields`": [
            {
            `"name`": `"$($fieldName)`",
            `"fieldType`": `"`",
            `"topic`": `"$($proto)://$($ip)$($port)/$($fieldTopic)`"
            }
        ]
    }
"@


    # Set the Method for this API Call
    $method = "POST"

    # Create the URLs for this call
    $baseURL = "https://iot.nutanix.com/"
    $apiurl = "v1.0/datasources"
    $url = "$baseURL"+"$apiurl"

    # Set the ContentType
    $contentType = "application/json"

    # Set the header, using the Connect-XiIot function
    $token = Connect-XiIoT
    $header = @{
                "Accept" = "application/json"
                "Authorization" = $($token)
                }
    
    Invoke-WebRequest -Uri $url -Method $method -Headers $header -ContentType $contentType -UseBasicParsing -Body $body
}

function New-XiIotEdge()
{
    <#
    .SYNOPSIS
        version 0.1 - Written by Dave Hocking, Nutanix SE, Jan 2019.
        Created to make PowerShell API Calls into the Nutanix Xi IoT RestAPI.

    .DESCRIPTION
        Requires:
        - A token for auth, from Connect-XiIot
        - An Edge Serial Number, from Get-XiEdgeSerial
        - An Edge IP, Subnet Mask and Gateway Address (the edge should already be connected to the internet)

    .EXAMPLE
    Creates a new Edge "Edge01", with the description "Xtrude FTW", on 10.0.0.1/24, with the gateway of 10.0.0.254
    The Edge's serial number was "abcdefghijklmnopqrstu"
    
    New-XiIotEdge -name "Edge01" -desc "Xtrude FTW" -IP 10.0.0.1 -mask 255.255.255.0 -gateway 10.0.0.254 -sn "abcdefghijklmnopqrstu"
    #>


    # Allow advanced parameter functions
    [CmdletBinding()]

    # Define the Parameters to pass the to function
    Param(
        [Parameter(Mandatory=$true)]
        [string]$name,
        [Parameter(Mandatory=$false)]
        [string]$desc,
        [Parameter(Mandatory=$true)]
        [string]$IP,
        [Parameter(Mandatory=$true)]
        [string]$mask,
        [Parameter(Mandatory=$true)]
        [string]$gateway,
        [Parameter(Mandatory=$true)]
        [string]$sn
    )

    $body =
@"
    {
        `"connected`": true,
        `"description`": `"$($desc)`",
        `"edgeDevices`": 0,
        `"gateway`": `"$($gateway)`",
        `"ipAddress`": `"$($IP)`",
        `"name`": `"$($name)`",
        `"serialNumber": `"$($sn)`",
        `"subnet`": `"$($mask)`"
    }
"@


    # Set the Method for this API Call
    $method = "POST"

    # Create the URLs for this call
    $baseURL = "https://iot.nutanix.com/"
    $apiurl = "v1.0/edges"
    $url = "$baseURL"+"$apiurl"

    # Set the ContentType
    $contentType = "application/json"

    # Set the header, using the Connect-XiIot function
    $token = Connect-XiIoT
    $header = @{
                "Accept" = "application/json"
                "Authorization" = $($token)
                }
    
    Invoke-WebRequest -Uri $url -Method $method -Headers $header -ContentType $contentType -UseBasicParsing -Body $body
}