Поиск открытых сетевых ресурсов и их права доступа

Общие сетевые ресурсы в домене Active Directory используются для упрощения и централизации доступа к файлам, папкам, принтерам и другим ресурсам в корпоративной сети. Это может привести к нарушению одной из основ информационной безопасности — конфиденциальности

Специалистам по информационной безопасности необходимо выполнять сканирование общих сетевых папок в домене по данным причинам:

  • Обнаружение и мониторинг угроз

    Сканирование папок позволяет выявлять несанкционированный доступ к данным и файлам. Это помогает рано обнаруживать потенциальные угрозы безопасности и предотвращать утечку чувствительных информационных ресурсов.

  • Контроль доступа

    Сканирование может помочь определить, кто имеет доступ к данным и файлам. Это позволяет специалистам по информационной безопасности убедиться, что только сотрудники с соответствующими правами имеют доступ к конфиденциальной информации.

  • Соблюдение нормативов

    Множество отраслевых и государственных регуляторов требуют соблюдения нормативов по защите данных и конфиденциальности. Сканирование помогает удостовериться, что организация соблюдает требования по уровню доступа и контролю к данным.

  • Аудит безопасности

    Сканирование общих сетевых папок может быть включено в процессы аудита безопасности, позволяя проводить оценку уровня безопасности и выявлять потенциальные слабые места.

  • Аудит безопасности

    Сканирование общих сетевых папок может быть включено в процессы аудита безопасности, позволяя проводить оценку уровня безопасности и выявлять потенциальные слабые места.

Текущие продукты по поиску открытых сетевых ресурсов

На просторах сети есть подобные программы, которые обладают куда большим функционалом, чем я планирую описать.

Как пример программа «SoftPerfect Network Scanner»

Окно программы

Окно программы «SoftPerfect Network Scanner»

Или такая программа как «advanced ip scanner»

Окно программы

Окно программы «advanced ip scanner»

Данные программы позволяют сканировать подсети внутри компании и выдавать информацию по поводу открытых сетевых папок, и даже какие файлы там содержатся.
Также можно воспользоваться встроенными средствами Windows для поиска и просмотра открытых сетевых ресурсов на том же файловом сервере. И напрашивается вопрос -, а зачем что-то изобретать по новому?

Ответ — не знаю, просто захотелось попробовать что-то свое сделать.

Описание работы программы

Изначально я попробовал сделать все только на PowerShell, сделать скрипт, затем батник, но решил, что это как-то просто.

Скрипт выглядит следующим образом:

# Установка английского языка для корректной работы
$prevCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
[System.Threading.Thread]::CurrentThread.CurrentThread.CurrentCulture = 'en-US'

# Получаем IP машины
$ipAddress = (Test-Connection -ComputerName $env:COMPUTERNAME -Count 1).IPV4Address.IPAddressToString

# Получаем имя компьютера
$computerName = $env:COMPUTERNAME

# Генерируем рандомное число
$randomNumber = Get-Random -Minimum 1 -Maximum 10000

# Создадим локальный файл  в Temp
$localFolderPath = "C:\\Temp"
$fileName = "$($randomNumber)_$($ipAddress)_$($computerName)_$(Get-Date -Format 'yyyy-MM-dd_HH-mm-ss').txt"
$localFilePath = "$localFolderPath\$fileName"

# Отладочная информация
Write-Host "File will be created at $localFilePath"

# Функция для получения прав доступа и замена на читабельные данные
function Get-AccessRights {
    param($path)
    $accessRights = & icacls $path | Out-String
    $accessRights = $accessRights -replace '\(OI\)', '/Owner'  # Owner object
    $accessRights = $accessRights -replace '\(CI\)', '/Container'  # Container
    $accessRights = $accessRights -replace '\(F\)', '/Full access'  # Full access
    accessRights = $accessRights -replace '\(RX\)', '/Read and execute'  # Read and execute
    return $accessRights
}

# Получаем список общих сетевых папок на текущем компьютере
$networkFolders = Get-WmiObject -Class Win32_Share | Where-Object { $_.Path -ne $null -and $_.Type -eq 0 }

# Если есть открытые сетевые папки, записываем информацию в файл
if ($networkFolders) {
    $outputData = @()
    $outputData += "$ipAddress \ $computerName \ `"Number of open folders:`" $($networkFolders.Count)"
    $outputData += "Path to folders:"

    foreach ($folder in $networkFolders) {
        folderPath = $folder.Path
        $outputData += "$folderPath"

        # Получаем информацию о правах доступа и сам процесс для записи в файл
        $accessRights = Get-AccessRights -path $folderPath
        $outputData += $accessRights
    }

    $outputData | Out-File -FilePath $localFilePath -Encoding UTF8
} else {
    # Если открытых сетевых папок нет, выводим сообщение об этом
    IP Address: $ipAddress `nComputer Name: $computerName `nNetwork folders not found." | Out-File -FilePath $localFilePath -Encoding UTF8
}

# Выводим сообщение об успешном выполнении задачи
Write-Host "Information gathered and saved to $localFilePath."

# Восстановить предыдущую настройку кодировки
[System.Threading.Thread]::CurrentThread.CurrentCulture = $prevCulture

Данный скрипт создает в папке C:\Temp файл с результатами и присваивает ему случайно сгенерированный номер, для дальнейшего поиска.

Для локального запуска можно заменить строку на какой-нибудь другой путь:

# Создадим локальный файл  в Temp
$localFolderPath = "C:\\Temp"

Но стоит вопрос централизованной проверки. То есть с одного компьютера или сервера можно сразу запустить на всех устройствах данный скрипт.
Поэтому я решил написать программу на Python для непосредственного использования на компьютера (и все усложнить в 1000 раз)

import subprocess
import os
import datetime
import shutil
import re
import tkinter as tk
from tkinter import messagebox, scrolledtext

# Функция для обновления лога в текстовом окне
def log_message(log_window, message):
    log_window.insert(tk.END, message + '\n')
    log_window.see(tk.END)
    log_window.update_idletasks()

# Функция для отображения окна с сообщением об ошибке
def show_error_message(error_message):
    messagebox.showerror("Error", error_message)

# Функция для отображения окна с успешным сообщением
def show_success_message(file_path, file_name):
    messagebox.showinfo("Success", f"File created successfully!\n\nFile name: {file_name}\nNetwork path: {file_path}")

# Основной код программы
def main_program(log_window):
    try:
        # Путь к сетевой папке и учетные данные (замените на реальные данные в рабочей среде)
        network_folder_path = r'\\путь\'  # Замените на реальный сетевой путь
        username = 'логин'  # Замените на реальное имя пользователя домена
        password = 'пароль'  # Замените на реальный пароль

        # Логирование подключения к сетевой папке
        log_message(log_window, "Attempting to disconnect old network connection...")
        disconnect_command = f"net use {network_folder_path} /delete"
        subprocess.run(disconnect_command, shell=True)

        log_message(log_window, "Attempting to connect to network folder...")
        net_use_command = f"net use {network_folder_path} /user:{username} {password}"
        result = subprocess.run(net_use_command, shell=True, capture_output=True, text=True, encoding='cp866')

        if result.returncode == 0:
            log_message(log_window, f"Successfully connected to the network folder: {network_folder_path}")
        else:
            error_message = result.stderr
            raise Exception(f"Error connecting to the network folder: {error_message}")

        # Генерация текущей даты и времени для именования файлов
        current_datetime = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')

        # Путь к временному скрипту PowerShell (используем C:\Temp для избежания ошибок доступа)
        temp_dir = "C:\\Temp"
        if not os.path.exists(temp_dir):
            os.makedirs(temp_dir)
        ps_script_path = os.path.join(temp_dir, 'temp_script.ps1')

        # Логирование создания скрипта
        log_message(log_window, "Creating PowerShell script...")

        # Содержимое скрипта PowerShell для сбора данных
        ps_script_content = r'''
        # Установка культуры на английский для корректной работы
        $prevCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
        [System.Threading.Thread]::CurrentThread.CurrentThread.CurrentCulture = 'en-US'

        # получаем IP машины
        $ipAddress = (Test-Connection -ComputerName $env:COMPUTERNAME -Count 1).IPV4Address.IPAddressToString

        # получаем имя компьютера
        $computerName = $env:COMPUTERNAME

        # генерируем рандомное число
        $randomNumber = Get-Random -Minimum 1 -Maximum 10000

        # Создадим локальный файл  в Temp
        $localFolderPath = "C:\\Temp"
        $fileName = "$($randomNumber)_$($ipAddress)_$($computerName)_$(Get-Date -Format 'yyyy-MM-dd_HH-mm-ss').txt"
        $localFilePath = "$localFolderPath\$fileName"

        # Отладочная информация
        Write-Host "File will be created at $localFilePath"

        # функция для получения прав доступа и замена на читабельные данные
        function Get-AccessRights {
            param($path)
            $accessRights = & icacls $path | Out-String
            $accessRights = $accessRights -replace '\(OI\)', '/Owner'  # Owner object
            $accessRights = $accessRights -replace '\(CI\)', '/Container'  # Container
            $accessRights = $accessRights -replace '\(F\)', '/Full access'  # Full access
            $accessRights = $accessRights -replace '\(RX\)', '/Read and execute'  # Read and execute
            return $accessRights
        }

        # Получаем список общих сетевых папок на текущем компьютере
        $networkFolders = Get-WmiObject -Class Win32_Share | Where-Object { $_.Path -ne $null -and $_.Type -eq 0 }

        # Если есть открытые сетевые папки, записываем информацию в файл
        if ($networkFolders) {
            $outputData = @()
            $outputData += "$ipAddress \ $computerName \ `"Number of open folders:`" $($networkFolders.Count)"
            $outputData += "Path to folders:"

            foreach ($folder in $networkFolders) {
                $folderPath = $folder.Path
                $outputData += "$folderPath"

                # Получаем информацию о правах доступа и сам процесс для записи в файл
                $accessRights = Get-AccessRights -path $folderPath
                $outputData += $accessRights
            }

            $outputData | Out-File -FilePath $localFilePath -Encoding UTF8
        } else {
            # Если открытых сетевых папок нет, выводим сообщение об этом
            "IP Address: $ipAddress `nComputer Name: $computerName `nNetwork folders not found." | Out-File -FilePath $localFilePath -Encoding UTF8
        }

        # Выводим сообщение об успешном выполнении задачи
        Write-Host "Information gathered and saved to $localFilePath."

        # Восстановить предыдущую настройку кодировки
        [System.Threading.Thread]::CurrentThread.CurrentCulture = $prevCulture
        '''

        # Запись содержимого PowerShell скрипта во временный файл
        with open(ps_script_path, 'w', encoding='utf-8') as f:
            f.write(ps_script_content)

        log_message(log_window, "PowerShell script created. Executing script...")

        # Команда для выполнения скрипта PowerShell
        ps_command = f'powershell.exe -ExecutionPolicy Bypass -File "{ps_script_path}"'
        result = subprocess.run(ps_command, shell=True, capture_output=True, text=True)

        if result.returncode == 0:
            log_message(log_window, "PowerShell script executed successfully.")
            log_message(log_window, result.stdout)

            # Поиск случайного числа в выводе PowerShell
            match = re.search(r'(\d+)', result.stdout)
            if match:
                random_number = int(match.group())
                log_message(log_window, f"Random number generated by PowerShell: {random_number}")

                # Проверяем, создался ли файл локально
                log_message(log_window, "Checking local Temp folder for the created file...")
                local_files = os.listdir(temp_dir)

                found_file = None
                for file_name in local_files:
                    if file_name.startswith(str(random_number)):
                        found_file = file_name
                        break

                if found_file:
                    local_file_path = os.path.join(temp_dir, found_file)
                    log_message(log_window, f"File created locally: {local_file_path}")

                    # Копируем файл в сетевую папку
                    log_message(log_window, f"Copying file to network folder: {network_folder_path}")
                    shutil.copy(local_file_path, network_folder_path)

                    # Проверка файла в сетевой папке
                    log_message(log_window, "Searching for the file in the network folder...")
                    files_in_network_folder = os.listdir(network_folder_path)
                    network_found_file = None
                    for file_name in files_in_network_folder:
                        if file_name.startswith(str(random_number)):
                            network_found_file = file_name
                            break

                    if network_found_file:
                        full_file_path = os.path.join(network_folder_path, network_found_file)
                        log_message(log_window, f"Found file: {full_file_path}")
                        
                        # Чтение файла и анализ содержимого
                        with open(full_file_path, 'r', encoding='utf-8') as output_file:
                            output_data = output_file.read()

                        # Лог содержимого файла для отладки
                        log_message(log_window, f"File content:\n{output_data}")

                        # Установка префикса в зависимости от содержимого файла
                        new_prefix = "Empty_"  # По умолчанию "Empty_"
                        if "Number of open folders:" in output_data:
                            open_folders_count = int(re.search(r'\d+', output_data).group())
                            log_message(log_window, f"Open folders count: {open_folders_count}")
                            if open_folders_count > 0:
                                # Проверяем наличие прав, связанных с "Everyone", "Все" или "All"
                                if re.search(r'(Everyone|Все|All)([:/\\])', output_data):
                                    new_prefix = "Нарушение_"
                                    log_message(log_window, "Violation detected based on folder permissions.")
                                else:
                                    new_prefix = "OpenShareFind_"
                                    log_message(log_window, "Open folders found, but no violations.")
                        else:
                            log_message(log_window, "No open folders found, setting prefix to 'Empty_'.")

                        # Переименование файла
                        new_filename = f"{new_prefix}{network_found_file}"
                        new_file_path = os.path.join(network_folder_path, new_filename)
                        os.rename(full_file_path, new_file_path)
                        log_message(log_window, f"File renamed to: {new_file_path}")

                        # Выводим сообщение об успешном создании файла
                        show_success_message(network_folder_path, new_filename)
                    else:
                        raise Exception("File not found in the network folder.")
                else:
                    raise Exception("File not found in local Temp folder.")
            else:
                raise Exception("Random number not found in PowerShell output.")
        else:
            raise Exception(f"Error executing PowerShell script: {result.stderr}")

    except Exception as e:
        show_error_message(str(e))

# Функция для запуска программы с интерфейсом
def run_gui():
    root = tk.Tk()
    root.title("Network File Creation Tool")

    # Окно для вывода лога
    log_window = scrolledtext.ScrolledText(root, wrap=tk.WORD, width=100, height=30)
    log_window.pack(padx=10, pady=10)

    # Запуск программы в отдельном потоке
    root.after(100, lambda: main_program(log_window))

    root.mainloop()

# Запуск программы
run_gui()

Данный код сделан специально с отладкой, чтобы можно было сразу понять где появляется ошибка при подключении или другие ошибки.
Логика работы данной программы:

  • Подключение к сетевой папке:

    • Попытка отключения предыдущих подключений с помощью команды net use /delete.

    • Попытка подключения к сетевой папке с использованием указанных учетных данных.

  • Создание временного PowerShell скрипта:

    • Генерация текущей даты и времени для именования файлов.

    • Создание временного каталога C:\Temp (если он не существует).

    • Запись PowerShell скрипта во временный файл.

  • Выполнение PowerShell скрипта:

  • Проверка и работа с файлом:

    • Поиск файла, созданного PowerShell скриптом в локальной папке C:\Temp.

    • Копирование файла в сетевую папку.

    • Проверка содержимого файла и переименование файла на основе анализа прав доступа и наличия открытых папок.

  • Завершение и обработка ошибок:

Для работы данной программы так же необходимо:

  1. Создать учетную запись с правами администратора, которая будет вшита в данную программу (нужно так же понимать, что для данной УЗ необходимо сделать ограничения на работу, кроме тех, которые выполняются в ходе работы программы).

  2. Создать на сервере папку и расшарить доступ к ней для данной УЗ, Так же для данной папки необходимо сделать разрешения на чтение\запись.

Код программы без отладочных механизмов:

import subprocess
import os
import datetime
import shutil
import re
import tkinter as tk
from tkinter import messagebox, scrolledtext

# Функция для обновления лога в текстовом окне
def log_message(log_window, message):
    log_window.insert(tk.END, message + '\n')
    log_window.see(tk.END)
    log_window.update_idletasks()

# Функция для отображения окна с сообщением об ошибке
def show_error_message(error_message):
    messagebox.showerror("Error", error_message)

# Функция для отображения окна с успешным сообщением
def show_success_message(file_path, file_name):
    messagebox.showinfo("Success", f"File created successfully!\n\nFile name: {file_name}\nNetwork path: {file_path}")

# Основной код программы
#def main_program(log_window):
def main_program():
    try:
        # Путь к сетевой папке и учетные данные (замените на реальные данные в рабочей среде)
        network_folder_path = r'\\DESKTOP-N391HHM\Users\warde\Desktop\test'  # Замените на реальный сетевой путь
        username = 'wardeathmor'  # Замените на реальное имя пользователя домена
        password = '1351'  # Замените на реальный пароль

        # Логирование подключения к сетевой папке
        #log_message(log_window, "Attempting to disconnect old network connection...")
        disconnect_command = f"net use {network_folder_path} /delete"
        subprocess.run(disconnect_command, shell=True)

        #log_message(log_window, "Attempting to connect to network folder...")
        net_use_command = f"net use {network_folder_path} /user:{username} {password}"
        result = subprocess.run(net_use_command, shell=True, capture_output=True, text=True, encoding='cp866')

        if result.returncode == 0:
            #log_message(log_window, f"Successfully connected to the network folder: {network_folder_path}")
            pass
        else:
            error_message = result.stderr
            raise Exception(f"Error connecting to the network folder: {error_message}")

        # Генерация текущей даты и времени для именования файлов
        current_datetime = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')

        # Путь к временному скрипту PowerShell (используем C:\Temp для избежания ошибок доступа)
        temp_dir = "C:\\Temp"
        if not os.path.exists(temp_dir):
            os.makedirs(temp_dir)
        ps_script_path = os.path.join(temp_dir, 'temp_script.ps1')

        # Логирование создания скрипта
        #log_message(log_window, "Creating PowerShell script...")

        # Содержимое скрипта PowerShell для сбора данных
        ps_script_content = r'''
        # Установка культуры на английский для корректной работы
        $prevCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
        [System.Threading.Thread]::CurrentThread.CurrentThread.CurrentCulture = 'en-US'

        # получаем IP машины
        $ipAddress = (Test-Connection -ComputerName $env:COMPUTERNAME -Count 1).IPV4Address.IPAddressToString

        # получаем имя компьютера
        $computerName = $env:COMPUTERNAME

        # генерируем рандомное число
        $randomNumber = Get-Random -Minimum 1 -Maximum 10000

        # Создадим локальный файл  в Temp
        $localFolderPath = "C:\\Temp"
        $fileName = "$($randomNumber)_$($ipAddress)_$($computerName)_$(Get-Date -Format 'yyyy-MM-dd_HH-mm-ss').txt"
        $localFilePath = "$localFolderPath\$fileName"

        # Отладочная информация
        Write-Host "File will be created at $localFilePath"

        # функция для получения прав доступа и замена на читабельные данные
        function Get-AccessRights {
            param($path)
            $accessRights = & icacls $path | Out-String
            $accessRights = $accessRights -replace '\(OI\)', '/Owner'  # Owner object
            $accessRights = $accessRights -replace '\(CI\)', '/Container'  # Container
            $accessRights = $accessRights -replace '\(F\)', '/Full access'  # Full access
            $accessRights = $accessRights -replace '\(RX\)', '/Read and execute'  # Read and execute
            return $accessRights
        }

        # Получаем список общих сетевых папок на текущем компьютере
        $networkFolders = Get-WmiObject -Class Win32_Share | Where-Object { $_.Path -ne $null -and $_.Type -eq 0 }

        # Если есть открытые сетевые папки, записываем информацию в файл
        if ($networkFolders) {
            $outputData = @()
            $outputData += "$ipAddress \ $computerName \ `"Number of open folders:`" $($networkFolders.Count)"
            $outputData += "Path to folders:"

            foreach ($folder in $networkFolders) {
                $folderPath = $folder.Path
                $outputData += "$folderPath"

                # Получаем информацию о правах доступа и сам процесс для записи в файл
                $accessRights = Get-AccessRights -path $folderPath
                $outputData += $accessRights
            }

            $outputData | Out-File -FilePath $localFilePath -Encoding UTF8
        } else {
            # Если открытых сетевых папок нет, выводим сообщение об этом
            "IP Address: $ipAddress `nComputer Name: $computerName `nNetwork folders not found." | Out-File -FilePath $localFilePath -Encoding UTF8
        }

        # Выводим сообщение об успешном выполнении задачи
        Write-Host "Information gathered and saved to $localFilePath."

        # Восстановить предыдущую настройку кодировки
        [System.Threading.Thread]::CurrentThread.CurrentCulture = $prevCulture
        '''

        # Запись содержимого PowerShell скрипта во временный файл
        with open(ps_script_path, 'w', encoding='utf-8') as f:
            f.write(ps_script_content)

        #log_message(log_window, "PowerShell script created. Executing script...")

        # Команда для выполнения скрипта PowerShell
        ps_command = f'powershell.exe -ExecutionPolicy Bypass -File "{ps_script_path}"'
        result = subprocess.run(ps_command, shell=True, capture_output=True, text=True)

        if result.returncode == 0:
            #log_message(log_window, "PowerShell script executed successfully.")
            #log_message(log_window, result.stdout)

            # Поиск случайного числа в выводе PowerShell
            match = re.search(r'(\d+)', result.stdout)
            if match:
                random_number = int(match.group())
                #log_message(log_window, f"Random number generated by PowerShell: {random_number}")

                # Проверяем, создался ли файл локально
                #log_message(log_window, "Checking local Temp folder for the created file...")
                local_files = os.listdir(temp_dir)

                found_file = None
                for file_name in local_files:
                    if file_name.startswith(str(random_number)):
                        found_file = file_name
                        break

                if found_file:
                    local_file_path = os.path.join(temp_dir, found_file)
                    #log_message(log_window, f"File created locally: {local_file_path}")

                    # Копируем файл в сетевую папку
                    #log_message(log_window, f"Copying file to network folder: {network_folder_path}")
                    shutil.copy(local_file_path, network_folder_path)

                    # Проверка файла в сетевой папке
                    #log_message(log_window, "Searching for the file in the network folder...")
                    files_in_network_folder = os.listdir(network_folder_path)
                    network_found_file = None
                    for file_name in files_in_network_folder:
                        if file_name.startswith(str(random_number)):
                            network_found_file = file_name
                            break

                    if network_found_file:
                        full_file_path = os.path.join(network_folder_path, network_found_file)
                        #log_message(log_window, f"Found file: {full_file_path}")
                        
                        # Чтение файла и анализ содержимого
                        with open(full_file_path, 'r', encoding='utf-8') as output_file:
                            output_data = output_file.read()

                        # Лог содержимого файла для отладки
                        #log_message(log_window, f"File content:\n{output_data}")

                        # Установка префикса в зависимости от содержимого файла
                        new_prefix = "Empty_"  # По умолчанию "Empty_"
                        if "Number of open folders:" in output_data:
                            open_folders_count = int(re.search(r'\d+', output_data).group())
                            #log_message(log_window, f"Open folders count: {open_folders_count}")
                            if open_folders_count > 0:
                                # Проверяем наличие прав, связанных с "Everyone", "Все" или "All"
                                if re.search(r'(Everyone|Все|All)([:/\\])', output_data):
                                    new_prefix = "Нарушение_"
                                    #log_message(log_window, "Violation detected based on folder permissions.")
                                else:
                                    new_prefix = "OpenShareFind_"
                                    #log_message(log_window, "Open folders found, but no violations.")
                        else:
                            #log_message(log_window, "No open folders found, setting prefix to 'Empty_'.")
                            pass
                        # Переименование файла
                        new_filename = f"{new_prefix}{network_found_file}"
                        new_file_path = os.path.join(network_folder_path, new_filename)
                        os.rename(full_file_path, new_file_path)
                        #log_message(log_window, f"File renamed to: {new_file_path}")

                        # Выводим сообщение об успешном создании файла
                        #show_success_message(network_folder_path, new_filename)
                    else:
                        raise Exception("File not found in the network folder.")
                else:
                    raise Exception("File not found in local Temp folder.")
            else:
                raise Exception("Random number not found in PowerShell output.")
        else:
            raise Exception(f"Error executing PowerShell script: {result.stderr}")

    except Exception as e:
        show_error_message(str(e))

# Функция для запуска программы с интерфейсом
#def run_gui():
    #root = tk.Tk()
    #root.title("Network File Creation Tool")

    # Окно для вывода лога
    #log_window = scrolledtext.ScrolledText(root, wrap=tk.WORD, width=100, height=30)
    #log_window.pack(padx=10, pady=10)

    # Запуск программы в отдельном потоке
    #root.after(100, lambda: main_program(log_window))
    #root.after(100, lambda: main_program())

    #root.mainloop()

# Запуск программы
#run_gui()
main_program()

Логика дополнительного усложнения

Зачем просматривать каждый файл с информацией, когда можно этого не делать? Именно поэтому я внедрил механизм переименовки файлов в зависимости от их содержимого. Это все регулируется в данном блоке и при желании можно отредактировать его:

# Установка префикса в зависимости от содержимого файла
new_prefix = "Empty_"  # По умолчанию "Empty_"
    if "Number of open folders:" in output_data:
        open_folders_count = int(re.search(r'\d+', output_data).group())
        #log_message(log_window, f"Open folders count: {open_folders_count}")
            if open_folders_count > 0:
            # Проверяем наличие прав, связанных с "Everyone", "Все" или "All"
              if re.search(r'(Everyone|Все|All)([:/\\])', output_data):
                    new_prefix = "Нарушение_"
                    #log_message(log_window, "Violation detected based on folder permissions.")
              else:
              new_prefix = "OpenShareFind_"
              #log_message(log_window, "Open folders found, but no violations.")

В данном случае есть три варианта: Нарушение, открытая шара найдена и пусто. Нарушение ставится в случае, если найдена открытая шара, и есть доступ для всех.

Результат работы программы, при наличии общего доступа с нарушением

Результат работы программы, при наличии общего доступа с нарушением

Результат работы программы, при наличии общего доступа с ограничениями

Результат работы программы, при наличии общего доступа с ограничениями

Результат работы программы, при отсутствии папок с общим доступом

Результат работы программы, при отсутствии папок с общим доступом

К вопросу о том, зачем генерировать случайное число: Для функции переименовки файла программа должна найти файл, с которым надо работать, поэтому этот механизма как некий идентификатор для дальнейшей работы.

Для непосредственного удаленного запуска можно использовать как и встроенные средства в АД, так и Kaspersky Endpoint Security.

Заключение

Данная программа позволяет централизовано собирать данные по открытым сетевым ресурсам в компании. Да, есть программы куда лучше, куда функциональнее, но в данном случае захотелось попробовать сделать подобное с другим подходом, сделать централизованный сбор информации, вместо того, чтоб сидеть сканировать пул IP-адресов и ждать.
Надеюсь кому-нибудь пригодятся данные наработки в своей работе.

© Habrahabr.ru