ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

jc 的 net_user 解析器详解:把 Windows `net user` 输出结构化并接入 jq 自动化

jc 的 net_user 解析器详解:把 Windows `net user` 输出结构化并接入 jq 自动化 开发工具【免费下载链接】jcCLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.项目地址https://gitcode.com/gh_mirrors/jc/jc点击查看免费下载net usernet users是 Windows 域管、安全审计和自动化运维中最常用的账号查询命令但其输出是自由排版的纯文本列式对齐的账号清单、跨行换行的详情块、以*分隔的组成员名单直接管道给jq或写入脚本都无从下手。jc 的net_user解析器jc/parsers/net_user.py解决的就是这个问题把net users的四种典型调用形态——列出本机账号、列出域账号、查看单个用户、查看域内单个用户——统一转换为 Schema 固定的 JSON方便jq过滤、Python 处理或落盘为数据文件。读完本文你能掌握该解析器的全部用法、完整输出 Schema、字段级处理逻辑日期归一化、布尔转换、组解析以及从源码层面理解它的行扫描状态机与推送回退迭代器的设计。命令用法CLI 与 Python 模块两种入口命令行用法解析器支持net users的四种标准形态对应文档 docs/parsers/net_user.md 中列出的全部用法$ net users | jc --net-user $ net users /domain | jc --net-user $ net users User1 | jc --net-user $ net users User1 /domain | jc --net-user不带参数列出本机或工作组全部账号此时每条记录只有user_name字段带/domain列出一个域控制器上的全部域账号会额外识别并填充domain字段带单个用户名输出该账号的完整属性详情块Account active、Password last set、Local Group Memberships等用户名 /domain域环境中查询指定用户详情中会包含global_group_memberships。配合-pprettify输出格式化 JSON再管道给jq即可做任意过滤例如只关心域账号名$ net users /domain | jc --net-user | jq [.user_accounts[].user_name]Python 模块用法作为库调用时通过jc.parse()指定解析器名import jc result jc.parse(net_user, net_user_command_output)parse()函数签名为parse(data, rawFalse, quietFalse)其中data为原始文本字符串rawTrue时返回未经二次加工的结构quietTrue时抑制兼容性告警。raw 与 processed 两种结构在形状上是相同的区别在于部分字段是否经过类型归一化见下文字段级处理一节。输出 Schema 全解解析器产出的顶层结构只有三部分domain域名字符串非域环境为空串、account_originUser accounts for 行中给出的账号来源形如\\WIN-SERVER16、user_accounts账号数组。每个账号对象的完整字段如下表即文档中 Schema 的逐项说明字段类型含义与取值说明user_namestring登录名。列表形态下这是该账号唯一出现的字段full_namestring显示名Full Name行未设置时字段缺省commentstring管理员备注Comment行user_commentstring用户自填备注Users comment行country_region_codestring国家/地区代码如000 (System Default)account_activeboolean账号是否启用。原始值Yes/No被转换为布尔account_expiresstring账号过期时间Never保持原样password_last_setstring密码上次设置时间归一化为 ISO 8601password_expiresstring密码过期时间Never保持原样password_changeablestring密码最早可修改时间归一化为 ISO 8601password_requiredboolean是否要求密码user_may_change_passwordboolean用户是否允许修改密码workstations_allowedstring允许登录的工作站All表示不限logon_scriptstring登录脚本路径未设置时缺省user_profilestring用户配置文件路径home_directorystring主目录 UNC 路径last_logonstring上次登录时间ISO 8601从未登录则为Neverlogon_hours_allowedstring允许登录时段All表示不限local_group_membershipsstring[]本地组成员*None被剥离为空数组global_group_membershipsstring[]全局组成员域外环境通常为空数组需要强调的是Schema 中列出的字段是可能出现的最大集合。Windows 对未设置的属性会输出只有键没有值的行如Full Name、Logon script解析器对这些行记录None值随后被静默丢弃因此实际输出只包含有值的字段。这一点从测试夹具 tests/fixtures/windows/windows-2016/net_user.json 可以直接印证该账号对象只有 17 个字段而 Schema 定义了 20 个。四种典型输入与对应输出以下示例完整继承自 docs/parsers/net_user.md并与仓库中的测试夹具逐一对应。1. 列出本机账号net users输入夹具见 tests/fixtures/windows/windows-2016/net_user.outUser accounts for \\WIN-SERVER16 ------------------------------------------------------------------------------- Administrator DefaultAccount Guest user1 The command completed successfully.输出jc --net-user -p{ account_origin: \\\\WIN-SERVER16, domain: , user_accounts: [ { user_name: Administrator }, { user_name: DefaultAccount }, { user_name: Guest }, { user_name: pentera_BnlLQVnd7p }, { user_name: user1 } ] }要点列表形态下解析器只做账号名切分每条记录仅含user_nameaccount_origin来自 User accounts for 行中的\\机器名。2. 列出域账号net users /domain{ account_origin: \\\\DESKTOP-WIN10-PRO.somecompany.corp, domain: somecompany.corp, user_accounts: [ { user_name: aaron }, { user_name: addison }, { user_name: Administrator }, { user_name: ansible }, { user_name: krbtgt }, { user_name: localadmin } ] }域环境下net users会先打印一行 The request will be processed at a domain controller for domain somecompany.corp.。解析器用大小写不敏感的正则捕获该行中的域名写入domain字段jc/parsers/net_user.py这是与本地清单输出最关键的区分点account_origin反映请求在哪台机器/域上执行domain反映目标域是哪个两者语义不同自动化脚本中应分别取用。3. 查看单个用户net users User1输入夹具见 tests/fixtures/windows/windows-2016/net_user.administrators.outUser name / Full Name / Comment ... 详情块输出{ domain: , user_accounts: [ { account_active: true, account_expires: Never, comment: Built-in account for administering the computer/domain, country_region_code: 000 (System Default), global_group_memberships: [], last_logon: 2024-08-23T13:47:11, local_group_memberships: [Administrators], logon_hours_allowed: All, password_changeable: 2021-12-17T11:07:14, password_expires: 2022-01-27T11:07:14, password_last_set: 2021-12-16T11:07:14, password_required: true, user_may_change_password: true, user_name: Administrators, workstations_allowed: All } ] }注意对比原始文本12/16/2021 11:07:14 AM变成了2021-12-16T11:07:14Yes变成了true*Administrators变成了数组[Administrators]——这三类转换由_process阶段完成下节详解。4. 域内查看单个用户net users User1 /domain与示例 3 的差异集中在domain与全局组{ domain: somecompany.corp, user_accounts: [ { account_active: true, global_group_memberships: [ Domain Admins, Domain Users, Group Policy Creator, Enterprise Admins, Schema Admins ], password_expires: Never, user_name: Administrators, local_group_memberships: [Administrators], last_logon: 2024-07-17T13:46:12 } ] }域账号的global_group_memberships通常多行、以*组名逐行输出例如*Domain Admins一行一个解析器会把它们全部收集进同一个数组。这类多行组值的解析是状态机中较精细的部分下面展开。源码级解析机制行扫描状态机与推送回退迭代器核心入口_parse()jc/parsers/net_user.py先把输入按行切分、去掉纯空白行然后进入单行分派循环按行内容识别四种语义域控制器提示行匹配^The request will be processed at a domain controller for domain (.)\.$忽略大小写提取域名L354-L356单用户详情块以 User name 开头的行进入键值对解析分支L358-L397账号清单块以 User accounts for 开头的行进入账号名切分分支L398-L437其他行直接抛出ValueError说明输入不属于任何已识别的net users输出形态属于显式失败而非静默吞错。由于详情块解析需要预读后续行键值对、组名单而组名单结束后要把不属于本组的行交还主循环代码实现了一个带栈的推送回退迭代器_PushbackIteratorL273-L285pushback(value)把行压栈__next__优先弹栈、栈空时再取真实下一行。这使得消费到非组行就归还的多级扫描成为可能而不必把输入整体拷贝成索引数组。键值对解析与键名归一化详情块每行按^([\w\s\/\\-]{1,29})\s*(.)?$L363拆成键和值两部分。键名经统一归一化L380小写化、空格/斜杠/连字符替换为下划线、去掉撇号——因此Country/region code得到country_region_codeUsers comment得到users_comment。若一行只有键没有值如Logon script记为None最终不会出现在输出中。一个值得注意的实现细节源码在_parse_user_account_keypairs()L287-L309中透传的键是users_commentUsers comment 归一化的自然结果而文档 Schema 中写作user_comment。从源码结构看若某账号设置了Users comment字段实际输出中的键名应为users_comment与文档 Schema 存在一处细微出入依赖该字段的脚本建议以实际输出为准并做容错取值。组成员名单的*解析Local Group Memberships与Global Group memberships的值行形如*Administrators域场景下同一键还会跨多行继续以*组名出现。_parse_groups()jc/parsers/net_user.py逐行按*切分、去空白并显式移除占位值NoneWindows 对无成员时输出*None遇到不以*开头的行即推送回退并结束。这就是为什么Global Group memberships *None在最终 JSON 中呈现为[]而不是[None]。字段级类型转换_process阶段parse(rawTrue)与默认输出的差异全部集中在_process()jc/parsers/net_user.py它对每个账号做三类转换布尔转换_process_string_is_yes()L231-L235account_active、password_required、user_may_change_password三个字段由Yes/No不区分大小写转为true/false。注意这是精确匹配 yes的实现Windows 中文系统可能输出是/否此场景下不会得到布尔值日期归一化_process_date()L237-L244依次尝试%m/%d/%Y %I:%M:%S %p12 小时制带 AM/PM与%m/%d/%Y %H:%M:%S %p两种格式成功则转为 ISO 8601如8/23/2024 1:47:11 PM→2024-08-23T13:47:11。Never这类非日期字符串原样保留并返回因此account_expires、last_logon仍可能是NeverNone 静默_set_if_not_none()保证转换结果为None的键不会被写入维持字段缺省即未设置的输出约定。入口parse()本身还做了两件公共职责的事L215-L216调用jc.utils.compatibility()依据info.compatible [win32]做平台检查在非 Windows 上解析会触发兼容性告警可用quietTrue抑制以及jc.utils.input_type_check(data)校验输入类型。空输入直接返回{}与测试test_net_user_nodata的断言一致。测试覆盖六种 Windows 版本的回归夹具test 文件 为 Windows XP、Windows 7、Server 2008、Server 2016、Windows 10、Windows 11 六个环境各维护了一对原始输出 期望 JSON夹具tests/fixtures/windows/windows-*/net_user.out|json并对每组执行parse(fixture)与期望 JSON 的严格相等断言。除列表形态外每个版本目录还有net_user.administrator.out|json覆盖单用户详情形态tests/fixtures/windows/windows-2016/net_user.administrators.out 展示了详情块中有值行 / 空值行 / 组名单行三类行共存的最完整样本。这套夹具意味着该解析器对 Windows 各版本net users输出的列宽差异如 Windows 11 的Last logon 9/27/2024 1:08:58 PM与 2016 的8/23/2024 1:47:11 PM保持了回归级别的保障。适用前提与限制平台info.compatible [win32]jc/parsers/net_user.py解析对象是 Windows 的net users输出Linux 上可以解析保存下来的输出文本但会收到兼容性告警。输入形态仅识别上述四种net users输出遇到无法分派的行会以ValueError显式报错不会输出残缺结果。键名大小写Windows 本地化界面如中文系统输出的键名与键值是/否不在当前正则与布尔匹配范围内属于已知边界本文结论均以仓库内英文 Windows 夹具与 docs/parsers/net_user.md 为准。版本信息解析器Version 1.0 by joehacksalot元数据见info类Schema 与示例输出详见 docs/parsers/net_user.md。小结与快速上手清单net_user解析器把 Windows 账号查询中最难机读的两个部分——多列对齐的账号清单和键值混排的详情块——收敛为一个字段稳定、日期/布尔已归一化的 JSON 结构是 Windows 侧账号盘点、AD 域用户核查、安全基线巡检类脚本的基础组件。常用速查# 本机账号清单只要账号名 net users | jc --net-user | jq -r .user_accounts[].user_name # 域账号清单过滤出域内账号 net users /domain | jc --net-user | jq -r .user_accounts[].user_name # 单用户详情检查密码过期策略 net users User1 | jc --net-user | jq .user_accounts[0] | {password_expires, password_required, account_active}继续深入可参考解析器源码 jc/parsers/net_user.py、回归测试 tests/test_net_user.py 与夹具目录tests/fixtures/windows/按windows-xp至windows-11分版本组织、解析器文档 docs/parsers/net_user.md。赞分享开发工具【免费下载链接】jcCLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.项目地址https://gitcode.com/gh_mirrors/jc/jc点击查看免费下载相关推荐jc net_localgroup 解析器将 Windows net localgroup 输出转为结构化 JSON 的完整指南jc net_localgroup 解析器将 Windows net localgroup 输出转为结构化 JSON 的完整指南 Windows 本地组lo开发工具jc mount 解析器把多平台 mount 输出转成结构化 JSON 的完整指南jc mount 解析器把多平台 mount 输出转成结构化 JSON 的完整指南 本文围绕 jc 项目中的 mount 解析器展开讲解如何把 Linux、开发工具jc lspci 解析器把 PCI 设备清单输出转换为结构化 JSON 的完整解析机制jc lspci 解析器把 PCI 设备清单输出转换为结构化 JSON 的完整解析机制 本文以 jc 仓库中的 lspci 解析器为核心完整讲解它支持的三种开发工具上一篇5个ffmpeg-python帧操作技巧视频编辑入门完全指南下一篇如何高效学习web-basics前端面试与场景题通关秘籍创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表