neverfail.psm1

<#
      .SYNOPSIS
        General purpose functions for the Neverfail API.
      .DESCRIPTION
        This module is for functions that are used in a multitude of scripts in the VEC viewpoint.local environment.
      .NOTES
        Version: 0.0.2
        Author: Michael G. Brown
        Update: 02/14/2019
        Purpose/Change:
        Reference: http://petstore.swagger.io/#/ | https://viewpoint.neverfail.com/api/v3/swagger.json
  #>

#region-----modules and global variables--------------------------------------------------------------------#
#-----------------------------------------------------------------------------------------------------------#
Add-Type -AssemblyName System.Security
Import-Module ActiveDirectory
Import-Module PoshBot
Import-Module 'C:\Repositories\PoshBot\plugins\PoshBot.Personality\PoshBot.Personality.psm1'
Import-Module 'C:\Repositories\PoshBot\plugins\viewpoint.local\viewpoint.local.psm1'

$CommandsToExport = @()
#endregion
#region-----functions---------------------------------------------------------------------------------------#
#-----------------------------------------------------------------------------------------------------------#
#region-----Neverfail Authentication---------------#
#--------------------------------------------------#
function Get-NfAPISession {
    [CmdletBinding()]
    param(
        #neverfail username
        [string]$nfU,
        #neverfail password
        [string]$nfP,
        #use the wstraining.neverfail.com site instead
        [switch]$test
    )

    Add-Type -AssemblyName System.Web
    $EncodedUsername = [System.Web.HttpUtility]::UrlEncode($nfU)
    $EncodedPassword = [System.Web.HttpUtility]::UrlEncode($nfp)
    if ($test) {
        $server = "https://wstraining.neverfail.com"    #testing environment
    }
    else {
        $server = "https://viewpoint.neverfail.com"
    }
    $version = "v3"
    $api = "$server/api/$version"

    $login_Uri = "$api/session/login?username=$EncodedUsername&password=$EncodedPassword"
    $token = Invoke-RestMethod -Uri $login_Uri -Method Post -ContentType "application/json" | Select-Object SessionId

    $authcode = "Session " + $token.sessionId
    $Headers = @{}
    $Headers.Add('Authorization', $authcode)

    $session = @{
        api     = $api
        headers = $Headers
        site    = $server
    }

    Return $session
}
#endregion
$CommandsToExport += 'Get-NfAPISession'
#region-----Neverfail Domains----------------------#
#--------------------------------------------------#
function Get-NfDomains {
    [CmdletBinding()]
    param (
        $session
    )
    $api = $session.api
    $Domains_Uri = "$api/domains"
    $Domains = Invoke-RestMethod -Uri $Domains_Uri -Method Get -Headers $session.Headers -ContentType 'application/json'
    return $Domains
}
function Get-NfDomain {
    [CmdletBinding()]
    param (
        $session,
        [string]$domainName,
        [string]$domainId
    )

    if ($domainName) {
        $domains = Get-NfDomains -session $session
        foreach ($domain in $domains) {
            if ($domainName -eq $domain.domain) {
                $domainId = $domain.id
            }
        }
    }

    $api = $session.api
    $Domain_Uri = "$api/domains/$domainId"
    $Domain = Invoke-RestMethod -Uri $Domain_Uri -Method Get -Headers $session.Headers -ContentType 'application/json'
    return $Domain
}
#endregion
#region-----Neverfail Clouds-----------------------#
#--------------------------------------------------#
function Get-NfClouds {
    [CmdletBinding()]param (
        $session
    )
    $api = $session.api
    $Clouds_Uri = "$api/clouds"
    $Clouds = Invoke-RestMethod -Uri $Clouds_Uri -Method Get -Headers $session.Headers -ContentType 'application/json'
    return $Clouds
}
function Get-NfCloud {
    [CmdletBinding()]param (
        $session,
        [string]$cloudName,
        [String]$cloudId
    )
    $api = $session.api

    if ($cloudName) {
        $clouds = Get-NfClouds -session $session
        foreach ($cloud in $clouds) {
            if ($cloudName -eq $cloud.name) {
                $cloudId = $cloud.id
            }
        }
    }
    $Cloud_Uri = "$api/clouds/$cloudId"
    $Cloud = Invoke-RestMethod -Uri $Cloud_Uri -Method Get -Headers $session.Headers -ContentType 'application/json'
    return $Cloud
}
function Get-NfCloudVirtualNetworks {
    [CmdletBinding()]
    param(
        $session,
        [String]$cloudName,
        [String]$cloudId
    )

    if ($cloudName) {
        $cloudId = (Get-NfCloud -session $session -cloudName $cloudName).Id
    }
    $api = $session.api
    $CloudVNets_Uri = "$api/clouds/$cloudId/virtualNetworks"
    $CloudVnets = Invoke-RestMethod -Uri $CloudVNets_Uri -Method Get -Headers $session.Headers -ContentType 'application/json'
    return $CloudVnets
}
#endregion
#region-----Neverfail Cloudstorage-----------------#
#--------------------------------------------------#
function Get-NfCloudstorages {
    [CmdletBinding()]param ($session, $cloudId)
    $api = $session.api
    $CloudStorages_Uri = "$api/clouds/$cloudId/storage"
    $CloudStorages = Invoke-RestMethod -Uri $CloudStorages_Uri -Method Get -Headers $session.Headers -ContentType 'application/json'
    return $CloudStorages
}
function Get-NfMostAvailableStorage {
    [CmdletBinding()]param ($session, $cloudId)
    $cloudStorages = Get-NfCloudstorages -session $session -cloudId $cloudId
    $maxFreeSpace = ($cloudStorages |Measure-Object -Property freeSpace -Maximum).Maximum
    $mostFreeCloudStorage = $cloudStorages | Where-Object {$_.freeSpace -eq $maxFreeSpace}
    return $mostFreeCloudStorage
}

#endregion
#region-----Neverfail Organizations----------------#
#--------------------------------------------------#
function Get-NfOrganizations {
    [cmdletbinding()]
    param($Session)
    $Organizations_Uri = $Session.api + "/organizations"
    $Organizations = Invoke-RestMethod -Uri $Organizations_Uri -Method Get -Headers $Session.headers -ContentType "application/json"
    return $Organizations
}
function Get-NfOrganization {
    [cmdletbinding()]
    param($Session, $orgName, $orgId)
    if ($orgName) {
        $organizations = Get-NfOrganizations -Session $Session
        foreach ($org in $organizations) {
            if ($orgName -like $org.Name) {
                return $org
            }
        }
    }
    elseif ($orgId) {
        $org_Uri = $Session.api + "/organizations/" + $orgId
        $org = Invoke-RestMethod -Uri $org_Uri -Method Get -Headers $Session.headers -ContentType "application/json"
        return $org
    }
}
function New-NfOrganization {
    <#
    .SYNOPSIS
    Creates a new organization via the Neverfail API.
    #>

    [CmdletBinding()]
    [PoshBot.BotCommand(
        Aliases = ('newOrg'),
        Permissions = 'create'
    )]
    param (
        [PoshBot.FromConfig('Credential')]
        [parameter(mandatory)]
        $neverfail,
        [parameter(mandatory)]
        [String]$name,
        [string]$domain = "viewpoint.local",
        [parameter(mandatory)]
        [String]$upnDomain,
        [string]$orgAdminP = 'Enterpr1se66',
        [int]$retryAttempts = 1,
        [switch]$test
    )

    if ($test) {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password -test
        $domain = "training.local"
    }
    else {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password
    }
    $api = $session.api
    $site = $session.site
    $newOrganization_Uri = "$api/organizations"
    $Headers = $session.headers

    $domainId = (Get-NfDomain -session $session -domainName $domain).id

    $newOrganization_Json = [PSCustomObject]@{
        "name"             = $name;
        "domainId"         = $domainId;
        "upnDomain"        = $upnDomain;
        "orgAdminPassword" = $orgAdminP;
    }

    $body = $newOrganization_Json | ConvertTo-Json

    $newOrganization = Invoke-RestMethod -Uri $newOrganization_Uri -Headers $Headers -Method Post -ContentType "application/json" -Body $Body

    $organizationWorkflow = Find-NfWorkflow -Session $session -wfName "Provision an Organization: $name"

    $wf = Watch-NFWorkflowStatus -session $session -wfId $organizationWorkflow.id -retryAttempts $retryAttempts

    if ($wf.Status -eq "complete") {
        $aff = Get-VectoriaResponse -type Confirmation
        $response = $aff.Response
        $user = $aff.User
        $emoji = $aff.Emoji
        New-PoshBotTextResponse -Text ("$response, $user! The organization *" + $newOrganization.Name + "* has been created. $emoji")
        $org = Get-NfOrganization -Session $session -orgName $newOrganization.Name
        $fields = [ordered]@{
            Status  = ''
            Website = $org.upnDomain
        }
        if ($org.status -eq 'valid') {
            $fields.Status = ':heavy_check_mark:'
        }
        else {
            $fields.Status = ':question:'
        }
        $title = $org.name
        $link = "$site/#/organizations/" + $org.Id
        New-PoshBotCardResponse -Type Normal -Title $title -Fields $fields -LinkUrl $link
    }    
}
$CommandsToExport += 'New-NfOrganization'
function Remove-NfOrganization {
    [CmdletBinding()]
    [PoshBot.BotCommand(
        Aliases = ('removeOrg'),
        Permissions = 'delete'
    )]
    param (
        [PoshBot.FromConfig('Credential')]
        [parameter(mandatory)]
        $neverfail,
        [string]$Name,
        [string]$orgId,
        [switch]$test
    )

    if ($test) {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password -test
    }
    else {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password
    }

    $orgId = (Get-NfOrganization -Session $session -orgName $Name).Id

    $api = $session.api
    $site = $session.site
    $removeOrganization_Uri = "$api/organizations/$orgId"
    $Headers = $session.headers

    $removedOrganizationWF = Invoke-RestMethod -Uri $removeOrganization_Uri -Headers $Headers -Method Delete -ContentType "application/json"
    $wf = Watch-NFWorkflowStatus -session $session -wfId $removedOrganizationWF

    if ($wf.Status -eq "complete") {
        $aff = Get-VectoriaResponse -Type Confirmation 
        $response = $aff.Response
        $emoji = $aff.emoji
        $user = $aff.User
        New-PoshBotTextResponse -Text ("$response, $user! The organization *" + $Name + "* has been deleted. $emoji")
        $fields = [ordered]@{
            Status = ':x:'
        }
        $title = "Delete Organization Workflow" #for some reason $wf.name woudln't work through Slack
        $wfId = $wf.Id
        $link = "$site/#/workflows/" + $wfId #where is the "%20" coming from???
        New-PoshBotCardResponse -Type Normal -Title $title -Fields $fields -LinkUrl $link
    }   
}
$CommandsToExport += 'Remove-NfOrganization'
#endregion
#region-----Neverfail Workspaces-------------------#
#--------------------------------------------------#
function Get-NfWorkspaces {
    [cmdletbinding()]param($Session, $cloudId)
    $workspaces_Uri = $Session.api + "/clouds/$cloudId/workspaces"
    $workspaces = Invoke-RestMethod -Uri $workspaces_Uri -Method Get -Headers $Session.headers -ContentType "application/json"
    return $workspaces
}
function Get-NfWorkspace {
    [cmdletbinding()]
    param($Session, $orgName, $orgId, $cloudId)

    if ($orgName) {
        $orgId = (Get-NfOrganization -Session $Session -orgName $orgName).Id
    }
    if ($orgId) {
        $workspaces = Get-NfWorkspaces -Session $Session -cloudId $cloudId
        foreach ($workspace in $workspaces) {
            if ($orgId -eq $workspace.orgId) {
                $orgWorkspace = $workspace
            }
        }
        return $orgWorkspace
    }
}
function New-NfWorkspace {
    [CmdletBinding()]
    [PoshBot.BotCommand(
        Aliases = ('newWS'),
        Permissions = ('create')
    )]
    param (
        [PoshBot.FromConfig('Credential')]
        [parameter(mandatory)]
        $neverfail,
        [ValidateSet("Las Vegas", "Vegas", "Austin", "Sydney", "Ashburn", "Training")]
        [parameter(mandatory)]
        [String]$cloud,
        [parameter(mandatory)]
        [String]$orgName,
        
        #newVmSpecs
        [ValidateLength(5, 10)]
        [String]$shortOrgName,
        [Int]$cores = 2,
        [int]$ram = 6,
        [int]$retryAttempts = 1,
        [switch]$test
    )

    if ($test) {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password -test
    }
    else {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password
    }

    $api = $session.api
    $site = $session.site
    #cloud id
    switch ($cloud) {
        "Las Vegas" {
            $cloud = 'Las Vegas'
            $cloudId = '4af64a4c-3310-40d3-b433-292708eca59c'
            $networkId = 'c55c2ef5-09eb-489b-bc22-a2d5efc52218'
            $templateId = 'eea063ca-5a25-4493-aa89-d14fcde8429b'
        }
        "Vegas" {
            $cloud = 'Las Vegas'
            $cloudId = '4af64a4c-3310-40d3-b433-292708eca59c'
            $networkId = 'c55c2ef5-09eb-489b-bc22-a2d5efc52218'
            $templateId = 'eea063ca-5a25-4493-aa89-d14fcde8429b'
        }
        "Austin" {
            $cloud = 'Austin'
            $cloudId = '396b53b6-739f-4c65-aaaa-85bf4b22fed4'
            $networkId = 'dfe18cbb-1220-49e9-812c-10f486ee7f99'
            $templateId = 'c908895c-70a3-4376-b772-a9b0589e5ca5'
        }
        "Sydney" {
            $cloud = 'Sydney'
            $cloudId = 'def0af1a-1ac6-4136-b89a-6d5dc19c53b0'
            $networkId = 'cc7a271d-4cbc-4d35-97c1-b0487c37f32d'
            $templateId = 'a1c603c3-1f13-49d9-81c8-07d6b7dd9313'
        }
        "Ashburn" {
            $cloudId = '78291dc5-d4fe-47af-ae5d-cb1e4d6dab24'
            $networkId
            $templateId = '808103d2-d970-4365-813c-36096f3ce76d'
        }
        "Training" {
            $cloudId = '9e902052-4658-4763-a57e-606e740f5dc0'
            $networkId = '4cb83a9a-b10e-4f2b-94ba-2663889e4d51' 
            $templateId = '9f94136b-ea6e-4cd3-be1f-45480637e680'
        }
    }

    $orgId = (Get-NfOrganization -Session $session -orgName $orgName).id
    $templateType = 'persistent_host'
    $roles = @("windows")

    $newWorkspace_Uri = "$api/clouds/$cloudId/workspaces"
    $sessionHostName = "vs-$shortOrgName" + "01"
    $pshSpec = [PSCustomObject]@{
        'name'  = $sessionHostName;
        'disk'  = 40;
        'roles' = $roles;
        'cores' = $cores;
        'ram'   = $ram;
    }

    $newWorkspace_Json = [PSCustomObject]@{
        'cloudId'      = $cloudId;
        'orgId'        = $orgId;
        'networkId'    = $networkId;
        'templateId'   = $templateId;
        'templateType' = $templateType;
        'pshSpec'      = $pshSpec;
    }

    $Body = $newWorkspace_Json | ConvertTo-Json
    $newWorkspace = Invoke-RestMethod -Uri $newWorkspace_Uri -Headers $session.Headers -Method Post -ContentType "application/json" -Body $Body
    #$newWorkspace = Get-NfWorkspace -Session $session -orgId $orgId -cloudId $cloudId
    $name = $newWorkspace.name
    $workspaceWorkflow = Find-NfWorkflow -Session $session -wfName "Create Workspace: $name"

    $wf = Watch-NFWorkflowStatus -session $session -wfId $workspaceWorkflow.Id -Timeout 1800 -retryInterval 30 -retryAttempts $retryAttempts

    if ($wf.Status -eq "complete") {
        $aff = Get-VectoriaResponse -type Confirmation
        $response = $aff.Response
        $emoji = $aff.Emoji
        $user = $aff.User
        New-PoshBotTextResponse -Text ("$response, $user! The workspace *" + $newWorkspace.Name + "* has been created. $emoji")
        $ws = Get-NfWorkspace -Session $session -orgId $orgId -cloudId $cloudId
        $fields = [ordered]@{
            Status               = ''
            Cloud                = $cloud
            'Distinguished Name' = $ws.wsDn
        }
        if ($ws.status -eq 'valid') {
            $fields.Status = ':heavy_check_mark:'
        }
        else {
            $fields.Status = ':question:'
        }
        $title = $ws.name
        $link = "$site/#/workspaces/" + $ws.Id
        New-PoshBotCardResponse -Type Normal -Title $title -Fields $fields -LinkUrl $link
        
        $psh = Get-NfVirtualMachine -Session $session -vmName $sessionHostName -cloudId $cloudId
        if (!$test) {
            $ip = (Get-ADComputer -Identity $sessionHostName -Properties IPv4Address).IPv4Address
        }
        else {
            $ip = $psh.profile.ipAddress
        }
        $fields = [ordered]@{
            Status = ''
            IP     = $ip
        }
        if ($psh.profile.status -eq 'normal') {
            $fields.Status = ':heavy_check_mark:'
        }
        else {
            $fields.Status = ':question:'
        }
        $title = $psh.profile.hostname
        $link = "$site/#/virtual-machines/" + $psh.Id
        New-PoshBotCardResponse -Type Normal -Title $title -Fields $fields -LinkUrl $link

        if (!$test) {
            Set-VecComputerDescription -computerName $sessionHostName
        }
    }
}
$CommandsToExport += 'New-NfWorkspace'
function Remove-NfWorkspace {
    [CmdletBinding()]
    [PoshBot.BotCommand(
        Aliases = ('removeWS'),
        Permissions = ('delete')
    )]
    param(
        [PoshBot.FromConfig('Credential')]
        [parameter(mandatory)]
        $neverfail,
        [ValidateSet("Las Vegas", "Vegas", "Austin", "Sydney", "Ashburn", "Training")]
        [parameter(mandatory)]
        [String]$cloud,
        [parameter(mandatory)]
        [String]$orgName,
        [switch]$test
    )

    if ($test) {
        $session = Get-NfAPISession -nfU $neverfail.username -nfP $neverfail.GetNetworkCredential().password -test
    }
    else {
        $session = Get-NfAPISession -nfU $neverfail.username -nfP $neverfail.GetNetworkCredential().password
    }

    $api = $session.api
    $site = $session.site

    switch ($cloud) {
        "Las Vegas" {
            $cloud = 'Las Vegas'
            $cloudId = '4af64a4c-3310-40d3-b433-292708eca59c'
        }
        "Vegas" {
            $cloud = 'Las Vegas'
            $cloudId = '4af64a4c-3310-40d3-b433-292708eca59c'
        }
        "Austin" {
            $cloud = 'Austin'
            $cloudId = '396b53b6-739f-4c65-aaaa-85bf4b22fed4'
        }
        "Sydney" {
            $cloud = 'Sydney'
            $cloudId = 'def0af1a-1ac6-4136-b89a-6d5dc19c53b0'
        }
        "Ashburn" {
            $cloud = 'Ashburn'
            $cloudId = '78291dc5-d4fe-47af-ae5d-cb1e4d6dab24'
        }
        "Training" {
            $cloud = 'Training'
            $cloudId = '9e902052-4658-4763-a57e-606e740f5dc0'
        }
    }
    $workspace = Get-NfWorkspace -Session $session -orgName $orgName -cloudId $cloudId
    $wsId = $workspace.Id
    $workspaceName = $workspace.Name

    $removeWorkspace_Uri = "$api/clouds/$cloudId/workspaces/$wsId"
    $removedWorkspaceWF = Invoke-RestMethod -Uri $removeWorkspace_Uri -Headers $session.Headers -Method Delete -ContentType "application/json"
    $wf = Watch-NFWorkflowStatus -session $session -wfId $removedWorkspaceWF

    if ($wf.Status -eq "complete") {
        $aff = Get-VectoriaResponse -type Confirmation
        $response = $aff.Response
        $emoji = $aff.emoji
        $user = $aff.User
        New-PoshBotTextResponse -Text ("$response, $user! The workspace *" + $workspaceName + "* has been deleted. $emoji")
        $fields = [ordered]@{
            Status = ':x:'
        }
        $title = $wf.name
        $link = "$site/#/workflows/" + $wf.Id
        New-PoshBotCardResponse -Type Normal -Title $title -Fields $fields -LinkUrl $link
    }   
}
$CommandsToExport += 'Remove-NfWorkspace'
#endregion
#region-----Neverfail Virtual Machines-------------#
#--------------------------------------------------#
function Get-NfVirtualMachines {
    [cmdletbinding()]param($Session, $cloudId)
    if ($cloudId) {
        $virtualMachines_Uri = $Session.api + "/clouds/$cloudId/vms"
        $virtualMachines = Invoke-RestMethod -Uri $virtualMachines_Uri -Method Get -Headers $Session.headers -ContentType "application/json"
        return $virtualMachines
    }
    else {
        $clouds = Get-NfClouds -session $Session
        $virtualMachines = @()
        foreach ($cloud in $clouds) {
            $cloudId = $cloud.Id
            $virtualMachines_Uri = $Session.api + "/clouds/$cloudId/vms"
            $cloudVMs = Invoke-RestMethod -uri $virtualMachines_Uri -Method Get -Headers $Session.headers -ContentType 'application/json'
            $virtualMachines += $cloudVMs
        }
        return $virtualMachines
    }
}
function Get-NfVirtualMachine {
    [cmdletbinding()]
    param($Session, $vmName, $vmId, $cloudId)
    if ($cloudId) {
        $virtualMachines = Get-NfVirtualMachines -Session $Session -cloudId $cloudId
    }
    else {
        $virtualMachines = Get-NfVirtualMachines -Session $Session
    }
    
    foreach ($vm in $virtualMachines) {
        if (($vmId -eq $vm.Id) -or ($vmName -eq ($vm.profile.hostname -split "\.")[0])) {
            $virtualMachine = $vm
        }
    }
    return $virtualMachine
}
function Get-NfVirtualMachineDrives {
    [cmdletbinding()]
    param($Session, $vmName)
    
    $vm = Get-NfVirtualMachine -Session $Session -vmName $vmName
    $vmId = $vm.Id
    $api = $session.api
    $cId = $vm.profile.cloudId
    $vmDrives_Uri = "$api/clouds/$cId/vms/$vmId/drives/tiles"
    $vmDrives = Invoke-RestMethod -Uri $vmDrives_Uri -Headers $Session.headers -Method Get -ContentType "application/json"
    return $vmDrives
}
function New-NfVirtualMachine {
    [CmdletBinding()]
    [PoshBot.BotCommand(
        Aliases = ('newVM'),
        Permissions = ('create')
    )]
    param (
        [PoshBot.FromConfig('Credential')]
        [parameter(mandatory)]
        $neverfail,
        [ValidateSet("Las Vegas", "Vegas", "Austin", "Sydney", "Ashburn", "Training")]
        [parameter(mandatory)]
        [String]$cloud,
        [parameter(mandatory)]
        [String]$orgName,
        #session host information
        [parameter(Mandatory)]
        [ValidateSet("Vista", "Web", "Field Time")]
        [String]$serverType,
        [ValidateLength(5, 15)]
        [String]$vmName,
        [ValidateRange(40, 100)]
        [Int]$disksize = 40,
        [ValidateRange(2, 16)]
        [Int]$cores = 2,
        [ValidateRange(4, 64)]
        [Int]$ram = 6,
        [int]$retryAttempts,
        [switch]$test
    )
    
    if ($test) {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password -test
    }
    else {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password
    }
    
    $api = $session.api
    $site = $session.site
    $roles = @("windows")

    #cloud id
    switch ($cloud) {
        "Las Vegas" {
            $cloudId = '4af64a4c-3310-40d3-b433-292708eca59c'
        }
        "Vegas" {
            $cloudId = '4af64a4c-3310-40d3-b433-292708eca59c'
        }
        "Austin" {
            $cloudId = '396b53b6-739f-4c65-aaaa-85bf4b22fed4'
        }
        "Sydney" {
            $cloudId = 'def0af1a-1ac6-4136-b89a-6d5dc19c53b0'
        }
        "Ashburn" {
            $cloudId = '78291dc5-d4fe-47af-ae5d-cb1e4d6dab24'
        }
        "Training" {
            $cloudId = '9e902052-4658-4763-a57e-606e740f5dc0'
        }
    }

    $Orgworkspace = Get-NfWorkspace -Session $session -orgName $orgName -cloudId $cloudId
    $workspaceId = $Orgworkspace.Id
    $newVirtualMachine_Uri = "$api/clouds/$cloudId/vms?wsId=$workspaceId"

    if (!$vmName) {
        $vms = Get-NfVirtualMachines -Session $session -cloudId $cloudId
        $workspaceVMs = @()
        foreach ($vm in $vms) {
            if ($vm.profile.wsId -eq $workspaceId) {
                $workspaceVMs += $vm
            }
        }
        foreach ($vm in $workspaceVMs) {
            if ($vm.profile.hostname -like "VS-*") {
                $sessionHost = $vm 
            }
        }
        $vmNameBase = ((($sessionHost.profile.hostname -replace "VS-", "") -replace "01", "") -split "\.")[0]
        switch ($serverType) {
            "Vista" {
                $vmName = $vmNameBase + "-v"
                $cores = 2
                $ram = 6
            }
            "Web" {
                $vmName = $vmNameBase + "-w"
            }
            "Field Time" {
                $vmName = $vmNameBase + "-ft"
            }
        }
    }
    $newVirtualMachine_json = [PSCustomObject]@{
        'name'           = $vmName
        'disk'           = $disksize
        'ip'             = ''
        'roles'          = $roles
        'templateId'     = ''
        'networkId'      = ''
        'cloudStorageId' = ''
        'cores'          = $cores
        'ram'            = $ram
    }
    $Body = ConvertTo-Json $newVirtualMachine_json 
    #$newVirtualMachine = Invoke-RestMethod -Uri $newVirtualMachine_Uri -Method Post -Headers $session.Headers -ContentType "application/json" -Body $Body
    $newVirtualMachine = Get-NfVirtualMachine -Session $session -vmName $vmName -cloudId $cloudId
    $newHostName = (($newVirtualMachine.profile.hostname) -replace ".viewpoint.local*", "")
    $newVmWorkflow = Find-NfWorkflow -Session $session -wfName "Create New Host: $newHostName"

    $wf = Watch-NFWorkflowStatus -session $session -wfId $newVmWorkflow.id -retryAttempts $retryAttempts
    if ($wf.status -eq "complete") {
        if (!$test) {
            Set-VecComputerDescription -computerName $vmName
            #Set-VecComputerFirewall -computerName $vmName
        }
        $aff = Get-VectoriaResponse -type Confirmation
        $response = $aff.Response
        $user = $aff.User
        $vm = Get-NfVirtualMachine -Session $session -vmName $vmName -cloudId $cloudId
        New-PoshBotTextResponse -Text ("$response, $user! The virtual machine *" + $vm.profile.hostname + "* has been created. :woman-raising-hand: ")
        $fields = [ordered]@{
            Status = ''
            Cloud  = $cloud
            IP     = ''
        }
        if (!$test) {
            $ip = ((Get-ADComputer -Identity $vmName -Properties IPv4Address).IPv4Address)
            $field.IP = $ip
        }
        else {
            $fields.IP = "n/a"
        }
        if ($vm.profile.status -eq 'normal') {
            $fields.Status = ':heavy_check_mark:'
        }
        else {
            $fields.Status = ':question:'
        }
        $title = $vm.profile.hostname
        $link = "$site/#/virtual-machines/" + $vm.Id
        New-PoshBotCardResponse -Type Normal -Title $title -Fields $fields -LinkUrl $link

        if ($serverType -eq "Vista") {
            Add-NfVirtualMachineDrive -neverfail $neverfail -vmName $vmName -size 150 -label 'E'
        }
    }
}
$CommandsToExport += 'New-NfVirtualMachine'
function Remove-NfVirtualMachine {
    [CmdletBinding()]
    [PoshBot.BotCommand(
        Aliases = ('removeVM'),
        Permissions = ('delete')
    )]
    param(
        [PoshBot.FromConfig('Credential')]
        [parameter(mandatory)]
        $neverfail,
        [parameter(mandatory)]
        [String]$vmName,
        [switch]$test
    )

    if ($test) {
        $session = Get-NfAPISession -nfU $neverfail.username -nfP $neverfail.GetNetworkCredential().password -test
    }
    else {
        $session = Get-NfAPISession -nfU $neverfail.username -nfP $neverfail.GetNetworkCredential().password
    }

    $api = $session.api
    $site = $session.site

    $vm = Get-NfVirtualMachine -Session $session -vmName $vmName 
    $vmId = $vm.Id
    $cloudId = $vm.profile.cloudId

    $removeVM_Uri = "$api/clouds/$cloudId/vms/$vmId"
    $removedVm = Invoke-RestMethod -Uri $removeVM_Uri -Headers $session.Headers -Method Delete -ContentType "application/json"
    $wf = Find-NfWorkflow -Session $session -wfName "Delete Guest"
    $wf = Watch-NFWorkflowStatus -session $session -wfId $wf.Id
    if ($wf.Status -eq "complete") {
        $aff = Get-VectoriaResponse -type Confirmation
        $response = $aff.Response
        $emoji = $aff.emoji
        $user = $aff.User
        New-PoshBotTextResponse -Text ("$response, $user! The virtual machine *" + $vmName + "* has been deleted. $emoji")
        $fields = [ordered]@{
            Status = ':x:'
        }
        $title = $wf.name
        $link = "$site/#/workflows/" + $wf.Id
        New-PoshBotCardResponse -Type Normal -Title $title -Fields $fields -LinkUrl $link
    }   
}
$CommandsToExport += 'Remove-NfVirtualMachine'
function Add-NfVirtualMachineDrive {
    [CmdletBinding()]
    [PoshBot.BotCommand(
        Aliases = ('newVMDrive'),
        Permissions = ('create')
    )]
    param (
        [PoshBot.FromConfig('Credential')]
        [parameter(mandatory)]
        $neverfail,
        [string]$vmName,
        [parameter(Mandatory)]
        [int]$size,
        [parameter(Mandatory)]
        [string]$label,
        [switch]$test
    )

    if ($test) {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password -test
    }
    else {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password
    }
    $api = $session.api
    $site = $session.site

    $vm = Get-NfVirtualMachine -Session $session -vmName $vmName
    $vmId = $vm.Id
    $cId = $vm.profile.cloudId

    $storage = Get-NfMostAvailableStorage -session $session -cloudId $cId

    $newVirtualMachineDrive_json = [PSCustomObject]@{
        'datastore' = $storage.Id;
        'size'      = $size;
        'label'     = $label;
    }

    $Body = ConvertTo-Json $newVirtualMachineDrive_json 
    $newVirtualMachineDrive_Uri = "$api/clouds/$cId/vms/$vmId/drives"
    $newVMDrive = Invoke-RestMethod -Uri $newVirtualMachineDrive_Uri -Method Post -Headers $session.Headers -ContentType 'application/json' -Body $Body
    
    $wfId = (Find-NfWorkflow -Session $session -wfName 'Provision Storage').Id
    $wf = Watch-NFWorkflowStatus -session $session -wfId $wfId -retryAttempts 1 -retryInterval 5

    if ($wf.status -eq "complete") {
        $aff = Get-VectoriaResponse -type Confirmation
        $response = $aff.Response
        $emoji = $aff.emoji
        $user = $aff.User
        New-PoshBotTextResponse -Text ("$response, $user! A new drive has been created and attached to *" + $vm.profile.hostname + "*. $emoji")
        $capacity = $newVMDrive.Capacity / 1Gb
        $fields = [ordered]@{
            Capacity = "$capacity GB"
            Label    = $newVMDrive.label + ":"
        }
        if ($vm.profile.status -eq 'normal') {
            $fields.Status = ':heavy_check_mark:'
        }
        else {
            $fields.Status = ':question:'
        }
        $title = $vm.profile.hostname
        $link = "$site/#/virtual-machines/" + $vm.Id + "?cloudId=" + $cId
        New-PoshBotCardResponse -Type Normal -Title $title -Fields $fields -LinkUrl $link
    }
}
$CommandsToExport += 'Add-NfVirtualMachineDrive'
function Remove-NfVirtualMachineDrive {
    [CmdletBinding()]
    [PoshBot.BotCommand(
        Aliases = ('removeVMDrive'),
        Permissions = ('delete')
    )]
    param (
        [PoshBot.FromConfig('Credential')]
        [parameter(mandatory)]
        $neverfail,
        [string]$vmName,
        [parameter(Mandatory)]
        [string]$label,
        [switch]$test
    )

    if ($test) {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password -test
    }
    else {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password
    }
    $api = $session.api
    $site = $session.site

    $vm = Get-NfVirtualMachine -Session $session -vmName $vmName
    $vmId = $vm.Id
    $cId = $vm.profile.cloudId

    $drives = Get-NfVirtualMachineDrives -Session $session -vmName $vmName
    foreach ($drive in $drives) {
        if ($drive.label -eq $label) {
            $driveId = $drive.id
        }
    }

    $removeVirtualMachineDrive_Uri = "$api/clouds/$cId/vms/$vmId/drives/$driveId"
    $wfId = Invoke-RestMethod -Uri $removeVirtualMachineDrive_Uri -Method Delete -Headers $session.Headers -ContentType 'application/json'

    $wf = Watch-NFWorkflowStatus -session $session -wfId $wfId -retryAttempts 1 -retryInterval 5

    if ($wf.status -eq "complete") {
        $aff = Get-VectoriaResponse -type Confirmation
        $response = $aff.Response
        $emoji = $aff.emoji
        $user = $aff.User
        New-PoshBotTextResponse -Text ("$response, $user! The $label drive has been removed from *" + $vm.profile.hostname + "*. $emoji")
        $fields = [ordered]@{
            Label  = $label + ":"
            Status = ":x:"
        }
        $title = $vm.profile.hostname
        $link = "$site/#/virtual-machines/" + $vm.Id + "?cloudId=" + $cId
        New-PoshBotCardResponse -Type Normal -Title $title -Fields $fields -LinkUrl $link
    }
}
$CommandsToExport += 'Remove-NfVirtualMachineDrive'
#endregion
#region-----Neverfail Workflows--------------------#
#--------------------------------------------------#
function Get-NfWorkflow {
    [CmdletBinding()]param ($session, $wfId)

    $api = $session.api
    $workflow_Uri = "$api/workflows/$wfId"
    $workflow = Invoke-RestMethod -Uri $workflow_Uri -Headers $session.headers -method Get -ContentType "application/json"
    return $workflow
}
function Get-NfWorkflowTasks {
    [CmdletBinding()]param ($session, $wfId)

    $api = $session.api
    $workflowTasks_Uri = "$api/workflows/$wfId/tasks"
    $workflowTasks = Invoke-Restmethod -Uri $workflowTasks_Uri -Headers $session.Headers -method Get -ContentType "application/json"
    return $workflowTasks
}
function Get-NfWorkflowCurrentTask {
    [CmdletBinding()]param ($session, $wfId)

    $workflow = Get-NfWorkflow -session $session -wfId $wfId
    $workflowTasks = Get-NfWorkflowTasks -session $session -wfId $wfId
    $currentTask = $workflowTasks | Where-Object {$_.ordinal -eq ($workflow.loadedTasks - 1)}

    return $currentTask
}
function Find-NfWorkflow {
    [cmdletbinding()]
    param($Session, $wfName)

    $api = $session.api
    $workflow_Uri = "$api/workflows"

    $workflow_json = [PSCustomObject]@{
        'name' = $wfName;
    }

    $Body = ConvertTo-Json $workflow_json 

    $workflows = Invoke-RestMethod -Uri $workflow_Uri -Method Post -Headers $session.Headers -ContentType "application/json" -Body $Body
    $mostRecentWF = $workflows.entities[0]
    foreach ($wf in $workflows.entities) {
        if ($wf.startTime -ge $mostRecentWF.startTime) {
            $mostRecentWf = $wf
        }
    }

    return $mostRecentWF
}
function Find-NfWorkflows {
    [cmdletbinding()]
    param($Session)

    $api = $session.api
    $Workflows_Uri = "$api/workflows"
    $status = @('complete', 'error', 'stopped', 'stopping')
    <#$orderBy = @(@{
        'attr' = 'startTime'
        'direction' = 'asc'
    })#>

    $workflows_json = [PSCustomObject]@{
        'status' = $status
        #'pageNumber' = 0
        #'pageSize' = 100
        #'orderBy' = $orderBy
    }

    $Body = ConvertTo-Json $workflows_json 

    $Workflows = Invoke-RestMethod -Uri $Workflows_Uri -Method Post -Headers $session.Headers -ContentType "application/json" -Body $Body

    return $Workflows
}
function Remove-NfWorkflows {
    [cmdletbinding()]
    param(
        $Session,
        [string[]]$workflowIds
    )

    $api = $session.api
    $deleteWorkflows_Uri = "$api/workflows/delete"

    $Body = ConvertTo-Json $workflowIds 

    $deleteWorkflows = Invoke-RestMethod -Uri $deleteWorkflows_Uri -Method Post -Headers $session.Headers -ContentType "application/json" -Body $Body

    return $deleteWorkflows
}
function Optimize-NfWorkflows {
    [cmdletbinding()]
    param(
        [PoshBot.FromConfig('Credential')]
        [parameter(mandatory)]
        $neverfail,
        [switch]$test
    )

    if ($test) {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password -test
    }
    else {
        $session = Get-NfAPISession -nfU $neverfail.Username -nfP $neverfail.GetNetworkCredential().password
    }

    $wfs = Find-NfWorkflows -session $session

    $wfsToDelete = @()
    foreach ($WF in $wfs.entities) {
    
        $start = $WF.startTime / 1000
        $epoch = New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0
        $start = $epoch.AddSeconds($start)
        #delete workflow if Older than 10 days
        $days = 10
        if ($start -lt (get-date).AddDays(-$days) -or (($wf.status -eq 'error') -and (!$wf.resumedFromWorkflow))) {
            $wfsToDelete += $wf.id
        }
    }
    $removedWorkflows = Remove-NfWorkflows -Session $session -workflowIds $wfsToDelete
    if(!$removedWorkflows){
        New-PoshBotTextResponse -Text "No workflows removed. Already optimized."
    }else{
        $removedWorkflows = $removedWorkflows |Format-List |Out-String
        New-PoshBotTextResponse -Text "Neverfail Workflows older than $days days removed. $removedWorkFlows"
    }
}
$CommandsToExport += 'Optimize-NfWorkflows'
function Restart-NfWorflow {
    [CmdletBinding()]param ($session, $wfId)

    $api = $session.api
    $restartWorkflow_Uri = "$api/workflows/$wfId/restart"
    $restartedWorkflow = Invoke-RestMethod -Uri $restartWorkflow_Uri -Method Put -Headers $session.Headers -ContentType "application/json"
    return $restartedWorkflow
}
function Watch-NFWorkflowStatus {
    [CmdletBinding()]param (
        $session, 
        [String]$wfId, 
        [Int]$Timeout = 1800, 
        [Int]$retryInterval = 20, 
        [Int]$retryAttempts = 1
    )

    $wf = Get-NfWorkflow -session $session -wfId $wfId
    $site = $session.site
    $workflowInProgress = $true
    $retriedCount = 0
    $timer = [Diagnostics.Stopwatch]::StartNew()
    $i = 0
    $halfway = $Timeout / 2
    while ($workflowInProgress -and $timer.Elapsed.TotalSeconds -lt $Timeout) {
        $totalSeconds = [math]::Round($timer.Elapsed.TotalSeconds, 0)
        if ($i -eq 0) {
            Send-SlackMessage -Token 'xoxb-2614483880-541541209732-kL3fRhyaQtuXWethevFqP1Jv' -Channel $global:PoshBotContext.To -Text ("Workflow *" + $wf.name + "* in progress...") -AsUser
        }
        elseif ($i -eq $halfway) {
            Send-SlackMessage -Token 'xoxb-2614483880-541541209732-kL3fRhyaQtuXWethevFqP1Jv' -Channel $Global:PoshBotContext.To -Text "Just checking in. We're halfway until the Watch-WorkflowStatus timesout. Workflow *" + $wf.name + "* still in progress..." -AsUser
        }
        if ($wf.status -eq "complete") {
            $workflowInProgress = $false
        }
        elseif ($wf.status -eq "error") {
            if ($retriedCount -ge $retryAttempts) {
                $ref = Get-VectoriaResponse -type Refutation
                $response = $ref.Response
                $emoji = $ref.emoji
                $user = $ref.User
                $task = (Get-NfWorkflowCurrentTask -session $session -wfId $wf.Id).Name
                if ($retryAttempts -eq 1) {
                    $restartText = "Something went wrong with the workflow on task: *$task*, even after 1 workflow restart"
                }
                elseif ($retryAttempts -ge 2) {
                    $restartText = "Something went wrong with the workflow on task: *$task*, even after $retryAttempts workflow restarts"
                }
                elseif ($retryAttempts -eq 0) {
                    $restartText = "Something went wrong with the workflow on task: *$task*"
                }
                New-PoshBotTextResponse -Text ("$response, $user. $restartText! $emoji")
                $title = $wf.Name
                $link = "$site/#/workflows/" + $wf.Id
                New-PoshBotCardResponse -Type Normal -Title $title -LinkUrl $link
                $workflowInProgress = $false
            }
            else {
                $restartedWorkflow = Restart-NfWorflow -session $session -wfId $wf.Id
                Send-SlackMessage -Token 'xoxb-2614483880-541541209732-kL3fRhyaQtuXWethevFqP1Jv' -Channel $global:PoshBotContext.To -Text ("Workflow *" + $wf.name + "* failed...Restarting...") -AsUser
                $wf = Get-NfWorkflow -session $session -wfId $restartedWorkflow.Id
                $retriedCount += 1
            }
        }
        elseif ($wf.status -eq "stopped" -or $wf.status -eq "stopping") {
            $ref = Get-VectoriaResponse -type Refutation
            $response = $ref.Response
            $emoji = $ref.emoji
            $user = $ref.User
            $task = Get-NfWorkflowCurrentTask -session $session -wfId $wf.Id
            New-PoshBotTextResponse -Text ("$response, $user. Someone stopped the worflow on task: *$task*. $emoji")
            $title = $wf.Name
            $link = "$site/#/workflows/" + $wf.Id
            New-PoshBotCardResponse -Type Normal -Title $title -LinkUrl $link
            $workflowInProgress = $false
        }
        elseif ($wf.status -eq "running" -or $wf.status -eq "init" -or $wf.status -eq "resumed") {
            Start-Sleep -Seconds $retryInterval
            $wf = Get-NfWorkflow -session $session -wfId $wf.Id
        }
        else {
            $workflowInProgress = $false
        }
        $i += $retryInterval
    }
    $timer.Stop()
    if ($totalSeconds -gt $Timeout) {
        $def = Get-VectoriaResponse -type Deflection
        $response = $def.Response
        $emoji = $def.Emoji
        $user = $def.user
        New-PoshBotTextResponse -Text "$response, $user. The workflow is still going and my Watch-Workflow function timed out. $emoji"
        $title = $wf.Name
        $link = "$site/#/workflows/" + $wf.Id
        New-PoshBotCardResponse -Type Normal -Title $title -LinkUrl $link
    }
    return $wf
}
$CommandsToExport += 'Watch-NFWorkflowStatus'
#endregion
#endregion
#Export-ModuleMember -Function $CommandsToExport
#endregion
#endregion