Not so long ago, I upgraded an RDS farm from Windows Server 2012 R2 to Windows Server 2016, where the main task was to reconfigure the roaming profile folders due to the name change from v2 to v6. After the transfer, the total number of folders was over 6000, they already took up decent disk space. There was an idea to remove unnecessary ones according to the criteria,
  1. Active Directory user account disabled more than 60 days ago.
  2. Move a folder over the network to an archive server.
  3. Move no more than 25 folders per day, so that in case of something there is not a large number of applications.
  4. Keep all rights to folders and subfolders.
  5. Place the script in scheduled tasks and run as scheduled,
    1. #Requires - Modules ActiveDirectory
    2. #Requires - RunAsAdministrator
    3. function Date {
    4. Get - Date - format "HH: mm: ss dd.MM.yyyy"
    5. }
    6. # Specify the folder
    7. for creating logs and the format of the file name,
    8. if it is not there, then create it
    9. $ log_folder = "$ PSScriptRoot \ Logs \" + $ ($ MyInvocation.MyCommand.Name -replace (".ps1 ", "
    10. "))
    11. $ log = "$ log_folder \ $ (Get-Date -Format"
    12. yyyy_MM_dd_HH_mm_ss "). txt"
    13. if (!(Test - Path $ log_folder - PathType Container - ErrorAction SilentlyContinue)) {
    14. New - Item $ log_folder - ItemType D - Force | Out - Null
    15. }
    16. "$ (Date) Start Processing" | Tee - Object $ log - Append
    17. # # # Maximum we move 25 folders
    18. $ max_folders_to_move = 25
    19. # Define variables where the sources of the source folders and their final location are specified
    20. $ source_ts_profiles_folder = "\\ Dfs07.root.pyatilistnik.org \ m $ \ Share \ tsProfiles_TermNew"
    21. $ dest_ts_profiles_folder = "\\ SBU03.root.pyatilistnik.org \ D $ \ share \ Unused Files \ tsProfiles_TermNew"
    22. # Define variables where the sources of the source folders and their final location are specified
    23. $ source_home_folder1 = "\\ Dfs05.root.pyatilistnik.org \ S $ \ Share \ home1"
    24. $ source_home_folder2 = "\\ Dfs05.root.pyatilistnik.org \ S $ \ Share \ home2"
    25. $ dest_home_folder = "\\ S03.root.pyatilistnik.org \ D $ \ share \ Unused Files \ home"
    26. # Specifies an Active Directory lookup that specifies a global catalog server
    27. $ DCs = @ {}
    28. foreach($ domain in (Get - ADForest).Domains) {
    29. $ DC = ""
    30. $ DC = (Get - ADDomain $ domain).ReplicaDirectoryServers | select - First 1
    31. $ DCs.Add($ domain, $ DC)
    32. }
    33. $ GC = $ DCs.
    34. "Root.pyatilistnik.org" + ": 3268"
    35. "$ (Date) Will use` "
    36. $ GC`" as Global Catalog Server "| Tee-Object $ log -Append
    37. ### Declaring the variable $ i for the first time
    38. $ i = 1
    39. foreach ($ folder in (Get-ChildItem $ source_ts_profiles_folder -Directory)) # | select -First 10
    40. {
    41. if ($ i -gt $ max_folders_to_move) {Continue}
    42. $ username = $ domain = $ domain_long = $ user = $ server = $ lastLogonTimeStamp = $ null
    43. # Divide the folder name of the domain \ username.v6 format
    44. $ domain = $ ($ folder.Name -split "\.") [- 2]
    45. $ v = $ ($ folder.Name -split "\.") [- 1]
    46. $ domain_long = $ DCs.Keys | ? {$ _ -like "$ domain *"}
    47. $ username = $ folder.Name -replace (". $ domain. $ v", "")
    48. if (! $ domain_long)
    49. {
    50. "$ (Date) Unable to identify domain. Please check folder`
    51. "$ ($ folder.Name)` "
    52. " | Tee-Object $ log -Append
    53. Continue
    54. }
    55. $ server = $ DCs.$ domain_long
    56. # "$ (Date) Trying to find user` "
    57. $ username`" in domain $ domain / $ domain_long using DC $ server "| Tee-Object $ log -Append
    58. try {
    59. $ user = Get-ADUser $ username -Properties lastLogonTimeStamp -Server $ server -ErrorAction Stop
    60. }
    61. catch {
    62. "$ (Date) $ ($ _. Exception.message)" | Tee-Object $ log -Append
    63. }
    64. $ lastLogonTimeStamp_diff = (New-TimeSpan -Start $ ([datetime] :: FromFileTime ($ user.lastLogonTimeStamp)) -End $ (Get-Date)). Days
    65. # It is indicated that we are looking for users with the status off for at least 60 days
    66. if ($ user.Enabled -eq $ false -and $ lastLogonTimeStamp_diff -gt 60)
    67. {
    68. "$ (Date) User`
    69. "$ username`"
    70. Enabled status is $($ user.Enabled), lastLogonTimeStamp diff days: $ lastLogonTimeStamp_diff "| Tee-Object $ log -Append
    71. "$ (Date) Going to move folder $ i / $ max_folders_to_move` "
    72. $($ folder.Fullname)` "to`
    73. "$ dest_ts_profiles_folder`"
    74. "| Tee-Object $ log -Append
    75. # Calling the utility of the robocopy utility with the necessary keys
    76. $ log_robocopy = "$ log_folder \ robocopy_" + (Get - Date - Format "yyyy_MM_dd_HH_mm_ss") + ".log" & robocopy `" $ ($ folder.Fullname) `
    77. " `"
    78. $ dest_ts_profiles_folder\ $($ folder.Name) `" / NJH / MOVE / S / B / UNILOG: $ log_robocopy # / L
    79. $ i ++
    80. }
    81. }
    82. ###
    83. $ i = 1
    84. foreach ($ folder in (Get-ChildItem $ source_home_folder1, $ source_home_folder2 -Directory)) # | select -First 10
    85. {
    86. if ($ i -gt $ max_folders_to_move) {Continue}
    87. $ username = $ user = $ users_found = $ lastLogonTimeStamp = $ null
    88. $ username = $ folder.Name # -replace (". $ domain. $ v", "")
    89. # "$ (Date) Trying to find user`
    90. "$ username`" in thw whole AD forest "| Tee-Object $ log -Append
    91. try {
    92. $ user = Get - ADUser $ username - Properties lastLogonTimeStamp - Server $ GC - ErrorAction Stop
    93. } catch {
    94. "$ (Date) $ ($ _. Exception.message)" | Tee - Object $ log - Append
    95. }
    96. $ users_found = ($ user | Measure - Object).Count
    97. # "$ (Date) Found users: $ users_found" | Tee - Object $ log - Append
    98. if ($ users_found - ne 1) {
    99. "$ (Date) Need to check AD for folder` "
    100. $($ folder.FullName)` '"| Tee-Object $ log -Append
    101. Continue
    102. }
    103. $ lastLogonTimeStamp_diff = (New-TimeSpan -Start $ ([datetime] :: FromFileTime ($ user.lastLogonTimeStamp)) -End $ (Get-Date)). Days
    104. # It is indicated that we are looking for users with the status off for at least 60 days
    105. if ($ user.Enabled -eq $ false -and $ lastLogonTimeStamp_diff -gt 60)
    106. {
    107. "$ (Date) User`
    108. "$ username`"
    109. Enabled status is $($ user.Enabled), lastLogonTimeStamp diff days: $ lastLogonTimeStamp_diff "| Tee-Object $ log -Append
    110. "$ (Date) Going to move folder $ i / $ max_folders_to_move` "
    111. $($ folder.Fullname)` "to`
    112. "$ dest_home_folder`"
    113. "| Tee-Object $ log -Append
    114. # Calling the utility of the robocopy utility with the necessary keys
    115. $ log_robocopy = "$ log_folder \ robocopy_" + (Get - Date - Format "yyyy_MM_dd_HH_mm_ss") + ".log" & robocopy `" $ ($ folder.Fullname) `
    116. " `"
    117. $ dest_home_folder\ $($ folder.Name) `" / NJH / MOVE / S / B / UNILOG: $ log_robocopy