如何一次向数千台 Windows 域计算机远程发出 CLI 命令?

Hop*_*00b 7 scripting windows active-directory domain

我需要向域中的所有数千台计算机发出 CLI 命令(cmd.exe 或 PowerShell)。出于显而易见的原因,这不会涉及手动执行任务或物理访问每台机器。

这应该怎么做?

Hop*_*00b 12

一般情况:

如何一次向数千台 Windows 域计算机远程发出 CLI 命令?

与我们专业中的大多数事情一样,您最简单的方法通常是将工作分解为简单、离散的任务,然后依次执行这些任务,或者将它们串在一起(例如将它们全部放入一个脚本中) .

在这方面,我可以建立 3 个独立的任务。

  1. 收集要发出命令的客户端列表。

  2. 连接到所有客户端。

  3. 向所有客户端发出命令。

在此之后,您可能想要验证结果,就像在此之前一样,您想要测试您的过程,但为了这个问题的目的,让我们忽略它。只是不要忽略现实世界中的预实施和实施后测试,否则你会后悔的。

您还需要做出“架构”决定(是并行还是串行执行第 2 步和第 3 步),但我们也忽略这一点。我将连续执行它们,因为它更容易,而且我很懒。

请注意,到目前为止,我从未提到任何特定的工具、实现或给定的示例。那是故意的。到目前为止,以上都是设计和/或架构工作。是的,如果您想“做对”,请实施之前进行设计和计划。(从一般到具体。)

为了实现这一点,下面是我通过同时向数千台 Windows 域计算机发出命令来解决的一个具体问题。


具体案例:

如何一次更正我所有 Windows 域计算机上的时间?

对于那些并不需要进入的原因,我最近遇到的情况是最好的解决方案是发出一个命令,以 由我的雇主拥有电脑,为了修复一个域范围内的时间偏差。(我也很受时间限制——有不到 2 小时的时间让域中的所有计算机与“真实”时间同步。)

  1. 收集要发出命令的客户端列表。

    • 由于我的环境的具体情况,再加上我的特定工具和技能,我使用 PowerShell 来执行此操作。
    • 因为我想要所有的计算机,并且因为我接下来要做的事情,我想简单地将此列表存储在一个变量中,所以我将使用的具体命令是:
    • $boxlist = Get-ADComputer -filter *(将在 Active Directory 中找到的所有计算机对象的列表存储到名为boxlist的变量中)

  2. 连接到所有客户端。

    • 因为我赶时间,所以我会坚持我所知道的。我经常将 PowerShell Remoting 用于单台计算机或一小组计算机,并且对它非常满意。我没有在这么大的团队中使用过它,但没有理由它不应该工作,而且我现在没有时间学习新事物或安装新工具,所以它必须这样做。
    • 在这一点上,我意识到我需要提供凭据才能实际完成请求,选择Get-Credentialcmdlet 来执行此操作,并最终得到以下两个命令。
    • $creds = Get-Credential domain\user(创建一个提示,我在其中输入我的凭据并将身份验证令牌存储在名为creds的变量中)
    • $session = New-PSSession -ComputerName $boxlist.name -Credential $creds(使用我刚刚提供的凭据为boxlist变量中的每台计算机创建新的 PowerShell 会话,并将这些 PowerShell 会话存储在名为session的变量中)

  3. 向所有客户端发出命令。

    • 由于我们域上的时间配置方式以及时间偏差的根本原因,我已经知道要发出什么命令。我们有一个 GPO 可以按照我们喜欢的方式设置所有 Windows 时间服务设置,我们的权威时间源同步到真实时间,我们的从属时间源与域的权威时间源同步,而我需要做的只是强制客户端立即与其本地时间源重新同步。- 这将调用w32tm /resync /nowait /rediscover,并使用 Powershell,将使用Invoke-Command cmdlet调用
    • Invoke-Command -Session $session -ScriptBlock {w32tm /resync /nowait /rediscover}(调用提供给 Scriptblock 开关的命令到会话开关,其中包含名为session的变量,其中包含我域中所有计算机的列表)

该脚本或其所有组件已编写完成,可以在 PowerShell shell 中一次一行执行,也可以保存为 PowerShell 脚本文件并运行。我很着急,这是一个很短的脚本,我认为我不需要再次使用(或者无法重新创建,因此我最终会在 shell 窗口中逐行打印它正在做。

$boxlist = Get-ADComputer -filter *
$creds = Get-Credential domain\user
$session = New-PSSession -ComputerName $boxlist.name -Credential $creds
Invoke-Command -Session $session -ScriptBlock {w32tm /resync /nowait /rediscover}
Run Code Online (Sandbox Code Playgroud)