A Windows service that collects inventory on the device it runs and reports it to Inventra over HTTPS. No database access, no SQL install, no reboot.
The essentials, four pop-ups. How the agent runs, what you need before deploying it, and exactly what it does and does not report.
Pick your deployment method. Each guide opens in place and covers deployment, upgrading and uninstalling for that method.
Reference material for a security review, a procurement questionnaire, or a deployment that is not behaving.
Get the package.
Download Aiyoda Inventra Agent (Endpoint) from
Inventra → Downloads.
The zip contains the agent, appsettings.json, the install, uninstall, preflight and detection scripts.
Once devices are reporting, manage them under
Inventra → Agents.
One self-contained executable installed as a Windows service. It is idle between scans; a scan is roughly 0.5 seconds of CPU and 30–80 KB of network.
AiyodaInventraAgent, delayed automatic start, running as LocalSystemC:\Program Files\Aiyoda\InventraAgent, resolved as the 64-bit path regardless of the installing processC:\ProgramData\Aiyoda\Agent, restricted to SYSTEM and local administratorsAiyoda Inventra AgentOn a domain-joined machine LocalSystem authenticates to Active Directory as the computer account, which can read the machine's own computer object. That is exactly the access the device collector needs and no more. A domain service account would instead require creating an account, granting it local administrator rights on every endpoint plus Log on as a batch job, and storing its password in the deployment. LocalSystem creates no accounts and stores no domain credentials anywhere.
Scan frequency, which sections to collect and the software row cap are all server-controlled, so collection can be narrowed or paused from the portal without touching endpoints. The interval in appsettings.json is only a fallback, used until the portal has answered once.
The first scan after an install uses a short delay of a few seconds so a freshly deployed machine does not look like a failed deployment. Scheduled scans afterwards are jittered by up to 30 minutes, so a fleet that boots together does not arrive as one spike.
The report is spooled locally and retried up to 14 times, oldest evicted first. Inventory is a current-state picture, so a three-week-old scan has little value once a newer one exists. A collector that fails is skipped rather than fatal: a device with a broken WMI repository still reports its software and hardware rather than vanishing from the estate and looking decommissioned.
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status
Prints the configuration, the resolved domain and whether the device is enrolled. Run it from an elevated CMD prompt. The data directory is deliberately unreadable by standard users, so an unelevated run returns exit code 3 rather than a wrong answer.
There is very little to prepare. The agent is self-contained, so there is no runtime to install first, no database to point it at and no service account to create.
https://aiyoda.tech. No inbound rulesAllow outbound TCP 443 from managed endpoints to https://aiyoda.tech. No inbound rules. No other ports. No other destinations.
HTTPS is enforced, not preferred. A plaintext portal URL is refused at service startup, because inventory identifies every machine in the estate, its software and its unpatched operating systems. Certificate validation is full chain validation against the OS trust store; optional thumbprint pinning is available for egress that passes through a TLS-inspecting proxy.
If you use a proxy: the agent honours the system proxy, but note that SYSTEM does not use per-user proxy settings. A proxy configured only in a user's profile will not be picked up.
appsettings.json, the install, uninstall, preflight and detection scripts.Nothing else needs provisioning. No SQL login on any database server, no accounts created, no domain credentials stored, no inbound firewall rules, and no reboot for for install, upgrade or removal.
Everything the agent reports, by the Inventra table it fills and the surface each value is read from. Every read is read-only.
| Inventra table | What is reported | Read from |
|---|---|---|
| Device | Machine name, domain or Entra tenant domain, OS caption and edition, machine GUID, plus the AD computer object's DN, account flags, password age and last logon | CIM, registry, LDAP read of its own computer object |
| Hardware | Primary IPv4, physical core and socket counts, fixed-disk total and free space, BIOS serial, model, manufacturer | CIM (WMI) |
| Software | Display name, version and publisher of installed products | Registry uninstall hives — 64-bit, 32-bit WOW6432Node and each loaded user profile |
| SQL Server | Instance names, product version and edition including stopped and decommissioned-but-installed instances | Registry. No connection is ever made to SQL Server |
| Physical server / VM | Physical or virtual determination; on a Hyper-V host, each guest's name, OS, vCPU count, power state and cluster | CIM, including the Hyper-V namespace |
| User | The account signed in at the console of this device | CIM. Only the signed-in user, not every local account |
| Directory (one agent per tenant) | All AD computer and user accounts, for the whole domain | Paged, read-only LDAP search performed only by the agent holding the directory-collector role, which is granted to a single domain controller |
Software comes from the registry, not Win32_Product. Enumerating that WMI class makes the Windows Installer validate and, where it finds a discrepancy, silently reconfigure every MSI-installed product on the machine, repair operations, event-log noise and occasional application breakage, on every scan. It also only ever sees MSI packages, missing everything installed by an EXE. The registry uninstall hives are what Add/Remove Programs reads.
SQL Server is never connected to. Everything the licence calculation needs is in the registry, readable by LocalSystem. So there is no SQL login to provision on every database server, and it finds stopped and decommissioned-but-still-installed instances, which are the ones that turn up in an audit.
The physical tab and the host/VM tab check the same thing, a machine's physical cores. Each machine therefore appears on exactly one:
| The machine is | Reported on | Why |
|---|---|---|
| Physical, Server SKU, no Hyper-V role | Physical | Nothing else covers it |
| Physical, Hyper-V role, has guests | Host/VM | That tab knows the guest editions, and the Datacenter-versus-Standard decision depends on them |
| Physical, Hyper-V role, no guests | Physical, typed as a Hyper-V host with no guests | It produces no host/VM rows, so excluding it here would license it nowhere |
| Virtual (a guest) | Neither | The host carries the obligation |
| Physical, client OS | Neither | Covered by a Windows client licence |
See it for yourself. "C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --collect-only prints exactly what would be sent from a machine, sends nothing anywhere, needs no elevation and creates no files.
There is no code path in the agent capable of collecting any of the following. For most review boards this list matters more than the one of what is collected.
SAM, no NTDS.dit, and no DPAPI blobs other than its own.The data set is IT asset and configuration data containing limited personal data. No sensitive personal information, financial data, health data or payment data. What is present is the signed-in username or AD account name (needed to count per-user licence entitlement), device name, IP and serial (asset identification), and last-logon date (which distinguishes active from dormant accounts, the whole basis of a licence reclaim).
It is inventory about accounts, not about behaviour. There is no record of what a person did, when they did it beyond a last-logon date, or what they accessed.
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --collect-only
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status
Get-NetTCPConnection -State Listen |
Where-Object { (Get-Process -Id $_.OwningProcess).Name -like 'AiyodaAgent*' }sc.exe qc AiyodaInventraAgent
Every collector lives in one folder of the agent's source, each auditable in a few minutes. That is deliberate.
Intune installs the agent as a Win32 app running in system context. No reboot, and no user needs to be logged on. The installer starts the service and sends the first report inline, so a machine appears in the portal within seconds of the deployment reaching it.
Before you start. Download the agent zip from Inventra → Downloads and unpack it. You will also need your tenant license key. Ask Aiyoda support or your reseller for it if you do not already have one. The tenant needs an active Inventra licence, or enrolment is refused with a clear message.
Download IntuneWinAppUtil.exe (Microsoft Win32 Content Prep Tool), then run it from the C:\Temp folder holding the unpacked files:
cd C:\Temp\
IntuneWinAppUtil.exe
Specify the source folder "C:\Temp\AppSource"
Specify the target folder "C:\Temp\AppOutput"
The above commands only creates the app package. The install command below is what actually runs.
Apps → Windows → Add → Windows app (Win32), upload the .intunewin, then set:
| Field | Value |
|---|---|
| Install command | powershell.exe -ExecutionPolicy Bypass -File Install-AiyodaAgent.ps1 -TenantApiKey "pk_..." |
| Uninstall command | powershell.exe -ExecutionPolicy Bypass -File Uninstall-AiyodaAgent.ps1 |
| Install behaviour | System |
| Device restart behaviour | No specific action |
| Requirements | Windows 10 1809 or later, 64-bit |
To keep the key out of the package, set it as an environment variable in a preceding Platform script and use -TenantApiKey $env:AIYODA_KEY, or install with -SkipEnrolment and enrol from a separate script that fetches the key from a vault. The agent installs cleanly unenrolled and starts reporting as soon as enrolment succeeds.
Manually configure → Rule type: Use a custom detection script, and upload Detect-AiyodaAgent.ps1 with Run script as 32-bit process on 64-bit clients: No and Enforce script signature check: No.
Upload the copy from inside the package, not one from anywhere else. The packaged copy is stamped with the version it shipped alongside, and that stamp is the only thing the rule compares against. Intune runs a detection script with no arguments, so there is nowhere in the console to pass a minimum version.
An unstamped script would detect any installed version: Intune would conclude the app is already present, never run the installer, and the estate would silently stay on the old build with nothing in the console indicating a problem.
Why not a %ProgramFiles% file rule. The Intune Management Extension is a 32-bit process, so %ProgramFiles% expands to C:\Program Files (x86), while a detection rule written with 32-bit app: No looks in C:\Program Files. On agent versions before 1.7 that mismatch produced a successful, reporting install that Intune declared "The application was not detected after installation".
Agent 1.7 and later always install to C:\Program Files\Aiyoda\InventraAgent, and upgrading an affected machine relocates it automatically. The script rule avoids the whole class of problem: it resolves the 64-bit path itself, checks the service registration as well as the file, and compares versions as versions rather than as strings.
To see exactly what Intune will see on a specific machine, run the packaged script there the way Intune does, with no arguments:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\Detect-AiyodaAgent.ps1; "exit $LASTEXITCODE"
Exit 0 with output means detected, so Intune will skip the install. Exit 1 with no output means not detected, so it will install. Intune's contract needs both the exit code and the output, neither alone counts as detected.
Assign to a device group, not a user group. The agent is a machine-scoped service and there is no user context at install.
On one machine, from an elevated prompt:
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status
Expect Enrolled : yes. To force a scan rather than waiting for the schedule:
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --run-once
Across the estate, check Inventra → Agents, which lists every enrolled device with its version, last seen and report count.
Deploy to everything at once, order does not matter, domain controllers included. Every write is a merge on a natural key, so an endpoint reporting before or after the directory sweep produces the same row either way.
Upgrading is an in-place re-install. The installer stops the service, replaces the program files and restarts it.
Do not uninstall first. Uninstall is not the first half of an upgrade. It deregisters the agent and revokes its credential, discards any spooled reports, releases the directory-collector role if this machine held it. Another domain controller can claim it in the gap and puts you back in the position of needing the tenant API key again.
%ProgramData%\Aiyoda\Agent rather than in the program directory. So no tenant API key is needed and there is no re-enrolment.appsettings.json, if one is already present, a customised portal URL, certificate pins or scan interval are not reverted. Pass -ResetSettings to deliberately take the packaged defaults instead. A new version that adds settings keys is fine: keys absent from the file fall back to the agent's compiled defaults.Upload the new .intunewin as a new version of the same app.
Uploading a new package replaces the payload but leaves the detection rule alone and the old rule still says "installed", so nothing upgrades. Re-upload Detect-AiyodaAgent.ps1 from inside the new package at the same time.
This is the single most common reason an Intune upgrade appears to do nothing. If you use a file String (version) rule instead, the comparison value has to be bumped by hand for the same reason.
Once the estate is enrolled, remove -TenantApiKey from the install command. Upgrades do not need it, and leaving it there re-stages a tenant-wide credential on every machine for no benefit.
Re-deploy the previous package the same way. The credential and configuration are untouched, so a rollback is just another in-place file replacement.
Removing the install assignment does not uninstall anything. The agent is already installed locally and will keep reporting. You have to deploy an explicit uninstall and in the right order, or the tools will fight each other.
Apps → Windows → Aiyoda Inventra Agent → Properties → Assignments, and remove the device group from Required. Skip this and the next install evaluation reinstalls whatever you just removed, usually within the hour.
Add the same device group to the Uninstall assignment and save. Intune then runs the uninstall command from the app definition:
powershell.exe -ExecutionPolicy Bypass -File Uninstall-AiyodaAgent.ps1
Devices pick it up on their next check-in, or immediately from Devices → the device → Sync.
Uninstall is confirmed by the same detection rule as install: with the files gone the rule no longer matches, and Intune reports the app as not installed. Per machine:
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status # should be False
Required beats Uninstall. A device still in a Required assignment, directly or through a nested group will be reinstalled. Nested groups are the usual reason an agent keeps coming back.
Deleting the app from Intune does not remove it from machines. It only removes Intune's ability to manage it, leaving the agent installed and reporting with nothing left to uninstall it. Always assign Uninstall, wait for it to complete, and only then delete the app.
On the machine, uninstall stops the service and deletes the service registration, the credential, the spool and the program files. Before any of that it tells the portal the agent is going, which marks it uninstalled with a timestamp, revokes its credential so a copy taken beforehand cannot resume reporting, and releases the directory-collector role if this machine held it.
The device's inventory rows are kept, deliberately. A machine that was in the estate last month was consuming licences last month, deleting its rows on uninstall would quietly reduce the licence position and lose the history an audit of that period depends on. To take a decommissioned machine out of the licence position, remove its rows through the Inventra UI, which is a deliberate decision rather than a side effect.
Deregistration is best effort. A machine wiped offline never reaches the portal, and uninstall does not fail because of it, the agent then shows as stale until someone removes it in the portal. Running the uninstall on a machine that never had the agent, or twice on the same machine, is safe.
The best route for a domain-joined estate without Intune. Files are staged on a share and a Group Policy Preferences immediate scheduled task runs the installer as SYSTEM.
Use an immediate scheduled task, not a startup script. A startup script only runs at boot, which means no server reports until it is restarted. That's not something anyone is going to do across a production estate to install an inventory agent. An immediate task applies on the next policy refresh, within 90 minutes by default or at once with gpupdate /force, runs as SYSTEM, and needs no reboot and no logon.
\\dc01\NETLOGON\AiyodaAgent\
AiyodaAgent.exe
appsettings.json
Install-AiyodaAgent.ps1
Uninstall-AiyodaAgent.ps1
Detect-AiyodaAgent.ps1Grant Domain Computers read access on both the share permissions and the NTFS permissions so machines authenticate as their computer account, so a user-only ACL will not work. Granting one and not the other is the common half-fix.
NETLOGON is readable by every authenticated user. That is fine for the executable but not for the tenant API key — put key.txt on a separate hidden share such as AiyodaKey$, granting read to Domain Computers only. Delete it once the rollout is done.
Save this as Deploy-AiyodaAgent.ps1 beside the other files:
$ErrorActionPreference = 'Stop'
$source = '\\dc01\NETLOGON\AiyodaAgent'
$staging = Join-Path $env:TEMP 'AiyodaAgent'
$installed = Join-Path $env:ProgramFiles 'Aiyoda\InventraAgent\AiyodaAgent.exe'
# A scheduled task has nowhere to send console output, so everything is transcribed
# to a local file. Without this a failure is an "Access Denied" in the Task Scheduler
# log with no indication of which path was denied, or which identity was denied it.
$log = Join-Path $env:ProgramData 'Aiyoda\deploy.log'
New-Item -ItemType Directory -Path (Split-Path $log) -Force | Out-Null
Start-Transcript -Path $log -Append -Force | Out-Null
try {
"=== $(Get-Date -Format s) running as $([Security.Principal.WindowsIdentity]::GetCurrent().Name) ==="
# A version check rather than "is it installed": with an existence check the task
# would never upgrade anything, and with no check it would reinstall on every refresh.
$shipping = (Get-Item "$source\AiyodaAgent.exe").VersionInfo.FileVersion
if (Test-Path $installed) {
$current = (Get-Item $installed).VersionInfo.FileVersion
if ([version]$current -ge [version]$shipping) { return }
}
# Copied locally first: running an installer straight off a share holds the
# executable open over SMB and fails awkwardly if the link drops mid-install.
New-Item -ItemType Directory -Path $staging -Force | Out-Null
Copy-Item "$source\*" $staging -Force
$key = (Get-Content '\\dc01\AiyodaKey$\key.txt' -Raw).Trim()
& "$staging\Install-AiyodaAgent.ps1" -TenantApiKey $key
}
finally {
Stop-Transcript | Out-Null
}Every run leaves its identity and outcome in C:\ProgramData\Aiyoda\deploy.log on the target machine. That file is the first thing to read when a deployment fails.
Install Aiyoda Inventra AgentNT AUTHORITY\Systempowershell.exe-ExecutionPolicy Bypass -NonInteractive -File \\dc01\NETLOGON\AiyodaAgent\Deploy-AiyodaAgent.ps1Setting the account to SYSTEM. Do not use the Change User or Group… picker. That picker searches the domain, and SYSTEM is a local well-known principal that exists on every machine rather than a directory object, so it will not appear in the results. Type NT AUTHORITY\System straight into the field instead. The console writes it to the preference XML and each client resolves it locally. If your GPMC build insists on validating the field, SYSTEM, NT AUTHORITY\System and the SID S-1-5-18 are equivalent.
Do not substitute a domain account. It would need local administrator rights on every target plus the Log on as a batch job right, and it is the usual cause of an "Access Denied" that looks like a share permissions problem but is actually Task Scheduler refusing the logon. SYSTEM needs neither, and on a domain-joined machine it reaches the network as the computer account, which is why the share is granted to Domain Computers.
Run gpupdate /force on a pilot machine, or wait for the normal refresh. No reboot, no logon. The installer sends a report inline, so the machine appears in the portal within seconds of the task running:
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status
If it fails with "Access Denied", establish which identity was denied, and denied what, before changing anything. The installer prints Running as : <identity> as its very first line. If deploy.log shows anything other than NT AUTHORITY\SYSTEM, the account on the task is the problem and no amount of share permissions will help.
If you must use a startup script, only when Preferences are unavailable, use the same wrapper under Computer Configuration → Policies → Windows Settings → Scripts (Startup/Shutdown) → Startup, on the PowerShell Scripts tab, with Run Windows PowerShell scripts first enabled. It will not run until each machine reboots.
Replace the files on the share. The wrapper's version check does the rest.
Do not uninstall first. Uninstall deregisters the agent and revokes its credential, discards spooled reports, releases the directory-collector role if this machine held it, and puts you back in the position of needing the tenant API key. Re-install over the top instead.
Copy the new AiyodaAgent.exe and scripts over the ones on \\dc01\NETLOGON\AiyodaAgent.
The wrapper compares the shipping version against the installed one and returns early only when the installed version is already current. So the same GPO handles the upgrade with no changes. If you used a wrapper that simply checks whether the service exists, add a version check or drop that early return during the upgrade window.
No tenant license key is needed for an upgrade. The device credential lives under %ProgramData% and survives replacing the program files. The last two lines of the wrapper become simply:
& "$staging\Install-AiyodaAgent.ps1"
Which is also the moment to delete key.txt from the key share.
If Apply once and do not reapply was ticked on the original task, create a new immediate task for the upgrade as the original will not run again. Then check Inventra → Agents: an agent still reporting the old release is badged behind current version.
appsettings.json — a customised portal URL, certificate pins or scan interval are not reverted. Pass -ResetSettings to deliberately take the packaged defaults.Stage the previous package on the share and let the task run again. The credential and configuration are untouched.
A second immediate task, with the install policy stopped first.
Unlinking the install GPO does not uninstall anything. The agent is already installed locally and will keep reporting. You have to deploy an explicit removal, and stop the install policy applying before you do, otherwise the two policies fight and the agent reinstalls.
Unlink the install GPO from the OU, or add the target machines to a security group and deny it Read on that GPO. If the install task was configured with Apply once and do not reapply it will not run again anyway but the documented wrapper treats "not installed" as "install it", so leaving the policy linked will reinstall.
Save this beside the others on the share, as Remove-AiyodaAgent.ps1:
$ErrorActionPreference = 'Continue'
$installed = Join-Path $env:ProgramFiles 'Aiyoda\InventraAgent\Uninstall-AiyodaAgent.ps1'
$log = Join-Path $env:ProgramData 'Aiyoda\remove.log'
New-Item -ItemType Directory -Path (Split-Path $log) -Force | Out-Null
Start-Transcript -Path $log -Append -Force | Out-Null
try {
"=== $(Get-Date -Format s) running as $([Security.Principal.WindowsIdentity]::GetCurrent().Name) ==="
# Nothing to do, and nothing to log noisily about, on a machine that never had it.
if (-not (Test-Path (Join-Path $env:ProgramFiles 'Aiyoda\InventraAgent\AiyodaAgent.exe'))) {
'Agent not present; nothing to remove.'
return
}
# The uninstall script ships alongside the agent, so it is already on the machine -
# no share access needed. That matters here: a machine being decommissioned may well
# have lost its connection to the file server before anyone removes the agent.
if (Test-Path $installed) {
& $installed
}
else {
# Installed by an older package that did not include the script.
& (Join-Path $env:ProgramFiles 'Aiyoda\InventraAgent\AiyodaAgent.exe') --uninstall
}
}
finally {
Stop-Transcript | Out-Null
}Same as the install task — Computer Configuration → Preferences → Control Panel Settings → Scheduled Tasks → New → Immediate Task (At least Windows 7) — with:
| Field | Value |
|---|---|
| Name | Remove Aiyoda Inventra Agent |
| Account | NT AUTHORITY\System: type it in, the picker will not find it |
| Options | Run whether user is logged on or not, Run with highest privileges |
| Action | powershell.exe with -ExecutionPolicy Bypass -NonInteractive -File \\dc01\NETLOGON\AiyodaAgent\Remove-AiyodaAgent.ps1 |
Applies on the next policy refresh, or at once with gpupdate /force. No reboot.
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status # should be False
Once the estate is clear, unlink the uninstall GPO too otherwise it re-runs on every refresh forever. It is harmless, since it exits immediately when the agent is absent, but it is pointless noise in the task history.
On the machine it stops the service and deletes the service registration, the credential, the spool and the program files. Before any of that it tells the portal the agent is going, which marks it uninstalled with a timestamp, revokes its credential, and releases the directory-collector role if this machine held it, so removing a collector DC does not silently stop AD collection.
The device's inventory rows are kept, deliberately. The licence position for the period the machine existed has to survive its retirement. To take a decommissioned machine out of the licence position, remove its rows through the Inventra UI.
No reboot required: a Required deployment applies on the client's next policy cycle, and the installer starts the service and sends the first report itself.
Before you start. Download and unpack the agent zip from Inventra → Downloads onto a UNC content location, and have your tenant API key ready — ask Aiyoda or your reseller if you do not have one.
Software Library → Application Management → Applications → Create Application → Manually specify the application information, then add a Script Installer deployment type pointing at the UNC content location.
| Field | Value |
|---|---|
| Installation program | powershell.exe -ExecutionPolicy Bypass -File Install-AiyodaAgent.ps1 -TenantApiKey "pk_..." |
| Uninstall program | powershell.exe -ExecutionPolicy Bypass -File Uninstall-AiyodaAgent.ps1 |
| Install behaviour | Install for system |
| Logon requirement | Whether or not a user is logged on |
| Program visibility | Hidden |
| Maximum allowed run time | 30 minutes |
| Estimated installation time | 5 minutes |
Either a file rule on %ProgramFiles%\Aiyoda\InventraAgent\AiyodaAgent.exe, or — better — a script that also confirms the service exists:
if (Get-Service -Name 'AiyodaInventraAgent' -ErrorAction SilentlyContinue) { Write-Output 'Installed' }Configuration Manager treats any output on stdout as "installed", so write nothing when the agent is absent — do not write "Not installed". The packaged Detect-AiyodaAgent.ps1 can also be used and additionally compares versions, which is what makes an upgrade deploy.
Add a requirement for 64-bit Windows. Distribute the content, then deploy to a device collection as Required. A recurring schedule is unnecessary — the agent schedules its own scans once installed.
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status
Expect Enrolled : yes. --run-once forces a scan rather than waiting for the schedule. Across the estate, check Inventra → Agents.
Deploy to everything at once — order does not matter, domain controllers included. Every write is a merge on a natural key, so a device reporting before or after the directory sweep produces the same row either way.
Upgrading is an in-place re-install: the installer stops the service, replaces the program files and restarts it.
Do not uninstall first. Uninstall deregisters the agent and revokes its credential, discards spooled reports, releases the directory-collector role if this machine held it, and re-stages a tenant-wide credential you would otherwise not need.
Replace the files at the content location with the new package, add a new deployment type or update the existing one, then redistribute the content to your distribution points.
With an "exists" detection rule, any machine that already has the agent is considered done and will never upgrade. Use the packaged Detect-AiyodaAgent.ps1 from the new package, or a file version rule with Greater than or equal to and the version being shipped — bumped by hand each release.
Remove -TenantApiKey from the installation program once the estate is enrolled. Upgrades do not need it — the device credential lives under %ProgramData%\Aiyoda\Agent and survives replacing the program files.
appsettings.json — a customised portal URL, certificate pins or scan interval are not reverted. Pass -ResetSettings to take the packaged defaults deliberately.Deploy the previous package the same way. The credential and configuration are untouched, so a rollback is just another in-place file replacement.
Removing the install deployment does not uninstall anything, and leaving it in place while you deploy the uninstall means the next evaluation cycle reinstalls. Do it in this order.
Software Library → Applications → the app → Deployments, and delete the Required install deployment — or exclude the target collection.
Right-click the application → Deploy → choose the collection → set Action to Uninstall and Purpose to Required. Configuration Manager runs the uninstall program from the deployment type and uses the detection method to confirm the result.
A Package/Program works for a one-off:
| Field | Value |
|---|---|
| Command line | powershell.exe -ExecutionPolicy Bypass -File Uninstall-AiyodaAgent.ps1 |
| Program can run | Whether or not a user is logged on |
| Run mode | Run with administrative rights |
Get-Service AiyodaInventraAgent -ErrorAction SilentlyContinue # should return nothing Test-Path "$env:ProgramFiles\Aiyoda\InventraAgent" # should be False Test-Path "$env:ProgramData\Aiyoda" # should be False
Delete the uninstall deployment once the collection is clear, for the same reason as the GPO: it will otherwise keep evaluating indefinitely.
Uninstall stops the service and deletes the service registration, the credential, the spool and the program files — and first tells the portal, which marks the agent uninstalled, revokes its credential, and releases the directory-collector role if it held it.
The device's inventory rows are kept, deliberately. The licence position for the period the machine existed must survive its retirement. Remove the rows through the Inventra UI when that is what you actually want.
For a pilot machine, a handful of servers, or anything no management tool reaches. Use the same installer, and is safe to run twice.
Before you start. Download and unpack the agent zip from Inventra → Downloads on the target machine, and have your tenant license key ready. Ask Aiyoda support or your reseller if you do not have one. You need an elevated PowerShell prompt.
.\Install-AiyodaAgent.ps1 -TenantApiKey "pk_..." -PortalUrl "https://aiyoda.tech"
The script registers the Windows service, enrols the device, starts the service and sends the first report inline so the machine appears in the portal within seconds rather than whenever it next scans. No reboot.
| Parameter | What it does |
|---|---|
| -TenantApiKey | The tenant licence key, used once to obtain this device's own credential. Not stored on the machine. Omit it on an upgrade. |
| -PortalUrl | Overrides the portal URL in appsettings.json. Must be HTTPS, plaintext is refused at startup. |
| -InstallPath | Defaults to C:\Program Files\Aiyoda\InventraAgent, resolved as the 64-bit path regardless of the installing process. |
| -SkipEnrolment | Install now, enrol later. Use when the key comes from a vault or a separate script. The service waits and re-checks rather than exiting, so running --enroll at any later point is enough on its own, no restart, no reboot. |
| -ForceEnrolment | Re-enrol a machine that already holds a credential. Requires a tenant licence key. |
| -ResetSettings | Overwrite an existing appsettings.json with the packaged defaults. Without it, your customised settings are kept. |
| -NoInitialScan | Skip the inline first report. The machine then appears at its first scheduled scan instead. |
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status
Expect Enrolled : yes. To force a scan rather than waiting for the schedule, use --run-once.
| Verb | Purpose |
|---|---|
| --install | Register the Windows service. Elevated. |
| --uninstall | Remove the service, the credential and the spool. Elevated. |
| --enroll <tenant-api-key> | Obtain this device's credential. Run once, after install. Elevated. |
| --run-once | Collect and send one report in the foreground. |
| --collect-only | Print exactly what would be sent. No credential, no network call, no elevation, no files created. |
| --status | Show configuration and enrolment state, including the resolved domain. |
| --help | Usage. |
--collect-only is the verb to hand a customer's security team. It shows exactly what would leave the machine, with nothing sent anywhere.
From an account with administrator rights on the targets:
$computers = Get-Content .\machines.txt
Invoke-Command -ComputerName $computers -ScriptBlock {
# Stage the unpacked package to a local path on each machine first, then:
& 'C:\Temp\AiyodaAgent\Install-AiyodaAgent.ps1' -TenantApiKey 'pk_...'
} -ErrorAction Continue-ErrorAction Continue so one unreachable machine does not stop the rest. Re-run against the failures rather than assuming the sweep was complete.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Not enrolled (--status), or the report could not be delivered and was spooled for retry |
| 2 | Bad usage, bad configuration, or an action that requires enrolment |
| 3 | The agent data directory is not readable by this account — re-run elevated |
--enroll, --install and --uninstall need elevation. --status, --collect-only and --run-once will run unelevated, but return 3 rather than a wrong answer once the machine is enrolled, the data directory is deliberately unreadable by standard users.
Re-install over the top. One command, no key, no reboot.
.\Install-AiyodaAgent.ps1
Do not uninstall first. Uninstall deregisters the agent and revokes its credential (noise in the audit trail, and the agent's history restarts), discards spooled reports, releases the directory-collector role if this machine held it, and requires the tenant API key again. Uninstall is for retiring a machine, not for updating one.
%ProgramData%\Aiyoda\Agent rather than in the program directory, so no re-enrolment, and no tenant-wide credential in a routine update.appsettings.json, if present. A customised portal URL, certificate pins or scan interval would otherwise revert to packaged defaults on every upgrade, which is invisible until something stops reporting. Pass -ResetSettings to take the packaged file deliberately. A new version that adds keys is fine, absent keys fall back to the agent's compiled defaults."C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status
Or check Inventra → Agents. An agent still on an older release than the portal's current version is badged behind current version.
Re-install the previous package the same way. The credential and configuration are untouched, so a rollback is just another in-place file replacement.
Elevated, on the machine:
powershell -ExecutionPolicy Bypass -File Uninstall-AiyodaAgent.ps1
Safe on a machine that never had the agent, and safe to run twice.
The agent can remove itself. It deletes its own service, credential and spool, but not its program directory, Uninstall-AiyodaAgent.ps1 does that, and it is in the same folder:
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --uninstall
$computers = Get-Content .\machines.txt
Invoke-Command -ComputerName $computers -ScriptBlock {
$exe = Join-Path $env:ProgramFiles 'Aiyoda\InventraAgent\AiyodaAgent.exe'
if (Test-Path $exe) { & $exe --uninstall } else { 'not installed' }
} -ErrorAction Continue-ErrorAction Continue so one unreachable machine does not stop the rest. Machines that were offline keep the agent installed and will still be reporting, so re-run against the failures rather than assuming the sweep was complete.
It stops the service, then deletes the service registration, the credential, the spool and the program files. Before any of that it tells the portal the agent is going, which:
Deregistration is best effort. A machine wiped offline never reaches the portal, and uninstall does not fail because of it. The agent then shows as stale until someone removes it in the portal.
The device's inventory rows are kept, deliberately. A machine that was in the estate last month was consuming licences last month; deleting it on uninstall would quietly reduce the licence position and lose the history an audit of that period depends on. To take a decommissioned machine out of the licence position, remove its rows through the Inventra UI. A deliberate decision about the licence position rather than a side effect of removing an agent.
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status
Across the estate, Inventra → Agents is the record. An agent that deregistered cleanly shows as uninstalled; one that still shows as reporting with an old last-seen date was removed without reaching the portal, or was never removed at all.
If a device was lost or compromised rather than simply rebuilt, revoke it in the portal as well so the record says so. Revoking refuses the credential on its next call, the agent then stops scanning and clears its local spool, with nothing to push to the machine.
A read-only Windows inventory collector. It runs as a service on an endpoint, reads what software and hardware that machine has, and sends it over HTTPS to Inventra so licence position can be calculated. It holds a credential valid for one device, opens no inbound ports, executes nothing it downloads, writes nothing to the operating system outside its own directories, and has no database access of any kind.
AiyodaAgent.exe — Windows service as LocalSystem. Reads CIM/WMI, the registry and its own AD computer object, all read-only.POST to one configured portal FQDN. The response can only narrow collection or change the interval./api/inventra/agent/v1 — POST only, writing into that tenant's own SQL database.Direction of trust: the endpoint initiates every connection. No inbound connections, no agent-to-agent traffic, no listening socket on the endpoint at all. Nothing in the portal can reach into the endpoint, push a command to it, or cause it to execute anything.
The one thing to plan for. The tenant API key has to reach the endpoint at install time, unavoidable with any enrolment scheme, and the weakest point of a deployment. The most effective mitigation takes a minute: rotate the tenant key once the rollout is done. Enrolled agents are unaffected, because they hold their own credentials. Prefer delivering the key at runtime from your management tool's script context or a secrets store (-SkipEnrolment exists for this); if it is in the package, treat the package as a secret.
| If an attacker obtains | They can | They cannot |
|---|---|---|
| One device's agent credential | Restate that one device's inventory rows; deregister that agent | Read any data; affect any other device; reach the database; discover the estate |
| The tenant API key | Enrol new agents into that tenant, each still confined to its own device | Read any data; write another tenant's data; obtain existing agents credentials |
| Local admin on one endpoint | Read that endpoint's credential, equivalent to the row above | Anything beyond that one device |
| The directory-collector agent's credential | Write tenant-wide AD device and user rows | Read data; write hardware, software, SQL or VM rows for other devices |
Directory collection is the single exception to per-device, because sweeping AD inherently writes rows for the whole tenant. It is contained four ways: granted to exactly one agent per tenant, enforced by a filtered unique index in the database rather than by application logic; granted only to a machine reporting itself as a domain controller, at enrolment, which already requires the tenant key; every other agent sending directory data is refused and logged, not silently ignored; and endpoint-reported user identities are insert-only, so an agent cannot alter a user row the directory sweep owns.
| Protocol | HTTPS only. A plaintext portal URL is refused at service startup, not warned about |
| Direction | Outbound only, endpoint-initiated |
| Port | TCP 443 |
| Destination | The single configured portal https://aiyoda.tech/. Nowhere else |
| Inbound firewall rules | None required |
| Certificate validation | Full chain validation against the OS trust store |
| Optional pinning | SHA-256 thumbprint pinning, applied in addition to chain validation, never instead of it |
| Proxy | Honours the system proxy. Note that SYSTEM does not use per-user proxy settings |
| Body | Gzipped JSON, request only |
Firewall request for a change board: allow outbound TCP 443 from managed endpoints to https://aiyoda.tech/. No inbound rules. No other ports. No other destinations.
On certificate pinning: off by default, and that is a considered position. It is there for customers whose egress passes through a TLS-inspecting proxy they do not wish this traffic readable by. It creates an operational obligation, a certificate renewal breaks every agent until the new thumbprint is deployed, so deploy the incoming thumbprint alongside the current one before a renewal.
| Path | Contents | Protection |
|---|---|---|
| %ProgramFiles%\Aiyoda\InventraAgent\ | Executable, appsettings.json | Default Program Files ACL |
| %ProgramData%\Aiyoda\Agent\credential.dat | The device credential | DPAPI machine scope with additional entropy; ACL restricted to SYSTEM and local administrators, inheritance broken |
| %ProgramData%\Aiyoda\Agent\spool\ | Undelivered reports (JSON), max 14, oldest evicted | Same restricted ACL |
| Windows event log | Operational logging | Standard event log ACL |
No inventory data is retained on the endpoint after successful delivery. The spool exists only for reports that could not be sent, is capped at 14, and is deleted on uninstall.
HKLM and HKU — installed software, SQL instances, cloud-join info%ProgramData%\Aiyoda — credential and spoolNot used and not requested: no debug privilege, no token impersonation, no driver or kernel component, no local security policy modification, and no Active Directory write of any kind.
On a domain-joined machine LocalSystem authenticates to Active Directory as the computer account, which can read the machine's own computer object. That is exactly the access the device collector needs and no more. The alternative (a domain service account) would require creating an account, granting it local administrator rights on every endpoint plus Log on as a batch job, and storing its password in the deployment. LocalSystem creates no accounts and stores no domain credentials anywhere.
The data set is IT asset and configuration data containing limited personal data. It is not sensitive personal information, financial data, health data or payment data. The personal data present is the signed-in username or AD account name (needed to count per-user licence entitlement), device name, IP and serial (asset identification), and last-logon date (which distinguishes active from dormant accounts, the whole basis of a licence reclaim).
Software is read from the registry uninstall hives, not from WMI Win32_Product. Enumerating Win32_Product causes the Windows Installer to validate and, where it finds a discrepancy, silently reconfigure every MSI-installed product on the machine which repair operations, event-log noise and occasional application breakage, on every scan. Many inventory tools do this. This one does not. The registry hives are also what Add/Remove Programs reads, so they see everything installed by an EXE too.
Similarly, the agent never connects to SQL Server. Everything the licence calculation needs is in the registry, readable by LocalSystem, so there is no SQL login to provision on every database server, and it finds stopped and decommissioned-but-still-installed instances, which are the ones that turn up in an audit.
What a reviewer can verify themselves, on their own machine: run AiyodaAgent.exe --collect-only to see exactly what would leave the machine with nothing sent anywhere, --status to see where it reports and whether it is enrolled, netstat to confirm no listening port belongs to the agent, and sc.exe qc AiyodaInventraAgent to confirm the service identity and binary path.
The questions asked most often by security teams, change boards and administrators. Click a question to expand it.
No, to both. The agent has no listening socket at all. It needs only outbound TCP 443 to https://aiyoda.tech/.
To one configured portal https://aiyoda.tech/ over HTTPS, and nowhere else. Once every 24 hours by default, adjustable centrally from the portal. There is no polling and no persistent connection, a scan is roughly 30–80 KB.
Yes, it honours the system proxy. Note that SYSTEM does not use per-user proxy settings, so a proxy configured only in a user's profile will not be picked up.
HTTPS is enforced, not preferred. A plaintext portal URL is refused at service startup. Full chain validation applies against the OS trust store. SHA-256 thumbprint pinning is available for egress that passes through a TLS-inspecting proxy, applied in addition to chain validation. It is off by default because a certificate renewal breaks every agent until the new thumbprint is deployed.
Neither. It runs as LocalSystem, which on a domain-joined machine authenticates to AD as the computer account, exactly the access needed to read the machine's own computer object and no more. Installing needs local administrator (or SYSTEM, when a management tool deploys it). The rollout creates no accounts and stores no domain credentials.
No. One user-mode Windows service, AiyodaInventraAgent. No drivers, no kernel components, no scheduled tasks of its own, though your GPO deployment method may create one to install it.
No, to both. Registry and AD access are strictly read-only. The only filesystem writes are to its own two directories.
Neither for install, upgrade or removal. The agent is a self-contained single executable, so there is no runtime prerequisite. The installer starts the service and sends the first report inline, so a machine appears in the portal within seconds.
It is idle between scans. A scan is roughly 0.5 seconds of CPU and 30–80 KB of network, once per 24 hours by default.
No, there is no code path capable of it. No file contents, no file or folder listings, no keystrokes, no screen capture, no clipboard, microphone or camera, no passwords, hashes or tokens, no credential store, LSA secrets, SAM or NTDS.dit, no email or browsing history, no network capture, and no process or command-line inventory.
Yes, centrally. Scan frequency, which sections to collect and the software row cap are all server-controlled, so collection can be narrowed or paused from the portal without touching endpoints.
The signed-in username or AD account name, device name, IP and serial, and last-logon date. It is inventory about accounts, not about behaviour. There is no record of what anyone did or accessed. Only the signed-in user is reported per device, deliberately, rather than every local account.
Yes. Run AiyodaAgent.exe --collect-only on any machine. It prints precisely what would be sent, sends nothing anywhere, needs no elevation and creates no files. It is the verb to hand a security team.
Yes to both. Each endpoint holds a credential scoped to itself, obtained at enrolment by exchanging the tenant key, which the agent never stores. Any single agent can be revoked from the portal: it is refused with 403 on its next call, stops scanning and clears its local spool, with nothing to push to the machine.
No. The API is write-only, there are no GET endpoints. A stolen device credential can restate that one device's rows and nothing else; it cannot read data, affect another device, reach the database, or discover the estate.
No, with one contained exception. The server pins every row to the device recorded at enrolment and ignores the device name in the payload. The exception is the single designated directory collector, one domain controller per tenant whose AD sweep writes rows tenant-wide; every other agent sending directory data is refused and logged.
Database per tenant, and the tenant is resolved from the credential rather than from anything the caller supplies. Every write is scoped to the resolved tenant database.
Yes, server-side: enrolments, failed enrolments, auth failures, directory sweeps, deregistrations and revocations, each with device, agent id and source IP. Routine successful reports are deliberately not audited per report. At 10,000 devices or more that would be millions of rows a year of "a machine reported, as scheduled", burying the entries that matter. The operational record is Inventra → Agents, which carries last seen, last report, report count, version and last IP per device.
No. There is no command channel and no code-download path. The server's policy response can only narrow what is collected and change how often it scans.
Not code-signed yet, verify the package against the published SHA-256 hash. Dependencies are six Microsoft first-party NuGet packages pinned to exact versions, with no third-party packages and no native binaries beyond the .NET runtime bundled by the self-contained publish.
No. Reports replace, they do not append. Each report deletes that device's existing software, hardware, SQL and VM rows inside one transaction and writes the current picture. Reports are also idempotent, each carries a scan id, so one the agent could not confirm delivery of is retried and recognised as a duplicate rather than applied twice.
No. Department, Division, Entity, Location, Profile and the custom fields are never touched on update. An endpoint has no way of knowing them, and writing NULLs over them would destroy the grouping the reports depend on. Environment is only filled in when it is still empty.
The report is spooled locally and retried up to 14, oldest evicted first. Inventory is a current-state picture, so a three-week-old scan has little value once a newer one exists. A collector that fails is skipped rather than fatal: a device with a broken WMI repository still reports its software and hardware rather than vanishing from the estate and looking decommissioned.
By design. The agent reports the signed-in user, not every account on the machine. Enumerating local accounts returns the built-in Administrator, a break-glass account and leftover profiles alongside the one real person, and each would become a row in a table used to count per-user licences. Four rows for one human is noise, not coverage. Domain and Entra users are covered by the directory sweep in any case, and a machine scanned while nobody was signed in correctly contributes no user at all.
Domain is resolved in order: the Active Directory domain, then the Entra ID tenant's verified domain, then Workgroup. Windows reports an Entra-joined machine as not domain-joined with a domain of WORKGROUP, so labelling it that way would hide a managed device among the genuinely unmanaged ones. On a hybrid-joined machine AD wins, since that is what the rest of the device row is derived from.
No. A server appears on exactly one licensable tab, because both tabs price the same thing, the machine's physical cores. A physical Server SKU with no Hyper-V role is reported as physical; a Hyper-V host with guests is reported on the host/VM tab, which knows the guest editions the Datacenter-versus-Standard decision depends on; a Hyper-V host with no guests goes back on the physical tab, typed as such, since it produces no host/VM rows. A guest is counted on neither, the host carries the obligation. A stale row from an earlier agent version that reported hosts on both tabs is removed automatically on the next scan.
No, deploy to everything at once. Every write is a merge on a natural key, so an endpoint reporting before or after the directory sweep produces the same row either way, and the sweep never overwrites the inventoried flag on a machine that has an agent. Several DCs enrolling in the same instant is a handled case, not a race: exclusivity of the directory-collector role is enforced by a unique index in the database, and the losers enrol normally without sweeping.
Yes, with no reboot. It removes the service, credential, spool and files, and tells the portal so the credential is revoked and the agent reads as removed. The device's inventory rows are kept deliberately: a machine that was in the estate last month was consuming licences last month, and deleting its rows would quietly reduce the licence position and lose the history an audit of that period depends on.
The symptoms that come up most, and what each one actually means. Start with --status and the Windows event log, between them they answer most questions.
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --status
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --run-once
Logs: Event Viewer → Windows Logs → Application, source Aiyoda Inventra Agent. The Windows event log is used rather than a text file because it is already collected by whatever monitoring you run, and it needs no rotation of its own.
The first scheduled scan is delayed by up to 30 minutes of startup jitter, deliberately, so a fleet that boots together does not arrive as one spike. A fresh install should not hit this, the installer sends a report inline but --run-once bypasses the wait either way.
If --status says enrolled and a --run-once still produces nothing in the portal, check the event log for a delivery error and confirm outbound 443 to the portal FQDN is permitted for the SYSTEM context. A proxy configured only in a user profile will not be used.
The installer treats enrolment failure as non-fatal. A machine imaged offline cannot reach the portal, and failing the whole install would leave nothing behind to retry with. Check the event log for the reason, then re-run enrolment elevated:
"C:\Program Files\Aiyoda\InventraAgent\AiyodaAgent.exe" --enroll <tenant-api-key>
No service restart and no reboot is needed, an unenrolled service waits and re-checks rather than exiting, so running --enroll at any later point is enough on its own. Enrolment also retries with jittered backoff for about ten minutes, so a rate-limited rollout usually resolves itself.
The message names the gate that failed: a wrong or rotated tenant key, a tenant that is inactive or expired, no active Inventra licence, or no provisioned tenant. If the key was recently regenerated, note that regenerating invalidates the previous key and if that tenant also runs the legacy Aiyoda Console (On-Prem), it uses the same key and will stop working until it is updated.
--status says the data directory is not readable (exit code 3)Expected when run unelevated. The data directory is restricted to SYSTEM and local administrators by design, and the agent returns 3 rather than a wrong answer. Without that, a standard user would see an enrolled machine reported as not enrolled. Re-run from an elevated prompt.
Almost always a detection-rule problem rather than an install problem. Check the portal first, the agent has usually enrolled and reported quite happily.
The Intune Management Extension is a 32-bit process, so %ProgramFiles% expands to C:\Program Files (x86). Agent versions before 1.7 took their install path from %ProgramFiles% too, so an Intune deployment installed the x64 agent under Program Files (x86), while a file rule written with 32-bit app: No looked in C:\Program Files. The service registration is authoritative about which path a machine actually used:
Agent 1.7 and later always install to C:\Program Files\Aiyoda\InventraAgent, and upgrading an affected machine relocates it automatically. The installer reads the service's registered path, re-registers the service against the correct directory and removes the old one. The credential lives under %ProgramData%, which is not bitness-dependent, so no re-enrolment is needed.
The fix is to use the packaged detection script, which resolves the 64-bit path itself and compares versions as versions. To see exactly what Intune sees, run it on the machine the way Intune does with no arguments:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\Detect-AiyodaAgent.ps1; "exit $LASTEXITCODE"
Exit 0 with output means detected. Exit 1 with no output means not detected. Intune needs both the code and the output, neither alone counts.
Uploading a new .intunewin replaces the payload but leaves the detection rule alone, and the old rule still says "installed". Re-upload Detect-AiyodaAgent.ps1 from inside the new package at the same time, the packaged copy is stamped with the version it shipped alongside, and that stamp is what makes the upgrade deploy. If you see the script's "no version stamped in" message, the wrong copy was uploaded. The same trap applies to a file String (version) rule, where the comparison value has to be bumped by hand.
The symptom has several distinct causes that need opposite fixes, so establish which identity was denied, and denied what, before changing anything. Run the packaged preflight as the identity the deployment uses:
psexec -s -i powershell.exe -ExecutionPolicy Bypass -File .\Test-AiyodaDeployment.ps1 `
-SourcePath \\dc01\NETLOGON\AiyodaAgent -KeyPath \\dc01\AiyodaKey$\key.txt-s runs it as SYSTEM, which is what the deployment uses. Running it as yourself only shows what your account can reach, which is usually not the question. It prints the identity and its SID, then checks each thing the install needs: source files, the key file, Program Files, the service manager and the portal, naming the fix for whichever failed. Without PsExec, point a second immediate task at the same script with -LogPath C:\ProgramData\Aiyoda\preflight.log and read the file.
| Where it appears | Cause | Fix |
|---|---|---|
| Task Scheduler event 101 | The task is set to a domain account that is not a local admin on the target, or lacks Log on as a batch job | Set the account to NT AUTHORITY\System. Type it in, the picker will not find it |
deploy.log shows a non-SYSTEM identity | The account field silently fell back to the logged-on user | Same fix. Confirm with the identity line at the top of deploy.log |
| Reading the UNC share | SYSTEM reaches the network as the computer account, and the share grants users only | Grant Domain Computers read on both the share and the NTFS permissions, granting one is the common half-fix |
| Reading the key file | Same, on the key share | Grant Domain Computers read there too, and keep it off NETLOGON, which every user can read |
Writing to Program Files, or sc.exe returning 5 | The task is running unelevated | Tick Run with highest privileges as well as setting the account |
| The installer says a file "was not found" | Older agent versions reported an ACL failure as a missing file | Upgrade the package, the installer now distinguishes the two and names the identity |
The installer prints Running as : <identity> as its first line, before anything can fail. If deploy.log shows anything other than NT AUTHORITY\SYSTEM, the account on the task is the problem and no amount of share permissions will help.
AD inventory comes only from the agent holding the directory-collector role, which is granted to one domain controller per tenant. Check Inventra → Agents — the holder is badged in both the list and the card header.
If the machine holding it was decommissioned, the role frees up and the next DC claims it on its next check-in, or immediately, if that DC was uninstalled properly, since uninstall releases the role. The role is also re-claimable when the holder has been revoked or silent for seven days, so decommissioning a DC does not silently stop AD collection.
That means it is joined to neither Active Directory nor an Entra tenant, genuinely standalone. An Entra-joined machine reports its tenant's verified domain instead, read from the cloud-join registry key; if such a machine still shows Workgroup, that key is absent or carries no user email. --status prints the resolved domain, so check there first.
Something is still deploying it. Removing the install assignment does not uninstall anything, and leaving it in place while you deploy the uninstall means the next evaluation reinstalls.
No contact for more than seven days: the machine is switched off, decommissioned, or the service has stopped. An agent that has enrolled but not yet completed its first scan counts from its enrolment time, so a fresh install is not immediately stale. A machine wiped offline never reaches the portal to deregister, so it shows stale until someone removes it in the portal. Remove can be applied to one agent, a ticked selection, or everything matching the current filter across all pages.
It is reporting an older release than the portal's configured current agent version. Upgrade it by re-installing over the top, no tenant key needed, and see the deployment guide for your method. Do not uninstall first.
No. A collector that fails is skipped, not fatal. A device with a broken WMI repository still reports its software and hardware rather than vanishing from the estate and looking decommissioned. Similarly, a permanent rejection, a revoked agent, stops the scan loop but not the process: the agent stays installed and keeps logging why, because exiting would put the service into a restart loop and bury the reason.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Not enrolled (--status), or the report could not be delivered and was spooled for retry |
| 2 | Bad usage, bad configuration, or an action that requires enrolment |
| 3 | The agent data directory is not readable by this account, re-run elevated |