ניטור הרשאות בעץ תיקיות

ניטור הרשאות בעץ תיקיות

לפעמים נרצה לעקוב אחר שינויי הרשאות בתיקיות רגישות.

ישנן תיקיות רגישות המצריכות סודיות וגישה מוגבלת. אנשי הסיסטם ואבטחת מידע יגבילו את הגישה לתיקיות אלה באמצעות הרשאות מערכת קבצים. הרשאות לתיקיה יקבלו אך ורק משתמשים מסוימים. אלה שחייבים גישה לתוכן ולתתי תיקיות, על מנת לבצע את עבודתם.

במצב כזה, רצוי לעקוב אחר השינויים בהרשאות הגישה לאותן התיקיות. זאת על מנת לעצור ולברר מקרים בהם התקבלה הרשאה עבור משתמש שאינו אמור לקבל אותה.

ישנן מערכות רבות ושונות המנטרות פעולות שכאלה, ורובן המוחלט מגישות את הנתונים בתרשימים גרפיים נוחים לעין.

אך כאן ינתן פתרון פשוט, שאינו מצריך שרת או מערכת משלו. פתרון שניתן להפעיל בצורה אוטומטית בזמנים קבועים, על מנת לקבל את אותו המידע.

להלן אסביר את פעולת הסקריפט, שיבוא בסוף כנספח.

התייחסות לשורות בסקריפט, כפי שהוא מוצג ב-PowerShell ISE.

הגדרת משתנים:

שורות 2-5 הן החשובות ביותר עבור מי שמשתמש בסקריפט.

לא צריך להבין יותר מדי את הסקריפט כדי להשתמש בו. אבל בשורות אלה מגדירים את מה שצריך כדי להתאים את הפעולה עבור הצורך הנוכחי.

בשורה 2 מגדירים לתוך משתנה את הנתיב של התיקיה שממנה ומטה תאספנה ההרשאות. אם זה כונן מקומי (כמו כונן בשרת, והסקריפט פועל מתוך השרת), או תיקיית רשת. ההרשאות תאספנה מכל התיקיות שתחת תיקיה זו, כולל התיקיה שהנתיב שלה נקבע במשתנה.

בשורה 3 מגדירים יעד עבור קבצי תוצאה. גם כאן מכניסים נתיב. בכל ריצה של הסקריפט, הסקריפט שומר בנתיב הזה קובץ המכיל את רשימת ההרשאות שמצא הסקריפט. אליו יתווסף קובץ המכיל את ההבדלים בין ההרשאות שעלו בריצה הנוכחית, לאלה שמצאו בריצה שעברה.

שורה 5 לוקחת את ההרשאות מריצה קודמת. כי בכל ריצה רשימת ההרשאות עולה לקובץ הנושא תאריך. כך נוכל למצוא את הקובץ מן הריצה הקודמת – לפי מס' הימים שעברו מאז.

ההנחה היא שהסקריפט רץ בתדירות קבועה. לכן בשורה זו תחת המתודה "AddDays", מחסרים את מספר הימים שעוברים בין הריצות. התאריך הנוכחי פחות מס' הימים, יתן לנו את חותמת הזמן מן הריצה האחרונה.

לבסוף, שורה 6 אוספת את הנתונים מקובץ התוצאות של הריצה האחרונה. שם על פי תנאי יתכן איסוף הרשאות בלבד. ללא השוואות. זאת אם הקובץ לא קיים – כמו בריצה ראשונה. או כשמספר הימים בשורה 5 לא הוגדר נכון.

איסוף התיקיות והרשאותיהן (שורות 9-24):

שורה 9 אוספת רשימת כל התיקיות ותתי התיקיות שתחת הנתיב שהוגדר בשורה 2.

בשורה 10 נוספת לרשימה תיקיית המקור שהוגדרה בשורה 2.

הרשימה מכילה אובייקטים של כל התיקיות, ושם שלל פרטים עליהן.

בשורות 13-20, לולאה עוברת על כל תיקיה ברשימה, ולוקחת את רשימת ההרשאות על התיקיה.

כל תיקיה מייצרת רשימת הרשאות. כל שורה ברשימה מכילה הגדרת הרשאות עבור חשבון אחד – על אותה התיקיה. השורה מכילה כמה וכמה מאפיינים.

חשוב להוסיף לנתונים הללו עוד מאפיינים שאינם ההרשאות עצמן. אלה חשובים להקשר של התיקיה שעליה ניתנים ההרשאות.

לכן לרשימת ההרשאות נוספים שלושה מאפיינים:

  1. הנתיב לתיקיה
  2. הפעם האחרונה שמישהו פתח את התיקיה
  3. מי מוגדר ברשימת ההרשאות כבעל התיקיה

את כל רשימת ההרשאות של אותה התיקיה, מוסיפים לרשימה כללית. לבסוף זו תהפוך לרשימת כלל ההרשאות בכל התיקיות. לרשימת כלל ההרשאות נצטרך כמה מאפיינים ולא את כולם. לכן לפני ההוספה לרשימה הכללית, מתבצע סינון מאפיינים (שורה 20).

בשורה 24 שומרים את הרשימה הכללית לקובץ CSV, לנתיב שנקבע בשורה 3.

השוואה ועיבוד נתונים (שורות 27-59):

בשורה 27 נבדק תנאי. בהתקיים התנאי, הסקריפט ימשיך למחציתו הבאה. אחרת יסתפק באיסוף הנתונים שבוצע עד עכשיו ויסיים את הריצה.

אם ישנו קובץ מן הריצה הקודמת, יש עם מה להשוות נתונים ואפשר להמשיך הלאה.

בשורות 29-30 כל אובייקט ברשימות ההרשאות הופך למחרוזת אחת ארוכה. המחרוזת מכילה את כל מאפייני ההרשאות וביניהם בנקודה-פסיק. צורת המחרוזת הזו מקלה את רישום ההרשאה לחשבון. מאובייקט המכיל כמה מאפיינים שונים, לאובייקט שטוח של מחרוזת.

קל להשוות בין מחרוזות. מספיק שבאחת קיים פסיק שאין באחרת – והמחרוזות שונות.

וזה מה שקורה בשורה 33 – מתבצעת השוואה בין ההרשאות הישנות לחדשות, על פי המחרוזות. תוצאות ההשוואה עוברות למשתנה.

המשתנה שומר אך ורק פריטים שקיימים באחת הרשימות ולא באחרת.

בשורה 36 מתבצעת בדיקה, תנאי. אם נמצאו הבדלים בין הרשימות, המשתנה אינו ריק ויש עם מה לעבוד. אם אין הבדלים – כלומר: המשתנה ריק, ההרשאות זהות לרשימה הקודמת ואפשר לסיים.

בהנחה ונמצאו הבדלים, צריך לעבד אותם בצורה ניתנת להשוואה.

מכינים מערך ריק חדש, שאליו תאספנה השורות המעובדות של ההרשאות שנמצאו בהן הבדלים (שורה 38).

שורות 39-55, לולאה עוברת על כל רשימת ההרשאות שיש בהן הבדלים. כל פריט מעובד חזרה – ממחרוזת לאובייקט. לאובייקט החדש נוסף מאפיין שאינו קיים ברשימת ההרשאות הרגילה – שיוך ההבדל. וכך זה קורה:

בשורה 40 נוצרת תבנית אובייקט ריק, על פי המאפיינים שאליהם נרצה להזין את הערכים. בכל אחד מהמאפיינים יכנס אותו חלק במחרוזת המייצג את הערך של אותו מאפיין.

בשורה 41 מפרקים את המחרוזת למערך שכל איבר בו מכיל ערך של מאפיין אחר.

בשורות 43-50 – הערכים מן המחרוזת שהפכה למערך מתיישבים כל אחד במקומו המיועד בתוך האובייקט שהוכן בשורה 40.

בשורות 51-52 נכנס ערך השיוך למאפיין האחרון. המאפיין האחרון אומר אם ההרשאה הזו קיימת רק ברשימת ההרשאות החדשה אן רק בישנה.

כך ניתן לאתר הרשאות שהוסרו או התווספו.

הרשאה שכבר היתה והשתנתה, תופיע פעמיים. כי הגרסה הישנה שלה מופיעה רק בישנה, והגרסה החדשה מופיעה רק ברשימה החדשה.

לבסוף (שורה 55) אובייקט ההרשאות שעבר עיבוד השוואות, מצטרף לרשימת השוואות מעובדות.

אז (שורה 59) שומרים את הרשימה לקובץ הבדלים הנושא את תאריך הריצה.

הקוד:

# The root folder which the script will acuire it's permissions
$rootfolderpath = "path"
$resfilepath = 'C:\Users\user\Desktop\'
# Summery of this folder permission from previous time - 7 days ago - if exist.
$oldfile = ($resfilepath + ((Get-Date).AddDays(-7).ToString('dd-MM-yyyy')) + ' Permissions.csv')
if (Test-Path $oldfile) {$old = Import-Csv $oldfile}


# Fetch objects of folders and subfolders from this root folder, including the root folder - down to specific generation.
$folders = Get-ChildItem -Path $rootfolderpath -Directory -Recurse | ?{$_.FullName.Split("\").count -le 6}
$folders += Get-Item $rootfolderpath


# Set an array of objects, each contains permissions for 1 account on a folder. 
$info = @()
foreach ($x in $folders) {
    $y = $x.GetAccessControl().access
    $y | Add-Member -MemberType NoteProperty -Name 'Owner' -Value $x.GetAccessControl().owner
    $y | Add-Member -MemberType NoteProperty -Name 'LastAccessTime' -Value $x.LastAccessTime
    $y | Add-Member -MemberType NoteProperty -Name 'Path' -Value $x.FullName


    $info += $y | select Path, LastAccessTime, Owner, IdentityReference, AccessControlType, FileSystemRights, IsInherited, InheritanceFlags, PropagationFlags
}


# Export the list of permissions to CSV file.
$info | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ($resfilepath + ((Get-Date).ToString('dd-MM-yyyy')) + ' Permissions.csv')


# If there is an older file from previous run, compare permissions.
if (Test-Path $oldfile) {
    # Convert object of an account permissions to a string, all attributes delimited with semicolon. makes it easy to compare.
    $older = $old | %{@($_.Path, $_.Owner, $_.IdentityReference, $_.AccessControlType, $_.FileSystemRights, $_.IsInherited, $_.InheritanceFlags, $_.PropagationFlags) -join ";"}
    $newer = $info | %{@($_.Path, $_.Owner, $_.IdentityReference, $_.AccessControlType, $_.FileSystemRights, $_.IsInherited, $_.InheritanceFlags, $_.PropagationFlags) -join ";"}


    # Compare the Older list and the new one. make a list of object exists only in one of the lists.
    $res = Compare-Object -ReferenceObject $older -DifferenceObject $newer


    # If any changes had been made, the changes will be writen to a file.
    if ($res -ne $null) { 
        # Convert the strings of changed permissions back to objects, add an attribute that tells if this object exists only in the old list, or only in the new list. 
        $change = @()
        foreach ($x in $res) {
            $y = '' | select Change, Path, Owner, IdentityReference, AccessControlType, FileSystemRights, IsInherited, InheritanceFlags, PropagationFlags
            $split = $x.InputObject.split(";")
        
            $y.Path = $split[0]
            $y.Owner = $split[1]
            $y.IdentityReference = $split[2]
            $y.AccessControlType = $split[3]
            $y.FileSystemRights  = $split[4]
            $y.IsInherited = $split[5]
            $y.InheritanceFlags = $split[6]
            $y.PropagationFlags = $split[7]


            if ($x.SideIndicator -eq "<=") {$y.Change = "Only In Old"}
            else{$y.Change = "Only In new"}
    
            $change += $y
        }


        # Export the list of changed permissions to another CSV file
        $change | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ($resfilepath + ((Get-Date).ToString('dd-MM-yyyy')) + ' difference.csv')
    }
}

כתיבת תגובה