How to Count Servers in Ivanti When Your Warehouse Has No Server Table
Ivanti shows a server, a printer, and a vendor contract as separate business objects. The warehouse lands all 35 kinds in one ci table where Server is a value. The semantic model makes it the filter.
Ivanti gives a server its own workspace, its own forms, and its own name in the REST API. Ask the same question of an Ivanti Neurons for ITSM warehouse and none of that survives. The connector lands 768 tables, and not one of them is named for a server. All 35 kinds of configuration item share a single table, and the column that tells them apart isn't documented anywhere the warehouse can see.
An asset lead wants a count of servers in the CMDB, broken out by operating system.
Query your Ivanti data with AI against a replicated warehouse and the catalog looks encouraging. It holds 768 tables. Two of them have "server" in the name. One is called ci, which is what a CMDB stores.
Every one of those three signals points somewhere wrong.
Before you start
- Ivanti Neurons for ITSM replicated through the Fivetran connector. It's a Lite connector, built from the vendor's API, so Ivanti's own business object reference is the authority for what anything means.
- The connector publishes table names and five system columns, and nothing else. Its schema ERD lists 768 tables. Of those, 633 are drawn with
rec_id,created_by,created_date_time,last_mod_date_time, andlast_modified_by; the other 135 carryrec_idalone. Not one business column appears on any of them. - 135 tables land without timestamps. Those are the objects Fivetran re-imports rather than syncing incrementally. On them, "created last month" has no answer in the landed columns.
- No free instance to practise on. Ivanti has no self-serve developer tenant, so this runs against an extract your employer already has. Ivanti's documentation is readable without a login, so you can study every schema below before you have access to anything. If you're a customer, Ivanti's guidance for schema work is to use the staging instance beside production, which is also the lower-risk place to point a first sync.
- Casing varies by route. Ivanti's fields are Pascal case (
CIType), Fivetran lands snake case, and Snowflake upper-cases the lot. The SQL below uses Fivetran's lower-case names.
The question
"How many servers are in our CMDB, and what are they running?"
Every IT organisation asks it, and it's rarely idle. Licence true-ups, patch coverage, an end-of-support migration, and the capacity line in next year's budget all start here.
It comes out of the warehouse rather than out of Ivanti because the question rarely stops at a count. It wants the servers beside the incidents they caused, the contracts that cover them, and last quarter's figure.
What breaks
Here's the query almost anyone writes first.
SELECT operating_system,
COUNT(*) AS servers
FROM ci
GROUP BY operating_system
ORDER BY servers DESC;Nothing about it is careless. ci is the configuration item table, and a CMDB is a database of configuration items. The query runs, returns a row per operating system, and reports a number.
The number counts printers. It also counts phones, monitors, racks, and uninterruptible power supplies. Then it counts the things nobody would call a device at all: business services, databases, documents, and vendor contracts.
A second attempt looks smarter and is worse.
SELECT COUNT(*) FROM frs_hc_servers;That table exists. Its name contains the word. It holds no configuration items.
Neither query errors, and neither returns anything obviously absurd. The first is a plausible count of servers for an organisation somewhat larger than yours, which is the worst failure mode available.
Why it breaks
Three facts are true at once, and the first query reads none of them.
Ivanti's servers are a derived type of one shared base
Ivanti calls this a group business object, and its documentation defines one in a sentence:
A group business object consists of an abstract base type and one or more derived types. A configuration item is one example of a group business object type. The configuration item group subtypes, such as workstations, servers, printers, and so on, derive fields and relationships from the configuration item base type.
The same page is explicit about how that looks to a person using the application: "For example, printer, workstation, server, and so on are all separate business objects."
Separate is doing real work in that sentence. Each member has its own workspace, its own forms, and its own saved searches. Ivanti's REST API addresses members by name, and its integrator documentation spells the convention out: "To query group business objects, provide the group business object name with the member object name. For example, CI.Server, Address.Email, Address.Mail, Address.Phone." Business rules do the same, matching children of type Task#Assignment rather than every task.
Wherever a person or a rule touches this data inside Ivanti, the member name does the filtering.
The group exists so the opposite is also possible. Ivanti again: "Without connecting these different business objects under a group, you cannot search across, or list these business objects together." Two views of the same records, and you choose one by name.
Replication keeps the group and drops the members
Counting Ivanti's own Default Business Objects list gives 133 names written Group.Member, spread across 27 groups. CI is the largest, with 35 members.
Against the connector's 768 landed tables:
- All 27 group bases land.
ci,task,journal,address,service_level_target,frs_knowledge, and 21 more. - None of the 133 members lands. No
ci_server, notask_assignment, nojournal_notes. - Exactly two table names contain "server". They're
frs_hc_serversandfrs_server_type, each its own separate business object. Neither isCI.Server, and neither holds CI records.
So the word "Server" survives replication only as a value in a column.

The application's view and the warehouse's view of the same records. The 35 member names and the absence of a ci_server table are Ivanti's and Fivetran's; the row values are illustrative.
Which column? Ivanti creates it automatically, and names it after the group. From the business object setup reference: "Type Selector: Created automatically based on the business object. The type selector field is only shown for the group-base and group-member business objects." Create a group called NewBusinessObject and its default fields include NewBusinessObjectType.
Three shipped groups confirm the pattern in Ivanti's own payloads: CIType on CI, JournalType on Journal, and FRS_KnowledgeType on FRS_Knowledge.
Ivanti's discovery tooling fills that column with member names. Its HEAT Discovery field mapping writes a device's class into CIType with the mapping ESX > Server, Server > Server, Unix Box > Server, PC > Workstation, Portable > Workstation, Macintosh > Workstation, Printer > Printer, and Unknown > UnknownDevice. The agent scan writes OS Class to CIType and OS Platform to OperatingSystem, both on CI.
The connector documents none of it
Here's the ci table as the connector publishes it:
ci
rec_id
created_by
created_date_time
last_mod_date_time
last_modified_byThat's the whole entry. The column the last section spent four paragraphs on doesn't appear, because the columns that land are whatever fields a tenant's business objects expose through the API, and the connector can't list per-tenant fields in a static schema.
The relations array is empty across all 768 tables. It isn't sparse or partial. Zero declared foreign keys in the entire schema.

What an agent can read from the connector's published schema, and what it can't. Table names, the five system columns and the empty relations array are Fivetran's; the question is ours.
So an agent pointed at this warehouse sees 768 table names, no business columns, no relationships, and no table named for the thing it was asked about. ci is a reasonable guess, and counting it is a reasonable next step. Nothing in the schema contradicts either move.
The naming rule is worth knowing, because it's how you predict the column before you look. Fivetran lower-cases, inserts an underscore at each lower-to-upper transition, and doesn't split a run of capitals. The landed table names prove it on this connector: CIStatusCIType became cistatus_citype, CIComputerType became cicomputer_type, and ServiceReqParamLink became service_req_param_link. By that rule CIType lands as citype.
Predict it, then check it. Ivanti's LastModBy lands as last_modified_by, so the connector renames at least one field outright.
What the application did for you
Inside Ivanti, none of this reaches the person asking. The member name is the interface.
Open the Server workspace and you see servers. Call CI__Servers and you get servers. Build a Neurons AI dashboard widget and Ivanti requires the prompt to "contain the name of the Business Object and at least one field from the same Business Object", so a prompt about servers resolves against CI.Server before it runs. Write a business rule and you write Task#Assignment, never Task plus a condition.
The application made a name do the work of a filter, everywhere, consistently. Then the extract copied the rows and left the names behind.
That's the shape this series keeps finding, and it inverts a familiar one. ServiceNow splits one record across two tables, so its trap is a join you must not fail to make. Ivanti does the opposite: 35 kinds of record share one table, so no join exists to get wrong, and the trap is a filter you must not fail to apply.
Maximo is the nearer cousin, and the difference matters. Maximo's own application stores work orders, tasks, and history in one WORKORDER table, so the app and the warehouse agree about the shape. Ivanti's application insists the members are separate objects. Here the warehouse contradicts what the user sees on screen, which is why the mistake survives review: the person checking has been looking at a Server workspace all week.
The fix
Patching this query fixes one afternoon. The licence true-up asks again next quarter, and the schema will look exactly the way it looks this morning.
The definitions belong in the semantic model, written once with Ivanti's own documentation as the citation, so every CMDB question inherits them.
Start with the joins, because the connector declares none.
# subject_areas/ivanti_service_management/relationships.yaml
relationships:
- from_table: journal
from_column: parent_link_rec_id
to_table: incident
to_column: rec_id
relationship: many_to_one
confidence: proposed
review_state: unreviewed
description: >
A journal entry's parent incident. The parent link column holds the
RecID of the parent whatever its type, so it also holds service
request, change and problem keys. Constrain parent_link_category =
'Incident' in every query that uses this join. Ivanti's own REST
example returns ServiceReq and Incident parents side by side from the
same journal endpoint.
source: https://docs.ivanti.com/neurons-for-itsm/admin-user-help/enu/latest/creating-group-business-objects-via-rest-api
- from_table: task
from_column: parent_link_rec_id
to_table: incident
to_column: rec_id
relationship: many_to_one
confidence: proposed
review_state: unreviewed
description: >
A task's parent incident, through the standard parent link Ivanti
stores in the child. Constrain parent_link_category = 'Incident'.
Column names follow Ivanti's ParentLink_RecID and ParentLink_Category
fields under Fivetran naming; confirm them in the destination.
source: https://docs.ivanti.com/neurons-for-itsm/admin-user-help/enu/latest/using-relationships
- from_table: incident
from_column: owner_team_valid
to_table: standard_user_team
to_column: rec_id
relationship: many_to_one
confidence: proposed
review_state: unreviewed
description: >
The incident's owning team, by key. owner_team holds a text copy of
the team name; join on the _valid key and group by the team table's
name.
source: https://docs.ivanti.com/neurons-for-itsm/admin-user-help/enu/latest/using-validation-business-objectsThen the declaration this post exists for. No column type can say that one table holds 35 kinds of thing, so the semantic model says it.
entities:
- name: ivanti_ci_type
description: >
Which Ivanti business object a ci row is. CI is a group business
object: an abstract base type with 35 derived types, each of which
Ivanti presents as a separate business object with its own workspace
and its own REST name. Replication lands one ci table for all of them,
and the type selector column is the only thing that says which member
a row belongs to. There is no ci_server table.
resolves_to:
table: ci
column: citype
values: [AccessPoint, BatchJob, Cluster, Computer, Contract, Database,
Document, ESX, EnterpriseApplication, FAX, Firewall, Generator,
Hub, Middleware, MobileDevice, Monitor, PeripheralDevice, Phone,
Printer, ProductivityApp, Rack, Router, SAN, Scanner, Server,
Service, Switch, System, UPS, UnknownDevice, VOIP,
VideoConference, VirtualServer, VirtualWorkstation, Workstation]
forbidden_selectors:
- >
Counting ci without constraining citype. The count includes business
services, databases, documents and vendor contracts alongside the
hardware.
- >
Reading frs_hc_servers or frs_server_type as a source of server
records. Both are separate business objects and hold no CI rows.
caveats:
- >
The 35 values above are Ivanti's default members. A tenant can add
its own, so run the member census before trusting the list.
- >
The landed column name citype is derived from Ivanti's CIType field
under Fivetran's observed casing rule. The connector documents no
business columns at all, so confirm the name in the destination.
source: https://docs.ivanti.com/neurons-for-itsm/admin-user-help/enu/latest/using-business-objectsAnd the metric binds to the entity rather than to the table.
metrics:
- name: ivanti_server_count
calculation: >
Configuration items whose Ivanti member type is Server or
VirtualServer, by operating system. The member lives in the type
selector column of the single ci table, never in a table of its own.
requires_entity: ivanti_ci_type
source_tables: [ci]
primary_table: ci
required_filters: [citype]
other_names: [servers, server count, server inventory, how many servers]
binding: >
SELECT ci.citype, ci.operating_system, COUNT(*) AS cis
FROM ci
WHERE ci.citype IN ('Server', 'VirtualServer')
GROUP BY ci.citype, ci.operating_system
citation: >
Ivanti, Using Business Objects (the group definition and the type
selector); Ivanti, Default Business Objects (the 35 CI members);
Fivetran Ivanti ERD (768 tables, no member tables, no relations).required_filters: [citype] is the load-bearing line. A server count reached by summing the raw table is a path the semantic model has already declared invalid, so the licence true-up, the patch report, and the capacity plan all start from the same rows.
The same declaration pays for itself across the other 26 groups. One entity on ci filtered by citype covers servers, virtual servers, and workstations with one definition and one parameter. Thirty-five member tables would have needed thirty-five.
Four decisions here can't be read from the schema, and a person makes each once.
Which members a word means. "Servers" could be Server, or Server plus VirtualServer, or those plus ESX. Ivanti's own discovery mapping already folds ESX hosts and Unix boxes into Server, so the schema won't settle it. "Devices" and "assets" are wider still.
The tenant's own members. An administrator can create an extension to a group business object. Custom members exist only in that tenant, as new citype values with no table and no documentation anywhere the warehouse can see.
Whether member-only fields land. Ivanti documents fields its scans write to CI, including OperatingSystem and SerialNumber. Whether a field defined on one member only arrives on ci has to be checked in the destination.
Which parent types a task or journal question covers. "Tasks per incident" and "tasks per ticket" are different parent_link_category filters.
Reproduce it yourself
No Ivanti trial exists to spin up, so this runs against the extract your employer already has.
- Find the type selector's landed name. The connector doesn't publish it, so the destination is the only authority.
- Run the member census. It tells you how
cidivides, and how much of it isn't the thing your question named. - Declare the entity and the metric, then ask "how many servers are in our CMDB" in plain English, in the assistant your team already opens, and check the answer against the corrected SQL.
Find the column. Run this before anything else, and upper-case the literal on Snowflake.
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'ci'
AND column_name LIKE '%type%';You're looking for citype. If your extract spells it differently, every query below takes your spelling instead. If nothing comes back, the API key's user and role couldn't read the field, which is a connector permissions question rather than a schema one.
The member census. This is your own version of the number this page can't give you.
SELECT citype,
COUNT(*) AS rows_in_ci
FROM ci
GROUP BY citype
ORDER BY rows_in_ci DESC;Read it like this.
- Every row is a member type that a query without a
citypefilter would have counted as a server. Add up the rows that aren'tServerorVirtualServerand that's the size of the error, in configuration items. - Values outside the 35 are your tenant's custom members. They exist in no documentation, and a person has to say what each one means.
- A
Contract,Service,Document, orDatabaserow is a reminder thatciisn't a table of devices. Those are configuration items in Ivanti's data model, and no one would call them servers.
Corrected. The member lives in a column, so the query filters on it.
SELECT citype,
operating_system,
COUNT(*) AS cis
FROM ci
WHERE citype IN ('Server', 'VirtualServer')
GROUP BY citype, operating_system
ORDER BY cis DESC;Substitute the member list your census returned. If your organisation counts ESX hosts as servers, add ESX, and write that decision down somewhere a person will find it next quarter.
If the count still disagrees with your asset register, check three things before the SQL. Whether the connector's API key can read every CI record, since what its user and role can see is what lands. Whether operating_system is populated on non-discovered records, because a manually created CI may carry nothing there. And whether anyone's counting frs_hc_servers, which is a different business object with a coincidental name.
What this looks like in Agami
Everything above holds whoever builds the semantic model. Here's what it is in our product, in the terms this post has used.
The type selector is declared, not inferred. Introspection reads what the warehouse exposes and gets the column types right. What it can't read is that citype carries Ivanti's member names, or that those members were separate business objects one hop upstream. ivanti_ci_type records that once, with Ivanti's own sentence as the citation, so the next CMDB question doesn't rediscover it.
A forbidden selector is a path the semantic model won't take. Counting ci without a citype filter is declared invalid on the entity, and so is reading frs_hc_servers as a source of server records. A question about servers routes through the named member list instead of through a table whose name happens to match.
Metrics carry their required filters. ivanti_server_count binds to the entity rather than the table and names citype as a filter it can't be computed without. A query that drops it isn't a different answer to the same question, and the metric says so.
Joins are declared with their evidence, and reviewed before they're trusted. The connector ships an empty relations array, so all three joins above are ours, each carrying the Ivanti page it came from. They ship confidence: proposed and review_state: unreviewed, because no analyst has read them yet. The review queue is where a proposed join stops being a guess.
The CMDB count ships once it matches the asset register. Reconciliation takes a screenshot of the report your asset team already trusts, a CSV, or numbers pasted into chat, and compares them. A difference opens the SQL. On these tables it points at a member type, a custom citype value, or a permissions gap, and finding which one is the useful output.
And the number we don't have. We haven't run this against a real Ivanti warehouse, so this page carries no figure for how much of a ci table isn't hardware. It depends entirely on which members a tenant uses, and that mix isn't documented anywhere we could read it. The census query returns yours. The semantic model also can't decide whether ESX hosts count as servers, or what a custom member means. It records the answer once a person gives it.
Frequently asked questions
Why is there no server table in my Ivanti warehouse?
Because CI is a group business object. Ivanti defines one as "an abstract base type and one or more derived types", and presents each derived type as a separate business object. Replication lands the base and none of the members, so all 35 kinds arrive as rows in the ci table. The connector's schema carries 768 table names and exactly two contain the word "server", frs_hc_servers and frs_server_type, neither of which holds CI records.
Which column tells me a CI is a server?
The type selector, which Ivanti creates automatically and names after the group. Its documentation says the field is "only shown for the group-base and group-member business objects", and three shipped groups confirm the naming: CIType on CI, JournalType on Journal, and FRS_KnowledgeType on FRS_Knowledge. Under Fivetran's casing it should land as citype, but the connector documents no business columns, so confirm it with the information_schema query above.
What are the 35 CI member types in Ivanti?
AccessPoint, BatchJob, Cluster, Computer, Contract, Database, Document, ESX, EnterpriseApplication, FAX, Firewall, Generator, Hub, Middleware, MobileDevice, Monitor, PeripheralDevice, Phone, Printer, ProductivityApp, Rack, Router, SAN, Scanner, Server, Service, Switch, System, UPS, UnknownDevice, VOIP, VideoConference, VirtualServer, VirtualWorkstation, and Workstation. That's Ivanti's default list. A tenant can add its own members, which appear as citype values with no documentation.
Does the Ivanti connector create any foreign keys?
No. The published ERD's relations array is empty across all 768 tables. Every join in a query against this schema is something you declare, which is why the three above each carry the Ivanti documentation page behind them.
Can I just count frs_hc_servers instead?
No. It's a separate default business object that happens to have servers in its name, and it holds no configuration items. frs_server_type is the same story. Matching a question to a table by name is exactly the move this schema punishes.
Doesn't Ivanti's own AI already answer this?
Inside the application, partly. Neurons AI builds dashboard widgets from a text prompt, and requires the prompt to "contain the name of the Business Object and at least one field from the same Business Object", so it works over one business object at a time. The Agentic AI Q&A agent, per its own limitations section, "can only inquire about the status of existing incidents and service requests". Neither reaches a warehouse or another system, and both work inside the application, where member names still exist.
References
- Using Business Objects, Ivanti Neurons for ITSM admin help. The group business object definition quoted above, the "separate business objects" sentence, the search-across rationale, and the Type Selector field description.
- Default Business Objects, Ivanti Neurons for ITSM admin help. The full business object list, from which the 133
Group.Membernames, the 27 groups, and the 35CI.*members were counted. - Using Relationships, Ivanti Neurons for ITSM admin help. Parent link fields, link fields and their categories, and the intermediate table behind many-to-many relationships.
- Creating Group Business Objects via REST API, Ivanti and Get Business Objects, Ivanti. Member addressing as
CI.ServerandAddress.Email, and the journal payload returning ServiceReq and Incident parents side by side. - Field Mappings for Ivanti HEAT Discovery 9.x Data Imports. The device-class to
CITypemapping, includingESX > ServerandUnix Box > Server. - Using Validation Business Objects, Ivanti. StandardUserTeam as the source of the team drop-down, and the
_Validkey beside the text copy. - Ivanti connector schema ERD, Fivetran. The 768 landed tables, their five system columns, the 633 and 135 split, and the empty
relationsarray. Re-fetched and parsed 2026-09-24. - Ivanti connector overview, Fivetran and its setup guide. The sync counts, the API key and role that decide what lands, and the deployment models.
- Lite connectors, Fivetran. The connector class whose schema starts from the available API, which is why Ivanti's reference is the authority for these columns.
- Making Database Schema Changes for Large Business Object Tables, Ivanti. The staging instance beside production.
- Metadata, Ivanti Neurons for ITSM admin help. How to pull a tenant's real field list from
/api/odata/{name}s/$metadata. - agami-core on GitHub
Make your Ivanti data answerable
Agami is the trust layer between your AI assistant and your warehouse. It declares which column tells one kind of record from another, so a question about servers returns servers or says why it cannot.