-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathADcopier3.ps1
More file actions
415 lines (338 loc) · 17.2 KB
/
ADcopier3.ps1
File metadata and controls
415 lines (338 loc) · 17.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
#! powershell.exe
############################################################
############################################################
<#
.SYNOPSIS
## This is version 6.2 for KOTKANBT and KYMKOULUT in one go! Valmis 10.4.2024
.DESCRIPTION
..Reference table:
### PART 1: Load modules and settings needed
________________________________
### PART 2: Define functions
________________________________
### PART 3: Ask for data to be worked on.
________________________________
### PART 4: Check input for validity and assign variables
________________________________
### PART 5: Move computer to a new AD location
________________________________
### PART 6: Copy Groups from old computer to new computer
________________________________
### PART 7: Copy description from old computer to new computer (OR write new desc.)
________________________________
.PARAMETER Name
No parameters in this version
.EXAMPLE
TBD
.NOTES
$newComputerObjectWithDescription is re-declared after moving
#>
### PART 1: Load modules needed and add some settings ###
Import-Module ActiveDirectory
#________________________________
### PART 2: Define functions ###
# This function asks for data to be worked on. Checks input for validity.
function Confirm-DataComputerNameIsValidAndExists {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Name
)
if ($name.Length -eq 0) {
Write-Host "Error: No input provided (Both PC names needed)"
exit 10
}
# Define the regular expression pattern for a valid computer object name
$pattern = "^[a-zA-Z0-9._-]+$"
# Check if the name matches the regular expression pattern
$result = [System.Text.RegularExpressions.Regex]::Match($name, $pattern)
# Check if the name is a valid computer object name
if ($result.Success) {
# Search for a computer object with the specified name
#-Filter is one of parameters, that allow using variables of script scope inside script block.
$computer = Get-ADComputer -Filter { Name -eq $name } -ErrorAction Stop
# Check if a matching computer object was found
if ($computer) {
$returnValue = $true
Write-Host "The name $name is a valid computer object name and a computer object with the specified name exists." -ForegroundColor Green
} else {
$returnValue = $false
Write-Host "The name $name is a valid computer object name, but a computer object with the specified name does not exist." -ForegroundColor Red
}
} else {
Write-Host "The name is not a valid computer object name."
$returnValue = $false
}
return $returnValue
} # endofofunction
#________________________________
### PART 3: Ask for data to be worked on.
# Script execution Start
Write-Host "This is version 6 for KOTKANBT and KYMKOULUT" -ForegroundColor Green
# Ask the user to enter the old and new computer hostnames, do basic check
# Both used in every part from now, because this string is easilly accesible form Write-Host
function Get-ValidatedHostname {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]$Prompt,
[string]$DefaultValue
)
do {
# Check if DefaultValue is not null or whitespace
$useDefaultValue = -not [string]::IsNullOrWhiteSpace($DefaultValue)
# Adjust the prompt based on whether a valid default value is available
if ($useDefaultValue) {
$inputPrompt = "$Prompt (or leave empty to use '$DefaultValue') "
} else {
$inputPrompt = "$Prompt`: "
}
$inputValue = Read-Host $inputPrompt
# If input is empty and default value is valid, use the default value
if ([string]::IsNullOrWhiteSpace($inputValue) -and $useDefaultValue) {
return $DefaultValue
}
# Check for non-empty input and validate hostname format
if (-not [string]::IsNullOrWhiteSpace($inputValue) -and $inputValue -match "^[a-zA-Z0-9][a-zA-Z0-9-]{0,62}$") {
return $inputValue
} else {
Write-Host "Invalid hostname. Please enter a valid hostname." -ForegroundColor Red
}
} while ($true)
}
# Script execution
# Ensure $oldHostname and $newHostname are initialized as empty strings if not already set
if ($null -eq $oldHostname) { $oldHostname = '' }
if ($null -eq $newHostname) { $newHostname = '' }
$oldHostname = Get-ValidatedHostname -Prompt "Enter the old hostname" -DefaultValue $oldHostname
$newHostname = Get-ValidatedHostname -Prompt "Enter the new hostname" -DefaultValue $newHostname
#________________________________
### PART 4: Check input for validity and assign variables
# Check every hostname for validity
Write-Host "Checking your entry for validity; name of the old computer:"
$resultOldComputerCheck = Confirm-DataComputerNameIsValidAndExists -Name $oldHostname
Write-Host "Checking your entry for validity; name of the New computer:"
$resultNewComputerCheck = Confirm-DataComputerNameIsValidAndExists -Name $newHostname
# make decision to either continue script or stop execution based on validity check. Checking the last value of collection of objects:
if ($resultNewComputerCheck[-1] -and $resultOldComputerCheck[-1])
{
# Make decision based on restricted paths and paths that are the same.
##
Write-Host "We are about to proceed with moving our computers"
}
else
{
Write-Host "Sorry, but we cannot continue to work withoud valid computers"
exit 10 # Exit with error
}
#### At this points we have valid computer names, so we need to perform check, if it is okay to do what script does
# Get computers from AD as an objects to be worked on.
# Get the old computer object with description property (not specifying it will not append it!) Descpiption will be used in P.7
# Object used in P.5,6,7
$oldComputerObjectWithDescription = Get-ADComputer -Identity $oldHostname -Properties *
$newComputerObjectWithDescription = Get-ADComputer -Identity $newHostname # Must be re-initiated after moving.
# Display the old and current paths of the computer object in Active Directory, those are strings.
# we will cut parent from theese strings, a parent is OU to move our computers
$oldPath = $oldComputerObjectWithDescription | Select-Object -ExpandProperty DistinguishedName
$newPath = $newComputerObjectWithDescription | Select-Object -ExpandProperty DistinguishedName
## ^^ Those paths will be used later on, but firstt, print them:
Write-Host "Old computer path: $oldPath"
Write-Host "New computer path: $newPath"
## Begginging to check, if current location of computers feels safe to operate (They are not in the same container)+
# (new machine is located exactly inside intended container and not in some strange place)
# Get names of the OU:s - there was LDAP path previously as STRING WITH COMMAS
# But first separate it with -split operator, which will be producing array. Split operator
# must be grouped with it's parameters and index operator takes only [1] of resulting array, whch is OU
$oldOU = ($oldPath -split ',')[1]
$newOU = ($newPath -split ',')[1]
# Now we are checking if they are in same OU, this is no-no
if ($oldOU -eq $newOU) {
Write-Host "`n`nThe hostnames are in the same OU: $oldOU - Sorry, that jsut feels wrong, we cannot continue, script will now exit" -ForegroundColor Red
exit 11
} else {
Write-Host "`n`nThe hostnames are in different OUs: $oldOU and $newOU, everyhing seems to be fine" -ForegroundColor Green
}
# Desired Organizational Unit for validation
$desiredOU = "OU=Tyoasemat Asennus"
# If a new computer is not inside this path, script will not continue.
# Check if the NEW hostname is in the desired OU
if ($newPath -match $desiredOU) {
Write-Host "$newHostname is located in the following path $newPath and UO is mathcing ($desiredOU)"
} else {
$newComputerPathWithoutLeftCn = $newPath -replace 'CN=[^,]*(,|$)', ''
Write-Host "Sorry, but the computer $newHostname is not in the right OU ($desiredOU). It is in the path $newComputerPathWithoutLeftCn, that feels very wrong." -ForegroundColor Red
$userChoice = Read-Host "Do you STILL want to continue? Y / [N]"
if ($userChoice.ToUpper() -ne 'Y') {
Write-Host "Script stopped by user choice." -ForegroundColor Yellow
exit 12
}
}
#________________________________
### PART 5: Move computer to a new AD location
# Ask the user if they want to move the new computer to the same path as the old computer
$moveComputer = Read-Host "`nDo you want to move the new computer to the same path as the old computer? [Default: Y] (Y/N/EXIT)"
if ($moveComputer -eq "YES" -or $moveComputer -eq "" -or $moveComputer -eq "Y" ){
$oldComputerPathWithoutCn = $oldPath -replace 'CN=[^,]*(,|$)', ''
Move-ADObject -Identity $newComputerObjectWithDescription.DistinguishedName -TargetPath $oldComputerPathWithoutCn -ErrorAction Stop
$success = $false
while (-not $success) {
Start-Sleep -Seconds 1
$newComputerObjectWithDescription = $null # Reset variable for new cycle
try {
Write-Host "Attempting to retrieve new computer object for hostname: $newHostname" -ForegroundColor Cyan
$newComputerObjectWithDescription = Get-ADComputer -Identity $newHostname -Properties * -ErrorAction Stop
# Check if computer is in the expected path
if ($newComputerObjectWithDescription.DistinguishedName -notlike "*$oldComputerPathWithoutCn*") {
throw "Custom Exception: Computer not in expected path"
}
Write-Host "Attempting to retrieve group membership for the new computer object" -ForegroundColor Cyan
$groupsOfNewHost = Get-ADPrincipalGroupMembership -Identity $newComputerObjectWithDescription.SamAccountName | Select-Object -ExpandProperty Name
Write-Host "Group membership retrieved successfully" -ForegroundColor Green
Write-Host "Moving operation successful. Computer $newHostname was moved to path $oldComputerPathWithoutCn" -ForegroundColor Green
$success = $true
} catch {
# Log the identity used for Get-ADPrincipalGroupMembership
Write-Host "Identity used for Get-ADPrincipalGroupMembership: $($newComputerObjectWithDescription.SamAccountName)" -ForegroundColor Magenta
# Determine if the exception is a custom exception
if ($_.Exception.Message -like "Custom Exception:*") {
Write-Host $_.Exception.Message -ForegroundColor Red
} else {
Write-Host "Error encountered: $($_.Exception.GetType().Name). Retrying operation..." -ForegroundColor Yellow
}
Write-Host "Retry cycle initiated for hostname: $newHostname" -ForegroundColor Yellow
}
}
} elseif ($moveComputer -eq "EXIT" -or $moveComputer -eq "e") {
Write-Host "User wanted to exit" -ForegroundColor Red
exit 22
}
# endif
#________________________________
### PART 6: Copy groups of old compter to a new computer
Write-Host "`n`n***** Starting analysing and copying of groups **********`n" -BackgroundColor DarkMagenta
# Set the restricted groups that should not be copied
$restrictedGroupsToCopy = "Domain Computers", "testy3"
# Get the groups that the old computer object is a member of. Array of strings.
$oldComputersGroups = Get-ADPrincipalGroupMembership -Identity $oldComputerObjectWithDescription.SamAccountName | Select-Object -ExpandProperty Name
# Get the groups that the new computer object is a member of. Array of strings.
$groupsOfNewHost = Get-ADPrincipalGroupMembership -Identity $newComputerObjectWithDescription.SamAccountName | Select-Object -ExpandProperty Name
# Display the groups that the old computer object is a member of
Write-Host "Groups for $oldHostname`:"
foreach ($group in $oldComputersGroups) {
Write-Host -NoNewLine "$group "
}
## Give me some space
Write-Host ""
# Display the groups that the new computer object is a member of
Write-Host "Groups for $newHostname`:"
foreach ($group in $groupsOfNewHost) {
Write-Host -NoNewLine "$group "
}
Write-Host "`n`nWe will start prompting the user about copying new groups: `n" -ForegroundColor DarkMagenta
function Get-CurrentDomain {
# Explain the operation to the user
Write-Host "Retrieving the current domain's DNS root..." -ForegroundColor Cyan
# Attempt to retrieve the current AD domain's DNS root
try {
$currentDomain = (Get-ADDomain).DNSRoot
Write-Host "Current domain's DNS root is: $currentDomain" -ForegroundColor Green
} catch {
Write-Host "Error encountered while retrieving the domain's DNS root: $_" -ForegroundColor Red
return $false
}
# Compare the retrieved domain with the expected value
$expectedDomain = "kotkankaupunki.fi"
if ($currentDomain -eq $expectedDomain) {
Write-Host "Current domain matches the expected domain: $expectedDomain" -ForegroundColor Green
return $true
} else {
Write-Host "Current domain does not match the expected domain: $expectedDomain" -ForegroundColor Yellow
return $false
}
}
$domainCheck = Get-CurrentDomain
foreach ($group in $oldComputersGroups) {
if ($group -notlike "sgwlan*") {
if ($groupsOfNewHost -contains $group) {
Write-Host "Both $oldHostname and $newHostname are members of the $group group, nothing to copy" -ForegroundColor DarkGreen
}
elseif ($restrictedGroupsToCopy -contains $group) {
Write-Host "The $group group is restricted and no action will be taken." -ForegroundColor Red
}
else {
$copyGroup = Read-Host "Do you want to copy the $group group to $newHostname? (Y/N, default: Y)"
if ($copyGroup -eq "Y" -or $copyGroup -eq "") {
Add-ADGroupMember -Identity $group -Members $newComputerObjectWithDescription
Write-Host "The $newHostname computer object has been added to the $group group." -ForegroundColor DarkGreen
}
elseif ($copyGroup -eq "EXIT" -or $copyGroup -eq "e") {
Write-Host "User wanted to exit. Changes are not reverted" -ForegroundColor Red
exit 23
}
else {
Write-Host "Not copying."
}
}
}
else {
Write-Host "The $group group is restricted and no action will be taken." -ForegroundColor Red
}
}
# Check if the new host is already a member of SGWLANKOTKA
if ($domainCheck -and ($groupsOfNewHost -notcontains "SGWLANKOTKA")) {
$joinSGWLANKOTKA = Read-Host "Do you want to join $newHostname to SGWLANKOTKA group? (Y/N, default: Y)"
if ($joinSGWLANKOTKA -eq "Y" -or $joinSGWLANKOTKA -eq "") {
Add-ADGroupMember -Identity "SGWLANKOTKA" -Members $newComputerObjectWithDescription
Write-Host "The $newHostname computer object has been added to the SGWLANKOTKA group." -ForegroundColor DarkGreen
}
}
elseif ($groupsOfNewHost -contains "SGWLANKOTKA") {
Write-Host "$newHostname is already a member of SGWLANKOTKA group." -ForegroundColor DarkGreen
}
# Display the final list of groups for the old and new computer objects
Write-Host "`nGroups of $oldHostname`:" -ForegroundColor DarkMagenta
foreach ($group in $oldComputersGroups) {
Write-Host -NoNewLine "$group "
}
# Update the groups that the new computer object is a member of, because they had changed.
$newComputerGroups = Get-ADPrincipalGroupMembership -Identity $newComputerObjectWithDescription.SamAccountName
Write-Host "`nFinal groups for $newHostname`:" -ForegroundColor DarkMagenta
foreach ($group in $newComputerGroups) {
Write-Host -NoNewLine "$group "
}
#________________________________
### PART 7: Copy description from old computer to new computer (OR write new desc.)
Write-Host "`n`n analysing Description: `n" -BackgroundColor DarkMagenta
# Check if the old computer object has a description
if ($oldComputerObjectWithDescription.Description) {
# Inform the user of the old description
Write-Host "Old description: $($oldComputerObjectWithDescription.Description)"
} else {
# Inform the user that the old computer object has no description
Write-Host "Old computer has no description, it is empty string"
}
# Prompt the user for a custom description
$description = Read-Host "Enter a custom description for the new computer object `
(enter EMPTY to set an empty string, or justpress Enter to copy the old description)"
# Use the custom description if provided, otherwise use the old description
if ($description -eq "EMPTY") {
# Use an empty string
$description = ""
# Copy older computer description as defaut action
} elseif ($description -eq "") {
# Use the old description
$description = $oldComputerObjectWithDescription.Description
}
# no else, as no action needed if if statements fail
if($description){
Set-ADComputer -Identity $newHostname -Description $description
# Get the description:
$newComputerObjectWithDescription = Get-ADComputer -Identity $newHostname -Properties Description
# Inform the user that the description was set
Write-Host "Description set for $newHostname`: $($newComputerObjectWithDescription.Description)" -BackgroundColor Green
}
else {
Write-Host "Description for new hostnme was not set, because you wanted it like that" -BackgroundColor DarkGreen
}
#________________________________
Write-Host "You had reached the end of script!" -ForegroundColor DarkGreen