Update - July 3rd, 2026

I recently revisited this script for the first time in a few years and ended up rewriting large parts of it. The collection creation script is now order-independent (the rows in the CSV file no longer need to be sorted by dependency), validates the entire CSV file before touching Configuration Manager, and supports fully unattended runs. I also wrote a new companion script, Remove-Collections.ps1, that bulk deletes collections. I’ve updated and expanded this post to cover both scripts. For details on what has changed, see the “What Changed” section at the bottom of this post.

Both scripts can be downloaded from my GitHub: https://github.com/ConfigJon/ConfigMgr-Scripts

Requirements

Both scripts share the same basic requirements:

  • Run on a computer with the Configuration Manager Admin Console installed. The scripts automatically locate the ConfigurationManager.psd1 file, import it, and connect to the specified site.
  • Run as a user account with rights to connect to the site and create (or delete) collections.
  • The removal script additionally queries the SMS Provider directly over WMI (using DCOM, the same way the console does), so the account also needs WMI access to the root\SMS\site_<SiteCode> namespace on the site server. No WinRM/PowerShell remoting configuration is required.

Create-Collections.ps1

This script can be used to dynamically create user collections, device collections, and folder structure based on information in a CSV file.

The script runs in three passes:

  1. Pass 0 - Validation - Every row in the CSV file is validated before anything is created. This includes required fields, duplicate collection names, and checks that the limiting, include, and exclude collections exist (either already in Configuration Manager or elsewhere in the CSV) and are the correct collection type.
  2. Pass 1 - Creation - The collections and their console folder structure are created. Creation runs in dependency-aware rounds: a row whose limiting collection is defined later in the CSV is simply deferred and retried once that collection exists. This means row order in the CSV does not matter - an alphabetically sorted file works the same as a hand-ordered one.
  3. Pass 2 - Membership rules - The include, exclude, and query membership rules are added to the collections.

The script has 4 parameters:

  • SiteCode - (Required) - The site code of the Configuration Manager site
  • SiteServer - (Required) - The name of the primary site server, or sms provider
  • CsvPath - (Required) - The path to the CSV file containing the collection information
  • ExistingCollectionAction - (Optional) - Controls what happens when a collection in the CSV already exists and the row contains membership rules. Prompt (the default) asks interactively, AddRules adds the rules from the CSV to the existing collection, and Skip leaves the existing collection untouched. Use AddRules or Skip for unattended runs.

The CSV file has 12 columns:

  • CollectionName - (Required) - The display name of the collection.
  • CollectionType - (Required) - The type of collection to create (valid values: User or Device)
  • LimitingCollectionName - (Required) - The name of the collection to be used as the limiting collection. This can be an existing collection or another collection defined in the same CSV file, and it must be the same collection type as the collection being created.
  • FolderPath - (Optional) - The folder path where the collection is to be created. If the folder path does not exist, it will be created. If the folder path is left blank, the collection will be placed at the root of Device Collections or User Collections. (Example folder path: Applications\Required)
  • Comment - (Optional) - A comment
  • ScheduleInterval - (Optional) - The interval to be used for collection evaluation (valid values: Days, Hours, or Minutes). If left blank, no refresh schedule is created.
  • IntervalCount - (Optional) - The number of intervals between collection evaluation. The value is validated against the limits Configuration Manager allows for the chosen interval (1-31 Days, 1-23 Hours, 1-59 Minutes).
  • IncrementalUpdate - (Optional) - Used to enable incremental updates (Valid values: Yes or No)
  • IncludeCollection - (Optional) - Used to specify collections to include. Specify the name of the collection(s). If specifying multiple collections, separate the names with a semi-colon
  • ExcludeCollection - (Optional) - Used to specify collections to exclude. Specify the name of the collection(s). If specifying multiple collections, separate the names with a semi-colon.
  • QueryName - (Optional) - Name of the query rule to create
  • QueryRule - (Optional) - The query language

An example CSV file can be found along with the script on my GitHub page.

Examples

Create the collections defined in a CSV file

.\Create-Collections.ps1 -SiteCode PS1 -SiteServer cm.example.local -CsvPath "C:\Temp\Collections.csv"

Run unattended, adding the CSV membership rules to any collections that already exist

.\Create-Collections.ps1 -SiteCode PS1 -SiteServer cm.example.local -CsvPath "C:\Temp\Collections.csv" -ExistingCollectionAction AddRules

Remove-Collections.ps1

The new companion script bulk deletes collections. It has two ways of selecting what to delete:

  • CSV mode - Point the script at a CSV file with a CollectionName column. Any additional columns are ignored, which means the same CSV file used by Create-Collections.ps1 works as-is. This makes the two scripts a natural pair for lab work: build an environment from a CSV, tear it back down with the same file.
  • Folder mode - Point the script at a console folder and it deletes every collection in that folder. Add -Recurse to include subfolders, and -RemoveEmptyFolders to also delete the folders themselves once they’ve been emptied.

Collections that reference each other (limiting collections, include rules, exclude rules) can’t be deleted in an arbitrary order, so the script uses the same logic as the creation script in reverse: deletion runs in retry rounds. Each round deletes every collection that is currently deletable, and the loop continues as long as progress is being made. References between collections inside the deletion set resolve themselves automatically across rounds.

Before anything is deleted, the script queries the SMS_CollectionDependencies class on the SMS Provider and warns about any collection in the deletion set that is referenced by a collection outside the set - including the name of the blocking collection and the type of reference. Those references have to be removed by hand, so the script tells you up front which deletions are expected to fail and why, and repeats the reason at the end for anything that couldn’t be deleted.

Deleting collections in bulk can be risky, so the script has a few safety measures:

  • Built-in collections are always refused. Anything with a CollectionID starting with SMS is never deleted, no matter how it was selected.
  • Collections with active deployments are skipped unless -Force is specified.
  • A summary and confirmation prompt precede any deletion. The full list of collections to be deleted is displayed (and logged) first.
  • -WhatIf is fully supported. The script runs all of its resolution and pre-flight checks and reports what would be deleted without changing anything.
  • Folders are only removed when they are completely empty. With -RemoveEmptyFolders, any folder that still contains something (a skipped collection, a collection that couldn’t be deleted, or a subfolder outside the -Recurse scope) is left in place, along with its parent folders.
  • The exit code is 1 if anything that should have been deleted remains, so unattended runs can detect an incomplete cleanup.

The script has 8 parameters:

  • SiteCode - (Required) - The site code of the Configuration Manager site
  • SiteServer - (Required) - The name of the primary site server, or sms provider
  • CsvPath - (CSV mode) - The path to a CSV file with a CollectionName column listing the collections to delete
  • FolderPath - (Folder mode) - The console folder path, relative to the Device Collections or User Collections root, whose collections will be deleted (Example folder path: Reporting\Hardware)
  • CollectionType - (Folder mode) - Which console root the FolderPath is under (valid values: Device or User)
  • Recurse - (Optional, folder mode) - Also delete collections found in subfolders
  • RemoveEmptyFolders - (Optional, folder mode) - Remove the folder (and, with Recurse, its subfolders) once the deletions leave it empty
  • Force - (Optional) - Skip the confirmation prompt and delete collections even if they have active deployments. Required for unattended runs.

Examples

Preview what a CSV-based deletion would do without deleting anything

.\Remove-Collections.ps1 -SiteCode PS1 -SiteServer cm.example.local -CsvPath "C:\Temp\Collections.csv" -WhatIf

Delete every collection in a console folder tree and clean up the emptied folders

.\Remove-Collections.ps1 -SiteCode PS1 -SiteServer cm.example.local -FolderPath "Reporting" -CollectionType Device -Recurse -RemoveEmptyFolders

Delete the collections listed in a CSV file with no prompts (for unattended runs)

.\Remove-Collections.ps1 -SiteCode PS1 -SiteServer cm.example.local -CsvPath "C:\Temp\Collections.csv" -Force

Here’s an example of the removal script working through a folder tree. Notice the pre-flight warning correctly predicting that one collection can’t be deleted (it’s referenced by a collection outside the deletion set), the retry rounds resolving the references between the collections being deleted, and the folder cleanup leaving the folder containing the surviving collection in place:

==== Pass 2: Deletion round 1 (74 remaining) ====
...
==== Pass 2: Deletion round 4 (1 remaining) ====
Could not delete collection "CM - Primary Site Server" this round (likely still referenced). It will be retried

Deleted 73 of 74 collections in 4 round(s)
Warning - Could not delete "CM - Primary Site Server": referenced by "EP - Exclusions - Primary Site Server" (include rule). Remove those references and run the script again

==== Pass 3: Removing empty folders ====
Successfully removed the empty folder "Reporting\Windows Updates"
Successfully removed the empty folder "Reporting\BitLocker"
Successfully removed the empty folder "Reporting\Client Health"
Successfully removed the empty folder "Reporting\Operating Systems"
Successfully removed the empty folder "Reporting\Hardware"
The folder "Reporting\ConfigMgr Infrastructure" is not empty (1 collection(s), 0 subfolder(s)). Leaving it in place
The folder "Reporting" is not empty (0 collection(s), 1 subfolder(s)). Leaving it in place

Logging

Both scripts write a CMTrace-format log file to the folder the script is run from: Create-CMCollections.log and Remove-CMCollections.log. Everything shown in the console (including the full list of what was created, deleted, or skipped, and why) is also written to the log.

What changed in the 2026 update

The creation script was significantly reworked, and the removal script is entirely new. The highlights:

  • CSV row order no longer matters in Create-Collections.ps1. Collections whose limiting collection is defined later in the CSV are deferred and retried in rounds instead of failing.
  • The entire CSV is validated up front before any changes are made - missing or misspelled header columns, duplicate collection names, empty required fields, and collection type mismatches (a User collection can’t limit a Device collection, and include/exclude rules can’t cross types) are all caught in a validation pass.
  • The new ExistingCollectionAction parameter makes unattended runs possible. Previously the script always prompted when a collection already existed; now you can choose AddRules or Skip on the command line.
  • Folder path checks are cached, so a CSV that places many collections in the same folders no longer checks the path for every row. In my testing, this roughly halved the total runtime.
  • Refresh schedules are now optional and validated. ScheduleInterval and IntervalCount can be left blank, Minutes is supported as an interval, and the interval count is checked against the limits Configuration Manager actually accepts.
  • A failed folder move no longer reports a failed creation. If a collection is created but can’t be moved to its folder, the script warns, leaves it in the root, and continues processing rows that depend on it.
  • Assorted logging fixes, including a corrected CMTrace timezone bias on every line and an END log entry that is written even when the script is interrupted with Ctrl+C.
  • Remove-Collections.ps1 is new, covering everything described above: CSV and folder selection modes, dependency-aware retry rounds, blocked-by reporting from SMS_CollectionDependencies, deployment and built-in collection safety checks, -WhatIf support, and optional empty-folder cleanup.