iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
IT Operation

系統工程師的 30 天自動化維運實戰:PowerShell × AD × Windows Server系列 第 16 篇

Day 16|AD Group 自動化盤點:誰在哪個群組?權限到底從哪裡來?

  • 分享至 

  • xImage
  •  

Day 14、Day 15 我們分別盤點了:

User Account
Computer Object

到了 Day 16,要開始碰 Active Directory 裡另一個非常重要的東西:

Group

很多企業環境的權限並不是直接給某一個 User。

而是:

User
↓
AD Group
↓
File Server / VPN / Application / Share Folder
↓
Permission

例如:

tedliu
↓
IT-File-RW
↓
\FileServer\IT
↓
Read / Write

或者:

tedliu
↓
VPN-Users
↓
VPN Permission

所以今天真正要回答的問題是:

這個 User 到底加入哪些 Group?

以及:

這個 Group 裡到底有哪些人?

更進一步還要處理:

Group 裡面還有 Group
Disabled User 還留在重要 Group
已經沒人的 Group
權限群組成員越來越多

最後做出第一份:

AD Group Membership Audit Report

先從 Get-ADGroup 開始

先看看 Domain 裡有哪些 Group:

Get-ADGroup -Filter *

可能會看到:

DistinguishedName
GroupCategory
GroupScope
Name
ObjectClass
ObjectGUID
SamAccountName
SID

整理一下:

Get-ADGroup -Filter * | Select-Object
Name,
SamAccountName,
GroupCategory,
GroupScope

可能:

Name GroupCategory GroupScope


Domain Admins Security Global
VPN-Users Security Global
IT-File-RW Security DomainLocal
HR-Mail Distribution Universal
Security Group 跟 Distribution Group

Group 最基本可以先分成:

Security
Distribution

Security Group 通常可以拿來:

ACL
File Permission
Application Permission
VPN Permission
Windows Security

Distribution Group 則比較偏:

Mail Distribution

所以如果今天做的是:

權限稽核

通常會更關心:

GroupCategory -eq "Security"

例如:

Get-ADGroup -Filter 'GroupCategory -eq "Security"' | Select-Object
Name,
GroupScope
Group Scope 又是什麼?

常見:

Global
DomainLocal
Universal

今天不深入 AD Group Design,但可以先簡單理解。

Global
→ 常拿來裝 User / Computer

DomainLocal
→ 常拿來給資源權限

Universal
→ 多 Domain 環境常見

在一些企業 AD 設計裡,會看到類似:

User
↓
Global Group
↓
Domain Local Group
↓
Permission

這也是為什麼後面會遇到:

Group 裡還有 Group。

查一個 Group

例如:

Get-ADGroup -Identity "VPN-Users"

如果想多看一點:

Get-ADGroup -Identity "VPN-Users"
-Properties Description, ManagedBy, Members |
Select-Object `
Name,
GroupCategory,
GroupScope,
Description,
ManagedBy

這時就可以知道:

這是什麼 Group?
Security 還是 Distribution?
誰負責?
Description 有沒有寫?
Group Description 其實很重要

例如:

VPN-Users

名稱看起來很好懂。

但過幾年可能出現:

VPN-Users
VPN-Users-New
VPN-Users-2025
VPN-Users-Temp
VPN-Test

沒有人知道:

哪個才是真的 Production Group?

所以企業 AD 裡:

Description
ManagedBy

其實非常值得盤點。

後面我們也可以做:

沒有 Description 的 Security Group
沒有 ManagedBy 的權限 Group

當成 Data Quality Review。

查 Group 裡有哪些 Member

今天最重要的 Cmdlet 之一:

Get-ADGroupMember

例如:

Get-ADGroupMember `
-Identity "VPN-Users"

可能:

distinguishedName
name
objectClass
objectGUID
SamAccountName
SID

整理:

Get-ADGroupMember -Identity "VPN-Users" | Select-Object
Name,
SamAccountName,
ObjectClass

例如:

Name SamAccountName ObjectClass


Ted Liu tedliu user
User A usera user
VPN-IT-Users VPN-IT-Users group
PC001 PC001$ computer

這裡立刻出現一個很重要的現象:

Group 裡面不一定只有 User

還可能有:

User
Group
Computer

所以做 Group Audit 時,不要假設每一筆 Member 都一定是 User。

ObjectClass 很重要

例如:

$Members = Get-ADGroupMember `
-Identity "VPN-Users"

只看 User:

$Members |
Where-Object {
$_.ObjectClass -eq "user"
}

只看 nested Group:

$Members |
Where-Object {
$_.ObjectClass -eq "group"
}

這樣就可以知道:

VPN-Users 裡面是不是還包了其他 Group?

Group 裡還有 Group 怎麼辦?

假設:

VPN-Users
│
├── Ted
├── User A
└── VPN-IT
│
├── User B
└── User C

如果:

Get-ADGroupMember `
-Identity "VPN-Users"

直接成員可能只看到:

Ted
User A
VPN-IT

不一定直接列出:

User B
User C

因為他們是:

Nested Group 的成員。

使用 -Recursive

可以:

Get-ADGroupMember -Identity "VPN-Users"
-Recursive

這樣 PowerShell 會往 nested Group 繼續展開。

結果可能:

Ted
User A
User B
User C

這就更接近:

最後有哪些 Principal 透過群組巢狀關係出現在這個群組底下。

Direct Member 跟 Recursive Member 要分開

這裡非常重要。

假設:

VPN-Users
↓
VPN-IT
↓
Ted

Ted 並不是:

VPN-Users 的直接 Member

而是:

VPN-IT 的 Member

VPN-IT 又是:

VPN-Users 的 Member

所以報表最好不要把這兩件事情完全混在一起。

因為排權限時你可能需要知道:

Ted 到底是誰加進來的?

實際答案可能不是:

有人把 Ted 加入 VPN-Users

而是:

Ted 加入 VPN-IT

VPN-IT 被加入 VPN-Users

這是查權限來源時很重要的差別。

查一個 User 加入哪些 Group

反過來,現在如果我知道:

tedliu

想知道他加入哪些 Group,可以使用:

Get-ADPrincipalGroupMembership `
-Identity "tedliu"

整理:

Get-ADPrincipalGroupMembership -Identity "tedliu" | Select-Object
Name,
GroupCategory,
GroupScope |
Sort-Object Name

例如:

Name GroupCategory GroupScope


Domain Users Security Global
IT-Team Security Global
VPN-Users Security Global

這種查詢非常適合回答:

這個帳號目前跟哪些 AD Group 有關?

另外一種方式:MemberOf

也可以:

Get-ADUser -Identity "tedliu"
-Properties MemberOf |
Select-Object -ExpandProperty MemberOf

可能:

CN=IT-Team,OU=Groups,DC=contoso,DC=com
CN=VPN-Users,OU=Groups,DC=contoso,DC=com

不過要注意:

MemberOf

主要反映的是直接 group membership,而且 Primary Group 不會單純透過 memberOf 這個屬性呈現。

所以如果只是日常查詢,我通常會比較偏向使用:

Get-ADPrincipalGroupMembership

如果需要追查:

直接加入?
透過 nested group?
真正權限從哪裡來?

就要再往下分析群組結構。

找出一個 Group 有多少 Member

例如:

$Members = Get-ADGroupMember `
-Identity "VPN-Users"

然後:

@($Members).Count

可能:

253

代表:

VPN-Users 有 253 個直接 Member。

Recursive:

$RecursiveMembers =
Get-ADGroupMember -Identity "VPN-Users"
-Recursive

再:

@($RecursiveMembers).Count

例如:

411

這就可以看到:

Direct Members = 253
Recursive Members = 411

兩個數字差很多,就代表:

這個 Group 內有不少 Nested Membership。

建立 Group Summary

例如:

$GroupName = "VPN-Users"

$Group = Get-ADGroup -Identity $GroupName
-Properties Description, ManagedBy

$DirectMembers =
Get-ADGroupMember `
-Identity $GroupName

$RecursiveMembers =
Get-ADGroupMember -Identity $GroupName
-Recursive

$Summary = [PSCustomObject]@{

GroupName =
    $Group.Name

GroupCategory =
    $Group.GroupCategory

GroupScope =
    $Group.GroupScope

Description =
    $Group.Description

ManagedBy =
    $Group.ManagedBy

DirectMemberCount =
    @($DirectMembers).Count

RecursiveMemberCount =
    @($RecursiveMembers).Count

}

結果可能:

GroupName : VPN-Users
GroupCategory : Security
GroupScope : Global
Description : VPN access users
ManagedBy : ...
DirectMemberCount : 253
RecursiveMemberCount : 411

這已經可以當一份基本 Group Inventory。

找出空 Group

有些 AD 用久之後會留下:

Old-App-Users
Project-A-2022
Temp-Access
Test-Group

Group 還存在,但裡面早就沒有人。

我們可以:

$Groups = Get-ADGroup `
-Filter 'GroupCategory -eq "Security"'

接著:

foreach ($Group in $Groups) {

$Members = @(
    Get-ADGroupMember `
        -Identity $Group `
        -ErrorAction SilentlyContinue
)

if ($Members.Count -eq 0) {

    $Group.Name

}

}

這就可以找:

Empty Security Groups

但一樣:

Empty 不等於可以直接刪。

有些 Group 可能:

目前沒有 Member
但 ACL 還在使用它

例如某個 File Server Folder 已經把權限給:

Project-A-Users

只是目前 Group 暫時沒有成員。

如果直接 Delete Group,可能會留下:

SID 無法解析的 ACL

所以 Empty Group 仍然只是:

Review Candidate。

今天很重要的實戰:Disabled User 還在重要 Group

這種情況在企業 AD 很常值得盤點。

例如:

VPN-Users

├── user01 Enabled
├── user02 Enabled
└── olduser Disabled

olduser 已經 Disable。

但是:

VPN-Users Membership

還沒有清理。

雖然 Disabled Account 本身通常無法正常登入,但從帳號生命週期與權限治理角度,還是值得把 Membership 清乾淨。

找出 Group 裡的 Disabled User

例如:

$GroupName = "VPN-Users"

$Members = Get-ADGroupMember `
-Identity $GroupName

先只找 User:

$UserMembers = $Members |
Where-Object {
$_.ObjectClass -eq "user"
}

接著:

$DisabledUsers = foreach (
$Member in $UserMembers
) {

$User = Get-ADUser `
    -Identity $Member.DistinguishedName `
    -Properties Enabled


if (-not $User.Enabled) {

    $User

}

}

顯示:

$DisabledUsers |
Select-Object `
Name,
SamAccountName,
Enabled

可能:

Name SamAccountName Enabled


Old User olduser False
User B userb False

現在就得到:

Disabled Users Still in VPN Group

對重要 Group 做 Audit 比掃全部 Group 更實際

如果 Domain 裡有:

3000 Groups

每天全部 Recursive 展開可能沒有必要。

我更喜歡先建立:

$CriticalGroups = @(
"Domain Admins"
"Server-Admins"
"VPN-Users"
"FileServer-Admins"
)

然後:

foreach ($GroupName in $CriticalGroups) {

# Audit

}

也就是:

先對高權限、高風險、重要資源群組做更詳細的稽核。

Domain Admins 要特別小心

例如:

Get-ADGroupMember `
-Identity "Domain Admins"

這種高權限 Group 通常應該:

成員數少
用途清楚
定期 Review
沒有不明帳號
沒有長期 Disabled User

但今天我們仍然只做:

Read
Audit
Report

不要在這種 Script 裡直接:

Remove-ADGroupMember

權限群組更應該保留:

Review
Approval
Change Record
Log
建立 Critical Group 設定

例如:

$CriticalGroups = @(
"Domain Admins"
"VPN-Users"
"Server-Admins"
)

接著:

$GroupAudit = @()

開始:

foreach ($GroupName in $CriticalGroups) {

$Group =
    Get-ADGroup `
        -Identity $GroupName `
        -Properties `
            Description,
            ManagedBy


$Members = @(
    Get-ADGroupMember `
        -Identity $GroupName
)


$RecursiveMembers = @(
    Get-ADGroupMember `
        -Identity $GroupName `
        -Recursive
)


$GroupAudit += [PSCustomObject]@{

    GroupName =
        $Group.Name

    GroupScope =
        $Group.GroupScope

    Description =
        $Group.Description

    ManagedBy =
        $Group.ManagedBy

    DirectMembers =
        $Members.Count

    RecursiveMembers =
        $RecursiveMembers.Count

    CheckTime =
        Get-Date

}

}

現在就有:

GroupName DirectMembers RecursiveMembers


Domain Admins 4 4
VPN-Users 253 411
Server-Admins 12 23

這是一份很好用的:

Critical Group Summary

產生 Member Detail

除了 Summary,我們當然還需要:

誰在裡面?

例如:

$GroupMemberReport = @()

然後:

foreach ($GroupName in $CriticalGroups) {

$Members = Get-ADGroupMember `
    -Identity $GroupName


foreach ($Member in $Members) {

    $GroupMemberReport +=
        [PSCustomObject]@{

            GroupName =
                $GroupName

            MemberName =
                $Member.Name

            SamAccountName =
                $Member.SamAccountName

            ObjectClass =
                $Member.ObjectClass

            MembershipType =
                "Direct"

            DistinguishedName =
                $Member.DistinguishedName

        }

}

}

結果:

Group Member Type Membership
VPN-Users tedliu user Direct
VPN-Users VPN-IT group Direct
Server-Admins Admin01 user Direct

這份資料對權限 Review 很有用。

Recursive Member 建議另外輸出

不要直接把:

Direct
Recursive

混成同一份且沒有標記。

例如:

$RecursiveReport = @()

然後:

foreach ($GroupName in $CriticalGroups) {

$Members = Get-ADGroupMember `
    -Identity $GroupName `
    -Recursive


foreach ($Member in $Members) {

    $RecursiveReport +=
        [PSCustomObject]@{

            GroupName =
                $GroupName

            MemberName =
                $Member.Name

            SamAccountName =
                $Member.SamAccountName

            ObjectClass =
                $Member.ObjectClass

            MembershipType =
                "Recursive"

            DistinguishedName =
                $Member.DistinguishedName

        }

}

}

現在:

Direct Report

回答:

誰直接被加入這個 Group?

而:

Recursive Report

回答:

展開 nested membership 後,可以看到哪些成員?

兩份用途不一樣。

建立 Disabled Membership Report

現在把重要 Group 裡的 Disabled User 找出來。

$DisabledMemberReport = @()

接著:

foreach ($GroupName in $CriticalGroups) {

$Members = Get-ADGroupMember `
    -Identity $GroupName `
    -Recursive


$UserMembers = $Members |
Where-Object {
    $_.ObjectClass -eq "user"
}


foreach ($Member in $UserMembers) {

    try {

        $User = Get-ADUser `
            -Identity $Member.DistinguishedName `
            -Properties `
                Enabled,
                LastLogonDate,
                Department `
            -ErrorAction Stop


        if (-not $User.Enabled) {

            $DisabledMemberReport +=
                [PSCustomObject]@{

                    GroupName =
                        $GroupName

                    Name =
                        $User.Name

                    SamAccountName =
                        $User.SamAccountName

                    Enabled =
                        $User.Enabled

                    Department =
                        $User.Department

                    LastLogonDate =
                        $User.LastLogonDate

                    DistinguishedName =
                        $User.DistinguishedName

                }

        }

    }
    catch {

        # Query error can be logged here

    }

}

}

最後:

Group User Enabled


VPN-Users olduser False
Server-Admins admin02 False

這就是一份很實際的:

Disabled Account Membership Audit

但 Recursive Report 有一個問題

假設:

VPN-Users
↓
VPN-IT
↓
olduser

Recursive Audit 會告訴你:

olduser
出現在 VPN-Users 的遞迴成員裡

但它不會直接告訴你完整路徑:

olduser
→ VPN-IT
→ VPN-Users

如果真的要做:

權限來源追蹤

就需要進一步分析 Nested Group Path。

這個我們今天先不展開,不然 Day 16 會變成 Group Graph 演算法。

今天先把:

Direct
Recursive

分清楚就已經很重要。

Group Membership ≠ 最終資源權限

這一點也非常重要。

假設:

tedliu

是:

IT-File-RW

的 Member。

不代表我們只看 AD Group 就能百分之百知道:

Ted 對所有 File Server 有哪些權限。

因為真正的資源可能還有:

NTFS ACL
Share Permission
Application RBAC
GPO
Local Group
Cloud Permission

所以今天做的是:

AD Group Membership Audit

而不是完整:

Enterprise Effective Permission Audit

不過 AD Group 往往是非常重要的第一層。

找出沒有 Description 的 Security Group

既然今天已經查 Group,也可以順便做一個簡單的 Data Quality Check。

Get-ADGroup -Filter 'GroupCategory -eq "Security"'
-Properties Description |
Where-Object {

[string]::IsNullOrWhiteSpace(
    $_.Description
)

} |
Select-Object `
Name,
GroupScope,
DistinguishedName

如果結果很多:

FileRW01
Test123
ABC-GRP
NewGroup
OldApp

未來管理上就會很痛苦。

找出沒有 ManagedBy 的 Security Group

同樣:

Get-ADGroup -Filter 'GroupCategory -eq "Security"'
-Properties ManagedBy |
Where-Object {

$null -eq $_.ManagedBy

} |
Select-Object `
Name,
GroupScope,
ManagedBy

這可以回答:

這個權限 Group 到底誰負責?

真正企業權限治理裡:

誰是 Group Owner?
誰可以核准加入?
這個 Group 是做什麼?

都非常重要。

今天完整 Script

下面把 Day 16 的主要內容整理成一支:

Critical AD Group Membership Audit

==========================================

AD Group Membership Audit

Day 16

==========================================

Import-Module ActiveDirectory

==========================================

Configuration

==========================================

$CriticalGroups = @(
"Domain Admins"
"VPN-Users"
"Server-Admins"
)

$ReportFolder =
"C:\Temp\ADReports"

$Date =
Get-Date -Format "yyyyMMdd"

==========================================

Report Folder

==========================================

if (-not (Test-Path $ReportFolder)) {

New-Item `
    -Path $ReportFolder `
    -ItemType Directory |
    Out-Null

}

==========================================

Result Containers

==========================================

$GroupSummary = @()

$DirectMemberReport = @()

$RecursiveMemberReport = @()

$DisabledMemberReport = @()

==========================================

Audit Groups

==========================================

foreach ($GroupName in $CriticalGroups) {

Write-Host "Checking Group: $GroupName"


try {

    $Group = Get-ADGroup `
        -Identity $GroupName `
        -Properties `
            Description,
            ManagedBy `
        -ErrorAction Stop


    # --------------------------
    # Direct Members
    # --------------------------

    $DirectMembers = @(
        Get-ADGroupMember `
            -Identity $GroupName `
            -ErrorAction Stop
    )


    foreach ($Member in $DirectMembers) {

        $DirectMemberReport +=
            [PSCustomObject]@{

                GroupName =
                    $Group.Name

                MemberName =
                    $Member.Name

                SamAccountName =
                    $Member.SamAccountName

                ObjectClass =
                    $Member.ObjectClass

                MembershipType =
                    "Direct"

                DistinguishedName =
                    $Member.DistinguishedName
            }
    }


    # --------------------------
    # Recursive Members
    # --------------------------

    $RecursiveMembers = @(
        Get-ADGroupMember `
            -Identity $GroupName `
            -Recursive `
            -ErrorAction Stop
    )


    foreach ($Member in $RecursiveMembers) {

        $RecursiveMemberReport +=
            [PSCustomObject]@{

                GroupName =
                    $Group.Name

                MemberName =
                    $Member.Name

                SamAccountName =
                    $Member.SamAccountName

                ObjectClass =
                    $Member.ObjectClass

                MembershipType =
                    "Recursive"

                DistinguishedName =
                    $Member.DistinguishedName
            }
    }


    # --------------------------
    # Disabled Users
    # --------------------------

    $UserMembers =
        $RecursiveMembers |
        Where-Object {
            $_.ObjectClass -eq "user"
        }


    foreach ($Member in $UserMembers) {

        try {

            $User = Get-ADUser `
                -Identity $Member.DistinguishedName `
                -Properties `
                    Enabled,
                    Department,
                    LastLogonDate `
                -ErrorAction Stop


            if (-not $User.Enabled) {

                $DisabledMemberReport +=
                    [PSCustomObject]@{

                        GroupName =
                            $Group.Name

                        Name =
                            $User.Name

                        SamAccountName =
                            $User.SamAccountName

                        Department =
                            $User.Department

                        Enabled =
                            $User.Enabled

                        LastLogonDate =
                            $User.LastLogonDate

                        DistinguishedName =
                            $User.DistinguishedName
                    }
            }

        }
        catch {

            Write-Warning `
                "Failed to query user $($Member.Name): $($_.Exception.Message)"
        }
    }


    # --------------------------
    # Group Summary
    # --------------------------

    $GroupSummary +=
        [PSCustomObject]@{

            GroupName =
                $Group.Name

            GroupCategory =
                $Group.GroupCategory

            GroupScope =
                $Group.GroupScope

            Description =
                $Group.Description

            ManagedBy =
                $Group.ManagedBy

            DirectMemberCount =
                $DirectMembers.Count

            RecursiveMemberCount =
                $RecursiveMembers.Count

            DisabledUserCount =
                @(
                    $DisabledMemberReport |
                    Where-Object {
                        $_.GroupName -eq
                        $Group.Name
                    }
                ).Count

            CheckTime =
                Get-Date
        }

}
catch {

    Write-Warning `
        "Failed to audit $GroupName : $($_.Exception.Message)"
}

}

==========================================

Export

==========================================

$GroupSummary |
Export-Csv -Path "$ReportFolder\AD_Group_Summary_$Date.csv"
-NoTypeInformation `
-Encoding UTF8

$DirectMemberReport |
Export-Csv -Path "$ReportFolder\AD_Group_DirectMembers_$Date.csv"
-NoTypeInformation `
-Encoding UTF8

$RecursiveMemberReport |
Export-Csv -Path "$ReportFolder\AD_Group_RecursiveMembers_$Date.csv"
-NoTypeInformation `
-Encoding UTF8

$DisabledMemberReport |
Export-Csv -Path "$ReportFolder\AD_Group_DisabledMembers_$Date.csv"
-NoTypeInformation `
-Encoding UTF8

==========================================

Display

==========================================

Write-Host ""
Write-Host "===== AD Group Audit Completed ====="
Write-Host ""

$GroupSummary

Write-Host ""
Write-Host "Reports:"
Write-Host "$ReportFolder\AD_Group_Summary_$Date.csv"
Write-Host "$ReportFolder\AD_Group_DirectMembers_$Date.csv"
Write-Host "$ReportFolder\AD_Group_RecursiveMembers_$Date.csv"
Write-Host "$ReportFolder\AD_Group_DisabledMembers_$Date.csv"
執行後會得到四份報表
C:\Temp\ADReports
│
├── AD_Group_Summary_20260924.csv
├── AD_Group_DirectMembers_20260924.csv
├── AD_Group_RecursiveMembers_20260924.csv
└── AD_Group_DisabledMembers_20260924.csv

每一份回答的問題不同。

Group Summary

例如:

Group Direct Recursive Disabled
Domain Admins 4 4 0
VPN-Users 253 411 6
Server-Admins 12 23 1

這一份適合快速看:

Group 成員數突然變多?
Nested Group 很複雜?
有 Disabled User?
Direct Members

這一份回答:

誰被直接加入這個 Group?

例如:

VPN-Users
├── user01
├── user02
└── VPN-IT

這在追查:

為什麼這個人有權限?

時非常重要。

Recursive Members

這一份回答:

把 Nested Group 展開後有哪些 Member?

例如:

VPN-Users
↓
VPN-IT
↓
tedliu

Recursive Report 會讓 tedliu 出現在結果裡。

Disabled Members

這一份則專門找:

Account Disabled
但 Membership 還留在重要 Group

這就可以交給帳號或權限負責人進一步 Review。

不要在 Audit Script 裡直接 Remove Member

今天特別不加入:

Remove-ADGroupMember

原因跟前兩天完全一樣。

假設:

olduser
Enabled = False

仍然在:

VPN-Users

從治理角度來看可能應該清掉。

但是正式環境仍然最好:

Audit
↓
Report
↓
確認帳號用途
↓
確認 Group Owner
↓
Approval
↓
Remove Membership
↓
Log

而不是:

PowerShell 發現
↓
自動移除

尤其:

Domain Admins
Enterprise Admins
Server Admins
Backup Operators

這類高權限群組,更應該留下完整的 Change Record。

Day 16 小結

今天我們正式開始碰 Active Directory 的:

Group

主要使用:

Get-ADGroup

Get-ADGroupMember

Get-ADPrincipalGroupMembership

並理解了 Group Audit 裡幾個很重要的概念:

Direct Membership
≠
Nested / Recursive Membership

以及:

User 在 Group 裡
≠
已經知道完整最終資源權限

因為真正的權限可能還牽涉:

AD Group
NTFS
Share Permission
Local Group
Application RBAC

今天我們已經可以回答:

某個 User 加了哪些 AD Group?

某個 Group 有哪些成員?

Group 裡是不是還有 Group?

展開 Nested Group 後有多少人?

重要 Group 裡還有 Disabled User 嗎?

哪些 Security Group 沒有 Description?
哪些 Group 沒有 Owner?

這代表我們從前幾天的:

這個帳號還有沒有在用?

開始往更重要的一層前進:

這個帳號到底擁有哪些權限?

Day 17 預告
Day 17|AD 帳號生命週期自動化:建立、停用與離職帳號該怎麼安全處理?

前面幾天一直都是:

Query
Audit
Report

到了 Day 17,我們才會第一次開始碰真正會:

修改 Active Directory

的 Cmdlet。

例如:

New-ADUser
Set-ADUser
Disable-ADAccount
Move-ADObject

但不會直接做成:

讀 CSV
↓
看到離職
↓
直接 Disable

而是設計成:

Input
↓
Validation
↓
WhatIf / Preview
↓
Approval
↓
Action
↓
Move Disabled OU
↓
Log
↓
Report

並開始討論一個很實際的離職流程:

Disable Account
Remove Sensitive Group Membership
Move OU
更新 Description
保留稽核紀錄

Day 17 會是整個系列第一次正式從「Read-Only Automation」進入「Change Automation」。


上一篇
Day 15|AD Computer 物件盤點:找出長期未登入與可能已淘汰的電腦
下一篇
Day 17|AD 帳號生命週期自動化:建立、停用與離職帳號該怎麼安全處理?
系列文
系統工程師的 30 天自動化維運實戰:PowerShell × AD × Windows Server 共 20 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言