בעולם ה-IT, ישנם כלים רבים לניטור חשבונות ומשתמשים. כלי אבטחת מידע וכלי עזר לניהול המערכת, המגוון רחב. חלק מן הכלים עולה יותר, חלק פחות, וחלקם בקוד פתוח. הצד השווה שבכולם, שהם מחזיקים מסד נתונים שהולך ותופח, ולרוב צריך להחזיק עבורם שרת יעודי, ולהקצות שטח אחסון למטרה זו.
האפשרויות שמציעה המערכת, משתנה בין כלי לכלי. וברוב המקרים, אותם כלים מנוהלים על ידי אנשי אבטחת המידע. פעמים רבות, לאנשי התמיכה שרוב העיסוק שלהם במשתמשי הקצה, אין גישה למידע הזה.
לכן החלטתי ליצור הליך קטן שאוסף מידע עבור אנשי התמיכה (Help-Desk) והסיסטם. התהליך אינו דורש שרת יעודי, וצורך שטח אחסון מועט יחסית. אבל האפשרויות שהוא מציע פשוטות ובסיסיות.
המטרה היא לקבץ את הלוגים של שינויים בחשבונות משתמשים, כגון – יצירה, מחיקה, השבתה, הפעלה, שינוי סיסמה ושינוי פרטים. מתוך כל אירוע שכזה, לאסוף כמה נתונים ולשבץ בטבלת CSV.
כך שעל כל שינוי בחשבון משתמש, יש לנו את המידע הבא:
1. החשבון שהשתנה.
2. מי שינה אותו.
3. חותמת זמן.
4. תוצאה – הצלחה או שגיאה.
5. סוג הפעולה.
6. מזהה האירוע.
7. ההודעה של הלוג – אפשרי.
השיקול אם לכלול את השדה הזה (ההודעה) או לא, נוגע לגודל הקובץ. בסופו של דבר, רוב הנתונים כלולים בהודעה ונאספים ממנה. ויתור על ההודעה יקטין משמעותית (באחוזים) את נפח הקובץ ששומר את הנתונים.
המידע נשמר בקבצים חודשיים. קובץ נתונים עבור כל חודש, וקובץ לוג עבור כל חודש.
אפשרות נוספת שיש, היא לקבוע מספר מסוים של חודשים, שלאחריו הקבצים ימחקו. דבר שמאפשר לשמור על הקצאה יציבה יחסית של שטח אחסון למטרה הזו.
הכלי עצמו בנוי משלושה מרכיבים:
1. סקריפט PowerShell.
2. משימה מתוזמנת שמריצה את הסקריפט בפרקי זמן קבועים.
3. ממשק משתמש (GUI) שיודע למצוא נתונים ספציפיים מתוך קבצי הנתונים.
לדוגמה – למצוא שינויים שהתבצעו על חשבון מסוים, בתאריך מסוים.
את ממשק המשתמש עוד לא בניתי, וזה יחכה למאמר הבא. כרגע אציג את הסקריפט ואסביר את המבנה שלו. אחרי הכל, מי שרוצה למצוא את הנתונים, יכול פשוט לפתוח קובץ CSV באקסל. שם אפשר לסנן לפי העמודה שבוחרים, או פשוט להשתמש בחיפוש של אקסל בתוך הקובץ.
מבנה הסקריפט:
הערות:
– הכתוב מסתמך על הסקריפט כפי שהוא מוצג בעורך הקוד של PowerShell – PowerShell ISE. ההפניות למספרי שורות, מכוונות לאותה הצורה. מי שרוצה לעבור על הקוד בהתאם להסברים שלי, מומלץ להעתיק לתוך PowerShell ISE ולעקוב במקביל.
– הסקריפט מתועד בפירוט רב מאוד. המטרה היא ללמד ולהציג בפירוט את דרך כתיבת הסקריפט, ואת הרעיונות שמאחוריו.
פונקציית Log (שורות 17-57):
הקוד מתחיל בשורה 17, עם פונקציית Log. המטרה של הפונקציה היא לנטר את פעולת הסקריפט. השימוש העיקרי של הניטור, נוגע לתדירות הריצה של הסקריפט.
הסקריפט נועד לרוץ באמצעות משימה מתוזמנת בפרקי זמן קבועים. תדירות גבוהה מדי, תמצא שוב ושוב את אותם הלוגים שכבר מצאנו בפעמים קודמו. המידע הזה כבר עובד ונשמר לקובץ. חבל על העבודה.
מצד שני, תדירות נמוכה מדי תגרום לאובדן נתונים. מאגר הלוגים שממנו אוספים את המידע, מהווה אולי את החלק הפעיל ביותר במאגר הלוגים. בגלל זה הלוגים החדשים דורסים את הישנים, ולא ניתן למצוא שם לוגים ישנים מדי.
עם כל ריצה של הסקריפט, יכתב לקובץ (בין השאר):
- כמה לוגים חדשים נוספו לקובץ המידע
- כמה מן הלוגים שנאספו בריצה הזו, כבר היו בקובץ מפעמים אחרונות.
אם מספר הלוגים הישנים גבוה, אפשר להאריך את פרק הזמן שבין ריצה לריצה. אם מספר הלוגים הישנים נמוך או עומד על 0, צריך להגביר את התדירות.
הכי טוב להתחיל עם תדירות גבוהה, ולהאריך את המרווח בזהירות, לפי הנתונים.
קלט:
הפונקציה מקבלת חמישה פרמטרים. פרמטר אחד חובה – סוג הריצה שהתבצע, מתוך שלוש סוגים. ועוד ארבעה פרמטרים שאינם חובה, ונשלחים בזמן ריצה רגילה. בזמן ריצה התחלתית, או בזמן ריצה ראשונה בכל חודש, הנתונים האלה אינם מתועדים.
יצירת משתנה המכיל את הנתיב שבו יושב קובץ הלוג.
כשהפונקציה רצה, היא מתעדת דבר ראשון את חותמת הזמן.
לאחר מכן, ישנו Switch-Case, שמגדיר את שלב התיעוד הבא על פי סוג הריצה – כאמור.
בריצה רגילה, מתועד כמה לוגים חדשים נוספו לרשימה, כמה מתוך אלה שנמצאו בשרתים כבר היו ברשימה, כמה היו בקובץ בתחילת התהליך, וכמה נכנס לקובץ בסוף התהליך.
בשני סוגי הריצה האחרים, מתועדת בשלב זה הודעה קצרה שאומרת שהתבצעה ריצה מסוג פלוני.
לבסוף נכנס קו מפריד, על מנת להבדיל בין נתוני של הריצה הנוכחית לריצה הבאה.
הגדרת משתנים (שורות 60-79):
כהתחלה של התהליך המרכזי, מוגדרים משתנים שונים שנועדו לשרת את התהליך:
1. Filename. התאריך בפורמט שכולל רק את החודש והשנה הנוכחיים נשמר כמחרוזת. המחרוזת הזו משמשת כשם עבור קובץ הנתונים, וכן עבור קובץ הלוג. נוצר כמשתנה גלובלי, כדי לחסוך העברה שלו לפונקציית הלוג.
2. Lastmonth. בא לידי שימוש בריצה הראשונה בכל חודש, שאז מתחלף התאריך וצריך לשמור חלק מהלוגים בקובץ שאינו נושא את התאריך של החודש הנוכחי.
3. Oldtodelete. כאן נקבע תאריך על פי מספר מסוים של חודשים אחורנית, כדי לקבוע מחזור חיים של קבצי הנתונים.
4. Path. מחרוזת המכילה את הנתיב לתיקיה שבה יושבים קבצי הנתונים. המשתנה גלובלי, כדי לחסוך העברה שלו לפונקציית הלוג.
כשבוחרים את המיקום הזה, צריך ליצור בתוכו את התיקיה עבור קבצי הלוג.
5. Filter. מכיל טבלה מסוג hashtable (key-value), שבה מאפייני החיפוש שבאמצעותם מסננים את הלוגים הדרושים, מתוך כל הלוגים שקיימים בשרת.
LogName – מכוון לתיקיה הספציפית במאגר הלוגים, שבה צריך לחפש.
ID – יש כאן רשימה של EventID שכל אחד מהם מצביע על שינויים בחשבון.
StartTime – אני לא בטוח כמה זה רלוונטי, כי בדומיין פעיל בדרך כלל לא נשארים במאגר לוגים ישנים מדי. אבל המאפיין הזה קובע נקודת זמן שהחל ממנה צריך למצוא לוגים. כאן מוגדר שבכל פעם שהתהליך רץ, הוא צריך למצוא את כל הלוגים החל מ-1,300 ימים אחורה.
6. Dc. מערך המכיל רשימה של כל שרתי ה-DC בדומיין. אין צורך ב-DC לקריאה בלבד, שהרי כל התהליך מתעד שינויים בחשבונות. שינויים לא מתרחשים ב-RODC.
7. Logs. מערך ריק שיקלוט לתוכו את כל הלוגים שימצאו בחיפוש בכל ה-DC.
איסוף לוגים (שורות 82-85):
כאן יש לולאת for שרצה על כל ה-DC ברשימה שנקלטה לעיל, ובכל אחד מהם מחפשת לוגים לפי הפילטר שהוגדר.
בסוף הפקודה ישנו מעבר Pipe Line שמקבל כל אחד מהלוגים ולוקח ממנו מאפיינים מסוימים. חלק מהמאפיינים אינם קיימים כרגע, אבל עצם הבחירה במאפיין הזה מגדירה עבורו תא בכל אחד מהלוגים. תא שנוכל לאכלס מאוחר יותר בנתונים המתאימים.
עיבוד המידע (שורות 88-103):
בשלב זה רצה לולאה שעוברת על כל הלוגים שנמצאו בשלב הקודם, ומכל לוג מוציאה את המידע שאנחנו רוצים, ומסדרת אותו בצורה שנוכל לאחסן.
נעקוב אחר השלבים של עיבוד המידע:
1. Message – לוקח את ההודעה המרכזית של הלוג, ומפרק אותה למערך שכל איבר בו מכיל שורה אחת מתוך ההודעה המרכזית. כך ניתן לאסוף נתונים שנמצאים בשורה מסוימת.
2. Sub – משתנה זמני שנועד לאחסן את השם שמופיע במחצית השניה של השורה החמישית.
3. X.ActBy – מכיל את המחרוזת שנגזרה בשורה הקודמת. מתעד את המשתמש שביצע את הפעולה.
4. Sub – פעם נוספת, גוזר ומכיל את השם שמופיע במחצית השניה של השורה ה-11.
5. X.Target – מכיל את המחרוזת שנגזרה בשורה הקודמת. מתעד את שם החשבון שהשתנה. החשבון שעליו התבצעה הפעולה.
6. X.Result – מכיל את הודעות התוצאה של הפעולה. כמו שגיאה, כשל, הצלחה וכו'. הנתונים עולים מתוך מאפיין שמכיל מערך ועוברים לתא הנוכחי. שם ישבו בצורה שבה כל אברי המערך מחוברים למחרוזת, ופסיק מפריד ביניהם.
7. X.Action – מכיל את כותרת הפעולה שהתבצעה. כגון – יצירת משתמש, החלפת סיסמה וכו'.
8. X.TimeCreated – לוקח את חותמת הזמן של הלוג, משנה אותה לפורמט שנקבע בסקריפט, וכך מאחסן אותה.
זה בגלל שיכולים להיות מקרים שבהם בכל פעם שתאריך גולמי ישמר לקובץ CSV, הוא יתורגם לפורמט אחר. שינוי מזערי בפורמט התאריך, יגרום בעיות בהשוואה בין הלוגים שהסקריפט מצא ב-DC, לבין הלוגים שכבר בקובץ. דבר זה יכול לגרום כפילויות, שכן בגלל חוסר תאימות בפורמט, אותו לוג יכול להשמר פעמיים, בשני פורמטים שונים של חותמת זמן.
השוואת נתונים, חלוקה ואחסון המידע (שורות 105-156):
בשלב זה, כבר הצטבר המידע על שינויים בחשבונות, ועובד לצורה נוחה, אחידה וקריאה. כעת צריך לאחסן את המידע, ורק להזהר שלא מוסיפים לאחסון בצורה כפולה, מידע שכבר קיים שם.
לכן שלב זה כולל שלוש אפשרויות:
1. אם קיים קובץ הנושא את תאריך החודש הנוכחי בתיקיה המיועדת לקבצים, מתבצעת ריצה רגילה ושגרתית (שורות 105-118).
במקרה כזה:
אוספים מתוך הקובץ את כל המידע שעלה לשם בריצות קודמות (שורה 109).
מתוך המערך המכיל את רשימת כל הלוגים שנמצאו ב-DC, מסננים רק כאלה שלא נמצאו בקובץ. אלה עולים למשתנה כאשר הם מכילים כמה מאפיינים מסוימים (שורה 111).
כאמור, אפשר להחליט להסיר מרשימת המאפיינים הללו, את המאפיין Message. המאפיינים האחרים כבר מכילים את כל המידע הנחוץ, והוא שם רק כי לפעמים כשמשנים Attributes בחשבון מסוים, המאפיין הזה מכיל איזה Attribute השתנה.
זה לא הכרחי, ותופס נפח. אפשר להחליט לוותר על זה.
הלוגים החדשים שעברו את הסינון נוספים ללוגים הישנים שנאספו מתוך הקובץ (שורה 113).
כל הלוגים האלה נשמרים מחדש לתוך הקובץ (שורה 114).
קריאה לפונקציית Log, שתוסיף לקובץ לוג תיעוד של הריצה הזו (שורה 117).
2. אם לא קיים קובץ הנושא את תאריך החודש הנוכחי, אבל קיים קובץ הנושא את תאריך החודש שעבר – כנראה שממש עכשיו התחלף החודש, וזו הריצה הראשונה לחודש החדש (שורות 119-138).
במקרה כזה:
שאיבת המידע מתוך הקובץ של החודש שעבר (שורה 124).
מתוך הלוגים החדשים שנאספו מה-DC, מסוננים לתוך משתנה כל הלוגים שחותמת הזמן שלהם שייכת לחודש שעבר (שורה 126-127).
כנ"ל, ניתן לוותר על המאפיין message, כדי לחסוך מקום אחסון.
מתוך הלוגים החדשים שנאספו מה-DC, מסוננים אל תוך משתנה אחר כל הלוגים שחותמת הזמן שלהם שייכת לחודש החדש (שורה 129-130).
הלוגים החדשים השייכים לחודש שעבר, מתווספים ללוגים שנאספו מתוך הקובץ, והסך הכללי חוזר ומאוחסן באותו הקובץ (שורה 132-133).
אם נמצאו בשרתים לוגים השייכים לחודש הנוכחי, אותם הלוגים מאוחסנים בקובץ חדש הנושא את תאריך החודש הנוכחי/החדש (שורה 135).
(אם אין לוגים מהחודש החדש, לא יווצר קובץ שכזה, והריצה הבאה של הסקריפט תחזור על המתכונת הנוכחית. עד שימצאו לוגים השייכים לחודש הנוכחי).
קריאה לפונקציית Log כדי לתעד את הריצה הנוכחית (שורה 138).
3. אחרת – כלומר – אם בתיקיה המיועדת לקבצים אין קובץ מן החודש הנוכחי, וגם אין קובץ מן החודש שעבר, זה נראה כאילו זו פעם ראשונה שהתהליך רץ (או שהיה מושבת זמן רב). זה אומר שצריך להתחיל מהתחלה (שורות 140-156).
במקרה כזה:
מתוך כל הלוגים שנמצאו ב-DC, מתבצע סינון עבור לוגים השייכים לחודשים הקודמים לחודש הנוכחי (שורה 144-145).
מתוך כל הלוגים שנמצאו ב-DC, מתבצע סינון עבור לוגים השייכים לחודש הנוכחי (שורה 148-149).
כנ"ל, עם הסינון ובחירת המאפיינים הנשמרים, ניתן לוותר על המאפיין Message.
אם מצאנו לוגים השייכים לחודשים קודמים, הם יעברו לקובץ שנקרא Old (שורה 150).
יצוא של כל הלוגים השייכים לחודש הנוכחי, לקובץ הנושא את תאריך החודש הנוכחי (שורה 152).
קריאה לפונקציית Log כדי לתעד את הריצה הנוכחית (שורה 155).
ניקוי קבצים ישנים (שורות 160-161):
ולבסוף, שתי שורות אחרונות שנועדו לבצע ניקוי. אפשר להחליט לסמן את שתיהן בסולמית, ולהמשיך לצבור ולשמור את הנתונים.
אפשר להחליט על מחזור חיים – למשל, אין צורך במידע לאחר שנה. במקרה כזה מגדירים במשתנה oldtodelete (המוגדר בשורה 65), את המספר -12, שמשמעו שנה אחורה. אם מחליטים על מחזור של שנתיים, זה יהיה -24, ואם מחליטים על מחצית השנה, זה יהיה -6.
בשתי שורות אחרונות אלה (האחת לקבצי נתונים והשניה לקבצי לוג), רצה בדיקה האם קיים קובץ שהתאריך שלו הוא מספר נקוב של חודשים אחורה. לדוגמה: -12. במקרה כזה רצה בדיקה האם קיים קובץ שהתאריך שלו הוא החודש הנוכחי, רק בשנה שעברה.
אם נמצא קובץ כזה, הוא ימחק.
הקוד:
<# This script is collecting event logs about acounts changing, proccess it and save data to csv files
If someone wants to see who create a user, reset his password or made other account modification, the
data is in the file.
There is a different file fore eache month, to avoid oversized files.
Every time the script is running, it's takes the data from last run, compare the new events occurred
since the previous run, and put it all in the file.
If the schedule to run the script is too often, there is a lot of overlapping events, comparing previous
run and the current one. if the time space between repeats is too long, some events can be missing.
Therefore, there is a function to log the process, count and compare the numbers, to know how many
overlapps there is, and how it's better to set the routine schedule for the script running.
Also, there is a cleanup at the end, to delete old files.
This function logging the proccess for comparing and monitoring. the funcrion takes 1 mandatory
parameter, and another 4 optional parameters.
The optional parameters are required only for routine run. at first new running, or first run of
each month, the function doesn't do comparing. just logs the process timestamp, and the type of run. #>
function Log {
# Parameters that the function receiving from the main process.
param (
# This parameter gets the type of run - out of 3 options.
$case,
# The number of new events found during current run, and wasn't found in the file.
[Parameter(Mandatory = $false)]$new = $null,
# The number of overlapping events. found now in the DC, but already exist in the file.
[Parameter(Mandatory = $false)]$old = $null,
# The total number of events found in the file, at the beginning of the process.
[Parameter(Mandatory = $false)]$imported = $null,
# The total number of events saved to the file at the end of the process.
[Parameter(Mandatory = $false)]$sum = $null
)
# Gets the full filepath of the log file.
$logpath = $path + "Logs\" + $filename + ".txt"
# Log timestamp.
Get-Date | Add-Content $logpath
# Determine which type, out of 3 scenarios, is the current running of the script.
switch ($case) {
# Regular run. collect events from the file, add new events and put it all back in the file.
"Routine" {
# Log all the numbers in the optional parameters.
"New events: " + $new | Add-Content $logpath
"Old events: " + $old | Add-Content $logpath
"Imported From file: " + $imported | Add-Content $logpath
"Summery of records: " + $sum | Add-Content $logpath
}
# The first run of the month.
"NewMonth" {
"Starting New Month" | Add-Content $logpath
}
# Start collecting data from scratch.
"Beginning" {
"Begin recording" | Add-Content $logpath
}
}
# Delimiter to seperate between logs of different runs.
"=========================" | Add-Content $logpath
}
# The file name is the date of current month.
$global:filename = (Get-Date -Format "MM-yyyy").ToString()
# At the first run of every month, can be found som events occurred at the end of previous month.
# Those are save to the file of the previous month.
$lastmonth = (Get-Date).AddMonths(-1).ToString("MM-yyyy")
# Defind the month that is out of perioud to keep save the data. the data of this month will be deleted.
$oldtodelete = (Get-Date).AddMonths(-12).ToString("MM-yyyy")
# The path of the folder where all the files is saved.
$global:path = "folder\subfolder\"
# Event-Log search filter builded as a hushtable, contains search parameters to find the required event logs.
$filter = @{
LogName = 'Security'
ID = 4720, 4022, 4723, 4724, 4725, 4738, 4781
StartTime = (Get-Date).AddDays(-1300)
}
# List of DC's in that domain. no need to include RODC, since no user changes happens there.
$dc = "dc01", "dc02", "dc03"
# An array to get the list of all the logs fund in the search.
$logs = @()
# Loop all DC's in the list, and search for account-change events in there. output specific attributes.
foreach ($x in $dc) {
$logs += Get-WinEvent -FilterHashTable $filter -ComputerName $x | `
select ActBy, Target, Result, Action, KeywordsDisplayNames, TimeCreated, Id, Message
}
# Loop all logs found in all DC's, and proccess them. collecting peaces of data and place it in the table.
foreach ($x in $logs) {
# Breakes the log message into lines. to collect certain info of some lines.
$message = $x.Message.Split("`n")
# Get the user who had conducted the change, put it in ActBy column.
$sub = $message[4].Split(":")[1]
$x.ActBy = $sub
# Get the changed account, put it in Target Column.
$sub = $message[10].Split(":")[1]
$x.Target = $sub
# The result message of the action in the log.
$x.Result = ($x.KeywordsDisplayNames | %{$_}) -join ","
# What kind of action had been logged.
$x.Action = $message[0]
# Make sure all timestamps are the same format.
$x.TimeCreated = $x.TimeCreated.ToString("dd/MM/yyyy HH:mm:ss")
}
if (Test-Path ($path + $filename + ".csv")) {
# If there is a file of current month.
# Get all data from the file.
$events = Import-Csv ($path + $filename + ".csv")
# From the logs found in the DC's, filter only those which is not already in the file - this are new logs.
$new = $logs | ?{$_.TimeCreated -notin $events.TimeCreated} | select ActBy, Target, Result, Action, TimeCreated, Id, Message
# Add the new logs to the olds from the file, and put all to gather in the file.
$sum = $events + $new
$sum | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ($path + $filename + ".csv")
# Log the process, and the numbers of the logs fund in DC's, in the file, the overlapping logs, and the total number of the logs.
Log -case "Routine" -new $new.count.ToString() -old ($logs.Count - $new.count).ToString() -imported $events.count.ToString() -sum $sum.count.ToString()
} elseif (Test-Path ($path + $lastmonth + ".csv")) {
# If there is no file of the current month, but there is a file of the previous month - happens at the beginning of every month.
# Because after the date is changed overnight, sometimes several runs of this type can be done, before new logs will be found.
# Get all data of the previous month from the file.
$events = ($path + $lastmonth + ".csv")
# From the new logs found on the DC's, filter thos which occurred before the month had changed, and therefore belong to the previous month.
$newlastmonth = $logs | ?{$_.TimeCreated.Substring(3,7) -eq $lastmonth} | ?{$_.TimeCreated -notin $events.TimeCreated} `
| select ActBy, Target, Result, Action, TimeCreated, Id, Message
# From the new logs found on the DC's, filter thos which occurred After the beginning of the new month.
$new = $logs | ?{$_.TimeCreated.Substring(3,7) -eq $filename} | ?{$_.TimeCreated -notin $events.TimeCreated} `
| select ActBy, Target, Result, Action, TimeCreated, Id, Message
# The total logs of last month, put it in the file of the last month.
$sum = $events + $newlastmonth
$sum | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ($path + $lastmonth + ".csv")
# If logs of the new month have been found, put it in a file for this month.
if ($new.count -gt 0) {$new | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ($path + $filename + ".csv")}
# Logg the process.
Log -case "NewMonth"
} else {
# If there is no file of corrent month, nore for last month, the process begin from scratch.
# Take all the logs occured before of the beginning of the current month.
$old = $logs | ?{$_.TimeCreated.Substring(3,7) -ne $filename} | ?{$_.TimeCreated -notin $events.TimeCreated} `
| select ActBy, Target, Result, Action, TimeCreated, Id, Message
# Take all the logs occurred during the current month
$new = $logs | ?{$_.TimeCreated.Substring(3,7) -eq $filename} | ?{$_.TimeCreated -notin $events.TimeCreated} `
| select ActBy, Target, Result, Action, TimeCreated, Id, Message
# If there is logs older then current month, put it in a file for older logs.
if ($old.count -gt 0) {$old | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ($path + "Old.csv")}
# Put in a file of current month, all matched logs.
$new | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ($path + $filename + ".csv")
# Log the process.
Log -case "Beginning"
}
# This lines is optional. it can be marked or be used. it's there to delete files after certain amount of months.
# The amount of months to keep the files and it's data, determined in the "oldtodelete" variable, in line 65.
if (Test-Path ($path + $oldtodelete + ".csv")) {Remove-Item ($path + $oldtodelete + ".csv") -Force}
if (Test-Path ($path + "Logs\" + $oldtodelete + ".txt")) {Remove-Item ($path + "Logs\" + $oldtodelete + ".txt") -Force } .