Скрипт перемещения папок профилей RDS

Скрипт перемещения папок профилей RDS

Добрый день! Уважаемые читатели и гости одного из крупнейших IT порталов в рунете Pyatilistnik.org. В прошлый раз мы с вами успешно устранили и нашли причины ошибки whea uncorrectable error. Идем дальше по пути системного администрирования и сегодня я хочу с вами поделиться скриптом на PowerShell, который поможете перемещать неиспользуемые папки с перемещаемыми профилями RDS на файловую шару с архивными данными.

Описание задачи

Не так давно я производил обновление RDS фермы с Windows Server 2012 R2 до Windows Server 2016, там основной задачей было перенастройка папок перемещаемых профилей из-за изменения имени с v2 на v6. После переноса общее количество папок было свыше 6000, они занимали уже приличное дисковое пространство. Появилась идея удалить лишние по критериям:

  • Учетная запись пользователя Active Directory отключена более 60 дней назад
  • Перемещать папку по сети на архивный сервер
  • Двигать за день не более 25 папок, чтобы в случае чего не было большого количества заявок
  • Сохранить все права на папки и подпапки
  • Разместить скрипт в запланированные задания и запускать по расписанию.

Содержимое скрипта

Напоминаю, что проверить скрипт и подредактировать его вы можете через PowerShell ISE, а запускать через саму оболочку PowerShell в режиме администратора.

#Requires -Modules ActiveDirectory
#Requires -RunAsAdministrator

function Date {Get-Date -format "HH:mm:ss dd.MM.yyyy"}

# Указывается папка для создания логов и формат названия файлов, если ее нет, то создаем ее

$log_folder = "$PSScriptRoot\Logs\" + $($MyInvocation.MyCommand.Name -replace (".ps1", ""))
$log = "$log_folder\$(Get-Date -Format "yyyy_MM_dd_HH_mm_ss").txt"

if (! (Test-Path $log_folder -PathType Container -ErrorAction SilentlyContinue))
{
New-Item $log_folder -ItemType D -Force | Out-Null
}

"$(Date) Start Processing" | Tee-Object $log -Append

### Максимально мы перемещаем 25 папок

$max_folders_to_move = 25

# Определяем переменные, где указываются источники исходных папок и их конечное местоположение

$source_ts_profiles_folder = "\\Dfs07.root.pyatilistnik.org\m$\Share\tsProfiles_TermNew"
$dest_ts_profiles_folder = "\\SBU03.root.pyatilistnik.org\D$\share\Unused Files\tsProfiles_TermNew"

# Определяем переменные, где указываются источники исходных папок и их конечное местоположение

$source_home_folder1 = "\\Dfs05.root.pyatilistnik.org\S$\Share\home1"
$source_home_folder2 = "\\Dfs05.root.pyatilistnik.org\S$\Share\home2"
$dest_home_folder = "\\S03.root.pyatilistnik.org\D$\share\Unused Files\home"

# Задается поиск Active Directory, где указывается сервер глобального каталога

$DCs = @{}
foreach ($domain in (Get-ADForest).Domains)
{
$DC = ""
$DC = (Get-ADDomain $domain).ReplicaDirectoryServers | select -First 1
$DCs.Add($domain, $DC)
}

$GC = $DCs."root.pyatilistnik.org"+":3268"
"$(Date) Will use `"$GC`" as Global Catalogue Server" | Tee-Object $log -Append

### Объявляем первый раз переменную $i

$i = 1

foreach ($folder in (Get-ChildItem $source_ts_profiles_folder -Directory)) # | select -First 10
{
if ($i -gt $max_folders_to_move) {Continue}

$username = $domain = $domain_long = $user = $server = $lastLogonTimeStamp = $null

# Делим имя папки формата domain\username.v6

$domain = $($folder.Name -split "\.")[-2]
$v = $($folder.Name -split "\.")[-1]
$domain_long = $DCs.Keys | ? {$_ -like "$domain*"}

$username = $folder.Name -replace (".$domain.$v", "")

if (! $domain_long)
{
"$(Date) Unable to identify domain. Please check folder `"$($folder.Name)`"" | Tee-Object $log -Append
Continue
}

$server = $DCs.$domain_long
# "$(Date) Trying to find user `"$username`" in domain $domain/$domain_long using DC $server" | Tee-Object $log -Append

try {
$user = Get-ADUser $username -Properties lastLogonTimeStamp -Server $server -ErrorAction Stop
}
catch {
"$(Date) $($_.exception.message)" | Tee-Object $log -Append
}

$lastLogonTimeStamp_diff = (New-TimeSpan -Start $([datetime]::FromFileTime($user.lastLogonTimeStamp)) -End $(Get-Date)).Days

# Указывается, что ищем пользователей со статусом выключен минимум 60 дней

if ($user.Enabled -eq $false -and $lastLogonTimeStamp_diff -gt 60)
{
"$(Date) User `"$username`" Enabled status is $($user.Enabled), lastLogonTimeStamp diff days: $lastLogonTimeStamp_diff" | Tee-Object $log -Append
"$(Date) Going to move folder $i/$max_folders_to_move `"$($folder.Fullname)`" to `"$dest_ts_profiles_folder`"" | Tee-Object $log -Append

# Вызов утилиты утилиты robocopy с нужными ключами

$log_robocopy = "$log_folder\robocopy_" + (Get-Date -Format "yyyy_MM_dd_HH_mm_ss") + ".log"
& robocopy `"$($folder.Fullname)`" `"$dest_ts_profiles_folder\$($folder.Name)`" /NJH /MOVE /S /B /UNILOG:$log_robocopy # /L

$i++
}
}

###

$i = 1

foreach ($folder in (Get-ChildItem $source_home_folder1, $source_home_folder2 -Directory)) # | select -First 10
{
if ($i -gt $max_folders_to_move) {Continue}

$username = $user = $users_found = $lastLogonTimeStamp = $null

$username = $folder.Name # -replace (".$domain.$v", "")

# "$(Date) Trying to find user `"$username`" in thw whole AD forest" | Tee-Object $log -Append

try {
$user = Get-ADUser $username -Properties lastLogonTimeStamp -Server $GC -ErrorAction Stop
}
catch {
"$(Date) $($_.exception.message)" | Tee-Object $log -Append
}

$users_found = ($user | Measure-Object).Count
# "$(Date) Found users: $users_found" | Tee-Object $log -Append

if ($users_found -ne 1)
{
"$(Date) Need to check AD for folder `"$($folder.FullName)`'" | Tee-Object $log -Append
Continue
}

$lastLogonTimeStamp_diff = (New-TimeSpan -Start $([datetime]::FromFileTime($user.lastLogonTimeStamp)) -End $(Get-Date)).Days

# Указывается, что ищем пользователей со статусом выключен минимум 60 дней

if ($user.Enabled -eq $false -and $lastLogonTimeStamp_diff -gt 60)
{
"$(Date) User `"$username`" Enabled status is $($user.Enabled), lastLogonTimeStamp diff days: $lastLogonTimeStamp_diff" | Tee-Object $log -Append
"$(Date) Going to move folder $i/$max_folders_to_move `"$($folder.Fullname)`" to `"$dest_home_folder`"" | Tee-Object $log -Append

# Вызов утилиты утилиты robocopy с нужными ключами

$log_robocopy = "$log_folder\robocopy_" + (Get-Date -Format "yyyy_MM_dd_HH_mm_ss") + ".log"
& robocopy `"$($folder.Fullname)`" `"$dest_home_folder\$($folder.Name)`" /NJH /MOVE /S /B /UNILOG:$log_robocopy # /L

$i++
}
}

###

"$(Date) End Processing" | Tee-Object $log -Append

Скрипт перемещения папок в сетевую шару с сохранением прав

Скачать готовый скрипт по перемещению папок

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

Теперь приведу некоторые настройки, которые я использую при запуске скрипта в планировщике Windows. Во первых у вас должна быть учетная запись, которая будет использоваться для запуска и у нее должны быть права на чтение пользователей из Active Directory, далее запускаем не зависимо залогинен кто-то или нет и с максимальными правами.

Настройки задания запуска скрипта в планировщике Windows

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

Скрипт перемещения папок в сетевую шару с сохранением прав

На этом у меня все. Вы смело можете дописать или модифицировать данный скрипт под свои нужды. С вами был Иван Семин, автор и создатель IT портала Pyatilistnik.org.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *