Private/Sessions.ps1

<#
.SYNOPSIS
Registers a session.
 
.DESCRIPTION
Registers a session by determining Resource Provider specific information.
Utilizes the information gathered, validated, and stored in $Global:session.
The information gathered is determined by the resource type, however some resource information is general.
We do not do a lot of input validation at this point since the inputs should already have been validated in prior steps.
 
.NOTES
Initial framework author: Cale Vernon (CAVERNON)
Adapted from the works of: Hayder Sabeeh (HAALZUBA); Qing Liu (QLIU); Andy Zhao (KUZHAO)
#>


function Register-Session
{
    # Begin parsing the URI.
    # This information is used as the foundation for later finding the Resource Provider specific instance information.
    $tokens = ($Global:session.uri).Split('/')
    $sessionProperties = @{
        subscriptionID = $tokens[2]
        resourceGroup = $tokens[4]
        resourceProvider = $tokens[6]
        resourceType = $tokens[7]
        # Spaces are trimmed on the resource token as URIs copied from other tools, like ASC, tend to have a trailing space.
        resource = ($tokens[8] -Replace '\s', '')
        timespanStart = (Get-Date($Global:session.start)).ToString()
        timespanEnd = (Get-Date($Global:session.end)).ToString()
        # If the following Kusto and Jarvis time calculations are changed then you must update the Invoke-Operation functions.
        # Standard is the format commonly used by Kusto and certain dashboards. Exmaple: 020-01-01T00:00:00Z.
        timespanStartStandard = "$(Get-Date $Global:session.start -Format s)Z"
        timespanEndStandard = "$(Get-Date $Global:session.end -Format s)Z"
        # Global is the format commonly used by certain dashboards and is calculated as delta of seconds. Example: 1590969600000.
        timespanStartGlobal = ([int]((Get-Date($global:session.start))-[datetime]'2020-01-01').TotalSeconds * 1000 + 1577836800000).toString()
        timespanEndGlobal = ([int]((Get-Date($global:session.end))-[datetime]'2020-01-01').TotalSeconds * 1000 + 1577836800000).toString()
    }
    $Global:session | Add-Member -NotePropertyMembers $sessionProperties

    # Begin using actual resource location processes.
    Switch ($Global:session.resourceType) {
        <########################################
        # Start: AFW instance selection.
        #########################################>

        'azureFirewalls' {
            # Locate instances of the resource.
            Write-Console "Searching for instances of $($Global:session.resource)..."
            $query = "
                cluster('Hybridnetworking').database('GatewayManager').SecureGatewayTable
                | where CustomerSubscriptionId has '$($Global:session.subscriptionID)' and GatewayName has '$($Global:session.resource)'
                | order by Timestamp desc
                | project Timestamp, CustomerSubscriptionId, GatewayId, GatewayName, Location, ResourceGroup, SubnetId, Version, TenantSubscriptionId, SkuName, SkuTier, VnetSubscriptionId
            "

            $instances = Invoke-Kusto -KustoCluster 'HybridNetworking' -KustoDatabase 'GatewayManager' -Query $query
            # Instances were found; begin instance selection and session creation.
            If ($instances) {
                $instance = $instances | Out-GridView -Title "[Nanite] Please select an instance of $($Global:session.resource):" -OutputMode Single
                If (!$instance) {
                    Write-Console "No instances of $($Global:session.resource) were selected."
                    Return
                }
                Else {
                    Write-Console -Message 'Executing additional sub-queries...'
                    # Look up the region's Shoebox name to be used in certain operations such as VMDash.
                    $query = "
                        cluster('azcrp').database('crp_allprod').VMApiQosEvent
                        | where TIMESTAMP > ago(30d)
                        | where resourceGroupName == 'armrg-$($instance.gatewayID)'
                        | where subscriptionId == '$($instance.TenantSubscriptionID)'
                        | where fabricTenantName != ''
                        | distinct fabricTenantName, fabricCluster
                        | join kind=leftouter(
                            cluster('azurecm').database('AzureCM').LogContainerSnapshot
                            | where TIMESTAMP > ago(30d)
                        )on `$left.fabricTenantName == `$right.tenantName
                        | distinct fabricTenantName, fabricCluster, Tenant
                    "

                    $tenants = Invoke-Kusto -KustoCluster 'azcrp' -KustoDatabase 'crp_allprod' -Query $query
                    $query = "
                        cluster('azcrp').database('crp_allprod').VMApiQosEvent
                        | where TIMESTAMP > ago(30d)
                        | where resourceGroupName == 'armrg-$($instance.gatewayID)'
                        | where subscriptionId == '$($instance.TenantSubscriptionID)'
                        | where fabricTenantName != ''
                        | distinct fabricTenantName, fabricCluster
                        | join kind=leftouter(
                            cluster('azurecm').database('AzureCM').LogContainerSnapshot
                            | where TIMESTAMP >=datetime('$($Global:session.timespanStartStandard)') and TIMESTAMP <=datetime('$($Global:session.timespanEndStandard)')
                            | where Tenant !contains 'TMBOX'
                            | extend ostype=tostring(split(billingType,'|',0)[0])
                            )on `$left.fabricTenantName == `$right.tenantName
                        | summarize STARTTIME=min(TIMESTAMP), ENDTIME=max(TIMESTAMP) by nodeId, containerId, roleInstanceName, tenantName, Tenant, billingType, containerType, ostype, virtualMachineUniqueId, subscriptionId, Region
                        | project STARTTIME, ENDTIME, nodeId, containerId, roleInstanceName, tenantName, Tenant, containerType, ostype, virtualMachineUniqueId, subscriptionId, Region
                        | extend NodeIdUpper=toupper(nodeId)
                        | join kind=leftouter(cluster('aznwcc').database('aznwmds').Servers) on `$left.NodeIdUpper == `$right.NodeId
                        | join kind=leftouter(cluster('aznwcc').database('aznwmds').DeviceInterfaceLinks) on `$left.DeviceName == `$right.StartDevice
                        | join kind=leftouter(cluster('aznwcc').database('aznwmds').DeviceStatic) on DeviceName
                        | join kind=leftouter(cluster('aznwcc').database('aznwmds').DeviceIpInterface | where AddressesV4 != '') on DeviceName
                        | distinct STARTTIME, ENDTIME, nodeId, AddressesV4, EndDevice, EndPort, containerId, roleInstanceName, tenantName, Tenant, ostype , containerType, DataCenter ,virtualMachineUniqueId , Region, subscriptionId
                        | order by roleInstanceName asc, STARTTIME asc
                    "

                    $firewallInstances = Invoke-Kusto -KustoCluster 'azcrp' -KustoDatabase 'crp_allprod' -Query $query
                    Write-Console -Message "Creating session information for the selected instance of $($Global:session.resource)..."
                    $instanceProperties = @{
                        customerSubscriptionId = $instance.CustomerSubscriptionId
                        gatewayID = $instance.GatewayID
                        gatewayName = $instance.GatewayName
                        location = $instance.Location
                        subnetID = $instance.SubnetId
                        version = $instance.Version
                        tenantSubscriptionID = $instance.TenantSubscriptionID
                        skuName = $instance.skuName
                        skuTier = $instance.skuTier
                        vnetSubscriptionId = $instance.VnetSubscriptionId
                        tenants = $tenants | Select-Object fabricTenantName, fabricCluster, Tenant
                        instances = $firewallInstances | Select-Object STARTTIME, ENDTIME, nodeId, AddressesV4, EndDevice, EndPort, containerId, roleInstanceName, tenantName, Tenant, ostype, containerType, DataCenter, virtualMachineUniqueId, Region, subscriptionId
                    }
                    $Global:session | Add-Member -NotePropertyMembers $instanceProperties
                    Write-Console -Message "URI: $($Global:session.uri)"
                    Write-Console -Message "Gateway Name: $($Global:session.gatewayName)"
                    Write-Console -Message "Gateway Version: $($Global:session.version)"
                    Write-Console -Message "Gateway ID: $($Global:session.gatewayID)"
                    Write-Console -Message "SKU Name: $($Global:session.skuName)"
                    Write-Console -Message "SKU Tier: $($Global:session.skuTier)"
                    Write-Console -Message "Subnet Resource ID: $($Global:session.subnetID)"
                    Write-Console -Message "Location: $($Global:session.Location)"                   
                    $i = 0
                    ForEach ($tenant in $Global:session.tenants) {
                        Write-Console -Message "Tenant #$($i + 1)"
                        Write-Console -Message "- Deployment ID: $($tenant.fabricTenantName)"
                        Write-Console -Message "- Fabric GeoID Name: $($tenant.Tenant)"
                        $firewallInstances = $Global:session.instances | Where-Object { $_.Tenant -eq $tenant.Tenant }
                        $i2 = 0
                        ForEach ($firewallInstance in $firewallInstances) {
                            Write-Console -Message "- Instance #$($i2 + 1)"
                            Write-Console -Message "-- Container ID: $($firewallInstance.containerID)"
                            Write-Console -Message "-- Node ID: $($firewallInstance.nodeID)"
                            Write-Console -Message "-- Role Instance Name: $($firewallInstance.roleInstanceName)"
                            Write-Console -Message "-- Node IP: $($firewallInstance.AddressesV4)"
                            $i2++
                        }
                        $i++
                    }
                }
            }
            # No instances were found.
            Else {
                Invoke-NoInstancesFound
                Return
            }
            # Break out of the Switch statement.
            Break
        }
        <########################################
        # End: AFW instance selection.
        #########################################>

        
        <########################################
        # Start: AKS instance selection.
        #########################################>

        'managedClusters' {
            Write-Console "Searching for instance information for $($Global:session.resource)..."
            $query = "
                cluster('aks').database('AKSprod').BlackboxMonitoringActivity
                | where PreciseTimeStamp > ago(10d)
                | where subscriptionID == '$($Global:session.subscriptionID)' and resourceGroupName has '$($Global:session.resourceGroup)' and clusterName has '$($Global:session.resource)'
                | summarize by fqdn, resourceGroupName, resourceName, underlayName
            "

            $instances = Invoke-Kusto -KustoCluster 'aks' -KustoDatabase 'AKSprod' -Query $query
            $instanceProperties = @{
                blackBox = $instances.fqdn
                cluster = $Global:session.resource
                underlay = $instances.underlayName
            }
            $Global:session | Add-Member -NotePropertyMembers $instanceProperties
            Write-Console -Message "Creating session information for $($Global:session.resource)..."
            Write-Console -Message "URI: $($Global:session.uri)"
            Write-Console -Message "Cluster: $($Global:session.resource)"
            Write-Console -Message "Black Box FQDN: $($Global:session.blackBox)"
            Write-Console -Message "Underlay: $($Global:session.underlay)"
            # Break out of the Switch statement.
            Break
        }
        <########################################
        # End: AKS instance selection.
        #########################################>

        
        <########################################
        # Start: ANF instance selection.
        #########################################>

        'netAppAccounts' {
            Write-Console "Searching for instance information for $($Global:session.resource)..."
            $instanceProperties = @{
                account = $Global:session.resource
                capacityPool = $tokens[10]
                volume = $tokens[12]
                snapshot = $tokens[14]
            }
            $Global:session | Add-Member -NotePropertyMembers $instanceProperties
            Write-Console -Message "Creating session information for $($Global:session.resource)..."
            Write-Console -Message "URI: $($Global:session.uri)"
            Write-Console -Message "NetApp Account: $($Global:session.resource)"
            Write-Console -Message "Capacity Pool: $($Global:session.capacityPool)"
            # Break out of the Switch statement.
            Break
        }
        <########################################
        # End: ANF instance selection.
        #########################################>


        <########################################
        # Start: ExR instance selection.
        #########################################>

        'expressRouteCircuits' {
            # Locate instances of the resource.
            Write-Console "Searching for instances of $($Global:session.resource)..."
            $query = "
                cluster('aznw').database('aznwcosmos').['ExpressRoute.CircuitTable']
                | where NrpResourceUri endswith '$($Global:session.uri)'
                | summarize arg_max(Timestamp, *) by AzureServiceKey, CircuitName, CircuitType, ServiceProviderName, Location, Bandwidth, BillingType, CreationTime, NumberOfConfiguredLinks, PrimaryDeviceName, SecondaryDeviceName, NrpResourceUri
                | project Timestamp, CreationTime, AzureServiceKey, CircuitName, CircuitType, ServiceProviderName, Location, Bandwidth, BillingType, NumberOfConfiguredLinks, PrimaryDeviceName, SecondaryDeviceName, NrpResourceUri
            "

            $instances = Invoke-Kusto -KustoCluster 'aznw' -KustoDatabase 'aznwcosmos' -Query $query
            # Instances were found; begin instance selection and session creation.
            If ($instances) {
                $instance = $instances | Out-GridView -Title "[Nanite] Please select an instance of $($Global:session.resource):" -OutputMode Single
                If (!$instance) {
                    Write-Console "No instances of $($Global:session.resource) were selected."
                    Return
                }
                Else {
                    Write-Console -Message 'Executing additional sub-queries...'
                    # Look up the region's Shoebox name to be used in certain operations such as VMDash.
                    $query = "
                        cluster('aznw').database('aznwcosmos').['ExpressRoute.SubinterfaceTable']
                        | where ServiceKey == '$($instance.AzureServiceKey)'
                        | distinct Cloud, Description, ServiceKey, InterfaceName, IpAddress, NetworkMask, DeviceName, Type, VrfId, SubscriptionId
                        | order by Type, DeviceName asc
                    "

                    $subinterfaces = Invoke-Kusto -KustoCluster 'aznw' -KustoDatabase 'aznwcosmos' -Query $query
                    If ($subinterfaces) {
                        Write-Console -Message "Creating session information for the selected instance of $($Global:session.resource)..."
                        $instanceProperties = @{
                            creationTime = $instance.CreationTime
                            azureServiceKey = $instance.AzureServiceKey
                            circuitName = $instance.CircuitName
                            circuitType = $instance.CircuitType
                            serviceProviderName = $instance.ServiceProviderName
                            location = $instance.Location
                            bandwidth = $instance.Bandwidth
                            billingType = $instance.BillingType
                            numberOfConfiguredLinks = $instance.NumberOfConfiguredLinks
                            primaryDeviceName = $instance.PrimaryDeviceName
                            secondaryDeviceName = $instance.SecondaryDeviceName
                            nrpResourceURI = $instance.NrpResourceUri
                            # Subinterfaces has to have explicit column selection or else the entire System.Data.DataRowView will be saved, resulting in issues with saving the session due to JSON conversions.
                            subinterfaces = $subinterfaces | Select-Object Cloud, Description, ServiceKey, InterfaceName, IpAddress, NetworkMask, DeviceName, Type, VrfId, SubscriptionId
                        }  
                        $Global:session | Add-Member -NotePropertyMembers $instanceProperties
                        Write-Console -Message "URI: $($Global:session.uri)"
                        Write-Console -Message "Service Key: $($Global:session.azureServiceKey)"
                        Write-Console -Message "Circuit Name: $($Global:session.circuitName)"
                        Write-Console -Message "Service Provider Name: $($Global:session.serviceProviderName)"
                        Write-Console -Message "Location: $($Global:session.location)"
                        Write-Console -Message "Bandwidth: $($Global:session.bandwidth)"
                        Write-Console -Message "Billing Type: $($Global:session.billingType)"
                        $i = 0
                        ForEach ($subinterface in $Global:session.subinterfaces) {
                            Write-Console -Message "Subinterface #$($i + 1)"
                            Write-Console -Message "- Interface Name: $($subinterface.InterfaceName)"
                            Write-Console -Message "- Device: $($subinterface.DeviceName) ($($subinterface.Type))"
                            Write-Console -Message "- Description: $($subinterface.Description)"
                            Write-Console -Message "- Addressing: $($subinterface.IpAddress)/$($subinterface.NetworkMask)"
                            $i++
                        }
                    }
                    Else {
                        Write-Console 'Could not locate the required subinterface information.'
                        Return
                    }
                }
            }
            # No instances were found.
            Else {
                Invoke-NoInstancesFound
                Return
            }
            # Break out of the Switch statement.
            Break
        }
        <########################################
        # End: ExR instance selection.
        #########################################>


        <########################################
        # Start: Storage Account instance selection.
        #########################################>

        'storageAccounts' {
            Write-Console "Searching for instance information for $($Global:session.resource)..."
            $instanceProperties = @{
                blob = $null
                file = $null
                queue = $null
                stamp = $null
                stampDeployment = $null
                stampFQDN = $null
                table = $null

            }
            # Try to resolve each storage service endpoint.
            # If there is resolution then the storage service is used.
            # If there is no resolution then there is no service.
            $recordsFound = @()
            ForEach ($storageType in @('blob', 'file', 'queue', 'table')) {
                If ($record = Resolve-DnsName -Name "$($session.resource).$storageType.core.windows.net" -ErrorAction SilentlyContinue) {
                    $recordsFound += $record
                    $instanceProperties.$storageType = "$($session.resource).$storageType.core.windows.net"
                }
            }
            # There was at least one storage service record returned.
            If ($recordsFound.Count -gt 0) {
                $instanceProperties.stampFQDN = ($recordsFound[0].NameHost)
                $instanceProperties.stamp = ($instanceProperties.stampFQDN).Split('.')[1]
                $instanceProperties.stampDeployment = "ms-$($instanceProperties.stamp)"
                $Global:session | Add-Member -NotePropertyMembers $instanceProperties
                Write-Console -Message "Creating session information for $($Global:session.resource)..."
                Write-Console -Message "Storage Account: $($Global:session.resource)"
                Write-Console -Message "Deployment Stamp: $($Global:session.stampDeployment)"

            }
            # No storage services resolved meaning that no storage services exist for the account.
            Else {
                Write-Console -Message "No storage services were found for $($session.resource)."
                Return
            }
            # Break out of the Switch statement.
            Break
        }
        <########################################
        # End: Storage Account instance selection.
        #########################################>


        <########################################
        # Start: VM instance selection.
        #########################################>

        'virtualMachines' {
            # Locate instances of the resource.
            Write-Console "Searching for instances of $($Global:session.resource)..."
            $query = "
                cluster('AzureCM').database('AzureCM').LogContainerSnapshot
                | where PreciseTimeStamp >= datetime($($Global:session.timespanStartStandard)) and PreciseTimeStamp <= datetime($($Global:session.timespanEndStandard))
                | where subscriptionId in ('$($Global:session.subscriptionID)')
                | where roleInstanceName in ('_$($Global:session.resource)', '$($Global:session.resource)')
                | distinct creationTime, CloudName, Region, DataCenterName, Tenant, AvailabilityZone, nodeId, containerId, roleInstanceName, tenantName, virtualMachineUniqueId
                | join kind=leftouter(cluster('Azuredcm'). database('AzureDCMDb').ResourceSnapshotV1) on `$left.nodeId == `$right.ResourceId
                | extend NodeIdUpper=toupper(nodeId)
                | join kind=leftouter(cluster('aznwcc').database('aznwmds').Servers) on `$left.NodeIdUpper == `$right.NodeId
                | join kind=leftouter(cluster('aznwcc').database('aznwmds').DeviceInterfaceLinks) on `$left.DeviceName == `$right.StartDevice
                | project roleInstanceName, creationTime, Region, DataCenterName, Tenant, AvailabilityZone, virtualMachineUniqueId, nodeId, containerId, tenantName, IPAddress, EndDevice
                | order by creationTime desc
            "

            $instances = Invoke-Kusto -KustoCluster 'AzureCM' -KustoDatabase 'AzureCM' -Query $query
            # Instances were found; begin instance selection and session creation.
            If ($instances) {
                $instance = $instances | Out-GridView -Title "[Nanite] Please select an instance of $($Global:session.resource):" -OutputMode Single
                If (!$instance) {
                    Write-Console "No instances of $($Global:session.resource) were selected."
                    Return
                }
                Else {
                    Write-Console -Message 'Executing additional sub-queries...'
                    # Look up the region's Shoebox name to be used in certain operations such as VMDash.
                    $query = "
                        cluster('AzureCM').database('AzureCM').LogClusterSnapshot
                        | where tenantName contains '$($instance.Tenant)'
                        | where shoeboxMdmAccountName !in ('', 'NA')
                        | distinct shoeboxMdmAccountName
                    "

                    $regionShoebox = Invoke-Kusto -KustoCluster 'AzureCM' -KustoDatabase 'AzureCM' -Query $query
                    Write-Console -Message "Creating session information for the selected instance of $($Global:session.resource)..."
                    $instanceProperties = @{
                        creationTime = $instance.creationTime
                        roleInstanceName = $instance.roleInstanceName
                        region = $instance.Region
                        regionShoebox = $regionShoebox.shoeboxMdmAccountName
                        nodeID = $instance.NodeID
                        bladeID = $instance.NodeID
                        vmID = $instance.VirtualMachineUniqueId
                        tenantName = $instance.tenantName
                        cluster = $instance.Tenant
                        containerID = $instance.ContainerID
                        nodeIP = $instance.IPAddress
                        torName = $instance.EndDevice
                    }
                    $Global:session | Add-Member -NotePropertyMembers $instanceProperties
                    Write-Console -Message "URI: $($Global:session.uri)"
                    Write-Console -Message "Role Instance Name: $($Global:session.roleInstanceName)"
                    Write-Console -Message "VM ID: $($Global:session.vmID)"
                    Write-Console -Message "Creation Time: $($Global:session.creationTime)"
                    Write-Console -Message "Region: $($Global:session.region)"                    
                    Write-Console -Message "Cluster: $($Global:session.cluster)"
                    Write-Console -Message "Node ID: $($Global:session.nodeID)"
                }
            }
            # No instances were found.
            Else {
                Invoke-NoInstancesFound
                Return
            }
            # Break out of the Switch statement.
            Break
        }
        <########################################
        # End: VM instance selection.
        #########################################>


        <########################################
        # Start: VMSS instance selection.
        #########################################>

        'virtualMachineScaleSets' {
            # Locate instances of the resource.
            Write-Console "Searching for instances of $($Global:session.resource)..."
            $query = "
                cluster('AzureCM').database('AzureCM').LogContainerSnapshot
                | where PreciseTimeStamp >= datetime($($Global:session.timespanStartStandard)) and PreciseTimeStamp <= datetime($($Global:session.timespanEndStandard))
                | where subscriptionId in ('$($Global:session.subscriptionID)')
                | where roleInstanceName startswith ('_$($Global:session.resource)')
                | distinct creationTime, CloudName, Region, DataCenterName, Tenant, AvailabilityZone, nodeId, containerId, roleInstanceName, tenantName, virtualMachineUniqueId
                | join kind=leftouter(cluster('Azuredcm'). database('AzureDCMDb').ResourceSnapshotV1) on `$left.nodeId == `$right.ResourceId
                | extend NodeIdUpper=toupper(nodeId)
                | join kind=leftouter(cluster('aznwcc').database('aznwmds').Servers) on `$left.NodeIdUpper == `$right.NodeId
                | join kind=leftouter(cluster('aznwcc').database('aznwmds').DeviceInterfaceLinks) on `$left.DeviceName == `$right.StartDevice
                | project roleInstanceName, creationTime, Region, DataCenterName, Tenant, AvailabilityZone,virtualMachineUniqueId, nodeId, containerId, tenantName, IPAddress, EndDevice
                | order by creationTime desc
            "

            $instances = Invoke-Kusto -KustoCluster 'AzureCM' -KustoDatabase 'AzureCM' -Query $query
            # Instances were found; begin instance selection and session creation.
            If ($instances) {
                $instance = $instances | Out-GridView -Title "[Nanite] Please select an instance of $($Global:session.resource):" -OutputMode Single
                If (!$instance) {
                    Write-Console "No instances of $($Global:session.resource) were selected."
                    Return
                }
                Else {
                    Write-Console -Message 'Executing additional sub-queries...'
                    # Look up the region's Shoebox name to be used in certain operations such as VMDash.
                    $query = "
                        cluster('AzureCM').database('AzureCM').LogClusterSnapshot
                        | where tenantName contains '$($instance.Tenant)'
                        | where shoeboxMdmAccountName !in ('', 'NA')
                        | distinct shoeboxMdmAccountName
                    "

                    $regionShoebox = Invoke-Kusto -KustoCluster 'AzureCM' -KustoDatabase 'AzureCM' -Query $query
                    Write-Console -Message "Creating session information for the selected instance of $($Global:session.resource)..."
                    $instanceProperties = @{
                        creationTime = $instance.creationTime
                        roleInstanceName = $instance.roleInstanceName
                        region = $instance.Region
                        regionShoebox = $regionShoebox.shoeboxMdmAccountName
                        nodeID = $instance.NodeID
                        bladeID = $instance.NodeID
                        vmID = $instance.VirtualMachineUniqueId
                        tenantName = $instance.tenantName
                        cluster = $instance.Tenant
                        containerID = $instance.ContainerID
                        nodeIP = $instance.IPAddress
                        torName = $instance.EndDevice
                    }
                    $Global:session | Add-Member -NotePropertyMembers $instanceProperties
                    Write-Console -Message "URI: $($Global:session.uri)"
                    Write-Console -Message "Role Instance Name: $($Global:session.roleInstanceName)"
                    Write-Console -Message "VM ID: $($Global:session.vmID)"
                    Write-Console -Message "Creation Time: $($Global:session.creationTime)"
                    Write-Console -Message "Region: $($Global:session.region)"                    
                    Write-Console -Message "Cluster: $($Global:session.cluster)"
                    Write-Console -Message "Node ID: $($Global:session.nodeID)"
                }
            }
            # No instances we found.
            Else {
                Invoke-NoInstancesFound
                Return
            }
        }
        Default {
            # Realistically, the unsupported resource type is caught by Test-URI in Nanite.ps1, but we Default to it here to be safe.
            Write-Console -Message "The specified resource type of $($Global:session.resourceType) is not supported."
            Exit
        }
        <########################################
        # End: VMSS instance selection.
        #########################################>

    }
    
    <########################################
    # Start: Session saving.
    #########################################>

    If ($Global:session.case) {
        $Global:session | ConvertTo-Json -Depth 5 | ForEach-Object { [System.Text.RegularExpressions.Regex]::Unescape($_) } | Out-File "$($Global:configuration.Output)\Sessions\$($Global:session.case).json" -Force
        Write-Console -Message "Saved session information under case number #$($Global:session.case)."
    }
    Else {
        Write-Console -Message "Not saving session information for reuse as no case number was provided."
    }
    <########################################
    # End: Session saving.
    #########################################>

}