当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 使用 PowerShell 获取组策略链接

作者:精品下载站 日期:2024-12-14 08:01:09 浏览:16 分类:玩电脑

使用 PowerShell 获取组策略链接


我最近正在和我的朋友 Gladys Kravitz 讨论组策略报告的问题。这次讨论让我重新整理了一些使用 PowerShell 获取组策略链接的旧代码。 GroupPolicy 模块有一个 Set-GPLink 命令,但没有任何命令可以轻松显示哪些 GPO 链接到您的站点、域和 OU。尽管您可能不需要这样的报告,但我希望我的脚本编写技术中的某些内容会对您有所帮助。

从核心命令开始

与任何 PowerShell 项目一样,您希望从控制台启动。您能否以交互方式运行命令来实现目标的本质?就我而言,这是来自 GroupPolicy 模块的 Get-GPInheritance cmdlet。我希望您能阅读帮助和示例。以下是它如何向我显示域级别链接的内容。

[玩转系统] 使用 PowerShell 获取组策略链接

在查看输出时,我看到一个属性可能包含我想要的信息。

[玩转系统] 使用 PowerShell 获取组策略链接

这看起来很有希望。我可以验证它也适用于组织单位。

(Get-ADOrganizationalUnit -filter * | Get-GPInheritance).GpoLinks | 
 Select-Object -Property Target,DisplayName,Enabled,Enforced,Order |
 Format-Table

[玩转系统] 使用 PowerShell 获取组策略链接

这看起来相当不错,并且接近我希望实现的目标。

查询站点链接

那么网站呢?假设我不知道所有网站的可分辨名称,我需要一个编程解决方案。我可以使用 ActiveDirectory 模块来发现站点。

$getADO = @{
     LDAPFilter = "(Objectclass=site)"
     properties = "Name"
     SearchBase = (Get-ADRootDSE).ConfigurationNamingContext
 }
 $sites = Get-ADObject @getADO

[玩转系统] 使用 PowerShell 获取组策略链接

我只有一个站点,但不幸的是 Get-GPInheritance 无法使用站点。有多种方法可以挖掘 Active Directory 并解析站点链接,但我决定采用一种更简单的方法并依靠旧的 COM 对象 GPMGMT.GPM。就是这样。

首先,我需要一个对象引用。我还将获取该对象所需的所有常量。

$gpm = New-Object -ComObject "GPMGMT.GPM"
$gpmConstants = $gpm.GetConstants()

我需要对域和林的引用。

$gpmdomain = $gpm.GetDomain("company.pri", "", $gpmConstants.UseAnyDC)
$SiteContainer = $gpm.GetSitesContainer("company.pri", "company.pri", $null, $gpmConstants.UseAnyDC)

我的域和林名为 Company.pri。

[玩转系统] 使用 PowerShell 获取组策略链接

$SiteContainer 对象有一个 GetSite() 方法,但它需要站点的名称。但我很早就明白了。

[玩转系统] 使用 PowerShell 获取组策略链接

这个新对象有一个名为 GetGPOLinks() 的方法。

[玩转系统] 使用 PowerShell 获取组策略链接

那很好。我所缺少的只是 GPO 名称。

$site.GetGPOLinks() | Select GPOId,@{Name="DisplayName";Expression = {$gpmdomain.GetGPO($_.gpoid).Displayname}},Enabled,Enforced,SOMLinkOrder

因为我有 GPOId,所以我可以获得 GPO。此代码使用 COM 对象。我本可以使用 cmdlet,但我需要解析出 {} 字符。

$site.GetGPOLinks() | Select GPOId,@{Name="DisplayName";Expression = {(Get-GPO -id ($_.gpoid.replace("{|",""))).Displayname}},Enabled,Enforced,SOMLinkOrder

有了这些部分,我就可以围绕这些代码片段构建一个 PowerShell 工具。

获取 GPLink

我编写了一个名为 Get-GPLink 的函数。由于我使用的是 GroupPolicy 和 ActiveDirectory cmdlet,并且它们支持指定服务器和/或域,因此我也想支持这一点。最初,我尝试使用splatting并动态分配参数值。但这很快就变得笨拙了。相反,我定义了 $PSDefaultParameter 值的脚本范围版本。

if ($Server) {
    $script:PSDefaultParameterValues["Get-AD*:Server"] = $server
    $script:PSDefaultParameterValues["Get-GP*:Server"] = $Server
}

if ($domain) {
    $script:PSDefaultParameterValues["Get-AD*:Domain"] = $domain
    $script:PSDefaultParameterValues["Get-ADDomain:Identity"] = $domain
    $script:PSDefaultParameterValues["Get-GP*:Domain"] = $domain
}

现在我不必担心它如果我运行 Get-ADDomain 并且从我的函数中使用 Server 参数,Get-ADDomain cmdlet 将自动使用它。

该函数使用 GroupPolicy 模块遍历并查询域和组织单位。使用 COM 对象检索站点级链接。从技术上讲,我可以使用 COM 对象来完成所有事情。

该功能收集所有链接,使我能够提供按 GPO 名称进行过滤或仅显示启用或禁用的链接。

[玩转系统] 使用 PowerShell 获取组策略链接

那还不错。但我总是想要更多。例如,我无法将函数的输出通过管道传输到 Get-GPO。虽然我可以,但如果我做一点小小的调整。

[玩转系统] 使用 PowerShell 获取组策略链接

但我不想一直这样做。我还想要一个表格的默认输出。我知道我可以使用自定义 format.ps1xml 文件和我值得信赖的 New-PSFormatXML 命令来做到这一点。但要做到这一点,我需要一个独特的自定义类型名称。

在我的代码中,我可以插入新的类型名称,因为我没有像通常那样从头开始创建自定义对象。

$results.GetEnumerator().ForEach( { $_.psobject.TypeNames.insert(0, "myGPOLink") })

一旦有了新的类型名称,我就可以定义类型扩展。

Update-TypeData -MemberType AliasProperty -MemberName GUID -Value GPOId -TypeName myGPOLink -Force
Update-TypeData -MemberType AliasProperty -MemberName Name -Value DisplayName -TypeName myGPOLink -Force
Update-TypeData -MemberType AliasProperty -MemberName GPO -Value DisplayName -TypeName myGPOLink -Force
Update-TypeData -MemberType AliasProperty -MemberName Link -Value Target -TypeName myGPOLink -Force
Update-TypeData -MemberType AliasProperty -MemberName Domain -Value GpoDomainName -TypeName myGPOLink -Force
Update-TypeData -MemberType ScriptProperty -MemberName TargetType -Value {
    switch -regex ($this.target) {
        "^((ou)|(OU)=)" { "OU" }
        "^((dc)|(DC)=)" { "Domain" }
        "^((cn)|(CN)=)" { "Site" }
        Default { "Unknown"}
    }
} -TypeName myGPOLink -Force

这使得现在使用我的组策略链接变得更加容易。

[玩转系统] 使用 PowerShell 获取组策略链接

自定义格式

当然,因为我有一个自定义类型,所以我可以创建一个 format.ps1xml 文件并变得非常奇特。现在我可以创建结果的默认表格视图。由于我一直在寻找为 PowerShell 添加颜色的方法,因此我决定突出显示禁用的链接以及使用 ANSI 转义序列强制执行的链接。

<TableColumnItem>
    <ScriptBlock>
    <!-- use ANSI formatting if using the console host-->
    if ($host.name -eq 'ConsoleHost') {
        if ($_.Enabled) {
        $_.Enabled
        }
        else {
        "$([char]0x1b)[1;91m$($_.enabled)$([char]0x1b)[0m"
        }
    }
    else {
        $_.Enabled
    }
    </ScriptBlock>
</TableColumnItem>

如果 PowerShell 检测到控制台主机,脚本块仅使用 ANSI。我使用的转义序列适用于 Windows PowerShell 和 PowerShell 7.x

[玩转系统] 使用 PowerShell 获取组策略链接

格式文件还包括其他视图。

[玩转系统] 使用 PowerShell 获取组策略链接

[玩转系统] 使用 PowerShell 获取组策略链接

[玩转系统] 使用 PowerShell 获取组策略链接

概括

我在我的大部分工作中使用了刚刚描述的工作流程。我从核心命令开始,以函数的形式围绕命令构建一个强大的包装器,将对象写入管道,并在必要时使用类型和格式扩展进行自定义。最终结果应该是一个易于使用且有用的 PowerShell 工具,它像任何其他 PowerShell 命令一样在管道中运行。

如果您想了解这一切是如何工作的,我已将代码作为 GitHub 要点发布。如果您想尝试一下,则需要将这两个文件保存到同一目录。请密切注意格式文件的名称,因为当您点源函数文件时会加载该文件。

如果您对我的做法或原因有任何疑问,请随时发表评论。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯