DynatracePS.psm1

### --- PUBLIC FUNCTIONS --- ###
#Region - Connect-DynatraceAccountManagement.ps1
function Connect-DynatraceAccountManagement {
<#
    .SYNOPSIS
        Connect to the Dynatrace Account Management API for SaaS. internal use
 
    .DESCRIPTION
        Connect to the Dynatrace Account Management API for SaaS. internal use
 
    .PARAMETER OauthClientSecret
        Client secret generated from the Manage account API OAuth Clients page
 
    .PARAMETER AccountUuid
        Account UUID from Dynatrace
 
    .PARAMETER GetNewToken
        Force getting a fresh token
 
    .EXAMPLE
        Connect-DynatraceAccountManagement
 
    .NOTES
        https://account.dynatrace.com/my/enterprise-api?
    #>


    [CmdletBinding()]
    param(
        [String]$OauthClientSecret,
        [String]$AccountUuid,
        [Switch]$GetNewtoken
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $config = Get-DynatracePSConfig
        $AccountUuid = $config.AccountUuid
        $OauthClientSecret = $config.OauthClientSecret

        if (-not $AccountUuid) {
            Write-Warning "[$($MyInvocation.MyCommand.Name)] AccountUuid is required. Please use Set-DynatracePSConfig first. Exiting..."
            break
        }
        if (-not $OauthClientSecret) {
            Write-Warning "[$($MyInvocation.MyCommand.Name)] OauthClientSecret is required. Please use Set-DynatracePSConfig first. Exiting..."
            break
        }

        $GetTokenURL = 'https://sso.dynatrace.com/sso/oauth2/token'
        $client_id = (($OauthClientSecret -split '\.') | Select-Object -First 2) -join '.'
        $scope = 'account-idm-read account-idm-write'
        $resource = "urn:dtaccount:$AccountUuid"
        $Body = @{
            grant_type = 'client_credentials'
            client_id = $client_id
            client_secret = $OauthClientSecret
            scope = $scope
            resource = $resource
        }
        $ContentType = 'application/x-www-form-urlencoded'
    }

    process {

        $ExistingTokenExpiration = $MyInvocation.MyCommand.Module.PrivateData.token_expires
        $Now = Get-Date
        if (($Now -lt $ExistingTokenExpiration) -and (-not $GetNewtoken)) {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Existing token should still be good, using it"
            $GetTokenReturn = $MyInvocation.MyCommand.Module.PrivateData |
                Select-Object scope,token_type,expires_in,access_token,resource
        } else {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Getting new token"
            try {
                $GetTokenReturn = Invoke-RestMethod -Uri $GetTokenURL -Method POST -Body $body -ContentType $ContentType
                Write-Verbose "[$($MyInvocation.MyCommand.Name)] Adding results to module PrivateData"
                $MyInvocation.MyCommand.Module.PrivateData = @{
                    'scope' = $GetTokenReturn.scope
                    'token_type' = $GetTokenReturn.token_type
                    'expires_in' = $GetTokenReturn.expires_in
                    'access_token' = $GetTokenReturn.access_token
                    'resource' = $GetTokenReturn.resource
                    'token_expires' = (Get-Date).AddSeconds($GetTokenReturn.expires_in)
                }
            } catch {
                Write-Warning "[$($MyInvocation.MyCommand.Name)] Problem with invoke-restmethod $GetTokenURL"
                $_
                break
            }
        }

        # return everything to the pipeline
        $GetTokenReturn
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


Export-ModuleMember -Function Connect-DynatraceAccountManagement
#EndRegion - Connect-DynatraceAccountManagement.ps1
#Region - Get-DynatraceContainer.ps1
function Get-DynatraceContainer {
<#
    .SYNOPSIS
        Gets containers in Dynatrace environment
 
    .DESCRIPTION
        Gets containers in Dynatrace environment
 
    .EXAMPLE
        Get-DynatraceContainer
 
    .NOTES
        https://api.dynatrace.com/spec/#/
#>


    [CmdletBinding()]
    param()

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $EnvironmentID = (Get-DynatracePSConfig).EnvironmentID

        $uri = "https://$EnvironmentID.live.dynatrace.com/api/v2/entities"

        $GetParameter = @{
            entitySelector = 'type("CONTAINER_GROUP_INSTANCE")'
            pageSize = 500
        }

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $Uri"
    }

    process {
        $splatParameters = @{
            Uri = $uri
            GetParameter = $GetParameter
            RestResponseProperty = 'entities'
        }
        Invoke-DynatraceAPIMethod @splatParameters
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceContainer
#EndRegion - Get-DynatraceContainer.ps1
#Region - Get-DynatraceEffectivePermission.ps1
function Get-DynatraceEffectivePermission {
<#
    .SYNOPSIS
        Gets effective permissions for a user or group
 
    .DESCRIPTION
        Gets effective permissions for a user or group
 
    .PARAMETER levelType
        The type of the policy level. Valid values: account or environment
 
    .PARAMETER levelId
        The ID of the policy level. for account, use the UUID of the account. For environment, use the ID of the environment.
 
    .PARAMETER entityType
        The entity type. Valid values: user or group
 
    .PARAMETER entityId
        The entity id
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceEffectivePermission -levelType account -levelID <accountUuid>
 
    .EXAMPLE
        Get-DynatraceEffectivePermission -levelType environment -levelID <environment id>
 
    .NOTES
        https://api.dynatrace.com/spec/#/Policy%20management/PolicyController_getEffectivePermissions
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateSet('account','environment')]
        [String]$levelType,
        [Parameter(Mandatory)]
        [String]$levelID,
        [String]$entityType,
        [String]$entityId,
        [switch]$explain,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $RestPath = "/iam/v1/resolution/$levelType/$levelID/effectivepermissions"
        $UrlParameters = "?entityType=$entityType&entityID=$entityID&explain=$explain"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] RestPath: $RestPath"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] URLParameters: $URLParameters"
        $path = "$RestPath$URLParameters"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$path
                OutputAsJson = $OutputAsJson
            }
            Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceEffectivePermission
#EndRegion - Get-DynatraceEffectivePermission.ps1
#Region - Get-DynatraceEntity.ps1
function Get-DynatraceEntity {
<#
    .SYNOPSIS
        Get entities in Dynatrace environment
 
    .DESCRIPTION
        Get entities in Dynatrace environment
 
    .PARAMETER Type
        The type of entity to get
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceEntity -Type HOST_GROUP
 
    .NOTES
        https://api.dynatrace.com/spec/#/
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [String]$Type,
        [Switch]$outputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $EnvironmentID = (Get-DynatracePSConfig).EnvironmentID

        $uri = "https://$EnvironmentID.live.dynatrace.com/api/v2/entities"

        $GetParameter = @{
            entitySelector = "type(`"$Type`")"
            pageSize = 200
        }

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $Uri"
    }

    process {
        $splatParameters = @{
            Uri = $uri
            GetParameter = $GetParameter
            RestResponseProperty = 'entities'
        }
        $output = Invoke-DynatraceAPIMethod @splatParameters
        if ($OutputAsJson) {
            $output | ConvertTo-Json -Depth 6
        } else {
            $output
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceEntity
#EndRegion - Get-DynatraceEntity.ps1
#Region - Get-DynatraceEntityProperty.ps1
function Get-DynatraceEntityProperty {
<#
    .SYNOPSIS
        Get properties for a specified entity in Dynatrace environment
 
    .DESCRIPTION
        Get properties for a specified entity in Dynatrace environment
 
    .PARAMETER entityID
        The entity ID
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceEntityProperty -entityID HOST-9FADEDA85A24F460
 
    .NOTES
        https://api.dynatrace.com/spec/#/
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [String]$entityID,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $EnvironmentID = (Get-DynatracePSConfig).EnvironmentID

        $uri = "https://$EnvironmentID.live.dynatrace.com/api/v2/entities/$entityID"

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $Uri"
    }

    process {
        $splatParameters = @{
            Uri = $uri
        }
        $output = Invoke-DynatraceAPIMethod @splatParameters

        if ($OutputAsJson) {
            $output | ConvertTo-Json -Depth 6
        } else {
            $output
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceEntityProperty
#EndRegion - Get-DynatraceEntityProperty.ps1
#Region - Get-DynatraceEntityType.ps1
function Get-DynatraceEntityType {
<#
    .SYNOPSIS
        Get list of entity types in Dynatrace environment
 
    .DESCRIPTION
        Get list of entity types in Dynatrace environment
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceEntityType
 
    .NOTES
        https://api.dynatrace.com/spec/#/
#>


    [CmdletBinding()]
    param(
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $EnvironmentID = (Get-DynatracePSConfig).EnvironmentID

        $uri = "https://$EnvironmentID.live.dynatrace.com/api/v2/entityTypes"

        $GetParameter = @{
            pageSize = 200
        }

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $Uri"
    }
    process {
        $splatParameters = @{
            Uri = $uri
            GetParameter = $GetParameter
            RestResponseProperty = 'types'
        }
        $output = Invoke-DynatraceAPIMethod @splatParameters
        if ($OutputAsJson) {
            $output | ConvertTo-Json -Depth 6
        } else {
            $output
        }

    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceEntityType
#EndRegion - Get-DynatraceEntityType.ps1
#Region - Get-DynatraceEnvironment.ps1
function Get-DynatraceEnvironment {
<#
    .SYNOPSIS
        Lists all environments and management zones of a Dynatrace account
 
    .DESCRIPTION
        Lists all environments and management zones of a Dynatrace account
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceEnvironment
 
    .NOTES
        https://api.dynatrace.com/spec/#/Environment%20management/EnvironmentResourcesController_getEnvironmentResources
#>


    [CmdletBinding()]
    param(
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $AccountUuid = (Get-DynatracePSConfig).AccountUuid
        $RestPath = "/env/v1/accounts/$($AccountUuid)/environments"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $RestPath"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$RestPath
                OutputAsJson = $OutputAsJson
            }
            Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceEnvironment
#EndRegion - Get-DynatraceEnvironment.ps1
#Region - Get-DynatraceGroup.ps1
function Get-DynatraceGroup {
<#
    .SYNOPSIS
        List the groups on a Dynatrace account
 
    .DESCRIPTION
        List the groups on a Dynatrace account
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceGroup
 
    .NOTES
        https://api.dynatrace.com/spec/#/Group%20management/GroupsController_getGroups
#>


    [CmdletBinding()]
    param(
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $AccountUuid = (Get-DynatracePSConfig).AccountUuid
        $RestPath = "/iam/v1/accounts/$($AccountUuid)/groups"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $RestPath"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$RestPath
                OutputAsJson = $OutputAsJson
            }
            $return = Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Count of results: $($return.count)"
        if ($OutputAsJson) {
            $return
        } else {
            $return.items
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceGroup
#EndRegion - Get-DynatraceGroup.ps1
#Region - Get-DynatraceGroupPermission.ps1
function Get-DynatraceGroupPermission {
<#
    .SYNOPSIS
        List all permissions of a user group
 
    .DESCRIPTION
        List all permissions of a user group
 
    .PARAMETER GroupUuid
        The UUID of a user group
 
    .PARAMETER GroupName
        The name of a group
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceGroupPermission -groupUuid e5e9b12d-daf8-40d0-a6b5-7094667dd142
 
    .EXAMPLE
        Get-DynatraceGroupPermission -GroupName 'Monitoring Viewer'
 
    .NOTES
        https://api.dynatrace.com/spec/#/Group%20management/GroupsController_getUsersForGroup
 
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'Uuid')]
        [String]$groupUuid,
        [Parameter(Mandatory,ParameterSetName = 'Name')]
        [String]$GroupName,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $AccountUuid = (Get-DynatracePSConfig).AccountUuid

        if ($GroupName) {
            $groupUuid = (Get-DynatraceGroup | Where-Object{$_.Name -eq $GroupName}).Uuid
        }
        $RestPath = "/iam/v1/accounts/$AccountUuid/groups/$groupUuid/permissions"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $RestPath"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$RestPath
                OutputAsJson = $OutputAsJson
            }
            Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceGroupPermission
#EndRegion - Get-DynatraceGroupPermission.ps1
#Region - Get-DynatraceGroupUser.ps1
function Get-DynatraceGroupUser {
<#
    .SYNOPSIS
        List all members of a group on a Dynatrace account
 
    .DESCRIPTION
        List all members of a group on a Dynatrace account
 
    .PARAMETER GroupUuid
        The UUID of the user group
 
    .PARAMETER GroupName
        The Name of the group
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceGroupUser -groupUuid e5e9b12d-daf8-40d0-a6b5-7094667dd142
 
    .EXAMPLE
        Get-DynatraceGroupUser -GroupName 'Monitoring Viewer'
 
    .NOTES
        https://api.dynatrace.com/spec/#/Group%20management/GroupsController_getUsersForGroup
 
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'Uuid')]
        [String]$groupUuid,
        [Parameter(Mandatory,ParameterSetName = 'Name')]
        [String]$GroupName,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $AccountUuid = (Get-DynatracePSConfig).AccountUuid

        if ($GroupName) {
            $groupUuid = (Get-DynatraceGroup | Where-Object{$_.Name -eq $GroupName}).Uuid
        }
        $RestPath = "/iam/v1/accounts/$AccountUuid/groups/$groupUuid/users"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $RestPath"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$RestPath
                OutputAsJson = $OutputAsJson
            }
            $return = Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Count of results: $($return.count)"
        if ($OutputAsJson) {
            $return
        } else {
            $return.items
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceGroupUser
#EndRegion - Get-DynatraceGroupUser.ps1
#Region - Get-DynatraceHost.ps1
function Get-DynatraceHost {
<#
    .SYNOPSIS
        Gets hosts in Dynatrace environment
 
    .DESCRIPTION
        Gets hosts in Dynatrace environment
 
    .EXAMPLE
        Get-DynatraceHost
 
    .NOTES
        https://www.dynatrace.com/support/help/dynatrace-api/environment-api/entity-v2
#>


    [CmdletBinding()]
    param()

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"
    }

    process {
        Get-DynatraceEntity -Type 'HOST'
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceHost
#EndRegion - Get-DynatraceHost.ps1
#Region - Get-DynatraceHostGroup.ps1
function Get-DynatraceHostGroup {
<#
    .SYNOPSIS
        Get host groups in Dynatrace environment
 
    .DESCRIPTION
        Get host groups in Dynatrace environment
 
    .EXAMPLE
        Get-DynatraceHostGroup
 
    .NOTES
        https://www.dynatrace.com/support/help/dynatrace-api/environment-api/entity-v2
#>


    [CmdletBinding()]
    param()

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"
    }

    process {
        Get-DynatraceEntity -Type 'HOST_GROUP'
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceHostGroup
#EndRegion - Get-DynatraceHostGroup.ps1
#Region - Get-DynatraceHostGroupProperty.ps1
function Get-DynatraceHostGroupProperty {
<#
    .SYNOPSIS
        Get properties for a host group
 
    .DESCRIPTION
        Get properties for a host group
 
    .PARAMETER Id
        Unique id of the host group
 
    .PARAMETER Name
        Name of the host group
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceHostGroupProperty -id hostgroupid
 
    .NOTES
        https://www.dynatrace.com/support/help/dynatrace-api/environment-api/entity-v2/get-entity
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'id')]
        [string]$Id,
        [Parameter(Mandatory,ParameterSetName = 'name')]
        [string]$Name,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        if ($Name) {
            $Id = (Get-DynatraceHostGroup | Where-Object {$_.displayName -eq $Name}).entityID
        }
    }

    process {
        $splatParm = @{
            entityID = $Id
            OutputAsJson = $OutputAsJson
        }
        Get-DynatraceEntityProperty @splatParm
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceHostGroupProperty
#EndRegion - Get-DynatraceHostGroupProperty.ps1
#Region - Get-DynatraceHostProperty.ps1
function Get-DynatraceHostProperty {
<#
    .SYNOPSIS
        Get properties for a host
 
    .DESCRIPTION
        Get properties for a host
 
    .PARAMETER Id
        Unique id of the host
 
    .PARAMETER Name
        Name of the host
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceHostProperty -id hostid
 
    .EXAMPLE
        Get-DynatraceHostProperty -Name hostname -OutputAsJson
 
    .NOTES
        https://www.dynatrace.com/support/help/dynatrace-api/environment-api/entity-v2/get-entity
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'id')]
        [string]$Id,
        [Parameter(Mandatory,ParameterSetName = 'name')]
        [string]$Name,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        if ($Name) {
            $Id = (Get-DynatraceHost | Where-Object {$_.displayName -eq $Name}).entityId
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Got $Name entityID value of $Id"
        }
    }

    process {
        $splatParm = @{
            entityID = $Id
            OutputAsJson = $OutputAsJson
        }
        Get-DynatraceEntityProperty @splatParm
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceHostProperty
#EndRegion - Get-DynatraceHostProperty.ps1
#Region - Get-DynatraceManagementZone.ps1
function Get-DynatraceManagementZone {
<#
    .SYNOPSIS
        Get list of management zones in Dynatrace environment
 
    .DESCRIPTION
        Get list of management zones in Dynatrace environment
 
    .EXAMPLE
        Get-DynatraceManagementZone
 
    .NOTES
        https://api.dynatrace.com/spec/#/
#>


    [CmdletBinding()]
    param()

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $EnvironmentID = (Get-DynatracePSConfig).EnvironmentID

        $uri = "https://$EnvironmentID.live.dynatrace.com/api/config/v1/managementZones"

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $Uri"
    }

    process {
        $splatParameters = @{
            Uri = $uri
            RestResponseProperty = 'values'
        }
        Invoke-DynatraceAPIMethod @splatParameters
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceManagementZone
#EndRegion - Get-DynatraceManagementZone.ps1
#Region - Get-DynatraceManagementZoneProperty.ps1
function Get-DynatraceManagementZoneProperty {
<#
    .SYNOPSIS
        Get properties of a management zone in Dynatrace environment
 
    .DESCRIPTION
        Get properties of a management zone in Dynatrace environment
 
    .PARAMETER Id
        The unique id of the management zone. Required if not using name
 
    .PARAMETER Name
        The name of the management zone. Required if not using id
 
    .PARAMETER OutputAsJson
        Output the management zone properties as Json
 
    .EXAMPLE
        Get-DynatraceManagementZoneProperty -id 1234554321
 
        Get management zone properties associated with management zone with id of 1234554321.
 
    .EXAMPLE
        Get-DynatraceManagementZoneProperty -Name PROD_WINDOWS -OutputAsJson
 
        Get management zone properties for the management zone named PROD_WINDOWS and output them as json
 
    .NOTES
        https://www.dynatrace.com/support/help/dynatrace-api/configuration-api/management-zones-api/get-mz
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'id')]
        [string]$id,
        [Parameter(Mandatory,ParameterSetName = 'name')]
        [string]$Name,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        if ($Name) {
            $id = (Get-DynatraceManagementZone | Where-Object {$_.Name -eq $Name}).id
        }

        $EnvironmentID = (Get-DynatracePSConfig).EnvironmentID
        $uri = "https://$EnvironmentID.live.dynatrace.com/api/config/v1/managementZones/$id"

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $Uri"
    }

    process {
        $splatParameters = @{
            Uri = $uri
        }
        $output = Invoke-DynatraceAPIMethod @splatParameters

        if ($OutputAsJson) {
            $output | ConvertTo-Json -Depth 6
        } else {
            $output
        }

    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceManagementZoneProperty
#EndRegion - Get-DynatraceManagementZoneProperty.ps1
#Region - Get-DynatracePermission.ps1
function Get-DynatracePermission {
<#
    .SYNOPSIS
        Lists all available permissions
 
    .DESCRIPTION
        Lists all available permissions
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatracePermission
 
    .NOTES
        https://api.dynatrace.com/spec/#/Reference%20data/ReferenceDataController_getPermissions
#>


    [CmdletBinding()]
    param(
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $RestPath = "/ref/v1/account/permissions"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $RestPath"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$RestPath
                OutputAsJson = $OutputAsJson
            }
            Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatracePermission
#EndRegion - Get-DynatracePermission.ps1
#Region - Get-DynatraceProcess.ps1
function Get-DynatraceProcess {
<#
    .SYNOPSIS
        Get list of monitored processes from Dynatrace environment
 
    .DESCRIPTION
        Get list of monitored processes from Dynatrace environment
 
    .EXAMPLE
        Get-DynatraceProcess
 
    .NOTES
        https://www.dynatrace.com/support/help/dynatrace-api/environment-api/entity-v2
#>


    [CmdletBinding()]
    param()

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"
    }

    process {
        Get-DynatraceEntity -Type 'PROCESS_GROUP_INSTANCE'
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceProcess
#EndRegion - Get-DynatraceProcess.ps1
#Region - Get-DynatraceProcessGroup.ps1
function Get-DynatraceProcessGroup {
<#
    .SYNOPSIS
        Get process groups in Dynatrace environment
 
    .DESCRIPTION
        Get process groups in Dynatrace environment
 
    .EXAMPLE
        Get-DynatraceProcessGroup
 
    .NOTES
        https://www.dynatrace.com/support/help/how-to-use-dynatrace/process-groups
 
#>


    [CmdletBinding()]
    param()

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"
    }

    process {
        Get-DynatraceEntity -Type 'PROCESS_GROUP'
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceProcessGroup
#EndRegion - Get-DynatraceProcessGroup.ps1
#Region - Get-DynatraceProcessGroupProperty.ps1
function Get-DynatraceProcessGroupProperty {
<#
    .SYNOPSIS
        Get process group properties from Dynatrace environment
 
    .DESCRIPTION
        Get process group properties from Dynatrace environment
 
    .PARAMETER Id
        Unique id of the process group
 
    .PARAMETER Name
        Name of the process group
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceProcessGroupProperty -Id <process-group-id>
 
    .EXAMPLE
        Get-DynatraceProcessGroupProperty -Name <process-group-name> -OutputAsJson
 
    .NOTES
        https://www.dynatrace.com/support/help/how-to-use-dynatrace/process-groups
 
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'id')]
        [string]$Id,
        [Parameter(Mandatory,ParameterSetName = 'name')]
        [string]$Name,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        if ($Name) {
            $entityIds = (Get-DynatraceProcessGroup | Where-Object {$_.displayName -eq $Name}).entityID
        } else {
            $entityIds = $Id
        }
    }

    process {
        foreach ($entityId in $entityIDs) {
            $splatParm = @{
                entityID = $entityId
                OutputAsJson = $OutputAsJson
            }
            Get-DynatraceEntityProperty @splatParm
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceProcessGroupProperty
#EndRegion - Get-DynatraceProcessGroupProperty.ps1
#Region - Get-DynatraceProcessProperty.ps1
function Get-DynatraceProcessProperty {
<#
    .SYNOPSIS
        Get a process's properties from Dynatrace environment
 
    .DESCRIPTION
        Get a process's properties from Dynatrace environment
 
    .PARAMETER Id
        Unique id of the process
 
    .PARAMETER Name
        Name of the process
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceProcessProperty -Id <process-id>
 
    .EXAMPLE
        Get-DynatraceProcessProperty -Name <process-name> -OutputAsJson
 
    .NOTES
        https://www.dynatrace.com/support/help/dynatrace-api/environment-api/entity-v2/get-entity
 
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ParameterSetName = 'id')]
        [string]$Id,
        [Parameter(Mandatory,ParameterSetName = 'name')]
        [string]$Name,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        if ($Name) {
            $entityIds = (Get-DynatraceProcess | Where-Object {$_.displayName -eq $Name}).entityID
        } else {
            $entityIds = $Id
        }
    }

    process {
        foreach ($entityId in $entityIDs) {
            $splatParm = @{
                entityID = $entityId
                OutputAsJson = $OutputAsJson
            }
            Get-DynatraceEntityProperty @splatParm
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceProcessProperty
#EndRegion - Get-DynatraceProcessProperty.ps1
#Region - Get-DynatracePSConfig.ps1
function Get-DynatracePSConfig {
<#
.SYNOPSIS
    Get default configurations for DynatracePS from config.json file
 
.DESCRIPTION
    Get default configurations for DynatracePS from config.json file
 
.EXAMPLE
    Get-DynatracePSConfig
#>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    Param ()

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"
        $config = "$([Environment]::GetFolderPath('ApplicationData'))\DynatracePS\config.json"
        $OauthXmlFile = "$([Environment]::GetFolderPath('ApplicationData'))\DynatracePS\OauthSecret.xml"
        $AccessXmlFile = "$([Environment]::GetFolderPath('ApplicationData'))\DynatracePS\AccessToken.xml"
    }

    process {
        $Output = [PSCustomObject]@()
        if (Test-Path $config) {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Getting config from [$config]"
            if (Test-Path $OauthXmlFile) {
                Write-Verbose "[$($MyInvocation.MyCommand.Name)] Getting Oauth Secret from [$OauthXmlFile]"
                $OauthCredential = [PSCredential](Import-Clixml $OauthXmlFile)
                $OauthClientSecret = $OauthCredential.GetNetworkCredential().Password
            } else {
                $OauthClientSecret = ''
            }
            if (Test-Path $AccessXmlFile) {
                Write-Verbose "[$($MyInvocation.MyCommand.Name)] Getting Access Token from [$AccessXmlFile]"
                $AccessCredential = [PSCredential](Import-Clixml $AccessXmlFile)
                $AccessToken = $AccessCredential.GetNetworkCredential().Password
            } else {
                $AccessToken = ''
            }
            $Output = (Get-Content -Path "$config" -ErrorAction Stop | ConvertFrom-Json)
            $Output | Add-Member -MemberType NoteProperty -Name OauthClientSecret -Value $OauthClientSecret
            $Output | Add-Member -MemberType NoteProperty -Name AccessToken -Value $AccessToken
        } else {
            Write-Warning "[$($MyInvocation.MyCommand.Name)] No config found at [$config]"
            Write-Warning "[$($MyInvocation.MyCommand.Name)] Use Set-DynatracePSConfig first!"
            break
        }
        $Output
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function complete"
    }
} # end function

Export-ModuleMember -Function Get-DynatracePSConfig
#EndRegion - Get-DynatracePSConfig.ps1
#Region - Get-DynatraceQuota.ps1
function Get-DynatraceQuota {
<#
    .SYNOPSIS
        Gets the host units quota of a Dynatrace account
 
    .DESCRIPTION
        Gets the host units quota of a Dynatrace account
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceQuote
 
    .NOTES
        https://api.dynatrace.com/spec/#/Quota%20management/QuotaController_getQuota
#>


    [CmdletBinding()]
    param(
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $AccountUuid = (Get-DynatracePSConfig).AccountUuid
        $RestPath = "/env/v1/accounts/$($AccountUuid)/quotas/host-monitoring"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $RestPath"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$RestPath
                OutputAsJson = $OutputAsJson
            }
            Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceQuota
#EndRegion - Get-DynatraceQuota.ps1
#Region - Get-DynatraceSettingsSchema.ps1
function Get-DynatraceSettingsSchema {
<#
    .SYNOPSIS
        Get list of settings schemas in Dynatrace environment
 
    .DESCRIPTION
        Get list of settings schemas in Dynatrace environment
 
    .EXAMPLE
        Get-DynatraceSettingsSchema
 
    .NOTES
        https://api.dynatrace.com/spec/#/
#>


    [CmdletBinding()]
    param()

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $EnvironmentID = (Get-DynatracePSConfig).EnvironmentID

        $uri = "https://$EnvironmentID.live.dynatrace.com/api/v2/settings/schemas"

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $Uri"
    }

    process {
        $splatParameters = @{
            Uri = $uri
            RestResponseProperty = 'items'
        }
        Invoke-DynatraceAPIMethod @splatParameters
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceSettingsSchema
#EndRegion - Get-DynatraceSettingsSchema.ps1
#Region - Get-DynatraceSubscription.ps1
function Get-DynatraceSubscription {
<#
    .SYNOPSIS
        Lists all Dynatrace platform subscriptions of an account
 
    .DESCRIPTION
        Lists all Dynatrace platform subscriptions of an account
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceSubscription
 
    .NOTES
        https://api.dynatrace.com/spec/#/Dynatrace%20platform%20subscription/LimaClaController_getClaSubscriptions
#>


    [CmdletBinding()]
    param(
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $AccountUuid = (Get-DynatracePSConfig).AccountUuid
        $RestPath = "/sub/v1/accounts/$($AccountUuid)/subscriptions"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $RestPath"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$RestPath
                OutputAsJson = $OutputAsJson
            }
            $return = Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Count of results: $($return.totalCount)"
        if ($OutputAsJson) {
            $return | ConvertTo-Json -Depth 6
        } else {
            $return.records
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceSubscription
#EndRegion - Get-DynatraceSubscription.ps1
#Region - Get-DynatraceUser.ps1
function Get-DynatraceUser {
<#
    .SYNOPSIS
        List the users of a Dynatrace account
 
    .DESCRIPTION
        List the users of a Dynatrace account
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceUser
 
    .NOTES
        https://api.dynatrace.com/spec/#/User%20management/UsersController_getUsers
 
#>


    [CmdletBinding()]
    param(
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $AccountUuid = (Get-DynatracePSConfig).AccountUuid
        $RestPath = "/iam/v1/accounts/$($AccountUuid)/users"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $RestPath"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$RestPath
                OutputAsJson = $OutputAsJson
            }
            $return = Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Count of results: $($return.count)"
        if ($OutputAsJson) {
            $return
        } else {
            $return.items
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



Export-ModuleMember -Function Get-DynatraceUser
#EndRegion - Get-DynatraceUser.ps1
#Region - Get-DynatraceUserGroup.ps1
function Get-DynatraceUserGroup {
<#
    .SYNOPSIS
        List the groups for a user
 
    .DESCRIPTION
        List the groups for a user
 
    .PARAMETER OutputAsJson
        Output the properties as a JSON string
 
    .EXAMPLE
        Get-DynatraceUserGroup -Email name@domain.com
 
    .NOTES
        https://api.dynatrace.com/spec/#/User%20management/UsersController_getUserGroups
 
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [String]$Email,
        [switch]$OutputAsJson
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

        $AccountUuid = (Get-DynatracePSConfig).AccountUuid
        $RestPath = "/iam/v1/accounts/$($AccountUuid)/users/$Email"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] $RestPath"
    }

    process {
        try {
            $splatParameters = @{
                RestPath =$RestPath
                OutputAsJson = $OutputAsJson
            }
            Invoke-DynatraceAccountManagementAPIMethod @splatParameters
        } catch {
            $_
            break
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}
Export-ModuleMember -Function Get-DynatraceUserGroup
#EndRegion - Get-DynatraceUserGroup.ps1
#Region - Set-DynatracePSConfig.ps1
function Set-DynatracePSConfig {
<#
.SYNOPSIS
    Set the Dynatrace SaaS Environment ID to use when connecting
 
.DESCRIPTION
    Set the Dynatrace SaaS Environment ID to use when connecting
    Saves the information to DynatracePS/config.json file in user profile
 
.PARAMETER EnvironmentID
    Dynatrace SaaS Environment ID. This is the left most part of the hostname name: envid.live.dynatrace.com
 
.PARAMETER AccountUuid
    Dynatrace Account ID. You can find the UUID on the Account > Account management API page, during creation of an OAuth client
 
.PARAMETER OAuthClientSecret
    The client_secret value that is created in the Account management API page. Used for connecting to Dynatrace Account Management API
 
.PARAMETER AccessToken
    The access token or personal access token for Dynatrace API
 
.EXAMPLE
    Set-DynatracePSConfig -EnvironmentID 'envid' -AccountUuid 'dynatrace-account-id'
 
.NOTES
    https://www.dynatrace.com/support/help/dynatrace-api/basics/dynatrace-api-authentication#tabgroup--generate-token--personal-access-token
    https://www.dynatrace.com/support/help/get-started/access-tokens
#>

    [CmdletBinding()]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',
        Justification='This function is trivial enough that we do not need ShouldProcess')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '',
        Justification='There is no other easy way to do this. at least i can not come up with it at 1am')]
    Param (
        [String]$EnvironmentID,
        [String]$AccountUuid,
        [String]$OAuthClientSecret,
        [String]$AccessToken
    )
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"

        $cliXmlFile = "$([Environment]::GetFolderPath('ApplicationData'))\DynatracePS\OauthSecret.xml"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Oauth secret will be stored in $($OauthXmlFile)"

        $AccessXmlFile = "$([Environment]::GetFolderPath('ApplicationData'))\DynatracePS\AccessToken.xml"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Access token will be stored in $($AccessXmlFile)"

        $configPath = "$([Environment]::GetFolderPath('ApplicationData'))\DynatracePS\config.json"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Configuration will be stored in $($configPath)"

        if (-not (Test-Path $configPath)) {
            # If the config file doesn't exist, create it
            $null = New-Item -Path $configPath -ItemType File -Force
        }
    }

    process {
        $ExistingConfig = Get-DynatracePSConfig

        # If no environment ID passed in, and there is existing value, use existing
        if ((-not $EnvironmentID) -and ($ExistingConfig.EnvironmentID)) {
            $EnvironmentID = $ExistingConfig.EnvironmentID
        }
        if ((-not $AccountUuid) -and ($ExistingConfig.AccountUuid)) {
            $AccountUuid = $ExistingConfig.AccountUuid
        }
        $config = [ordered]@{
            EnvironmentID = $EnvironmentID
            AccountUuid = $AccountUuid
        }
        $config | ConvertTo-Json | Set-Content -Path "$configPath"

        if ($OAuthClientSecret) {
            $username = 'DynatraceAccountManagement'
            $pass = ConvertTo-SecureString $OAuthClientSecret -AsPlainText -Force
            [PSCredential]$credential = New-Object System.Management.Automation.PSCredential(
                $UserName, $pass
            )
            $credential | Export-Clixml $cliXmlFile
        }

        if ($AccessToken) {
            $username = 'DynatraceAccess'
            $pass = ConvertTo-SecureString $AccessToken -AsPlainText -Force
            [PSCredential]$credential = New-Object System.Management.Automation.PSCredential(
                $UserName, $pass
            )
            $credential | Export-Clixml $AccessXmlFile
        }
    }

    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
} # end function
Export-ModuleMember -Function Set-DynatracePSConfig
#EndRegion - Set-DynatracePSConfig.ps1
### --- PRIVATE FUNCTIONS --- ###
#Region - ConvertTo-GetParameter.ps1
function ConvertTo-GetParameter {
    <#
    .SYNOPSIS
    Generate the GET parameter string for an URL from a hashtable
    #>

    [CmdletBinding()]
    param (
        [Parameter( Position = 0, Mandatory = $true, ValueFromPipeline = $true )]
        [hashtable]$InputObject
    )

    process {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Making HTTP get parameter string out of a hashtable"
        Write-Verbose ($InputObject | Out-String)
        [string]$parameters = "?"
        # If the key is name nextPageKey is in the input object, it is *the only*
        # key that should be included in the parameters
        #
        if ('nextPageKey' -in $InputObject.Keys) {
            $value = $InputObject['nextPageKey']
            $parameters += "nextPageKey=$($value)&"
        } else {
            foreach ($key in $InputObject.Keys) {
                $value = $InputObject[$key]
                $parameters += "$key=$($value)&"
            }
        }
        $parameters -replace ".$"
    }
}
#EndRegion - ConvertTo-GetParameter.ps1
#Region - ConvertTo-ParameterHash.ps1
function ConvertTo-ParameterHash {
    [CmdletBinding( DefaultParameterSetName = 'ByString' )]
    param (
        # URI from which to use the query
        [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'ByUri' )]
        [Uri]$Uri,

        # Query string
        [Parameter( Position = 0, Mandatory, ParameterSetName = 'ByString' )]
        [String]$Query
    )

    process {
        $GetParameter = @{}

        if ($Uri) {
            $Query = $Uri.Query
        }

        if ($Query -match "^\?.+") {
            $Query.TrimStart("?").Split("&") | ForEach-Object {
                $key, $value = $_.Split("=")
                $GetParameter.Add($key, $value)
            }
        }

        Write-Output $GetParameter
    }
}
#EndRegion - ConvertTo-ParameterHash.ps1
#Region - Invoke-DynatraceAccountManagementAPIMethod.ps1
function Invoke-DynatraceAccountManagementAPIMethod {
    <#
        .SYNOPSIS
            Invoke a method on in the Dynatrace Account Management API
 
        .DESCRIPTION
            Invoke a method on in the Dynatrace Account Management API
 
        .PARAMETER RestPath
            The rest path to append to base url
 
        .EXAMPLE
            Invoke-DynatraceAccountManagementAPIMethod -RestPath '/ref/v1/account/permissions'
 
        .NOTES
            https://api.dynatrace.com/spec/#/
 
        #>


        [CmdletBinding()]
        param(
            [Parameter(Mandatory)]
            [String]$RestPath,
            [Microsoft.PowerShell.Commands.WebRequestMethod]$Method = 'GET',
            [switch]$OutputAsJson
        )

        begin {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
            Write-Debug "[$($MyInvocation.MyCommand.Name)] Function started"

            $Connection = Connect-DynatraceAccountManagement
            $access_token = $Connection.access_token
            $headers = @{
                Authorization = "Bearer $access_token"
            }
            $Uri = "https://api.dynatrace.com$RestPath"
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] $Uri"
        }

        process {
            try {
                $output = Invoke-RestMethod -Uri $Uri -Method $Method -Headers $headers
            } catch {
                Write-Warning "[$($MyInvocation.MyCommand.Name)] Problem with Invoke-RestMethod $uri"
                $_
                break
            }
            if ($OutputAsJson) {
                $output | ConvertTo-Json -Depth 6
            } else {
                $output
            }
        }
        end {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
            Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
        }
    }



#EndRegion - Invoke-DynatraceAccountManagementAPIMethod.ps1
#Region - Invoke-DynatraceAPIMethod.ps1
function Invoke-DynatraceAPIMethod {
<#
.SYNOPSIS
    Invoke a method in the Dynatrace API. This is a service function to be called by other functions.
 
.DESCRIPTION
    Invoke a method in the Dynatrace API. This is a service function to be called by other functions.
 
.PARAMETER Uri
    Uri to use for Invoke-RestMethod
 
.PARAMETER Method
    Defaults to GET
 
.PARAMETER Headers
    Headers to use. Will be joined with authorization header.
 
.PARAMETER GetParameter
    Get parameters to include
 
.PARAMETER RestResponseProperty
    Property of the rest response to return as results.
 
.PARAMETER LevelOfRecursion
    Internal parameter used to help determine how far into the matrix we are
 
.EXAMPLE
    Invoke-DynatraceAPIMethod -Uri https://environmentid.live.dynatrace.com/api/v2/entityTypes -RestResponseProperty types
 
.NOTES
    https://api.dynatrace.com/spec/#/
 
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [Uri]$Uri,
        [Microsoft.PowerShell.Commands.WebRequestMethod]$Method = 'GET',
        [Hashtable]$Headers,
        [Hashtable]$GetParameter = @{},
        [string]$RestResponseProperty,
        [int]$LevelOfRecursion = 1
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name) $LevelOfRecursion] Function started"
        Write-Debug "[$($MyInvocation.MyCommand.Name) $LevelOfRecursion] Function started. PSBoundParameters: $($PSBoundParameters | Out-String)"

#region AuthHeaders
        $config = Get-DynatracePSConfig
        $access_token = $config.accesstoken

        if (-not $access_token) {
            Write-Warning "[$($MyInvocation.MyCommand.Name) $Level] Must first configure an access token with Set-DynatracePSConfig -AccessToken <token>. Exiting..."
            break
        }

        $_headers = @{
            Authorization = "Api-Token $access_token"
        }
#endregion AuthHeaders

        $uriQuery = ConvertTo-ParameterHash -Uri $Uri

        $internalGetParameter = Join-Hashtable $uriQuery, $GetParameter
        [Uri]$LeftPartOfURI = $Uri.GetLeftPart('Path')
        [Uri]$FinalURI = "{0}{1}" -f $LeftPartOfURI,(ConvertTo-GetParameter $internalGetParameter)

        Write-Verbose "[$($MyInvocation.MyCommand.Name) $LevelOfRecursion] FinalURI: [$FinalUri]"

        try {
            $RestResponse = Invoke-RestMethod -Uri $FinalURI -Method $Method -Headers $_headers
        } catch {
            Write-Warning "[$($MyInvocation.MyCommand.Name) $LevelOfRecursion] Problem with Invoke-RestMethod $uri"
            $_
            break
        }
        Write-Verbose "[$($MyInvocation.MyCommand.Name) $LevelOfRecursion] Executed RestMethod"

        Test-ServerResponse -InputObject $RestResponse
    }

    process {
        if ($RestResponse) {
            Write-Verbose "[$($MyInvocation.MyCommand.Name) $LevelOfRecursion] nextPageKey: $($RestResponse.nextPageKey)"

            $NextPageKey = $RestResponse.nextPageKey

            if ($RestResponseProperty) {
                $result = ($RestResponse).$RestResponseProperty
            } else {
                $result = $RestResponse
            }

            if (-not $PSBoundParameters["GetParameter"]) {
                $PSBoundParameters["GetParameter"] = $internalGetParameter
            }

            do {

                if (-not $NextPageKey) {
                    # if there is no page key, then quit
                    break
                } else {
                    # Output results from this loop
                    $result
                }

                $PSBoundParameters["GetParameter"]['nextPageKey'] = $NextPageKey
                $PSBoundParameters["LevelOfRecursion"] = $LevelOfRecursion + 1

                Write-Verbose "[$($MyInvocation.MyCommand.Name) $LevelOfRecursion] Calling Invoke-DynatraceApiMethod"
                $result = Invoke-DynatraceApiMethod @PSBoundParameters
            } while (-not $NextPageKey)

            $result
        }
    }
    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}
#EndRegion - Invoke-DynatraceAPIMethod.ps1
#Region - Join-Hashtable.ps1
function Join-Hashtable {
    <#
    .SYNOPSIS
        Combines multiple hashtables into a single table.
    .DESCRIPTION
        Combines multiple hashtables into a single table.
        On multiple identic keys, the last wins.
    .EXAMPLE
        PS C:\> Join-Hashtable -Hashtable $Hash1, $Hash2
        Merges the hashtables contained in $Hash1 and $Hash2 into a single hashtable.
#>

    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    Param (
        # The tables to merge.
        [Parameter( Mandatory, ValueFromPipeline )]
        [AllowNull()]
        [System.Collections.IDictionary[]]
        $Hashtable
    )
    begin {
        $table = @{ }
    }

    process {
        foreach ($item in $Hashtable) {
            foreach ($key in $item.Keys) {
                $table[$key] = $item[$key]
            }
        }
    }

    end {
        $table
    }
}
#EndRegion - Join-Hashtable.ps1
#Region - Test-ServerResponse.ps1
function Test-ServerResponse {
    [CmdletBinding()]
    <#
        .SYNOPSIS
            Evaluate the response of the API call
        .NOTES
            Thanks to Lipkau:
            https://github.com/AtlassianPS/JiraPS/blob/master/JiraPS/Private/Test-ServerResponse.ps1
    #>

    param (
        [Parameter( ValueFromPipeline )]
        [PSObject]$InputObject
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Checking response for error"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Checking response for error"
    }

    process {
        if ($InputObject.Code -gt 200) {
            Write-Debug "[$($MyInvocation.MyCommand.Name)] Error code found, throwing error"
            throw ("{0}: {1}" -f $InputObject.Code,($InputObject.message -join ','))
        }
    }

    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Done checking response for error"
        Write-Debug "[$($MyInvocation.MyCommand.Name)] Done checking response for error"
    }
}
#EndRegion - Test-ServerResponse.ps1

# SIG # Begin signature block
# MIIFjQYJKoZIhvcNAQcCoIIFfjCCBXoCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU+hEbpIw72YbbZPDzDiT2RSrX
# RPWgggMnMIIDIzCCAgugAwIBAgIQfxlXoOWZRbhMi6xrw92ZDzANBgkqhkiG9w0B
# AQsFADAbMRkwFwYDVQQDDBBzZWxmLnNpZ25lZC5jZXJ0MB4XDTIyMDQzMDAyNDYw
# MFoXDTIzMDQzMDAzMDYwMFowGzEZMBcGA1UEAwwQc2VsZi5zaWduZWQuY2VydDCC
# ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALUk2x84obgu2AqpvrBQ47LK
# T01imCRSOYU3wIVEyd0H0WE/gZkc/Aji68mojxlKcdLKGRNiEFDsXbWX2fWM6KC2
# PVS/txe1fgCpz5eeq9CyHqTuUz8m3XDRMtAX91R8xyiLQSFWgrfDPJWRBWHv3sNv
# ZD4c00hle+YHLhuw76oc2z22ikMhCND8GfVlSWxoIiI2hcNN5oCkqiNjxYs3fWD5
# sUcYTDWj62AL00Zml+FI6CvRO2XSdKVRMvAqN2vskwwO6ayMASYrEcJ4WTcQj1dp
# WjCZdgqMrBGVxvc6wg6YWVDzlHRCg4AxVZjt12LGkqYwkjROHN2wzE/4/0svU00C
# AwEAAaNjMGEwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsG
# A1UdEQQUMBKCEHNlbGYuc2lnbmVkLmNlcnQwHQYDVR0OBBYEFMYfeufU5fggCTcR
# +V0v1lQC6bOkMA0GCSqGSIb3DQEBCwUAA4IBAQAsI+0UFKIeVPZ36nodt9JqhyQK
# yC1SsuvIwGew0QsdeDaM2mLwbZfmKumAPq27tOIhozaydme4vnbKyDv4MShR6MLk
# UwquAJ70k+mMrivol7SL+I208iO0itt5Kxxd+cNKl2G1tRIfGvE9qoZ02WIjvNQH
# BazJHjldlW/QXkoy0Ip/02mR3KvnGGRiipU8DjLi/lUbAUJAVO3zZ99iiXg2w5Be
# 2gOt7n7Csx10Fe2KJfKrbXVYShcim6wMbrHtvYBrtagFaAT2RXzZyQfCoGYtP2Vw
# w8fHDmJ8yFy3fRCHL53A7FsJ499gJDbj0afH0AE7uDShNoc2F8WoHaLLe7UfMYIB
# 0DCCAcwCAQEwLzAbMRkwFwYDVQQDDBBzZWxmLnNpZ25lZC5jZXJ0AhB/GVeg5ZlF
# uEyLrGvD3ZkPMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAA
# MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgor
# BgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTSGyLRc/qv4goxoQjUHcll2GvQfDAN
# BgkqhkiG9w0BAQEFAASCAQB4boRCMwETmS869kwsGmvKJw0z84/oPZRCu7E+QgDN
# oJoGqLSS8lRjpAIOWCDe4Eobb4qYWuN8sZkB0T4EUzwLiaE3n2xUh82zcX1oRIAQ
# 0+u53Q/4RUHye/gN3nOZbQ8xeNzbn1WoRFsJy7GADYwfQlBoQ047OfDzsH+tcf6z
# 7K2ZkSgKa5xJvtaY5R3S9QuZAXTNVVAN1KZQuo/dHmKgE5OgyNU0HATDrQqPTwsV
# RJ8rDb8F6JnmwiLzgM1m7L8JZZmXj4rB4ZCDMDCwqKJujaTAjUlS0nzMid4GDnAo
# qONpdet7SM5nw23hiaSsA9TDUqvapWKf7IguSRBSXLdm
# SIG # End signature block