Partilhar via


Sorting the contents of an MDT 2010 deployment share

Quite some time ago (well over a year ago – time flies) I posted a script at https://blogs.technet.com/mniehaus/archive/2008/06/20/sorting-mdt-s-lists-of-applications-task-sequences-patches-etc.aspx that described how to sort the content in an MDT 2008 distribution share.  Now that MDT 2010 has been released, it’s important to first point out that this script will not work with MDT 2010 for a variety of reasons.

Since MDT 2010 has the same behavior, showing the items in the order that they were added in Workbench, that means you are now in need of a new script.  Fortunately, this isn’t too hard to do using a PowerShell script (and a little bit of knowledge of the underlying workings of the MDT 2010 PowerShell provider).  Here’s the script (also attached in a Zip file for those interested in a simpler download):

# ***************************************************************************
#
# File:      DeploymentShareSorter.ps1
#
# Author:    Michael Niehaus
#
# Purpose:   This PowerShell script will sort the existing files and folders
#            in a deployment share.
#
#            Note that there should be no one actively adding items to the
#            deployment share while running this script, as some of the
#            operations performed could cause these items to be lost.
#
#            This requires PowerShell 2.0 CTP3 or later.
#
# Usage:     Copy this file to an appropriate location.  Edit the file to
#            change the $rootPath variable below, pointing to your
#            deployment share. (This can be a local path or a UNC path.)
#
# ------------- DISCLAIMER --------------------------------------------------
# This script code is provided as is with no guarantee or warranty concerning
# the usability or impact on systems and may be used, distributed, and
# modified in any way provided the parties agree and acknowledge the
# Microsoft or Microsoft Partners have neither accountability or
# responsibility for results produced by use of this script.
#
# Microsoft will not provide any support through any means.
# ------------- DISCLAIMER --------------------------------------------------
#
# ***************************************************************************

# Constants

$rootPath = "\\mniehaus-t61p-7\DeploymentShare$"

# Conect to the deployment share

Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction SilentlyContinue
New-PSDrive -Name DeploymentPointSorter -PSProvider MDTProvider -Root "$rootPath"

# Functions

function Sort-MDTFolderItems {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1, ValueFromPipeline=$true)] $folder
    )
    Process
    {
        Write-Host "Sort-MDTFolderItems: Processing folder $($folder.Name)"
        # Initialize the sorted array
        $sorted = @()
        # Get the list of immediate subfolders, sort by name, and add to the array
        $folderPath = $folder.PSPath.Substring($folder.PSPath.IndexOf("::")+2)
        Get-ChildItem $folderPath | ? {-not $_.PSIsContainer} | Sort Name | % { $sorted += $_.Guid }
        # If there were any items found, process them.
        if ($sorted.Count -gt 0)
        {
            # See if the list is already sorted.  If it is, we don't need to make any updates.
            $compareResults = compare-object $sorted $folder.Item("Member") -SyncWindow 0
            if ($compareResults -eq $null)
            {
                Write-Host "Already sorted."
            }
            else
            {
                Write-Host "Saving sorted list."
                # First remove all members of the list because the PowerShell provider will "optimize" the change by seeing there
                # were no items added or removed.  Then put all the members back in the sorted order.  (This is actually quite
                # dangerous to do as it could orphan the items, so we need to immediately put them back.)
                $folder.Item("Member") = @()
                $folder.Item("Member") = $sorted
            }
        }
    }
}

function Sort-MDTFolderSubfolders {

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=1, ValueFromPipeline=$true)] $folder
    )
    Process
    {
        Write-Host "Sort-MDTFolderSubfolders: Processing folder $($folder.Name)"
        # Initialize the arrays
        $sorted = @()
        $unsorted = @()
        # Get the list of immediate child folders, sorted and unsorted
        $folderPath = $folder.PSPath.Substring($folder.PSPath.IndexOf("::")+2)
        $folderList = Get-ChildItem $folderPath | ? {$_.PSIsContainer}
        $folderList | % { $unsorted += $_.Name }
        $folderList | Sort Name | % { $sorted += $_.Name }
        # If there were any subfolders found, process them.
        if ($sorted.Count -gt 0)
        {
            # See if the list is already sorted.  If it is, we don't need to make any updates.
            $compareResults = compare-object $sorted $unsorted -SyncWindow 0
            if ($compareResults -eq $null)
            {
                Write-Host "Already sorted."
            }
            else
            {
                Write-Host "Sorting folders."
                # Create the temporary folder
                $null = New-Item "$folderPath\__TEMP__" -ItemType Folder
                # Move the folders into the temporary folder
                $sorted | % { Move-Item "$folderPath\$_" "$folderPath\__TEMP__" }
                # Move the folders back
                $sorted | % { Move-Item "$folderPath\__TEMP__\$_" "$folderPath" }

                # Remove the temporary folder
                Remove-Item "$folderPath\__TEMP__"
            }
        }
    }
}

# Enumerate the folders and call the functions above to process each one

Get-ChildItem DeploymentPointSorter: -Recurse | ? {$_.PSIsContainer} | Sort-MDTFolderItems

Get-ChildItem DeploymentPointSorter: -Recurse | ? {$_.PSIsContainer} | Sort-MDTFolderSubfolders

Save this as “DeploymentShareSorter.ps1” and you are all set.  A few notes on this script:

  • This script requires PowerShell 2.0 – that’s all I use any more.
  • As provided, this will only sort one deployment share at a time, but it would be fairly simple to do multiple: just duplicate the final two lines, passing each path (e.g. DS001:) that you want to sort.
  • There is one operation in this script that is somewhat dangerous:
  •                  $folder.Item("Member") = @()
  •                 $folder.Item("Member") = $sorted
  • I would suggest avoiding adding other items (drivers, applications, etc.) to the deployment share while this script is running, because those two lines could possibly cause those new items to be lost.  They first remove all items from the current folder and then add them back again (working around an optimization in the PowerShell provider code that tries to be smart about modified items – if you took out the first line the second line would have absolutely no effect).
  • This could take a while the first time through, but it should get faster after that first time because most of the content will already be sorted.
  • Don’t use a folder name of “__TEMP__” because that’s used by the script for sorting purposes.
  • Remember to edit the value assigned to the $rootPath variable.
  • If you want to schedule this script to run using the Windows Task Scheduler, just specify an action command line of “powershell.exe -File C:\Scripts\DeploymentShareSorter.ps1” (assuming the script was saved in C:\Scripts).

DeploymentShareSorter.zip

Comments

  • Anonymous
    January 01, 2003
    Hmm, haven't seen that error before.  Does it happen every time you try?

  • Anonymous
    January 01, 2003
    Running the script for the first time and I had this error: Get-ChildItem : This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row. At C:Documents and SettingsadmjfmartelDesktopDeploymentShareSorter.ps1:143 char:14

  • Get-ChildItem <<<<  DeploymentPointSorter: -Recurse | ? {$_.PSIsContainer} | Sort-MDTFolderSubfolders    + CategoryInfo          : InvalidOperation: (:) [Get-ChildItem], RowNotInTableException    + FullyQualifiedErrorId : ExceptionCaught,Microsoft.PowerShell.Commands.GetChildItemCommand Looks like everything is fine tough.
  • Anonymous
    January 01, 2003
    Hi Mike, Nevermind.  I've managed to fix it by repairing the MDT2010 installation.  

  • Anonymous
    January 01, 2003
    A functionality that should be in MDT by default, nevertheless this blog made my day! Many thanks!

  • Anonymous
    January 01, 2003
    The comment has been removed

  • Anonymous
    July 07, 2010
    Got the same error as jfmartel, most everything was sorted, but it dies at the same spot each time. Ran a second time and got the same thing

  • Anonymous
    June 27, 2011
    I know this might be asking a lot. But is there anyway to make this work with MDT 2012 Beta 1? I have tried and it doesn't sort anything, I am guessing they changed the xml files around so they are slightly different...

  • Anonymous
    February 09, 2014
    Get-ChildItem : This row has been removed from a table and does not have any data. BeginEdit() will allow creation of new data in this row. At C:Users__apjtDesktopDeploymentShareSorter.ps1:144 char:1 + Get-ChildItem DeploymentPointSorter: -Recurse | ? {$_.PSIsContainer} | Sort-MDTF ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [Get-ChildItem], RowNotInTableException + FullyQualifiedErrorId : ExceptionCaught,Microsoft.PowerShell.Commands.GetChildItemCommand