Módulo WMI
O módulo wmi fornece funções para interagir com o Windows Management Instrumentation (WMI), permitindo consultar informações do sistema, hardware, software e configurações em máquinas Windows remotas ou locais. Este módulo suporta tanto a execução cross-platform (usando o utilitário wmic) quanto a execução nativa no Windows (usando a API COM).
Funções Disponíveis
Seção intitulada “Funções Disponíveis”1. wmi.buildwql(instance_id, table, fields)
Seção intitulada “1. wmi.buildwql(instance_id, table, fields)”Constrói uma consulta WQL (WMI Query Language) a partir de parâmetros simplificados.
Parâmetros:
-
instance_id(string opcional): Identificador de instância no formato “Tabela|Campo|Valor” -
table(string opcional): Nome da tabela WMI (usado quando não há instance_id) -
fields(tabela): Lista de campos a serem selecionados
Retorno:
string: Consulta WQL formatada
Exceções:
-
Lança erro se nenhum dos parâmetros
instance_idoutablefor fornecido -
Lança erro se
instance_idestiver em formato inválido
Exemplos:
-- Consulta simples a uma tabelalocal wql1 = wmi.buildwql(nil, "Win32_OperatingSystem", {"Caption", "Version", "BuildNumber"})-- Resultado: "select Caption,Version,BuildNumber from Win32_OperatingSystem"
-- Consulta a uma instância específicalocal wql2 = wmi.buildwql("Win32_Process|Name|explorer.exe", nil, {"ProcessId", "WorkingSetSize"})-- Resultado: "select ProcessId,WorkingSetSize from Win32_Process where Name = \"explorer.exe\""
-- Consulta com múltiplos camposlocal wql3 = wmi.buildwql(nil, "Win32_LogicalDisk", {"DeviceID", "Size", "FreeSpace", "FileSystem"})-- Resultado: "select DeviceID,Size,FreeSpace,FileSystem from Win32_LogicalDisk"2. wmi.exec(config, wql, namespace)
Seção intitulada “2. wmi.exec(config, wql, namespace)”Executa uma consulta WMI usando o utilitário wmic
Parâmetros:
-
config(tabela): Configuração de conexão contendo:-
net.address(string): Endereço IP ou hostname do alvo -
wmi.username(string): Nome de usuário para autenticação -
wmi.password(string): Senha para autenticação -
wmi.timeout(número opcional, padrão: 10): Timeout em segundos
-
-
wql(string): Consulta WQL a ser executada -
namespace(string opcional): Namespace WMI (padrão: “root\cimv2”)
Retorno:
tabela: Array de resultados, onde cada elemento é uma tabela com pares campo-valor
Nota: Em vez de criar manualmente uma tabela de configuração, você pode usar a tabela global params que já contém todos os campos necessários (net.address, wmi.username, wmi.password, etc.). Esta tabela é automaticamente disponibilizada pelo sistema quando o script é executado no contexto de um dispositivo gerenciado.
Exemplo usando params:
-- A tabela 'device' já contém as credenciais e endereço do dispositivo alvolocal success, results = pcall(function() return wmi.exec(params, wql, "root\\cimv2")end)Exemplo prático:
-- Consulta simplificada usando a tabela devicelocal wql = "select Caption,Version from Win32_OperatingSystem"local results = wmi.exec(device, wql)
-- Para consultas locais no próprio dispositivoif device["net.address"] == "127.0.0.1" or device["net.address"] == "localhost" then -- Pode-se usar exec_native para melhor performance if wmi.exec_native then results = wmi.exec_native(device, wql) endendExceções:
-
Lança erro se a conexão falhar
-
Lança erro “Timeout” se a consulta exceder o tempo limite
-
Lança erro se o utilitário
wmicretornar código de erro
Exemplos:
-- Configuração básicalocal config = { ["net.address"] = "192.168.1.100", ["wmi.username"] = "Administrator", ["wmi.password"] = "senha123", ["wmi.timeout"] = 15}
-- Consulta informações do sistema operacionallocal wql = "select Caption,Version,BuildNumber,OSArchitecture from Win32_OperatingSystem"local success, results = pcall(function() return wmi.exec(config, wql, "root\\cimv2")end)
if success then for _, row in ipairs(results) do print("Sistema: " .. row.Caption) print("Versão: " .. row.Version) print("Build: " .. row.BuildNumber) print("Arquitetura: " .. row.OSArchitecture) endelse print("Erro na consulta WMI: " .. results)end
-- Consulta processos em execuçãolocal process_wql = "select Name,ProcessId,WorkingSetSize,CommandLine from Win32_Process"local process_results = wmi.exec(config, process_wql)
-- Consulta discos lógicoslocal disk_wql = [[select DeviceID,Size,FreeSpace,FileSystemfrom Win32_LogicalDiskwhere DriveType = 3]]local disk_results = wmi.exec(config, disk_wql, nil) -- namespace padrão3. wmi.exec_native(config, wql, namespace) (Apenas no agente Windows)
Seção intitulada “3. wmi.exec_native(config, wql, namespace) (Apenas no agente Windows)”Executa uma consulta WMI usando a API nativa do Windows (COM). Esta função está disponível apenas em sistemas Windows e oferece melhor performance e integração.
Parâmetros:
-
config(tabela): Configuração de conexão (ignorada na execução local) -
wql(string): Consulta WQL a ser executada -
namespace(string opcional): Namespace WMI
Retorno:
tabela: Array de resultados, onde cada elemento é uma tabela com pares campo-valor
Exceções:
-
Lança erro se a API COM falhar
-
Lança erro se a consulta for inválida
Exemplos:
-- Apenas funciona em Windowsif wmi.exec_native then -- Consulta local (config é ignorado) local config = nil -- Deixar vazio para consultas do agente local wql = "select Name,Manufacturer,Model from Win32_ComputerSystem"
local success, results = pcall(function() return wmi.exec_native(config, wql) end)
if success and #results > 0 then local computer = results[1] print("Computador: " .. computer.Name) print("Fabricante: " .. computer.Manufacturer) print("Modelo: " .. computer.Model) endendInformações Adicionais
Seção intitulada “Informações Adicionais”1. Suporte Cross-Platform
Seção intitulada “1. Suporte Cross-Platform”-
A função
execusa o utilitáriowmicque funciona em sistemas Linux -
Permite consultar máquinas Windows remotamente
-
Esta funcionalidade é legada, pois versões mais recentes do Windows não permitem conexões WMI remotas.
2. Execução Nativa no Windows
Seção intitulada “2. Execução Nativa no Windows”-
A função
exec_nativeoferece melhor performance em sistemas Windows -
Não requer autenticação para consultas locais
-
Usa a API COM do Windows diretamente
3. Timeout Configurável
Seção intitulada “3. Timeout Configurável”-
Timeout padrão de 10 segundos
-
Configurável via parâmetro
wmi.timeoutna configuração
Melhores Práticas
Seção intitulada “Melhores Práticas”1. Otimização de Consultas
Seção intitulada “1. Otimização de Consultas”-- RUIM: Seleciona todas as colunaslocal bad_wql = "select * from Win32_Process"
-- BOM: Seleciona apenas colunas necessáriaslocal good_wql = "select Name,ProcessId,WorkingSetSize from Win32_Process"
-- MELHOR: Adiciona filtros para reduzir resultadoslocal best_wql = [[select Name,ProcessId,WorkingSetSizefrom Win32_Processwhere WorkingSetSize > 10485760 -- > 10MB]]4. wmi.exec(config, wql, namespace, replace_backslash)
Seção intitulada “4. wmi.exec(config, wql, namespace, replace_backslash)”Versão estendida da função exec com suporte a timeout e opção para substituir barras invertidas.
Parâmetros:
Seção intitulada “Parâmetros:”-
config (tabela): Configuração de conexão
-
wql (string): Consulta WQL a ser executada
-
namespace (string, opcional): Namespace WMI (usa
wmi._namespaceouparams.wmiNamespacese não especificado) -
replace_backslash (booleano, opcional): Se
true, substitui\por\\na WQL (padrão:true)
Retorno:
Seção intitulada “Retorno:”- tabela: Resultados da consulta WMI
Comportamento:
Seção intitulada “Comportamento:”-
Suporta execução via probe WMI quando
params["wmi.type"] == 0 -
Para localhost (
127.0.0.1), usa execução nativa
Exemplo de Uso:
Seção intitulada “Exemplo de Uso:”-- Executar com timeout configurado-- params.wmiTimeout = 10 (10 segundos)
local config = { address = "192.168.1.100", username = "administrator", password = "senha123"}
local wql = "select Name, ProcessId, WorkingSetSize from Win32_Process"local results = wmi.exec(config, wql, "root\\cimv2")
for _, process in ipairs(results) do print(string.format("Processo: %s (PID: %d, Memória: %d bytes)", process.Name, process.ProcessId, process.WorkingSetSize))end5. wmi.query(wmiobj, ...)
Seção intitulada “5. wmi.query(wmiobj, ...)”Consulta simplificada a uma tabela WMI sem instância específica.
Parâmetros:
Seção intitulada “Parâmetros:”-
wmiobj (string): Nome da tabela WMI
-
… (strings): Campos a serem selecionados (pode incluir
namespace=...)
Retorno:
Seção intitulada “Retorno:”- qualquer tipo: Valor único se apenas um campo for selecionado, tabela se múltiplos campos
Comportamento:
Seção intitulada “Comportamento:”-
Constrói WQL automaticamente com
wmi.buildwql -
Armazena resultado internamente para uso com
prevelapsed -
Suporta especificação de namespace via
namespace=no início dos campos
Exemplo de Uso:
Seção intitulada “Exemplo de Uso:”-- Consultar informações do sistema operacionallocal os_name = wmi.query("Win32_OperatingSystem", "Caption")print("Sistema Operacional:", os_name)
-- Consultar múltiplos camposlocal disk_info = wmi.query("Win32_LogicalDisk", "DeviceID", "Size", "FreeSpace")for _, disk in ipairs(disk_info) do local used_percent = 100 - (disk.FreeSpace / disk.Size * 100) print(string.format("Disco %s: %.1f%% usado", disk.DeviceID, used_percent))end
-- Consultar com namespace específicolocal cluster_info = wmi.query("MSCluster_Cluster", "namespace=root\\MSCluster", "Name", "State")6. wmi.queryinst(...)
Seção intitulada “6. wmi.queryinst(...)”Consulta WMI para instância específica definida em params.InstanceId.
Parâmetros:
Seção intitulada “Parâmetros:”- … (strings): Campos a serem selecionados (pode incluir
namespace=...)
Retorno:
Seção intitulada “Retorno:”- qualquer tipo: Valor único se apenas um campo for selecionado, tabela se múltiplos campos
Comportamento:
Seção intitulada “Comportamento:”-
Usa
params.InstanceIdpara construir consulta de instância -
Lança erro se instância não for encontrada
-
Armazena resultado em
_mem_storepara uso comprevelapsed
Exemplo de Uso:
Seção intitulada “Exemplo de Uso:”-- params.InstanceId = "Win32_Process|Name|explorer.exe"
-- Consultar informações do processo explorer.exelocal pid = wmi.queryinst("ProcessId")local memory = wmi.queryinst("WorkingSetSize")
print(string.format("Explorer.exe - PID: %d, Memória: %d bytes", pid, memory))
-- Consultar múltiplos camposlocal process_info = wmi.queryinst("ProcessId", "WorkingSetSize", "ThreadCount", "Priority")7. wmi.prev(wmiobj, ...)
Seção intitulada “7. wmi.prev(wmiobj, ...)”Obtém o valor anterior de uma consulta WMI.
Parâmetros:
Seção intitulada “Parâmetros:”-
wmiobj (string): Nome da tabela WMI
-
… (strings): Campos da consulta original
Retorno:
Seção intitulada “Retorno:”- qualquer tipo: Valor anterior armazenado
Comportamento:
Seção intitulada “Comportamento:”-
Reconstrói a WQL original
-
Busca valor em
store.get("wmi.value." .. wql) -
Retorna valor único se consulta original retornou único valor
Exemplo de Uso:
Seção intitulada “Exemplo de Uso:”-- Obter valor atuallocal current_memory = wmi.query("Win32_OperatingSystem", "TotalVisibleMemorySize")
-- Obter valor anteriorlocal previous_memory = wmi.prev("Win32_OperatingSystem", "TotalVisibleMemorySize")
-- Calcular diferençalocal memory_diff = current_memory - previous_memoryprint("Variação de memória:", memory_diff, "bytes")8. wmi.previnst(...)
Seção intitulada “8. wmi.previnst(...)”Obtém o valor anterior de uma consulta WMI de instância.
Parâmetros:
Seção intitulada “Parâmetros:”- … (strings): Campos da consulta original
Retorno:
Seção intitulada “Retorno:”- qualquer tipo: Valor anterior armazenado
Exemplo de Uso:
Seção intitulada “Exemplo de Uso:”-- params.InstanceId = "Win32_Process|Name|svchost.exe"
-- Obter uso atual de CPUlocal current_cpu = wmi.queryinst("PercentProcessorTime")
-- Obter uso anteriorlocal previous_cpu = wmi.previnst("PercentProcessorTime")
-- Calcular variaçãolocal cpu_change = current_cpu - previous_cpuprint("Variação no uso de CPU:", cpu_change, "%")9. wmi.lapsed(wmiobj, ...)
Seção intitulada “9. wmi.lapsed(wmiobj, ...)”Obtém o tempo decorrido desde a última consulta WMI.
Parâmetros:
Seção intitulada “Parâmetros:”-
wmiobj (string): Nome da tabela WMI
-
… (strings): Campos da consulta original
Retorno:
Seção intitulada “Retorno:”- número: Tempo em segundos desde última consulta
Exemplo de Uso:
Seção intitulada “Exemplo de Uso:”-- Calcular taxa de transferência de discolocal current_reads = wmi.query("Win32_PerfRawData_PerfDisk_LogicalDisk", "DiskReadBytesPerSec")local previous_reads = wmi.prev("Win32_PerfRawData_PerfDisk_LogicalDisk", "DiskReadBytesPerSec")local time_elapsed = wmi.lapsed("Win32_PerfRawData_PerfDisk_LogicalDisk", "DiskReadBytesPerSec")
local read_rate = (current_reads - previous_reads) / time_elapsedprint("Taxa de leitura de disco:", read_rate, "bytes/segundo")10. wmi.lapsedinst(...)
Seção intitulada “10. wmi.lapsedinst(...)”Obtém o tempo decorrido desde a última consulta WMI de instância.
Parâmetros:
Seção intitulada “Parâmetros:”- … (strings): Campos da consulta original
Retorno:
Seção intitulada “Retorno:”- número: Tempo em segundos desde última consulta
Exemplo de Uso:
Seção intitulada “Exemplo de Uso:”-- params.InstanceId = "Win32_PerfRawData_PerfDisk_LogicalDisk|Name|C:"
-- Calcular taxa de escrita para disco C:local current_writes = wmi.queryinst("DiskWriteBytesPerSec")local previous_writes = wmi.previnst("DiskWriteBytesPerSec")local time_elapsed = wmi.lapsedinst("DiskWriteBytesPerSec")
local write_rate = (current_writes - previous_writes) / time_elapsedprint("Taxa de escrita no disco C:", write_rate, "bytes/segundo")11. wmi.diff(typ, lhs, rhs)
Seção intitulada “11. wmi.diff(typ, lhs, rhs)”Calcula a diferença entre dois valores WMI, tratando rollover de contadores.
Parâmetros:
Seção intitulada “Parâmetros:”-
typ (número): Tipo do contador (32 ou 64 bits)
-
lhs (número): Valor atual
-
rhs (número): Valor anterior
Retorno:
Seção intitulada “Retorno:”- número: Diferença entre os valores
Comportamento:
Seção intitulada “Comportamento:”-
Usa a mesma implementação que
snmp.diff -
Trata rollover de contadores de 32 e 64 bits
-
Sinaliza
RepeatPrevValuese a diferença for negativa
Exemplo de Uso:
Seção intitulada “Exemplo de Uso:”-- Calcular diferença para contador de 64 bitslocal current_bytes = wmi.queryinst("DiskReadBytesPerSec")local prev_bytes = wmi.previnst("DiskReadBytesPerSec")local bytes_diff = wmi.diff(64, current_bytes, prev_bytes)
print("Bytes lidos desde última leitura:", bytes_diff)Exemplos Completos
Seção intitulada “Exemplos Completos”Monitoramento de Processo Específico:
Seção intitulada “Monitoramento de Processo Específico:”-- Configurar instância para monitorar processo específico-- params.InstanceId = "Win32_PerfRawData_PerfProc_Process|Name|chrome.exe"
-- Obter métricas atuaislocal cpu_usage = wmi.queryinst("PercentProcessorTime")local memory_usage = wmi.queryinst("WorkingSetPrivate")local thread_count = wmi.queryinst("ThreadCount")
-- Calcular variaçõeslocal prev_cpu = wmi.previnst("PercentProcessorTime")local prev_memory = wmi.previnst("WorkingSetPrivate")local time_elapsed = wmi.lapsedinst("PercentProcessorTime")
local cpu_delta = wmi.diff(32, cpu_usage, prev_cpu)local memory_delta = memory_usage - prev_memory
print(string.format("Chrome.exe - CPU: %d%%, Memória: %d bytes, Threads: %d", cpu_delta / time_elapsed, memory_delta, thread_count))Inventário de Hardware com Cache:
Seção intitulada “Inventário de Hardware com Cache:”-- Função para obter informações de hardware com cachelocal function get_hardware_info() local cache_key = "hardware_info_" .. params.device.address local cached = cache.get(cache_key)
if cached then return cached end
-- Coletar informações diversas local hardware_info = { os = wmi.query("Win32_OperatingSystem", "Caption", "Version", "BuildNumber"), cpu = wmi.query("Win32_Processor", "Name", "NumberOfCores", "MaxClockSpeed"), memory = wmi.query("Win32_ComputerSystem", "TotalPhysicalMemory"), disks = wmi.query("Win32_LogicalDisk", "DeviceID", "Size", "FreeSpace", "FileSystem") }
-- Armazenar em cache por 1 hora cache.put(cache_key, hardware_info, 3600)
return hardware_infoend
-- Usar informações em cachelocal info = get_hardware_info()print("Sistema:", info.os.Caption, info.os.Version)print("Processador:", info.cpu.Name, "(" .. info.cpu.NumberOfCores .. " núcleos)")print("Memória total:", info.memory / (1024*1024*1024), "GB")