-
Notifications
You must be signed in to change notification settings - Fork 0
/
Convert-OUsToCollections.ps1
255 lines (196 loc) · 8.15 KB
/
Convert-OUsToCollections.ps1
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
<#
.SYNOPSIS
Get membership of 1+ AD OUs recursively, check for AD object enablement, and ConfigMan presence.
Divide into groups using provided collection count divisor.
Convert lists to comma-separated names & export individual .txt files at script root.
Lists intended for use w/ CM collection's 'Add Resources' option to copy/paste computer names for bulk add.
.NOTES
Name: Convert-OUsToCollections
Author: Payton Flint
Version: 1.0
DateCreated: 2023-Dec
.LINK
https://github.com/p8nflnt/CM-Toolbox/blob/main/Convert-OUsToCollections.ps1
https://paytonflint.com/powershell-configman-convert-ous-to-collections/
#>
#= Prerequisites ===================================================================================================================
# Clear variables for repeatability
Get-Variable -Exclude PWD,*Preference | Remove-Variable -EA 0
# identify location of script
$scriptPath = Split-Path ($MyInvocation.MyCommand.Path) -Parent
# Install/check for ConfigurationManager module
Import-Module ConfigurationManager -ErrorAction 'Stop'
#= ConfigMan info ==================================================================================================================
# CM Site Code
$SiteCode = '<CM SITE CODE>'
# CM Server Name
$CMServer = '<CM SERVER>'
#= OrganizationalUnit Input info ===================================================================================================
# canonical name of OU(s) to search
$inputOU = @('<OU CANONICAL NAME>','<OU CANONICAL NAME>')
#= Collections Output info =========================================================================================================
# number of collections to create (for staged deployment)
$collectionCount = '<INT>'
#===================================================================================================================================
Function Convert-ADName {
param (
$name,
$nameType
)
# check name formatting
if ($name -like '*.*' -or $name -like '*/*' -or $name -like '*=*') {
# Check if the input is a canonical name format
if ($name -match "(^CN=.*|^OU=.*|^DC=.*)") {
# replace characters for reformatting
$processedCN = $name -replace ',', '' -replace 'DC=', '.' -replace 'OU=', '/' -replace 'CN=', ''
# drop leading '/' if present
if ($processedCN -match "^/.*") {
$processedCN = ($processedCN -split '\/', 2)[1]
}
# split canonical name in 2 parts at first '.'
$splitCN = $processedCN -split '\.', 2
# domain portion of canonical name
$domain = $splitCN[1]
# get remaining portion of canonical name if not empty
if ($($splitCN[0]) -ne '') {
# split remaining portion by '/' character
$splitRemainder = $($splitCN[0]) -split '/'
# invert order of the remaining items array
$reversedRemainder = $splitRemainder[($splitRemainder.Length-1)..0]
# reassemble in canonical name format for output
$output = $domain + '/' + ($reversedRemainder -join '/')
# if remainder is empty, list domain
} else {
$output = $domain
}
# if input is distinguished name format
} else {
# alert user to provide input type
if ($nameType -ne 'container' -and $nameType -ne 'object') {
Write-Host -ForegroundColor Red "Distinguished name format detected.`r`n-inputType must be set to 'Container' or 'Object'."
}
# glitch in replace, had to invoke method this way
# replace characters for reformatting
$processedDN = $($name -replace '/', ',OU=').Replace('.', ',DC=')
# if 'OU=' is present
if ($processedDN -match ".*OU=.*") {
# split in 2 parts at first ',OU='
$splitDN = $processedDN -split '\,OU=', 2
# domain portion of distinguished name
$domain = $splitDN[0]
# split remaining portion by ',OU='
$splitRemainder = $($splitDN[1]) -split ',OU='
# invert order of the remaining items array
$reversedRemainder = $splitRemainder[($splitRemainder.Length-1)..0]
# reassemble in distinguished name format for output
$reassembledDN = ($reversedRemainder -join ',OU=') + ',DC=' + $domain
# add appropriate prefix to distinguished name and output
if ($nameType -eq 'object') {
$output = 'CN=' + $reassembledDN
} elseif ($nameType -eq 'container' ) {
$output = 'OU=' + $reassembledDN
}
# if remainder is empty, list domain
} else {
$output = 'DC=' + $processedDN
}
}
return $output
# warn on invalid name format
} else {
Write-Host -ForegroundColor Red "Invalid name format."
}
} # end Convert-ADName function
Function Split-List {
param (
$inputList,
[int]$divisor
)
# initialization
$lists = @()
$startIndex = 0
$listArray = @()
# Calculate the count of each list & remainder
$listSize = [math]::floor($inputList.Count / $divisor)
$remainder = $inputList.Count % $divisor
# Iterate through each list
for ($i = 0; $i -lt $divisor; $i++) {
# Calculate the size of the current list
$size = $listSize + [math]::min(1, $remainder)
# Decrease the remainder by 1 if remainder
$remainder = [math]::max(0, $remainder - 1)
# Clear the current list array
$listArray = @()
# Add items to the current list array
$listArray += $cmPresent[$startIndex..($startIndex + $size - 1)]
# Add the current list array to lists
$lists += ,$listArray
# Update the start index for the next list
$startIndex += $size
}
return $lists
} # end Split-List function
# initialize arrays
$inputDN = @()
$objDNs = @()
$computerNames = @()
$enabledNames = @()
$cmPresent = @()
# convert canonical name to distinguished name & add to array
$inputOU | ForEach-Object {
$inputDN += Convert-ADName -name $_ -nameType $nameType
}
# get all object distinguished names recursively within OU & filter containers/duplicates
$inputDN | ForEach-Object {
$objDNs += (Get-ADObject -Filter * -SearchBase $_).DistinguishedName | Where-Object {$_ -match "^CN=.*" -and $_ -notlike "*{*}*"}
}
# get results in canonical name format
$objCNs = $objDNs | ForEach-Object {
Convert-ADName -name $_
}
# separate computer names & add to array
$objCNs | ForEach-Object {
if ($_ -match '\/([^/]+)$') {
$computerNames += $matches[1]
}
}
# add enabled computerNames to array
$computerNames | ForEach-Object {
$enabledStatus = $null
$enabledStatus = $(Get-ADComputer -Filter { Name -eq $_ }).Enabled
if ($enabledStatus) {
$enabledNames += $_
}
}
# precautionary deduplication and sort
$enabledNames = $enabledNames | Select-Object -Unique | Sort-Object
# ConfigMan presence check
# append ':' to site code
if ($SiteCode -notlike "*:") {
$SiteCode = "$SiteCode" + ':'
}
# connect to CM Site
Set-Location $SiteCode
# check for presence in CM
$enabledNames | ForEach-Object {
# initialize variable for loop
$cmCheck = $null
# check for device name in CM
$cmCheck = Get-CMDevice -Fast -Name $_
# if present, add to array
if ($cmCheck) {
$cmPresent += $_
}
}
# return to system drive
Set-Location $env:SystemDrive
# separate list
$collections = Split-List -inputList $cmPresent -divisor $collectionCount
# Export each collection to a separate text file
for ($i = 0; $i -lt $collectionCount; $i++) {
$collection = $collections[$i]
$filePath = $scriptPath + "\Collection_$($i + 1).txt"
# Join the computers in the collection with a comma and export to a text file
$collection -join ',' | Out-File -FilePath $filePath -Encoding UTF8
Write-Host -ForegroundColor Green "Exported $filePath"
}